Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion agent_context/MAP.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,25 @@ topics:
tests/lab/task_program/, tests/lab/task_program/semantics/]
related_topics: [atomic-actions, env-framework, simulation-system, motion-planning, sensor-system, data-pipeline]
status: active
- id: task-spec
title: TaskSpec Semantic Protocol
aliases: [TaskSpec, TaskTemplate, 任务语义协议, 任务模板身份]
keywords: [SceneInstance, ActionWitness, ExpansionManifest, ValidationCertificate, legacy_plan_hash,
certificate_passed, canonical_template, scene_instance_hash]
paths: [topics/task-spec/task-spec.md]
source_of_truth:
- embodichain/task_spec/contracts.py
- embodichain/task_spec/validation.py
- embodichain/task_spec/expressions.py
- embodichain/task_spec/canonicalization.py
- embodichain/task_spec/registry.py
- embodichain/lab/task_evaluation.py
- embodichain/compute/task_predicates.py
- embodichain/gen_sim/task_engine/_task_spec.py
watch_paths: [embodichain/task_spec/, tests/task_spec/, embodichain/lab/task_evaluation.py,
embodichain/compute/task_predicates.py, tests/lab/test_task_evaluation.py]
related_topics: [gen-sim, task-programs]
status: active
- id: gen-sim
title: Gen Sim
aliases: [gen sim, Scene Engine, SimReady, scene generation, scene editing, 场景生成, 场景编辑, 生成式仿真]
Expand All @@ -256,8 +275,11 @@ topics:
- embodichain/gen_sim/simready_pipeline/pipeline/ingest.py
- embodichain/gen_sim/gradio_ui/app_processes.py
- embodichain/gen_sim/gradio_ui/app_env.py
- embodichain/gen_sim/task_engine/semantic_planner.py
- embodichain/gen_sim/task_engine/semantic_graph.py
- embodichain/gen_sim/task_engine/task_program_bundle.py
watch_paths: [embodichain/gen_sim/, embodichain/cli/main.py, tests/gen_sim/]
related_topics: [simulation-system, data-assets, env-framework]
related_topics: [simulation-system, data-assets, env-framework, task-spec]
status: active
- id: data-assets
title: Data Assets
Expand Down
11 changes: 11 additions & 0 deletions agent_context/topics/atomic-actions/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ Held-object guards and phase-effect gates are observational:
- gates can hold a named plan segment until evidence proves a transition; and
- neither mechanism creates constraints, freezes objects, or overwrites poses.

`HeldObjectGuardResult.pending_mask` can hold the shared command cursor while
an invariant remains unresolved. Pending rows cannot overlap failed rows and
must belong to the active request. The runner issues an observed hold and polls
fresh evidence; unresolved results past the request deadline are rejected.
Omitting the mask preserves the historical loss-only guard contract.

Pick gates attachment before lift. Place gates detachment before retract.
HandOver owns independent source/destination transfer boundaries.

Expand All @@ -105,6 +111,11 @@ Scene-relative goals declare the exact entity poses they consume. The session
compares dependency revisions against fresh snapshots and replans only within
the selected `RecoveryPolicy`.

A failed initial empty plan owns no command targets or feedback routes; its
first successful retry may establish both. Once established, runtime target
addresses and tracking source/projector ownership remain fixed across recovery.
An intervening empty failed replan does not erase that ownership.

`PlanningContext.control_dt` is the authoritative control grid. Every emitted
trajectory or endpoint command must align to it; integrations must not silently
resample fractional durations.
Expand Down
6 changes: 6 additions & 0 deletions agent_context/topics/env-framework/env-framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ dataset persistence are separate contracts; see
[Task Programs](../task-programs/task-programs.md) and
[data pipeline](../data-pipeline/data-pipeline.md).

`execute_demo_episode(final_acceptance=...)` optionally lets the host freeze
whole-task evidence after segments/cleanup and before episode metadata is
finalized. It requires an exact per-row boolean tuple and only rejects existing
program success; the callback must not step, reset or persist dataset samples.
The caller still owns the eventual save/reset transaction.

## Change sites and focused validation

| Change | Validation surface |
Expand Down
16 changes: 16 additions & 0 deletions agent_context/topics/gen-sim/gen-sim.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ Edit: import export → validate graph/typed edit plan → generate additions
Read [pipeline details](pipeline-details.md) for stage contracts, parser resume
behavior, Gradio artifact ownership and focused failure diagnosis.

Task Engine lives in `task_engine/`: TaskAgent produces legacy candidates,
SemanticTaskPlanner expands E1–E5 recipes into candidate graphs, and
`task_program_bundle.py` composes the Task Program deployment. Explicit
TaskSpec template/instance inputs to the planner produce graph/v2 provenance;
the existing no-TaskSpec path remains graph/v1. v2 bundle export/execution stays
gated on measured instance/witness qualification. CLI `--task-template` provides
a bounded E2 observed-goal acceptance route using a strict sidecar with
fingerprint/v3, a legacy executable graph and a pre-metadata Gym final hook.
It does not claim full certification. CLI defaults to dual_franka and rejects
other executable profiles before generation. Preparation invokes the existing
FeasibilityBroker on a static manifest; unknown/runtime-probe results skip the
static feasibility stage instead of claiming successful physical validation.
Follow
[TaskSpec](../task-spec/task-spec.md) for semantic identity, evidence and the
current qualification boundary.

## Durable scene boundary

The `scene_export/` directory contains `scene.json`, `scene_config.json`,
Expand Down
20 changes: 20 additions & 0 deletions agent_context/topics/task-programs/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,26 @@ its call ID, revision, and target Atomic Skill descriptor. Use this extension
to expose shared Atomic Skills; do not place task-local motion generators in a
lowerer.

Registered lowerers can declare a typed `RegisteredPhaseProtectionKind` and
return a matching `RegisteredPhaseProtection` from `SemanticLowering`.
The compiler checks effect ownership and binds the declared endpoint/object
through the preset's existing measured-effect monitor. Acquisition gates motion
on attachment and guards subsequent held phases; release guards the input hold
and gates retreat on detachment. Release gates omit terminal geometric separation,
which can only be observed after retreat. Retention guards verified task state
without adding a terminal effect or changing symbolic-state ownership. Guard-only
and registered calls validate their declared segment names against each active
plan before dispatch. Guard-only retention requires affirmative current evidence:
unavailable or not-yet-stable evidence holds the command cursor while the existing
consecutive-sample policy accumulates fresh observations. Reaching the action
deadline fails the call and removes the stale held relation. Projected presets
do not install measured protections.

GenSim registered Pick and relative Place use these phase declarations. Its
configured held-move service opts in with
`phase_protection: held_object_v1` and a matching monitor mapping; omitted
configuration keeps legacy exported bundles on their existing behavior.

## MLLM boundary

`embodichain.agents.mllm.task_program` accepts untrusted JSON, reuses the
Expand Down
73 changes: 73 additions & 0 deletions agent_context/topics/task-spec/task-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# TaskSpec semantic protocol

`embodichain/task_spec/` owns pure JSON task meaning, canonical task identity
and content/evidence references. It depends only on the standard library.
It does not own LLM calls, scene creation, check execution, simulation
lifecycle, retries, dataset submission or persistence.

## Owning entry points

- `validation.py` validates template fields, role references and capability
vocabulary; `expressions.py` validates bounded predicate AST and quantities.
- `registry.py` returns a detached semantic-version/predicate-revision snapshot.
This declares semantics, not installed checkers or Semantic Calls.
- `canonicalization.py` canonicalizes roles, inverse relations and SI units.
Top-level self hash is excluded; unknown execution fields are rejected.
- `contracts.py` validates the five records, computes exact instance content
identity, checks optional template/instance owners and applies certificate
required-check acceptance. URI/digest references are not resolved here.

Template v0.1 permits six roles, 128 predicate occurrences and depth 16.
Canonical quantity values are exact decimal strings; accepted units are
m/cm/mm, s/ms and rad. Role relabeling is independent of spelling/order,
including equal role declarations. Temporal sequence order remains normative.
These are restricted equivalences, not arbitrary formula equivalence.

SceneInstance owns grounded roles, assets, scene/embodiment and observed
initial-state references. Instance roles are canonical IDs; use
`canonical_role_map` to rekey author grounding and evaluate the corresponding
`canonical_template`. This prevents ambiguous physical meaning under role
alpha-renaming. ActionWitness owns graph/program/integration/policy/
constraints and execution evidence; candidate execution is null. Existing
integration_fingerprint is reused. Certificate checks bind template, instance,
witness and one env/episode, with explicit versions, metrics and evidence.
Missing/not_run/unavailable/unsupported/failed required checks do not pass.
Hosts must verify evidence content before accepting report statuses.

## GenSim boundary

`SemanticTaskPlanner.plan(task_template=..., scene_instance=...)` consumes
paired explicit inputs and emits a candidate `semantic_task_graph/v2`.
It verifies physical-object bindings and records template_hash, instance_hash
and legacy_plan_hash. The existing recipe remains a proposed solution and
does not redefine or prove the normative goal.

Without TaskSpec inputs, TaskCandidate and graph/v1 behavior is unchanged.
`task_program_bundle.py` and `_bundle_runner.py` refuse v2 export/execution
until measured instance/witness evidence qualification exists.

An independent opt-in E2 acceptance route passes an explicit template through
CLI `--task-template`, Workflow and bundle generation. It keeps graph/v1 as the
executable recipe and writes a strict template/binding sidecar referenced by
fingerprint/v3. `lab/task_evaluation.py` accepts only one local-+Z upright goal
and optional initially-not-upright constraint; other requirements fail early.
`compute/task_predicates.py` owns shared angle measurement. GenSim stability
policies derive their upright threshold from the explicit template.

The runner captures actual reset/settled poses and refuses invalid, unavailable
or trivial initial batches. Its final hook evaluates simultaneous final poses
after cleanup and before Gym metadata/commit/reset. Program and task results
are separate. The host owns evidence files, not the evaluator. The result is
observed-goal-only with certificate_status=unavailable: it does not construct
a qualified SceneInstance/ActionWitness or assert asset/whole-process/robustness
certification. TaskAgent migration, template-derived scene generation, other
predicate checkers, Workflow certificates and expansion hosting remain future
work. See [GenSim](../gen-sim/gen-sim.md).

## Focused validation

Run `tests/task_spec/` for identity, schema, quantity and evidence boundaries.
Run `tests/gen_sim/task_engine/test_task_spec_planning.py` and existing
`test_agent.py`/`test_semantic_graph.py` for the paired planning entry,
graph versions and legacy compatibility. These CPU tests do not certify
physical rollout or installed predicate observers.
8 changes: 8 additions & 0 deletions docs/source/api_reference/public_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2176,3 +2176,11 @@ embodichain_tasks.utils.importer
.. autosummary::

import_packages
.. toctree::
:hidden:

task_spec
.. toctree::
:hidden:

task_evaluation
17 changes: 17 additions & 0 deletions docs/source/api_reference/task_evaluation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Task observation evaluation
===========================

These measurements and evaluators do not own simulation stepping, reset,
retries or persistence. The initial implementation qualifies instantaneous
local-+Z upright observations only; process and unsupported requirements are
rejected explicitly, and invalid pose rows are unavailable rather than passing.

.. autosummary::

embodichain.compute.task_predicates.axis_tilt
embodichain.lab.task_evaluation.UprightTaskEvaluator

.. autofunction:: embodichain.compute.task_predicates.axis_tilt

.. autoclass:: embodichain.lab.task_evaluation.UprightTaskEvaluator
:members:
78 changes: 78 additions & 0 deletions docs/source/api_reference/task_spec.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
TaskSpec semantic contracts
===========================

TaskSpec v0.1 separates normative task identity from grounded instances and
candidate or executed solutions. All decoders return detached JSON records,
reject unknown fields and avoid simulator, execution and filesystem ownership.

Task identity includes roles, initial/final conditions, invariants, explicit
temporal sequences and capability requirements. It excludes concrete assets,
robots, plans and trajectories by rejecting them at the template boundary.
Canonical quantities use exact decimal strings in SI units; supported units are
m/cm/mm, s/ms and rad. Role renaming, inverse spatial relations and commutative
sorting are supported; arbitrary logical equivalence is not.

