chore(task): archive 08-25-rc-p1-package-boundary

This commit is contained in:
2026-08-25 17:27:53 +08:00
parent 2469cfdbff
commit b44c995457
7 changed files with 2 additions and 2 deletions

View File

@@ -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."}

View File

@@ -0,0 +1,53 @@
# Phase 1 Technical Design
## Boundary
`packages/road-compiler/` becomes the single implementation owner for native
road compilation. It is a CommonJS workspace package with explicit public
entrypoints for compiler APIs, traffic-signal schema, turn-lane helpers, OSM
parsing, reference conversion, and CLIs. It never imports `area-config`, reads
`config/areas`, or derives host paths.
The host owns `scripts/lib/area-config.js` and maps normalized configuration to
the v1 `RoadCompilerInput` shape using `toRoadCompilerInput(area)`. During P1,
`build-area.js` calls the package in-process; P2 is the only phase that changes
that call to a child process.
## Source Ownership and Compatibility
The following current `scripts/lib` implementations move into package `src`:
`native-road`, `complex-junction`, `turn-lane-arrows`, `lane-geometry`,
`gaode-junction-reference`, `native-traffic-signals`, and `osm`.
Some moved modules also serve legacy host paths: QGIS uses turn-lane arrows,
vehicle preview and reimport use OSM parsing, and preview tests use lane
geometry. Those consumers import the package entrypoints after the move. This
preserves one implementation while allowing host -> package dependency.
Traffic signal ownership follows the matrix in
`research/traffic-signals-split-matrix.md`: schema, geometry, validation, and
runtime construction move to the package. The host retains only two file-I/O
adapters, `readTrafficSignalFeatures()` and `readTrafficSignals()`, both
delegating to package exports. No duplicated schema code remains.
## Input and Path Handling
The package compiler API accepts only `RoadCompilerInput` from
`docs/native-road-package-v1.md`. Package CLI commands accept an explicit JSON
input file (`--input`) and never load area configuration. The compatibility
host CLI still accepts `--config`, but immediately maps it through
`toRoadCompilerInput()` before entering the package.
`junctionTemplates.*.referenceFile` changes to a path relative to its area
configuration. `readAreaConfig()` resolves it while normalizing configuration;
the package receives an absolute path and does no path resolution.
## Tests and Rollout
The package receives the required Fengshu OSM fixture plus migrated unit tests.
Its `npm test` must run from the package directory without reading host inputs
or outputs. After each source batch, run the two Phase 0 parity baselines. The
existing host command names remain compatibility wrappers through P1.
Rollback is a normal Git revert of the latest batch commit. No module has a
parallel host copy after its batch lands, preventing divergence.

View File

@@ -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."}

View File

