chore(task): archive 08-25-rc-p0-contract-baseline
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -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 root;staging 目录名 → 字面量 `<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 验证不需要等仓库拆分。
|
||||
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1,118 @@
|
||||
# Phase 0 执行计划
|
||||
|
||||
## 前置
|
||||
|
||||
- [ ] 分支:`experiment/road-compiler-rethink`(已在)
|
||||
- [ ] 确认工作区干净(`.trellis/tmp-*.js` 五个未跟踪文件与本任务无关,可先清理或忽略)
|
||||
- [ ] 阅读父任务 `design.md` §1 契约定义
|
||||
|
||||
## Step 1 — 摸清两区域当前状态
|
||||
|
||||
```bash
|
||||
ls config/areas/
|
||||
for d in outputs/*/native-road/layers; do echo "$d: $(ls $d | wc -l)"; done
|
||||
```
|
||||
|
||||
判定:`hanyang-block` 为废案,不纳入本阶段;只核查两个有效区域的配置与当前产物。
|
||||
|
||||
- [x] 逐区域检查 config 的 `nativeRoad.edgeLines` / `junctionTemplates.enabled`
|
||||
- [x] 将两个有效区域的配置差异记录在基线 README
|
||||
|
||||
**门槛**:两个有效区域的图层差异有书面解释。
|
||||
|
||||
## Step 2 — 确定性核查
|
||||
|
||||
```bash
|
||||
# 备份
|
||||
cp -r outputs/<area>/native-road /tmp/rc-baseline-a
|
||||
# 重编
|
||||
rm -rf outputs/<area>/native-road
|
||||
npm run road:compile -- --config config/areas/<area>.json
|
||||
cp -r outputs/<area>/native-road /tmp/rc-baseline-b
|
||||
# 比对
|
||||
diff -r /tmp/rc-baseline-a /tmp/rc-baseline-b
|
||||
```
|
||||
|
||||
- [x] 对两个有效区域各跑一遍
|
||||
- [x] 记录所有差异字段 → volatile 清单
|
||||
- [x] 额外一轮:删掉 `native-traffic-signals.json` 重生成,
|
||||
确认信号 ID 是否确定(`traffic-signals.js` require 了 `crypto`,重点核查)
|
||||
- [ ] 若发现**几何坐标级**的非确定性 → 停止本阶段,先开 bug 任务修掉
|
||||
|
||||
**门槛** 🔴:确定性已证明,或非确定性已定位并修复。这是全案的地基。
|
||||
|
||||
## Step 3 — 写 `scripts/road-parity.js`
|
||||
|
||||
按 `design.md` §2 实现。
|
||||
|
||||
- [x] `--snapshot` 生成归一化 checksum 清单
|
||||
- [x] `--compare` 比对并逐文件报差异,不一致时非零退出
|
||||
- [x] GeoJSON 双 hash(`contentHash` 排序后 / `orderHash` 原序)
|
||||
- [x] volatile 字段按 Step 2 结论归一化
|
||||
- [x] 自验:同一区域连跑两次 snapshot,`--compare` 必须通过
|
||||
|
||||
```bash
|
||||
node scripts/road-parity.js --config config/areas/fengshu-er-road.json --snapshot /tmp/s1.json
|
||||
node scripts/road-parity.js --config config/areas/fengshu-er-road.json --compare /tmp/s1.json
|
||||
echo "exit=$?" # 必须为 0
|
||||
```
|
||||
|
||||
**门槛**:脚本对未改动的代码报告一致。
|
||||
|
||||
## Step 4 — 建立两区域基线
|
||||
|
||||
```bash
|
||||
mkdir -p .trellis/tasks/08-25-road-compiler-extraction/baseline
|
||||
for a in fengshu-er-road nantaizi-lake-innovation-valley; do
|
||||
rm -rf outputs/$a/native-road
|
||||
npm run road:compile -- --config config/areas/$a.json
|
||||
node scripts/road-parity.js --config config/areas/$a.json \
|
||||
--snapshot .trellis/tasks/08-25-road-compiler-extraction/baseline/$a.json
|
||||
done
|
||||
```
|
||||
|
||||
- [x] 两个基线 JSON 生成
|
||||
- [x] 写 `baseline/README.md`:生成时的 git commit、命令、volatile 字段清单、
|
||||
两个有效区域图层差异的解释
|
||||
- [x] 反向自验:再跑一次 `--compare` 两个基线全部通过
|
||||
|
||||
## Step 5 — K2 决策
|
||||
|
||||
- [x] 检查 `comparison.json` 当前是否真被消费(grep 宿主与 workbench)
|
||||
- [x] 若有 → 方案 B(可选注入),在契约里定义 `comparisonDir` 为 optional
|
||||
|
||||
## Step 6 — 落契约文档
|
||||
|
||||
- [x] 写 `docs/native-road-package-v1.md`,内容源自父任务 `design.md` §1
|
||||
- [x] 补入 Step 2 的 volatile 字段清单
|
||||
- [x] 补入 Step 5 的 K2 决策
|
||||
- [x] 在 `docs/changelog.md` 记一行
|
||||
|
||||
## 验证命令汇总
|
||||
|
||||
```bash
|
||||
# parity 两区域全绿
|
||||
for a in fengshu-er-road nantaizi-lake-innovation-valley; do
|
||||
node scripts/road-parity.js --config config/areas/$a.json \
|
||||
--compare .trellis/tasks/08-25-road-compiler-extraction/baseline/$a.json || echo "FAIL $a"
|
||||
done
|
||||
|
||||
# 既有测试未破
|
||||
npm run test:native-road
|
||||
npm run test:road-workbench
|
||||
|
||||
# 确认无生产代码改动
|
||||
git diff --stat -- scripts/lib blender
|
||||
```
|
||||
|
||||
最后一条必须为空输出 —— Phase 0 不碰生产代码。
|
||||
|
||||
## Review Gate
|
||||
|
||||
全部 AC0.1–AC0.6 打勾后,再进 Phase 1。**基线不可靠时不要前进。**
|
||||
|
||||
## Rollback
|
||||
|
||||
本阶段纯新增(文档 / 脚本 / 基线数据)。回滚 = 删除新增文件。
|
||||
唯一例外:Step 2 若发现并修复了非确定性 bug,那部分是真实代码改动,
|
||||
应拆成独立 commit 并单独保留。
|
||||
@@ -0,0 +1,84 @@
|
||||
# Phase 0:冻结契约与 parity 基线
|
||||
|
||||
父任务:`.trellis/tasks/08-25-road-compiler-extraction/`
|
||||
契约权威定义:父任务 `design.md` §1
|
||||
|
||||
## Goal
|
||||
|
||||
在任何代码移动之前,把 `native-road-package/v1` 契约落成仓库内文档,
|
||||
并为两个有效区域建立可复跑的逐文件 parity 基线,作为全案唯一 oracle。
|
||||
|
||||
**本阶段不移动、不重构任何生产代码。** 只新增文档、基线数据和一个校验脚本。
|
||||
|
||||
## Requirements
|
||||
|
||||
### R0.1 契约文档
|
||||
|
||||
- 把父任务 `design.md` §1(输入契约 / 输出契约 / 消费方式)落成
|
||||
`docs/native-road-package-v1.md`。
|
||||
- 文档必须列全 12 个图层名、`compiled.json` 顶层结构、`diagnostics.json` 记录形状、
|
||||
stdout 标记格式。
|
||||
- Phase 2 会把该文档搬进编译器仓库,此处先落在宿主。
|
||||
|
||||
### R0.2 确定性前置核查 🔴
|
||||
|
||||
**基线只有在编译器确定性的前提下才有意义。** 必须先证明这一点。
|
||||
|
||||
- 对同一输入连续跑两次 `road:compile`,比较全部输出文件。
|
||||
- 识别并记录所有 volatile 字段(时间戳、绝对路径、staging 目录名、
|
||||
任何来自 `mkdtemp` 的随机名、Map/Set 迭代顺序敏感的输出)。
|
||||
- 校验脚本必须归一化或排除这些字段。
|
||||
- 若发现真实的非确定性(相同输入产出不同几何),**必须先修掉再继续**,
|
||||
否则整个拆分没有 oracle。
|
||||
|
||||
### R0.3 parity 校验脚本
|
||||
|
||||
- 新增 `scripts/road-parity.js`(宿主侧,Phase 2 随编译器搬走)。
|
||||
- 能力:
|
||||
- `--snapshot <out.json>` 遍历指定区域的 `native-road/` 全部文件 +
|
||||
`native-traffic-signals.json`,归一化后输出排序稳定的 checksum 清单
|
||||
- `--compare <baseline.json>` 与基线比对,差异逐文件报告
|
||||
- 非零退出码表示不一致
|
||||
- GeoJSON 需按稳定键排序后再 hash(避免 feature 顺序抖动造成假阳性),
|
||||
但**顺序本身若变化必须被报告**——用两个 hash:`contentHash`(排序后)
|
||||
与 `orderHash`(原序),分别报告。
|
||||
|
||||
### R0.4 两区域基线
|
||||
|
||||
- 区域:`fengshu-er-road`、`nantaizi-lake-innovation-valley`
|
||||
- 从干净状态跑 `npm run road:compile`,产出基线 JSON 提交进版本控制
|
||||
- 基线文件位置:`.trellis/tasks/08-25-road-compiler-extraction/baseline/<area>.json`
|
||||
(Phase 2 搬进编译器仓库当测试语料,见父任务 R4)
|
||||
|
||||
`hanyang-block` 是废案,不纳入编译、快照或后续 parity 兼容范围。
|
||||
|
||||
### R0.5 K2 决策定档
|
||||
|
||||
`comparison.json` 依赖宿主 osm2streets 产物(`compile-native-roads.js:87` 读
|
||||
`area.outputs.geojsonDir`),拆出后不可达。本阶段必须做出决策并写入契约文档:
|
||||
|
||||
- 方案 A:移除 `comparison.json`(osm2streets 已 legacy)
|
||||
- 方案 B:保留,`comparisonDir` 作为可选输入注入
|
||||
- 倾向 A。决策写入 `docs/native-road-package-v1.md` 的「已移除能力」一节。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] AC0.1 `docs/native-road-package-v1.md` 存在,覆盖输入契约、输出契约、
|
||||
12 图层清单、stdout 标记、已移除能力
|
||||
- [x] AC0.2 连续两次编译的 parity 比对通过(确定性已证明),volatile 字段清单已记录在文档内
|
||||
- [x] AC0.3 `scripts/road-parity.js` 可用,`--snapshot` / `--compare` 均工作,
|
||||
不一致时非零退出
|
||||
- [x] AC0.4 两个区域基线 JSON 已提交,且每个都能用 `--compare` 自比对通过
|
||||
- [x] AC0.5 K2 决策已定档并写入契约文档
|
||||
- [x] AC0.6 未修改任何生产代码(`git diff` 只含新增文档 / 脚本 / 基线)
|
||||
|
||||
## 依赖与顺序
|
||||
|
||||
- 无前置依赖,本阶段是全案入口
|
||||
- **阻塞** Phase 1、2、3、4 —— 没有基线就没有 oracle
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 任何生产代码改动(含"顺手修一下")
|
||||
- 目录结构调整
|
||||
- `compiled.json` 结构变更
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "rc-p0-contract-baseline",
|
||||
"name": "rc-p0-contract-baseline",
|
||||
"title": "Phase 0:冻结契约与 parity 基线",
|
||||
"description": "写死 native-road-package/v1 输入输出契约,并对两个有效区域建立逐文件 checksum 基线作为全案 oracle",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P1",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-25",
|
||||
"completedAt": "2026-08-25",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": "08-25-road-compiler-extraction",
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user