A certificate is a report record, not a verifier. Required checks must exist
and pass with matching input identities, checker/predicate versions and
evidence references. Hosts must verify referenced content and observations.
Unavailable/not-run/unsupported checks cannot be accepted as passes.

Public package interface
------------------------

.. automodule:: embodichain.task_spec
:members:
:imported-members:

Canonicalization
----------------

Templates are bounded to six roles, 128 predicate occurrences and logical depth
16. Canonicalization compares all relabelings within equal role declarations,
preserving normative temporal order. The stored semantic hash is excluded only
at the top level, so hashing an already sealed template is stable.

.. automodule:: embodichain.task_spec.canonicalization
:members:

Records and acceptance
----------------------

Instances own grounded asset/component and observed initial-state references.
Instance bindings use canonical role IDs, obtained through canonical_role_map,
and checkers consume canonical_template against these bindings. Author labels
cannot be used directly: equivalent templates may permute their meanings.
Witnesses own program/integration/policy/constraint and execution references.
An expansion records lineage and invalidated checks without scheduling them.
A certificate binds checks to one template, instance, witness and episode.

.. automodule:: embodichain.task_spec.contracts
:members:

Expression and vocabulary boundaries
-------------------------------------

Predicate quantities are explicit, dimensional and nonnegative except signed
revolute-joint positions. The coordinate convention is scene +X right, +Y front,
+Z up. The vocabulary describes bounded geometry and attachment observations;
it does not assert installed evaluators, liquid transfer, force support or
continuous-contact proof.

.. automodule:: embodichain.task_spec.expressions
:members:

.. automodule:: embodichain.task_spec.registry
:members:

.. automodule:: embodichain.task_spec.validation
:members:

GenSim candidate graph version
------------------------------

The optional TaskSpec planner entry preserves the legacy candidate step hash
as provenance, emits v2 candidate graphs and retains the v1 path unchanged.
Bundle export and execution reject v2 until final task evaluation is integrated before data
submission and reset. This interface is not a certified rollout path.

.. autodata:: embodichain.gen_sim.task_engine.semantic_graph.TASK_SPEC_GRAPH_SCHEMA
39 changes: 39 additions & 0 deletions embodichain/compute/task_predicates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------


"""Stateless batched measurements used by task policies and final evaluation."""

from __future__ import annotations
import torch

__all__ = ["axis_tilt"]


def axis_tilt(pose: torch.Tensor, local_axis: torch.Tensor) -> torch.Tensor:
"""Measure tilt with atan2, preserving small angles in float32 observations.

Args:
pose: Batched rigid transforms, shaped ``(N, 4, 4)``.
local_axis: Unit local axis, shaped ``(3,)``.

Returns:
Tilt in radians as float64, shaped ``(N,)``. Invalid numbers propagate.
"""
if pose.ndim != 3 or pose.shape[-2:] != (4, 4) or local_axis.shape != (3,):
raise ValueError("Expected poses (N, 4, 4) and one local axis (3,).")
axis = pose[:, :3, :3].double() @ local_axis.double()
return torch.atan2(torch.linalg.vector_norm(axis[:, :2], dim=-1), axis[:, 2])
Comment on lines +36 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Invalid axes yield zero tilt

This public API documents local_axis as a unit vector but validates only its shape. A caller can pass a zero axis, for which atan2(0, 0) produces a plausible zero tilt that downstream threshold checks may treat as upright. Validating or normalizing finite, nonzero axes here would prevent misleading orientation measurements.

Prompt To Fix With AI
This is a comment left during a code review.
Path: embodichain/compute/task_predicates.py
Line: 36-39

Comment:
**Invalid axes yield zero tilt**

This public API documents `local_axis` as a unit vector but validates only its shape. A caller can pass a zero axis, for which `atan2(0, 0)` produces a plausible zero tilt that downstream threshold checks may treat as upright. Validating or normalizing finite, nonzero axes here would prevent misleading orientation measurements.

---

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

Loading