Implement AXIS parity UI and execution baseline
This commit is contained in:
112
docs/linuxcnc-web-wasm-contracts.md
Normal file
112
docs/linuxcnc-web-wasm-contracts.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# LinuxCNC Web/WASM 契约快照
|
||||
|
||||
**契约版本**:`sim-contracts.v1`
|
||||
**任务**:`P0-03`
|
||||
**Context**:`linuxcnc-2.10.0-pre0-wasm-m1-py-c1`
|
||||
**状态**:implementation-verified(只冻结现有边界;不表示 release accepted)
|
||||
|
||||
本文冻结浏览器 Dedicated Worker 与 WASM 核心之间可观察的字段、版本和错误策略。它是当前 context 的兼容性快照,不替换 `context-lock.json`,也不改变已有 C ABI、Worker protocol 或 recovery schema。`sim_task.v1` 只冻结 P1-01 将实现的状态对象形状;本任务不实现该 runtime。
|
||||
|
||||
## 1. 版本和边界
|
||||
|
||||
| 契约 | 线上的版本标识 | 当前实现边界 |
|
||||
|---|---|---|
|
||||
| `sim_task` | `sim_task.v1` | P1-01 authoritative state 预留;本任务只做形状校验 |
|
||||
| 命令信封 | `command-envelope.v1` | Worker 输入使用 `schema_version: 1` |
|
||||
| 快照 | `snapshot.v1` | `web/worker/replay.mjs` 的 snapshot 记录 |
|
||||
| 事件日志 | `event-log.v1` | `web/worker/replay.mjs` 的事件日志 |
|
||||
| 工作区包 | `workspace-package.v1` | 包 schema 固定;`format_version` 1/2 是同一 envelope 的可验证迁移 |
|
||||
|
||||
版本号是整数且不隐式降级。未知版本、缺少必填字段、未知顶层字段、非有限数、哈希或游标不一致都 fail closed。新必填字段或语义变化必须建立新 schema 标识和迁移测试;同一 v1 只允许增加明确标为可选的诊断字段。
|
||||
|
||||
## 2. `sim_task.v1`
|
||||
|
||||
这是单 Worker authoritative task 的可观察状态,不是 C ABI 结构体。字段顺序在 canonical JSON 中按键名排序,数值使用 JSON 安全整数或有限 IEEE-754 数。
|
||||
|
||||
| 字段 | 类型 | 要求 |
|
||||
|---|---|---|
|
||||
| `schema` | string | 固定 `sim_task.v1` |
|
||||
| `context_id`、`session_id` | string | 非空;恢复时必须与锁定 context/session 相符 |
|
||||
| `state` | enum | `NEW`、`READY`、`RUNNING`、`PAUSED`、`ESTOP`、`FAULT`、`STOPPED`、`DESTROYED` |
|
||||
| `mode` | enum | `MANUAL`、`MDI`、`AUTO` |
|
||||
| `program_status` | enum | `idle`、`loaded`、`running`、`paused`、`completed`、`aborted`、`fault` |
|
||||
| `seq` | positive integer | 最后应用的命令序号 |
|
||||
| `simulation_tick` | non-negative integer | 逻辑 tick;不使用墙钟 |
|
||||
| `current_line` | non-negative integer or null | 当前程序行;未知时为 null |
|
||||
| `state_hash` | string | 对除 hash 外的完整状态做确定性 hash |
|
||||
|
||||
P1-01 可以在同一 schema 内增加由契约测试先登记的可选域;改变上述语义或枚举必须升级版本。Task 状态、事件、快照和 operation ledger 必须在相同 tick 边界提交。
|
||||
|
||||
## 3. `command-envelope.v1`
|
||||
|
||||
命令及其 Worker 响应共享以下信封字段:
|
||||
|
||||
| 字段 | 要求 |
|
||||
|---|---|
|
||||
| `schema_version` | 固定整数 `1`,对应 C `sim_protocol_accept` 的 schema 参数 |
|
||||
| `kind` | 非空字符串,长度不超过 128(C `has_text` 边界);命令种类由 capability/Worker 白名单决定 |
|
||||
| `context_id` | 非空字符串,必须等于 context lock |
|
||||
| `session_id` | 非空字符串;同一会话不可改变 |
|
||||
| `seq` | 从 1 开始严格连续递增;重复副作用通过 `operation_id` 对账 |
|
||||
| `operation_id` | 副作用命令必填的非空字符串,长度不超过 128;只读查询可省略 |
|
||||
| `simulation_tick` | 可选的非负安全整数;不得小于 Worker 当前 tick |
|
||||
| `sent_at_monotonic_ms` | 可选有限数,仅用于诊断,绝不参与状态或 hash |
|
||||
| `payload` | 必填 JSON object;不能是数组、null 或包含非有限数 |
|
||||
|
||||
当前 C ABI 的状态与错误保持不变:`SIM_PROTOCOL_ERR_SCHEMA=-100`、`SEQUENCE=-101`、`STATE=-102`、`OPERATION_ID=-103`、`KIND=-104`、`ARGUMENT=-105`、`TICK=-106`。Worker 以稳定的 `protocol_*` 错误键映射这些结果,不能把错误改成成功或静默重排命令。
|
||||
|
||||
## 4. `snapshot.v1`
|
||||
|
||||
`SnapshotStore` 导出的对象固定为 `{schema, snapshots}`;每条 snapshot 使用:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "snapshot.v1",
|
||||
"snapshot_id": "snap:<seq>:<state_hash>",
|
||||
"base_snapshot_id": null,
|
||||
"seq": 1,
|
||||
"tick": 0,
|
||||
"state": {},
|
||||
"state_hash": "fnv1a64:<16 lowercase hex>"
|
||||
}
|
||||
```
|
||||
|
||||
`seq` 为正整数且同一序号只能有一个内容,`tick` 不回退;增量 snapshot 的 `base_snapshot_id` 必须引用已导入的 snapshot。`state_hash` 和 `snapshot_id` 必须由同一 canonical state 重算。容量不足、重复序号、缺少 base、哈希不符和非有限 state 均拒绝,导入失败不得替换当前 store。
|
||||
|
||||
## 5. `event-log.v1`
|
||||
|
||||
日志对象固定为 `{schema: "event-log.v1", cursor, tick, events}`。每条事件固定字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"seq": 1,
|
||||
"tick": 0,
|
||||
"kind": "SESSION_READY",
|
||||
"payload": {},
|
||||
"payload_hash": "fnv1a64:<16 lowercase hex>"
|
||||
}
|
||||
```
|
||||
|
||||
`seq` 从 1 严格连续,`tick` 单调不减,`kind` 非空且最多 64 个字符,payload 必须是 object。C 端保留 `sim_event_record` 的固定宽度布局(`uint32_t seq/tick`、`uint64_t payload_hash`、32 字节 kind),并保留 `SIM_EVENT_CAPACITY=256` 与错误码 `-200..-204`。WASM 和 Worker 对同一输入必须得到相同 cursor/tick/hash;半成品导入不改变当前日志。
|
||||
|
||||
## 6. `workspace-package.v1`
|
||||
|
||||
包 envelope 的必填字段为 `schema`、`format_version`、`context_id`、`committed_seq`、`checkpoint`、`timeline`、`journal`、`content_hash`、`package_hash`。`format_version: 1` 是当前基线;已实现的 `format_version: 2` 只添加 `migration` 和 `integrity` 元数据,事件、snapshot、checkpoint、journal payload 保持 byte-for-byte v1 兼容。
|
||||
|
||||
迁移规则:
|
||||
|
||||
1. v1→v2 必须标记 `lossless: true`、源 package hash 和 timeline/journal/checkpoint integrity hash。
|
||||
2. v2→v1 只有在源 hash 对账成功时允许;原包不可变,回滚只生成新目标包。
|
||||
3. 不支持的版本、context、提交序号、timeline/checkpoint、content/package hash 或 journal 顺序均拒绝。
|
||||
4. 缺失/损坏资源在离线模式返回明确错误;不能用空包或当前内存状态替代已提交包。
|
||||
|
||||
## 7. 兼容性决策记录
|
||||
|
||||
- **ABI**:保留 `sim_api.h`、`sim_protocol.h`、`sim_event.h` 的函数签名、整数宽度、错误码和容量语义;没有修改锁定 ABI。
|
||||
- **协议**:Worker 继续传递 `schema_version: 1`,C validator 继续拒绝非 1、序号缺口、tick 回退和副作用命令缺失 `operation_id`。
|
||||
- **快照/事件**:沿用 `replay.mjs` 的 `schema` 字段和 FNV-1a-64 canonical hash;不把 `snapshot.v1` 或 `event-log.v1` 改成新的顶层结构。
|
||||
- **工作区**:沿用现有 workspace migration 的 v1/v2 envelope;v2 不是新的 payload schema,不修改已锁定的事件/快照/checkpoint/journal 版本。
|
||||
- **未知字段**:v1 顶层未知字段和缺失字段 fail closed;仅 `sent_at_monotonic_ms` 这一诊断字段可选且不影响 hash。需要其它字段时先建 v2 schema/迁移测试。
|
||||
- **排除边界**:真实硬件、宿主路径、实时内核和动态库仍是 `REAL-EXCLUDED`;主轴、编码器、探针、限位、换刀、冷却和 IO 的仿真契约不因此排除。
|
||||
|
||||
直接证据:`web/worker/contracts.mjs`、`web/worker/test_contracts.mjs`、`wasm-core/tests/sim_contract_test.c`、`scripts/test_sim_contract.py`、`coverage/sim-contract.report.json`。
|
||||
Reference in New Issue
Block a user