Repository navigation
Reject wrongly shaped params in ParameterizedOption.ground - #205
Open
yichao-liang wants to merge 3 commits into
Open
yichao-liang wants to merge 3 commits into
yichao-liang wants to merge 3 commits into
Conversation
State.pretty_str() reads CFG.excluded_objects_in_state_str, a setting that predicators/args.py defines and only reset_config() sets. Tests that format a state without calling reset_config() themselves passed only when an earlier test in the same process had called it: alone, tests/test_structs.py errored in 5 tests and tests/agent_sdk/test_bilevel_sketch_samplers.py failed test_refine_and_validate_report_returns_plan. A session-scoped autouse fixture in tests/conftest.py now calls reset_config() once before the first test.
ops_and_specs_to_dummy_nsrts gave every NSRT the dummy sampler np.zeros(1), whatever its option's params, and relied on the np.clip before grounding to broadcast that to the option's shape (to no params for the PDDL options of test_llm_open_loop_approach). Its samplers now return zeros of each option's params shape. With legacy options, PickJug takes no params, yet the Grow, Boil and Coffee pick process samplers returned a grasp offset, which that clip also broadcast away. They now return no params with legacy options, as the place and push samplers already do. Coffee's TwistJug process used null_sampler, although TwistJug takes a twist amount when coffee_twist_sampler is on (the default). It grounded only because ground()'s bounds fallback passed empty params vacuously. It now draws the amount as the TwistJug NSRT's sampler does. The new test checks that every endogenous process of Grow, Boil and Coffee, with skill-factory and legacy options, samples params of its option's shape.
When params_space.contains() failed, ground() fell back to a float-tolerance bounds check that ignored the shape. Empty params passed it vacuously for a one-parameter space, so Grow's oracle grounded the skill-factory PickJug with no params and crashed later in _descend_pose reading params[0]. ground() now raises a ValueError naming the option, the received shape and the expected shape whenever they differ, after the default_params substitution. The NSRT and endogenous-process sample_option() clipped sampled params with np.clip before grounding, which broadcasts: it dropped a value meant for a parameterless option, copied one value into every entry of a larger space, and raised a bare broadcast error for empty params and a four-parameter space (Coffee's PlaceJugInMachine). They now clip only correctly shaped params and leave the rest for ground() to reject.
yichao-liang
force-pushed
the
ground-params-shape-check
branch
from
October 3, 2026 08:30
eeca216 to
1c8b708
Compare
8 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ParameterizedOption.groundnow raises a clearValueErrorwhen the params' shape differs from the params space's shape, for exampleCannot ground 'PickJug': params [] have shape (0,), expected shape (1,).Why. When
params_space.contains(params)failed,groundfell back to a float-tolerance bounds check (added in #57) that never looked at the shape.Empty params for a one-parameter space passed it vacuously (
np.allover no values isTrue), so the option was grounded with no params and failed later.This is how Grow's
oraclecrash got through grounding before #201 fixed its samplers: the NSRT'snull_samplergave the skill-factoryPickJugno params, andpick.py's_descend_poseraised anIndexErrorreadingparams[0].For a space with more than one entry, the bounds comparison raised a bare broadcast error instead.
The sampler path had the same hole.
_GroundNSRT.sample_optionand_GroundEndogenousProcess.sample_optionclip sampled params withnp.clip(params, low, high)before grounding, andnp.clipbroadcasts.It turned a
(1,)sample into(0,)for a parameterless option and copied one value into all four params of a(4,)space.For empty params and a
(4,)space it raised theoperands could not be broadcast together with shapes (0,) (4,) (4,)error seen with Coffee'sPlaceJugInMachine, beforegroundwas even called.Both now clip only correctly shaped params (
_clip_sampled_params) and pass anything else toground, which rejects it.default_paramssubstitution for empty params is unchanged, soWaitoptions still ground from[].Callers that relied on the old behavior, found by the full suite and by a sampler-shape audit over every ground-truth NSRT and endogenous process (default config and each env's legacy options), now fixed:
utils.ops_and_specs_to_dummy_nsrtsgave every NSRT the dummy samplernp.zeros(1)and relied on the clip to reshape it;test_llm_open_loop_approachgrounded its parameterless PDDL options through it.Its samplers now return zeros of each option's params shape, which the clip turns into the same values as before.
[x]even with legacy options, whosePickJugtakes no params; the clip used to drop it silently.They now return
[]with legacy options, as their place and push samplers already do.TwistJugprocess usednull_sampleralthoughTwistJugtakes a twist amount whencoffee_twist_sampleris on (the default); it passed only through the vacuous check.It now draws the amount as the
TwistJugNSRT's sampler does.Left as is. On top of #201, which fixed the Grow and Coffee NSRT samplers, the audit finds only legacy Grow's
Place(withgrow_use_skill_factoriesoff) still sampling the wrong shape.Its
PlaceJugOnTableprocess gives[]to the two-parameterPlace, and withgrow_place_option_no_sampleron, itsPlaceJugNSRT gives[x, y]to the parameterless one.Both already raised broadcast errors on master and now raise the clear error; legacy Grow does not plan on master in either mode.
LinearChainParameterizedOption's consistency check has the same hole (np.allcloseon(0,)and(1,)bounds passes), and Coffee's combinedTwistchain relies on it, so it is left for a separate change.Test isolation fix.
pytest tests/test_structs.pyon its own errored in 5 tests, andtests/agent_sdk/test_bilevel_sketch_samplers.pyon its own failedtest_refine_and_validate_report_returns_plan.State.pretty_str()readsCFG.excluded_objects_in_state_str, anargs.pysetting that exists only after areset_config()call, so these tests passed only when an earlier test in the process had called it.A session-scoped autouse fixture in
tests/conftest.pynow callsreset_config()once before the first test.Test plan
test_option_ground_rejects_wrong_params_shape(theBox(0, 0.1, (1,))option grounded withnp.array([]), plus(4,),(1, 1)and scalar cases, parameterless options anddefault_params) failed on master and passes here.test_sample_option_rejects_wrong_params_shapecovers NSRTs and endogenous processes: wrong shapes raise, correct shapes are still clipped, empty params still takedefault_params.423cae0c1), split round-robin by test file into 16 jobs in CI's Ubuntu 24.04 container: 2546 passed, 0 failed (4030 skipped, 14 xfailed, 4 xpassed).The first run, with only the
groundcheck, found the order-dependenttest_bilevel_sketch_samplersfailure (also on master); the second foundtest_llm_open_loop_approach(the dummy samplers).test_process_samplers_match_option_params(Grow, Boil and Coffee, skill-factory and legacy options) fails on master in exactly the four fixed cases and passes here.main.py --approach oracleandoracle_process_planning, seed 0, one task, 60 s) on Grow and Coffee ends as on master423cae0c1: Grow's oracle times out in refinement and its process planning solves 1/1; Coffee fails oncup0's pose with both.864ed48c7), Grow'soracleraisedIndexErrorin_descend_pose; with this change it stopped at grounding withCannot ground 'PickJug': params [] have shape (0,), expected shape (1,).🤖 Generated with Claude Code