chore(task): archive 08-25-rc-p0-contract-baseline

This commit is contained in:
2026-08-25 16:53:04 +08:00
parent e7bc7f82b1
commit d7c2e13124
26 changed files with 792 additions and 3 deletions

View File

@@ -0,0 +1,81 @@
# Phase 0 技术设计
契约本体见父任务 `design.md` §1本文件只补 Phase 0 自身的实现设计。
## 1. 确定性核查的具体做法
编译器的潜在非确定性来源,按可疑度排序:
| 来源 | 表现 | 处置 |
|---|---|---|
| `fs.mkdtempSync(path.join(pipelineDir, "native-road-"))` | staging 目录名随机 | 若名字出现在 `compiled.json``source` 字段里,需归一化 |
| `compiled.json` 内的绝对路径 | `source.osm` / `source.overrides` / `source.trafficSignals` 是绝对路径 | 归一化为相对 repo root |
| 时间戳 | 未确认是否存在 | 核查 `compile-native-roads.js` 写入的 metadata |
| `Map` / `Set` 迭代顺序 | JS 保证插入序,若插入源本身有序则确定 | 观测两次运行 `orderHash` 是否一致即可暴露 |
| 浮点累加顺序 | 几何坐标末位抖动 | 若出现,说明存在顺序依赖,属真 bug需修 |
| `crypto` 随机(`traffic-signals.js` require 了 `crypto` | 信号 ID 可能含随机成分 | 重点核查 —— `native-traffic-signals.json``loadOrGenerate`,已存在则复用,首次生成可能不确定 |
**核查顺序**
1. 备份两个有效区域的 `native-road/``native-traffic-signals.json`
2. 删除 `native-road/`(保留 signals因为 `loadOrGenerate` 语义是已存在则复用)
3. 跑第一次 → snapshot A
4. 再删 `native-road/`,跑第二次 → snapshot B
5. diff A/B → volatile 字段清单
6. 额外一轮:删掉 signals 文件也重生成一次,确认 signal ID 是否确定
## 2. `scripts/road-parity.js` 设计
```
用法:
node scripts/road-parity.js --config <area-config> --snapshot <out.json>
node scripts/road-parity.js --config <area-config> --compare <baseline.json>
```
### 归一化规则(写死在脚本里,并回写进契约文档)
1. **路径**:任何绝对路径 → 相对 repo rootstaging 目录名 → 字面量 `<staging>`
2. **JSON**:递归按 key 排序后 `JSON.stringify`,再 hash
3. **GeoJSON**
- `contentHash` = features 按 `properties.native_id`(缺失则按几何首坐标)排序后 hash
- `orderHash` = 原序 hash
- 两者都记录;比对时 `contentHash` 不一致 = 语义变化(严重),
`orderHash` 不一致 = 顺序抖动(需解释但可能可接受)
4. **浮点**:不做舍入。坐标变化就是变化,不允许用容差掩盖
(拆分是纯搬迁,任何坐标位移都是 bug
### 输出形状
```json
{
"contract": "native-road-package/v1",
"areaId": "fengshu-er-road",
"files": {
"compiled.json": { "contentHash": "…", "bytes": 12345 },
"diagnostics.json": { "contentHash": "…", "bytes": 678, "count": 42 },
"layers/road_surface.geojson": {
"contentHash": "…", "orderHash": "…", "features": 128 }
},
"volatileExcluded": ["source.osm", "source.overrides", "<staging>"]
}
```
`count` / `features` 是冗余的人类可读字段 —— hash 变了但计数没变,
说明是内容变化;计数也变了,说明是增删。加速归因。
## 3. 基线目录布局
```
.trellis/tasks/08-25-road-compiler-extraction/baseline/
fengshu-er-road.json
nantaizi-lake-innovation-valley.json
README.md ← 记录生成时的 git commit、命令、volatile 字段清单
```
`README.md` 必须记录生成基线时的 commit hash否则将来无法判断
"基线是在哪个代码状态下产生的"。
## 4. 为什么校验脚本放宿主而不是直接放未来的编译器仓库
Phase 0 时编译器仓库还不存在。脚本先落宿主 `scripts/`
Phase 2 随编译器一起搬走,届时宿主保留一个薄封装(或直接调编译器包的 CLI
这样 Phase 1 的 parity 验证不需要等仓库拆分。