Skip to content

Centralize numeric range validation - #494

Merged
kstonekuan merged 4 commits into
Hebbian-Robotics:mainfrom
Kaileshwar16:refactor/numeric-field-guards
Sep 10, 2026
Merged

kstonekuan merged 4 commits into
Hebbian-Robotics:mainfrom
Kaileshwar16:refactor/numeric-field-guards

Conversation

@Kaileshwar16

Copy link
Copy Markdown
Contributor

Adds shared numeric guards for finite-value and bounds validation, then uses them in build_ai_vlm_checks.py and batching.py.

This removes duplicated bool checks and standardizes numeric validation errors while preserving existing valid-input behavior, including batching's support for fractional values.

catalog.py remains unchanged.

Validation

  • uv sync --locked --all-extras
  • uv run ruff check
  • uv run ruff format --check
  • uv run ty check
  • uv run pytest -q1,780 passed, 7 skipped
  • Verified that disabling each of the seven new guards causes a caller test to fail.
  • Confirmed there are no remaining inline bool guards in either target file.

Closes #487

@kstonekuan kstonekuan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard set and composition are right, and require_non_negative_real keeps batching's numbers.Real contract rather than narrowing it.

Three conversions are not. Every place you needed a cast or a try/except is a place the guard does not belong: :366, :520, :789 are the only bool sites in that file outside a __post_init__, and all three parse an external model response. _field_guards says it is for caller-constructed configuration.

The cost shows in your own test edit: parse_hand_count_response("two") went from "hand count must be 0, 1, or 2" to "must be an int, got str". The second is a fact about Python types; the first is the contract a model failed.

Revert those three, keep the ten. Separately, have require_int return the value instead of None and the remaining seven casts go away.

@Kaileshwar16

Copy link
Copy Markdown
Contributor Author

Got it, thanks fir review @kstonekuan , I reverted the three response-handling sites and updated the guards to return the narrowed value so the casts are gone. Pushed the changes

Deleting that guard left the whole suite green, so it gets a case: 1 and 0
are the rows that matter, since they compare equal to True and False.

Reverts type(x) is not bool to isinstance. bool cannot be subclassed, so the
two are equivalent here, and isinstance is the idiom everywhere else in the
tree including the guards this PR adds.

@kstonekuan kstonekuan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, merging.

Casts gone entirely, and the three response sites are byte-identical to main.

Pushed one commit: skip_black_frames was the only guard left unheld, and type(x) is not bool went back to isinstance (bool cannot be subclassed, so they are equivalent).

@kstonekuan
kstonekuan merged commit c22cefe into Hebbian-Robotics:main Sep 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

_field_guards covers the type half only, so 49 sites hand-roll the bool guard and 7 issues have been the same bug

2 participants