三类产物分别承担什么职责
Run 是作者声明。 它是 YAML、JSON 或 TOML 中的人类可读入口,选择 schema、名称、后端、运行策略、Scenario、控制策略、插件和显式覆盖。Run 应表达“这次运行选择什么”,而不是复制所有组件细节。
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、能力或插件契约问题应尽量在编译阶段失败;运行阶段只处理确实依赖实时世界的状态与操作错误。
从 Run 到 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理解解析输入,或使用编写与检查配置完成一条可验证的配置工作流。