@@ -0,0 +1,118 @@
# Phase 1 执行计划
分批搬迁,每批后跑 parity。**不要一次性大搬。**
## Step 0 — 前置
```bash
# 基线必须先绿
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
```
- [ ] 两个有效区域基线全绿(否则回 Phase 0
## Step 1 — K1 矩阵(动代码之前)
- [ ]`scripts/lib/traffic-signals.js` 全文,列出所有 export
- [ ] 对每个 export `grep -rn` 找使用方
- [ ] 产出 `research/traffic-signals-split-matrix.md`:函数 × 使用方 × 归属判定
- [ ] `buildTrafficSignals``test-preview-assets.js`)归属定档
**门槛**:矩阵完成,无"待定"项。
## Step 2 — 建包骨架
```
packages/road-compiler/
package.json # CommonJS无构建步骤父任务 C2
src/
bin/
test/fixtures/
docs/
```
- [ ] `package.json` 名称、入口、`test` script
- [ ]`package.json` 加 workspace 或 `file:` 依赖
## Step 3 — 分批搬迁(每批一个 commit + 一次 parity
**批 1纯函数零风险**
- [ ] `lib/lane-geometry.js``src/geometry/lane-geometry.js`
- [ ] `lib/gaode-junction-reference.js``src/reference/gaode.js`
- [ ] 宿主侧改 require 指向包
- [ ] parity ✓
**批 2几何模块**
- [ ] `lib/turn-lane-arrows.js`
- [ ] `lib/complex-junction.js`
- [ ] parity ✓
**批 3信号K1 执行)**
- [ ] 按 Step 1 矩阵拆 `lib/traffic-signals.js`
- [ ] `lib/native-traffic-signals.js` 与 schema 部分入包
- [ ] `lib/osm.js` 入包
- [ ] 宿主保留 legacy 读取器,从包 import schema
- [ ] parity ✓ + `npm run test:traffic-signals`(若存在)
**批 4编译器核心**
- [ ] `lib/native-road.js``src/compile/native-road.js`
- [ ] parity ✓
**批 5CLI + 窄契约R1.2**
- [ ] `compile-native-roads.js``bin/compile.js`,入参改 `RoadCompilerInput`
- [ ] `check-native-roads.js``bin/check.js`
- [ ] 宿主 `area-config.js``toRoadCompilerInput(area)`
- [ ] `build-area.js` 改为传 input 对象
- [ ] K3`referenceFile` 改为宿主解析后传绝对路径config 内改相对路径
- [ ] parity ✓
**批 6workbench**
- [ ] `road-workbench.js` + `workbench/app.js` 入包
- [ ] OpenLayers 依赖暂沿用宿主 `node_modules`(同仓库内可行),记入 Phase 2 K4
- [ ] `npm run test:road-workbench`
**批 7测试 fixtureR1.5**
- [ ] `inputs/osm/枫树二路.osm` 复制进 `test/fixtures/`
- [ ] `test-native-road.js` 改读包内 fixture
- [ ] 在包目录内独立跑 `npm test`
## Step 4 — 清理与验证
- [ ] 删除 `scripts/lib/` 下所有搬迁文件的残留AC1.6
- [ ] `grep -rn "area-config\|config/areas" packages/road-compiler/` 必须为空AC1.4
- [ ] `grep -rn "\.\./\.\./scripts\|osm2streets-qgis-workflow" packages/road-compiler/` 检查反向依赖
## 验证命令汇总
```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
(cd packages/road-compiler && npm test)
# 端到端(含 blender / cesium
npm run build:area -- --config config/areas/fengshu-er-road.json
# 反向依赖为 0
grep -rn "area-config\|config/areas" packages/road-compiler/ && echo "VIOLATION"
```
## Review Gate
AC1.1AC1.8 全绿。**parity 有任何一项不绿都不得进 Phase 2** —— 那意味着搬迁改变了行为,
而在同一仓库内查因比拆仓库后查因便宜得多。
## Rollback
每批一个 commit可逐批 `git revert`
过渡期内若需紧急回退,宿主 require 改回 `scripts/lib/` 旧路径即可
(前提:该批尚未执行 Step 4 清理)。

View File

