Skip to content

feat(motion): add source-neutral generation foundation - #681

Open
yuecideng wants to merge 48 commits into
mainfrom
codex/generation-foundation
Open

yuecideng wants to merge 48 commits into
mainfrom
codex/generation-foundation

Conversation

@yuecideng

@yuecideng yuecideng commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

Add the source-neutral foundation for high-throughput expert trajectory generation.

This PR defines the shared contracts needed to combine Affordance and trajectory expansion across handwritten experts, MotionGenerator, Atomic Actions, and Task Program adapters. Runtime randomization and observation fan-out profiles are deliberately deferred until their physical and persistence owners exist. It intentionally keeps physical execution, fixed-scene restoration, candidate scheduling, and dataset persistence out of this layer.

Included

  • Add source-neutral SourceAdapter boundary with handwritten-template and MotionGenerator PlanResult adapters.
  • Add same-grid ActionPlanTemplateAdapter for explicit phase permissions.
  • Add source-neutral CandidateSpec:
    • one slot-independent candidate identity;
    • separate Affordance and trajectory provenance;
    • compatibility key and estimated execution cost;
    • post-rollout observation profiles without creating extra physical candidates.
  • Extend TrajectoryGenerationJobCfg into a reusable Generation Profile:
    • handwritten, MotionGenerator, Atomic Action, and Task Program source kinds;
    • reference-family budget;
    • Affordance proposal budget;
    • a single reference-family budget owned by scheduling;
    • FIFO or coverage-per-cost scheduling;
    • bounded in-flight execution settings.
  • Add world-frame Affordance sampling provenance for selected poses, reference poses, row IDs, and geometric success.
  • Add a same-grid ActionPlanTemplateAdapter and Atomic materialization helper.
  • Add a call-scoped Atomic plan_transform hook:
    • normal ActionPlan is validated first;
    • collector-owned transform runs once for that planning call;
    • transformed ActionPlan is validated again before execution.
  • Keep the API independent of Task Program and environment slot identity.

Deliberately excluded

  • Task Program-specific Affordance collection;
  • run-env collector routing;
  • fixed-scene host and initial-state restoration;
  • C>B candidate queues and physical slot scheduling;
  • unified EpisodeSink implementation;
  • measured rollout coordinator;
  • coverage/cost execution policy.

Those belong in the next integration layer and should reuse these contracts instead of adding a second identity or configuration protocol.

Dependencies and relationship to existing PRs

Refs #670, #591, #594, #653

Validation

  • Focused motion, expansion, Affordance, and Atomic tests: 475 passed.
  • python docs/scripts/check_api_docs.py: 2259/2259 exports documented.
  • Changed-file Black checks passed.
  • git diff --check passed.
  • Same-grid ActionPlan/template materialization is covered by focused Atomic tests; no physical/GPU rollout is claimed by this foundation PR.

Type of change

  • Bug fix
  • Enhancement
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • I have run Black on changed files.
  • I have added tests for the new contracts and call-scoped transform.
  • Public API documentation coverage is aligned.
  • Dependencies have been reviewed; no dependency changes are required.
  • The design does not add Task Program DSL or task-specific configuration.

Follow-up decision for #591 / #594

The fixed-scene host, LeRobot sink, PickUp contact validator, and Atomic Runtime execution remain deferred. They belong in the Coordinator/PhysicalExecutor layer and should consume this source adapter and CandidateSpec contract rather than be copied into the foundation.

@yuecideng yuecideng added enhancement New feature or request motion gen Things related to motion generation for robot atomic action atomic action related functionality labels Sep 23, 2026
@yuecideng
yuecideng marked this pull request as ready for review September 23, 2026 15:51
@greptile-apps

greptile-apps Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 2/5

[High risk] Adds generation profile loading and motion expansion coordination.

The PR does not appear safe to merge until slot reuse, combined-batch assignment alignment, and initial-state recording are corrected.

Fix All in CodexFindings

  1. P1 Runner remains bound to first slot ▶
  2. P1 Assignments mismatch executed recipes ▶
  3. P1 Initial recording uses old pose ▶
Fix with agent prompt
### Issue 1
embodichain/lab/sim/motion/execution.py:317-320
When successive candidates need different compatible slots, the first reservation permanently binds the shared `SingleSlotRunner` to its slot. `MultiSlotRunner` reserves a slot for each candidate, but the runner raises if a later reservation uses another slot. The valid queue cannot be drained.

### Issue 2
embodichain/lab/sim/motion/expansion/combined_runtime.py:348-351
For an uneven batch crossing a reference-family boundary, this round-robin ordering changes which recipe is assigned to each slot. The showcase still sets each row's pose and visual profile and selects its planning recipe in the original slice order. A slot can therefore be assigned one family's recipe while executing another's, so its assignment identity and terminal accounting describe the wrong episode.

### Issue 3
examples/sim/motion/repeated_pick_place_generation_showcase.py:354-357
`env.reset()` has already captured the initial observation and trajectory state when this code moves the cube to its authored family pose. The recorded first frame therefore shows the old pose, while planning and later frames use the new one, corrupting the initial state of an accepted episode.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR adds source-neutral generation contracts, candidate coordination, Task Program transforms, and a combined generation showcase. The latest changes repair several earlier findings, but:

  • Mixed-compatibility multi-slot execution can stop on a later slot reservation.
  • Uneven combined batches can execute recipes under the wrong assignment identity.
  • Applying a cube pose after reset leaves the recorded initial state stale.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  R[Candidate recipes] --> C[Combined coordinator]
  C --> S[Slot assignments]
  R --> P[Showcase row poses and profiles]
  P --> E[Physical episode]
  S --> E
  E --> D[Recorded episode]
Loading

Reviews (15) · Last reviewed commit: "refactor(generation): simplify combined ..."

Comment thread embodichain/lab/sim/atomic_actions/engine.py
Comment thread embodichain/lab/sim/atomic_actions/engine.py Outdated
Comment thread embodichain/lab/sim/atomic_actions/affordance_sampling.py
Comment thread embodichain/lab/sim/motion/expansion/source.py Outdated
Comment thread embodichain/lab/sim/motion/expansion/source.py Outdated
Comment thread embodichain/lab/sim/motion/expansion/coordinator.py
Comment thread embodichain/lab/sim/motion/expansion/coordinator.py Outdated
Comment thread embodichain/lab/sim/motion/expansion/single_slot.py Outdated
Comment thread embodichain/lab/sim/motion/expansion/single_slot.py Outdated
Comment thread examples/sim/motion/task_environment_augmentation_showcase.py
Comment thread embodichain/lab/sim/motion/expansion/coordinator.py Outdated
Comment thread embodichain/lab/sim/motion/expansion/combined_runtime.py
Comment thread embodichain/lab/sim/motion/execution.py
Comment thread embodichain/lab/sim/motion/expansion/combined.py
Comment thread embodichain/lab/sim/motion/execution.py Outdated
Comment thread examples/sim/motion/repeated_pick_place_generation_showcase.py
Comment thread examples/sim/motion/repeated_pick_place_generation_showcase.py Outdated
Comment on lines +317 to +320
if slot_id is not None and self._slot_id not in (None, slot_id):
raise RuntimeError("runner is bound to a different physical slot")
if slot_id is not None and self._slot_id is None:
self._slot_id = slot_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Runner remains bound to first slot

When successive candidates need different compatible slots, the first reservation permanently binds the shared SingleSlotRunner to its slot. MultiSlotRunner reserves a slot for each candidate, but the runner raises if a later reservation uses another slot. The valid queue cannot be drained.

Prompt To Fix With AI
This is a comment left during a code review.
Path: embodichain/lab/sim/motion/execution.py
Line: 317-320

Comment:
**Runner remains bound to first slot**

When successive candidates need different compatible slots, the first reservation permanently binds the shared `SingleSlotRunner` to its slot. `MultiSlotRunner` reserves a slot for each candidate, but the runner raises if a later reservation uses another slot. The valid queue cannot be drained.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Comment on lines +348 to +351
for offset in range(max(len(group) for group in groups.values())):
for family in groups:
if offset < len(groups[family]):
ordered.append(groups[family][offset])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Assignments mismatch executed recipes

For an uneven batch crossing a reference-family boundary, this round-robin ordering changes which recipe is assigned to each slot. The showcase still sets each row's pose and visual profile and selects its planning recipe in the original slice order. A slot can therefore be assigned one family's recipe while executing another's, so its assignment identity and terminal accounting describe the wrong episode.

Prompt To Fix With AI
This is a comment left during a code review.
Path: embodichain/lab/sim/motion/expansion/combined_runtime.py
Line: 348-351

Comment:
**Assignments mismatch executed recipes**

For an uneven batch crossing a reference-family boundary, this round-robin ordering changes which recipe is assigned to each slot. The showcase still sets each row's pose and visual profile and selects its planning recipe in the original slice order. A slot can therefore be assigned one family's recipe while executing another's, so its assignment identity and terminal accounting describe the wrong episode.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Comment on lines +354 to +357
cube.set_local_pose(
pose,
env_ids=torch.arange(batch_size, device=env.unwrapped.device),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Initial recording uses old pose

env.reset() has already captured the initial observation and trajectory state when this code moves the cube to its authored family pose. The recorded first frame therefore shows the old pose, while planning and later frames use the new one, corrupting the initial state of an accepted episode.

Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/sim/motion/repeated_pick_place_generation_showcase.py
Line: 354-357

Comment:
**Initial recording uses old pose**

`env.reset()` has already captured the initial observation and trajectory state when this code moves the cube to its authored family pose. The recorded first frame therefore shows the old pose, while planning and later frames use the new one, corrupting the initial state of an accepted episode.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

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

atomic action atomic action related functionality enhancement New feature or request motion gen Things related to motion generation for robot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant