chore(task): archive 08-25-rc-p1-package-boundary
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,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.
|
||||
@@ -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 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 ✓
|
||||
|
||||
**批 5:CLI + 窄契约(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 ✓
|
||||
|
||||
**批 6:workbench**
|
||||
- [ ] `road-workbench.js` + `workbench/app.js` 入包
|
||||
- [ ] OpenLayers 依赖暂沿用宿主 `node_modules`(同仓库内可行),记入 Phase 2 K4
|
||||
- [ ] `npm run test:road-workbench` ✓
|
||||
|
||||
**批 7:测试 fixture(R1.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.1–AC1.8 全绿。**parity 有任何一项不绿都不得进 Phase 2** —— 那意味着搬迁改变了行为,
|
||||
而在同一仓库内查因比拆仓库后查因便宜得多。
|
||||
|
||||
## Rollback
|
||||
|
||||
每批一个 commit,可逐批 `git revert`。
|
||||
过渡期内若需紧急回退,宿主 require 改回 `scripts/lib/` 旧路径即可
|
||||
(前提:该批尚未执行 Step 4 清理)。
|
||||
@@ -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 2(K4) |
|
||||
| 一次性大搬迁难以归因 | 按模块分批:先纯函数(lane-geometry / gaode-reference),再 complex-junction,最后 native-road 与 CLI |
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 换仓库(Phase 2)
|
||||
- layer manifest(Phase 3)
|
||||
- IR / pass manager 重构(父任务 C1)
|
||||
- 引入 TypeScript 或构建步骤(父任务 C2)
|
||||
@@ -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.
|
||||
@@ -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": {}
|
||||
}
|
||||
Reference in New Issue
Block a user