@@ -0,0 +1,98 @@
# Phase 1包边界不换仓库
父任务:`.trellis/tasks/08-25-road-compiler-extraction/`
技术设计:父任务 `design.md` §2模块清单 / K1 拆分建议)
## Goal
在**当前仓库内**建立 `packages/road-compiler/`,移入编译器全部模块,
把对 `readAreaConfig` 的耦合换成窄输入契约,产物对 Phase 0 基线逐字节一致。
**本阶段不换仓库。** 目的是把"改坏了编译器"与"拆坏了仓库"分成两个可归因的步骤
(父任务 D4
## Requirements
### R1.1 目录与模块搬迁
`packages/road-compiler/` 内建立结构,移入父任务 `design.md` §2.1 列出的全部文件
(约 3400 行核心 + workbench
搬迁后 `scripts/lib/` 下不应再留下这些文件的副本 —— 并存会导致
"改了一份忘了另一份"的静默不一致。
### R1.2 窄输入契约
- 编译器入口只接受父任务 `design.md` §1.1 定义的 `RoadCompilerInput`
- 编译器内不得出现 `require("area-config")`、不得读 `config/areas/*.json`
不得从 areaId 推导任何路径
- 宿主 `scripts/lib/area-config.js` 新增 `toRoadCompilerInput(area)` 做映射
- 三个 CLI`compile` / `check` / `workbench`)改为接受显式参数或 input JSON
### R1.3 K1`traffic-signals.js` 拆分 🔴
**全案唯一需要细读再动的地方。** 按父任务 `design.md` §2.3
- 随编译器走OSM 信号节点提取 + 信号文档 schema
- 留宿主:`readTrafficSignalFeatures``build-osm2streets-qgis.js`)、
`readTrafficSignals``build-area.js`
- 待判定:`buildTrafficSignals``test-preview-assets.js`)—— 需读代码确认归属
- 拆完后宿主从编译器包 import schema宿主→编译器是允许方向
动手前必须先产出一份「函数 × 使用方」矩阵,确认无遗漏。
### R1.4 K3参考文件路径约定
`config/areas/fengshu-er-road.json`
`junctionTemplates.clusters[].referenceFile` 是指向宿主仓库的绝对路径。
- 定义解析约定:相对 config 文件所在目录,或由宿主在 `toRoadCompilerInput()`
中解析为绝对路径后传入
- 倾向后者:**编译器只接受已解析的绝对路径,不做路径推导**(符合 R1.2
- config 内改为相对路径,宿主负责解析
### R1.5 K5自带测试 fixture
- `test-native-road.js:167``inputs/osm/枫树二路.osm`
- 该文件(或裁剪版)复制进 `packages/road-compiler/test/fixtures/`
- 测试改为读包内 fixture不再访问宿主 `inputs/`
- 目标:编译器包 `npm test` 不依赖宿主任何目录
### R1.6 宿主侧接线保持不变
- `build-area.js` 本阶段继续 in-process `require`(子进程改造留到 Phase 2
- `npm run road:compile` / `road:check` / `road:workbench` 行为对用户不变
- `blender/` 完全不改
## Acceptance Criteria
- [x] AC1.1 两个有效区域 `road-parity --compare` 对 Phase 0 基线全绿
- [x] AC1.2 `npm run test:native-road``npm run test:road-workbench` 通过
- [x] AC1.3 `npm run build:area` 枫树二路完整跑通(含 blender / cesium 阶段)
- [x] AC1.4 `grep -rn "area-config\|config/areas" packages/road-compiler/` 无命中
- [x] AC1.5 `packages/road-compiler/``npm test` 不访问宿主 `inputs/``outputs/`
- [x] AC1.6 `scripts/lib/` 下无搬迁文件的残留副本
- [x] AC1.7 K1 的「函数 × 使用方」矩阵已产出并归档到 `research/`
- [x] AC1.8 `compiled.json` 结构未变(父任务 AC7 / C1
## 依赖与顺序
- **前置**Phase 0 必须完成且基线可靠
- **阻塞**Phase 2
- 与 Phase 3、4 无直接依赖,但它们都在 Phase 2 之后
## 风险
| 风险 | 缓解 |
|---|---|
| K1 拆分遗漏某个使用方 → 运行时才炸 | 先做矩阵,再动代码;`grep -rn` 全仓验证 |
| 搬迁过程中相对 require 路径改错 | 分小步 commit每步跑 parity |
| `workbench/app.js` 的 OpenLayers import map 指向宿主 node_modules | 本阶段仍在同仓库,可暂不处理;记入 Phase 2K4 |
| 一次性大搬迁难以归因 | 按模块分批先纯函数lane-geometry / gaode-reference再 complex-junction最后 native-road 与 CLI |
## Out of Scope
- 换仓库Phase 2
- layer manifestPhase 3
- IR / pass manager 重构(父任务 C1
- 引入 TypeScript 或构建步骤(父任务 C2

View File

@@ -0,0 +1,21 @@
# Traffic Signals Split Matrix
Evidence gathered from `scripts/lib/traffic-signals.js` and repository-wide
call-site search on 2026-08-25.
| Export | Current users | Owner after P1 | Migration |
|---|---|---|---|
| `SIGNAL_LAYOUT` | `buildTrafficSignalsFromFeatures` | compiler package | Export from `@osm-asset/road-compiler/traffic-signals` |
| `signalNodeKey` | `buildTrafficSignalsFromFeatures` | compiler package | No host caller today; preserve public export for runtime identity contract |
| `buildTrafficSignalFeatures` | `native-traffic-signals`, `readTrafficSignalFeatures` | compiler package | Host QGIS adapter imports it from the package |
| `validateTrafficSignalFeatures` | `native-traffic-signals`, signal tests | compiler package | Tests import package entrypoint |
| `validateTrafficSignalSourceReferences` | `native-traffic-signals`, `reimport-gpkg`, `readTrafficSignals` | compiler package | Reimport adapter imports package function |
| `buildTrafficSignalsFromFeatures` | `native-traffic-signals`, `readTrafficSignals`, `buildTrafficSignals` | compiler package | Host preview adapter imports package function |
| `buildTrafficSignals` | `test-preview-assets` | compiler package | Test imports package function; it is geometry/schema behavior, not host I/O |
| `readTrafficSignalFeatures` | `build-osm2streets-qgis` | host adapter | Keep a thin file-reading wrapper under `scripts/lib/traffic-signals.js`; it imports package functions |
| `readTrafficSignals` | `build-area` | host adapter | Keep a thin file-reading wrapper under `scripts/lib/traffic-signals.js`; it imports package functions |
`scripts/lib/traffic-signals.js` must not retain a second implementation of
the schema or geometry. Its only P1 responsibility is host file I/O for the
legacy QGIS / preview paths. This preserves the one-way dependency:
host -> compiler package; the package never imports the host.

View File

@@ -0,0 +1,26 @@
{
"id": "rc-p1-package-boundary",
"name": "rc-p1-package-boundary",
"title": "Phase 1包边界不换仓库",
"description": "在本仓库内建 packages/road-compiler移入编译器模块用窄输入契约替换 readAreaConfig 耦合,产物对基线逐字节一致",
"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": {}
}