Skip to content

fix(policies/wbc): allow_missing_models is checked, not read by truthiness - #3574

Merged
cagataycali merged 2 commits into
strands-labs:mainfrom
cagataycali:fix/wbc-allow-missing-models-checked
Sep 13, 2026
Merged

cagataycali merged 2 commits into
strands-labs:mainfrom
cagataycali:fix/wbc-allow-missing-models-checked

Conversation

@cagataycali

@cagataycali cagataycali commented Sep 13, 2026

Copy link
Copy Markdown
Member

What

WBCPolicy.__init__ refuses a non-boolean allow_missing_models at construction with boolean_flag_error - the domain the same signature already applies to walk - placed before the ONNX load the flag gates.

Why

Two posture flags in one signature: walk was checked and allow_missing_models beside it was read by if not allow_missing_models. Every non-empty string is truthy, so the spelling a JSON policy_config reaches for to ask for the eager load selected the test seam instead.

Measured on fb159ba:

allow_missing_models constructed sessions loaded truthy
"false", "False", "no", "off", "0", "none" yes no True
1.5 yes no True
None, 0, [] reached the loader (RuntimeError, onnxruntime absent) - False

The "false" caller then reads, at the first get_actions:

WBCPolicy has no ONNX session loaded. Construct with a valid checkpoint
(allow_missing_models=False), or construct with allow_missing_models=True and ...

which advises the value they believe they passed. That is the refusal-inherits-the-inversion shape the posture-flag rule in AGENTS.md names: the branch is reachable only where its advice is not actionable. WBCGaitPolicy forwards the flag to super().__init__, so it had the same reading and the one check covers both providers.

Four corners

tests/policies/wbc/test_allow_missing_models_is_checked_not_read_by_truthiness.py, 21 cells. The refused set is derived from boolean_flag_error itself rather than copied.

tests production result
pre pre 751 passed (wbc suite + shared posture grader)
new pre 16 failed, 5 passed
new new 21 passed
pre new 751 passed - no pre-existing cell moved

The 5 that pass on both trees are the over-reach controls: True / np.bool_(True) still skip the load, False / np.bool_(False) still reach it. The 16 are the 13 non-boolean values, the verbatim-wording cell, the ordering cell (a falsy 0 is refused by name rather than reaching the loader), and the gait-variant cell.

Not a row in tests/policies/test_posture_flags_are_checked_not_coerced.py on purpose: its table asserts the value is stored, and this flag is consumed inline - storing it would add an attribute with no reader.

Gate

check result
ruff check + ruff format --check on touched files clean
mypy on policy.py + the new test no issues
tests/policies/wbc/ + shared posture grader 772 passed, 6 failed - the 6 are Gr00tPolicy rows needing pyzmq, byte-identical on main
tests/test_changelog_fragments.py 28 passed
whole-tree grader roster (141 graders, --continue-on-collection-errors) 4187 passed, 63 failed, 153 errors - all 216 byte-identical node ids on main fb159ba, every one an absent extra (lerobot, awsiot, torch, serial, psutil, mujoco); 0 name wbc

Overlap

check_merge_base_overlap.py --paths names #3343 on policy.py. Its hunk is the _extract_state docstring at 601-618; this one is __init__ at 230-240 and the class docstring. Disjoint, merge-order only.

Cost

Production: +2 executable statements, a comment, two docstring sentences. Tests: +1 file (21 cells). Docs: +7 in docs/policies/wbc.md beside the parameter block that shows the flag. Fragment: changelog.d/3574-wbc-allow-missing-models-checked.md, pushed while still a draft so no approval can be dismissed by it.

Auto-merge (squash) armed.

Round log

  • round 0: opened as draft, fragment pushed, whole-tree gate attributed, marked ready.

…iness

WBCPolicy.__init__ checked `walk` with boolean_flag_error and read
`allow_missing_models` beside it by truthiness. Every non-empty string is
truthy, so "false" selected the test seam: no ONNX session was loaded,
construction succeeded, and the missing checkpoint surfaced at the first
get_actions as a refusal advising allow_missing_models=False - the value
the caller believed they had passed. None, 0 and [] took the loading
branch while spelling neither posture.

The check sits on the base class only, ahead of the load it gates.
WBCGaitPolicy forwards the flag to super().__init__, so one site covers
both providers.
@cagataycali
cagataycali marked this pull request as ready for review September 13, 2026 00:32
@cagataycali
cagataycali enabled auto-merge (squash) September 13, 2026 00:32

@yinsong1986 yinsong1986 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.

Summary

Applies the AGENTS.md posture-flag rule ("Posture flags are checked, never read by truthiness") to the second flag in WBCPolicy.__init__: allow_missing_models is now refused at construction via the shared boolean_flag_error domain, placed before the ONNX load it gates, exactly as walk already is in the same signature. The registry exposes allow_missing_models as a config_keys entry for both wbc and wbc_gait, so the JSON-string spelling the fix targets is a reachable input, and WBCGaitPolicy forwards the flag to super().__init__ so the one check site covers both providers. The only remaining truthiness read of the flag (if not allow_missing_models at the load site) now sees a guaranteed boolean. Independently verified at 777ad866: the new 21-cell test passes on the head and reports the claimed 16 failed / 5 passed when run against pre-fix production at the merge base fb159ba; the pre-existing wbc suite plus the shared posture grader (869 tests) is green; the xref/Raises/Args/ASCII/changelog graders (638 tests) are green; ruff check and ruff format --check are clean on the touched files. All in-tree callers pass real booleans, so nothing regresses; the only behaviour change is an explicit ValueError on values that previously selected a posture the caller did not spell, with the Raises: block updated to match.

What's good

  • Refused set is derived from boolean_flag_error itself rather than copied, so the test tracks the shared domain without edits.
  • Over-reach controls pin both boolean postures (True/np.bool_(True) still skip the load; False/np.bool_(False) still reach it and fail loudly).
  • Verbatim-wording cell keeps this flag and walk on one refusal owner, and the ordering cell pins the check ahead of the loader.
  • Changelog fragment named with the PR number and pushed while still a draft; docs updated beside the parameter block that shows the flag.

@cagataycali
cagataycali merged commit df1ea2a into strands-labs:main Sep 13, 2026
14 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.

2 participants