Skip to content

Fix generic action contracts for locomotion policies - #698

Open
yuecideng wants to merge 3 commits into
mainfrom
codex/fix-generic-action-contracts
Open

yuecideng wants to merge 3 commits into
mainfrom
codex/fix-generic-action-contracts

Conversation

@yuecideng

Copy link
Copy Markdown
Contributor

Description

This PR decouples persisted policy action semantics from concrete ActionManager Python class names and migrates the official locomotion configurations to generic versioned action contracts.

It adds the generic joint_position.default_offset@1 contract and the built-in action contract registry, records contract IDs in action descriptors, binds locomotion state through the contract, and keeps legacy pretrained bundles containing DefaultJointPositionTerm loadable. The six velocity locomotion tasks now use the stable contract in both Default and Newton deployments. Documentation and project context describe the new configuration and migration behavior.

Issue: no issue number was provided.

Dependencies: none.

Type of change

  • Bug fix (non-breaking change which fixes an existing functionality)
  • Enhancement (non-breaking change which improves an existing functionality)
  • New feature
  • Breaking change
  • Documentation update

Screenshots

Not applicable. Viewer smoke tests were run for all 12 official pretrained velocity policy bundles.

Validation

  • 207 passed targeted gym/action/config tests.
  • Gym and policy evaluation test group completed with exit code 0.
  • All 6 Default and 6 Newton pretrained velocity bundles completed a one-control-step Viewer smoke test. Newton runs used --sim-device gpu; Newton ContactSensor is not supported on CPU.
  • python docs/scripts/check_api_docs.py — 2295/2295 exports documented.
  • black . and git diff --check passed.
  • context.py check passed.

Checklist

  • I have run the black . command to format the code base.
  • I reviewed affected documentation and agent context, updated them where needed.
  • Public API changes are reflected in the API docs.
  • I have added tests that prove my fix is effective or that my feature works.
  • Dependencies have been updated, if applicable.

Persist generic versioned action contracts in locomotion configurations and resolve them through the current ActionManager implementation registry. Migrate legacy pretrained bundles, update locomotion bindings and documentation, and validate all default and Newton policy examples.
@yuecideng yuecideng added bug Something isn't working enhancement New feature or request docs Improvements or additions to documentation gym robot learning env and its related features rl Features related to reinforcement learning labels Sep 26, 2026
@yuecideng
yuecideng requested a review from acrlw September 26, 2026 17:16
@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium risk] Adds versioned action contracts to locomotion policies.

The PR is not ready to merge because failed USDZ packaging can leave inconsistent scene artifacts and exported articulations can receive incorrect textures.

Summary

The PR introduces versioned action contracts for locomotion and legacy policy-bundle loading. Changes since the previous review also add physical-objective evaluation, trajectory and dataset recording paths, configurable asset downloads, and Scene USD export and preview. The Scene USD delivery path needs attention to artifact consistency and articulation textures.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Export[Scene export] --> USDA[Publish scene.usda]
  USDA --> USDZ[Package scene.usdz]
  USDZ -->|success| Delivery[Matching delivery artifacts]
  USDZ -->|failure caught| Stale[New USDA and previous USDZ]
Loading

Reviews (2) · Last reviewed commit: "fix(rl): address generic action contract..."

Comment thread embodichain_tasks/embodichain_tasks/locomotion/velocity/_embodichain.py Outdated
Comment thread embodichain/lab/gym/envs/managers/action_manager.py
Comment thread embodichain/lab/gym/utils/gym_utils.py
Comment on lines +63 to +65
def resolved_contract_id(self) -> str | None:
"""Return the configured contract or the implementation's stable ID."""
return self.cfg.contract or self.contract_id

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Validate configured contracts against the action implementation

With ActionTermCfg(func=JointVelocityAction, contract="joint_position.absolute@1", ...), the manager instantiates JointVelocityAction and writes qvel, but this method labels it as an absolute-position action. The built-in descriptor copies the same overridden ID, so the new descriptor mismatch check accepts it, and get_term_by_contract() returns the velocity action for the position contract. A CPU probe confirmed the incorrect metadata and the call to set_qvel().

The same fields passed through config_to_cfg() instead select JointPositionAction, so Python and YAML configurations disagree on which command to execute. Please resolve or validate func and contract consistently at the shared initialization boundary, and add a regression test that checks the declared contract against the actual command written to the robot.

Comment on lines +923 to +924
if term_contract is None and isinstance(term_class_name, str):
term_contract = _LEGACY_ACTION_CONTRACTS.get(term_class_name)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Preserve legacy clipping semantics when migrating saved actions

All 12 published locomotion snapshots inspected here contain DefaultJointPositionTerm with params: {}. The legacy implementation treated an omitted or null clip as unbounded, whereas DefaultJointPositionAction defaults to clip=1.0. This migration changes the implementation without translating that default.

A CPU comparison with action 2.0, offset 0.2, and scale 0.5 produces a joint target of 1.2 before migration and 0.7 afterward; the stored action also changes from 2.0 to 1.0. Thus, outputs outside [-1, 1] change both control targets and action-history observations. An explicit legacy clip: null instead fails at float(None). Please preserve the legacy omitted/null behavior during migration and test numerical outputs and history buffers; the added test currently checks only the resolved class and contract ID.

Comment on lines +256 to +258
action_term = self.action_manager.get_term_by_contract(
"joint_position.default_offset@1"
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Preserve binding for existing custom locomotion actions

An existing configuration can provide a custom ActionTerm named joint_position with the required raw_actions, previous_raw_actions, and position_bias buffers, without declaring a contract ID. Such a term still passes ActionManager initialization because contract IDs remain optional, but this lookup now raises KeyError and prevents environment construction. A CPU probe using the same custom term confirmed that the previous name-based binding succeeds and the new binding fails.

The constructor still locates joint_position by name to inject joint order, offset, and scale. Please retain a validated compatibility path for that existing named term, or provide an explicit migration mechanism for custom implementations, and add a regression test covering initialization without a contract ID.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working docs Improvements or additions to documentation enhancement New feature or request gym robot learning env and its related features rl Features related to reinforcement learning

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants