3.7 KiB
3.7 KiB
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,已存在则复用,首次生成可能不确定 |
核查顺序:
- 备份两个有效区域的
native-road/与native-traffic-signals.json - 删除
native-road/(保留 signals,因为loadOrGenerate语义是已存在则复用) - 跑第一次 → snapshot A
- 再删
native-road/,跑第二次 → snapshot B - diff A/B → volatile 字段清单
- 额外一轮:删掉 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>
归一化规则(写死在脚本里,并回写进契约文档)
- 路径:任何绝对路径 → 相对 repo root;staging 目录名 → 字面量
<staging> - JSON:递归按 key 排序后
JSON.stringify,再 hash - GeoJSON:
contentHash= features 按properties.native_id(缺失则按几何首坐标)排序后 hashorderHash= 原序 hash- 两者都记录;比对时
contentHash不一致 = 语义变化(严重), 仅orderHash不一致 = 顺序抖动(需解释但可能可接受)
- 浮点:不做舍入。坐标变化就是变化,不允许用容差掩盖 (拆分是纯搬迁,任何坐标位移都是 bug)
输出形状
{
"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 验证不需要等仓库拆分。