三类产物分别承担什么职责

Run 是作者声明。 它是 YAML、JSON 或 TOML 中的人类可读入口,选择 schema、名称、后端、运行策略、Scenario、控制策略、插件和显式覆盖。Run 应表达“这次运行选择什么”,而不是复制所有组件细节。

yaml
schema: fastsim/2
name: kitchen-evaluation
backend: isaaclab
runtime:
  physics_hz: 60
  control_hz: 30
  seed: 7
scenario:
  use: scenario://kitchen/evaluation
plugins:
  recorder:
    use: plugin://official/record

ExecutionPlan 是唯一执行权威。 编译器展开 Project 与 Registry,解析组件 release 和后端 variant,验证插件 binding、频率与资源,并生成深层不可变的 ExecutionPlan。Plan 中保存规范化 Scenario、运行策略、已解析实体、插件绑定和 provenance。

源码 Run 发生变化时需要重新编译;Runtime 不应继续持有原始配置字典并在中途读取新字段。

Lock 是可验证的复现边界。 Lock 固化组件准确版本、Manifest、资源摘要和 plan digest。它用于部署、审计与复现实验,回答“这次真正执行了什么”,而不是替代 Run 成为新的编辑格式。

产物 主要读者 是否适合手工编辑 生命周期
Run 项目作者 是 随项目修改
ExecutionPlan Runtime、诊断工具 否 每次编译生成
Lock 部署、复现、审计 不建议 随批准的输入固定

能在构建阶段确认的失败也应该在这里暴露。语法、字段、组件冲突、资源 digest、能力或插件契约问题应尽量在编译阶段失败;运行阶段只处理确实依赖实时世界的状态与操作错误。

字段级事实见配置参考;命令见CLI 与输出。

从 Run 到 Lock 的完整路径

Run 经过验证、解析、绑定后形成 ExecutionPlan 与 Lock 的编译流程
Run 经过验证、解析、绑定后形成 ExecutionPlan 与 Lock 的编译流程放大查看

编译不是把 YAML 转成另一份 YAML。Compiler 会把作者可读的引用转换为 Runtime 需要的准确事实:组件 URI 变为选定 release,资源 URI 变为经过可信根与摘要检查的文件,Scenario 别名变为稳定实体 ID,插件声明变为带 bindings/access 的实例计划,控制来源变为完整 precedence。

每一步都可能发现不同问题。validate 负责 schema 和跨字段约束;resolve 负责 Project、Registry、版本、variant 与资源;bind 负责实体、插件服务和 authority;normalize 负责消除等价写法并形成稳定 digest。只有全部成立,Plan 才能进入 Runtime。

Plan 中应该出现什么。 一个可执行 Plan 至少能回答:后端与 launch profile、runtime 时钟和 seed、组件准确版本、每个实体的稳定身份、实际资源与摘要、Scenario 三个区域、插件 distribution/factory、服务 grant、控制 precedence,以及所有可影响语义的覆盖来源。

Plan 不包含运行中不断变化的世界状态,也不保存后端临时句柄。它是“如何构造应用”的事实,不是“应用此刻发生了什么”的快照。

复现与变更审查

什么时候需要 Lock。 本地开发中频繁修改 Run 时,可以每次重新编译并检查 Plan;准备 CI、远程部署、正式录制或可重复实验时,应生成 Lock。Lock 让调用方拒绝被替换的 Registry 内容、组件 release 或资源,而不是在同一个 Run 文本下执行不同输入。

Lock 不是永远不变的文件。依赖升级、组件修复或插件版本变化后,应重新编译、评审差异并生成新 Lock。旧 Lock 作为历史输入保留,不应原地伪装成同一版本。

用 explain 而不是猜覆盖关系。 当 runtime.physics_hz 或组件选择与预期不符时,先查看 expand 结果,再对准确路径运行 explain。有效值可能来自 Run、组件默认、部署允许的显式覆盖或用户设置回退;只有 explain 的 provenance 能说明实际来源。

CI 推荐把 validate --json、Lock digest 与最终 Plan digest 保存为构建产物。失败时同时保留命令、退出码和结构化错误,避免只截取一行面向人的终端文本。

常见误区

  • 把 Lock 当成新的手工配置文件:它是编译产物,人工修补会破坏来源关系。
  • 把 Plan 当成 Runtime 状态:它不会随 robot pose、tick 或 Operation 变化。
  • 只固定 Python 包版本,不固定组件资源:相同代码仍可能加载不同 USD/URDF/MJCF。
  • 运行时自动下载“最新”内容:未固定内容不能形成可验证复现边界。
  • 为了通过验证删掉能力声明:这会隐藏真实依赖,运行时仍无法正确工作。

接下来阅读Project、Registry 与 Component理解解析输入,或使用编写与检查配置完成一条可验证的配置工作流。