Initialize Trellis project guidelines
This commit is contained in:
196
.trellis/tasks/00-bootstrap-guidelines/design.md
Normal file
196
.trellis/tasks/00-bootstrap-guidelines/design.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 技术设计:Trellis spec 重建
|
||||
|
||||
> 对应 `prd.md`。本文件定义目录结构、每个文件的内容边界与取材来源。
|
||||
|
||||
---
|
||||
|
||||
## 1. 为什么按这四个包切分
|
||||
|
||||
Trellis 单仓模式下,`.trellis/spec/` 的每个子目录自动成为一个 "spec layer"
|
||||
(`packages_context.py:30-41`,`guides` 被显式排除)。零配置,不需要动
|
||||
`config.yaml` 的 `packages:`(那是 monorepo 用的)。
|
||||
|
||||
切分依据是**运行时边界**,不是目录名:
|
||||
|
||||
| 包 | 覆盖代码 | 运行时 | 切分理由 |
|
||||
|---|---|---|---|
|
||||
| `pipeline/` | `scripts/*.js`, `scripts/lib/scene-layers.js` | Node(宿主机) | 唯一能调外部进程(QGIS/Blender/ogr2ogr)的层 |
|
||||
| `blender/` | `blender/**/*.py` | Blender 内嵌 Python + 系统 Python | 依赖 `bpy`,且内部还有一条纯 Python 子边界 |
|
||||
| `preview/` | `scripts/lib/cesium-preview.{js,css}` | 浏览器 | 无构建步骤的 IIFE,唯一的 DOM 环境 |
|
||||
| `config/` | `config/areas/*.json`, `config/examples/template.json` | 数据(无运行时) | 三层共同消费的契约,改一个字段会同时影响三层 |
|
||||
|
||||
`scripts/normalize-lane-arrows.py` 虽是 Python,但跑在 QGIS 的 Python 里、由
|
||||
`build-osm2streets-qgis.js` 调起,属于管线的外部工具调用,归 `pipeline/`。
|
||||
|
||||
## 2. 目标结构
|
||||
|
||||
```
|
||||
.trellis/spec/
|
||||
├── index.md # 顶层索引:四个包 + guides 的路由表
|
||||
├── pipeline/
|
||||
│ ├── index.md # 包索引 + 五个 stage 的数据流全景
|
||||
│ ├── cli-and-stages.md
|
||||
│ ├── layer-registry.md
|
||||
│ └── external-tools.md
|
||||
├── blender/
|
||||
│ ├── index.md # 包索引 + osmassets 依赖分层图
|
||||
│ ├── module-structure.md
|
||||
│ ├── asset-generation.md
|
||||
│ └── testing.md
|
||||
├── preview/
|
||||
│ └── index.md
|
||||
├── config/
|
||||
│ └── index.md
|
||||
└── guides/
|
||||
├── index.md # 更新:触发点换成本项目的
|
||||
├── code-reuse-thinking-guide.md # 保留,补本项目实例
|
||||
├── cross-layer-thinking-guide.md # 保留,补本项目实例
|
||||
└── artifact-parity-guide.md # 新增
|
||||
```
|
||||
|
||||
被删除:`.trellis/spec/frontend/` 全部 7 个文件(6 个模板 + index)。
|
||||
|
||||
## 3. 每个文件的内容边界与取材
|
||||
|
||||
### 3.1 `pipeline/cli-and-stages.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| `--kebab-case` → `camelCase` 的参数解析约定,重复实现在三个脚本里 | `build-area.js:50`, `reimport-gpkg.js:93`, `build-osm2streets-qgis.js` |
|
||||
| 五个 stage 的职责与依赖顺序 | `build-area.js:32-46` 的顶层调度 |
|
||||
| `reimport` 不在 `all` 里,是恢复步骤不是构建步骤 | `build-area.js:157-160` 注释 |
|
||||
| `intermediates` × `reimport` 互斥,显式抛错 | `build-area.js:19-26` |
|
||||
| 配置归一化:从 `id` 推导默认输出路径,`outputs` 可覆盖 | `build-area.js:74` `normalizeAreaConfig` |
|
||||
| 缺失必填项用 `requireText` 抛错而非默认值兜底 | `build-area.js:143`, `reimport-gpkg.js:125` |
|
||||
| 外部命令统一走 `runCommand`,非零退出即终止 | `build-area.js:301` |
|
||||
|
||||
**边界**:只写"怎么加一个 stage / 怎么加一个 CLI 参数",不复述 README 里的用法示例。
|
||||
|
||||
### 3.2 `pipeline/layer-registry.md`
|
||||
|
||||
最重要的一篇。核心是"九个图层在两种语言里各存一份"这个刻意设计。
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| `SCENE_LAYERS` 是 JS 侧唯一事实源,`zIndex` 兼作绘制顺序 | `scene-layers.js:3-13` 顶部注释 |
|
||||
| 从前同一份表复制了四次(z_index 表 / 样式 JSON / QGIS 工程 / README),改一处漏一处会静默错栈 | `scene-layers.js:5-10` |
|
||||
| `outline: null` = 无描边,QGIS 侧转成全透明 | `scene-layers.js:13-14` |
|
||||
| `mergeScene(getCollection)` 用回调取集合,让 build(内存)和 reimport(磁盘)共用同一套合并 | `scene-layers.js:107-124` |
|
||||
| Python 侧 `catalog.ROAD_LAYERS` 存的是另一组事实(Blender 高度 `z` + 线性色) | `catalog.py:25-47` |
|
||||
| **颜色故意不同步**:JS 是 QGIS sRGB 调试色,Python 是 Blender 线性场景色,分别调过 | `catalog.py:11-15` |
|
||||
| `check_layers()` 只校验图层**集合与顺序**,读的是产物 `osm2streets_scene_style.json` | `catalog.py:162-195` |
|
||||
| 校验是 warn 不是 fail:过期或缺失的输出目录不该阻断重建 | `catalog.py:168-169` |
|
||||
| **加一个图层的完整清单**:改 `scene-layers.js` + `catalog.py` 两处,顺序必须一致 | 综合 |
|
||||
|
||||
### 3.3 `pipeline/external-tools.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| QGIS 可执行文件路径推导(`Contents/MacOS/{ogr2ogr,ogrinfo}`),启动前 `existsSync` 校验 | `reimport-gpkg.js:30-41` |
|
||||
| GDAL 必须注入 `PROJ_LIB` / `GDAL_DATA`,否则坐标系静默出错 | `reimport-gpkg.js:132-137` |
|
||||
| **不设 `COORDINATE_PRECISION`**:会触发精度裁剪,实测丢 28 个顶点 | `reimport-gpkg.js:152-157` |
|
||||
| `ogr2ogr` 失败会留 0 字节文件 → 必须 staging 目录先导出+校验,全通过才拷回 | `reimport-gpkg.js:11-13, 61-91` |
|
||||
| 用 `copyFileSync` 不用 `rename`:临时目录可能跨文件系统 | `reimport-gpkg.js:72-73` |
|
||||
| 导出后必须验 `type === "FeatureCollection"` 且 `features` 是数组 | `reimport-gpkg.js:168-179` |
|
||||
| Blender 以 `--background --factory-startup` 调起,`--` 之后才是脚本参数 | `build-area.js:237-290`, README 低层命令 |
|
||||
| 空图层是警告不是错误 | `reimport-gpkg.js:85-88` |
|
||||
|
||||
### 3.4 `blender/module-structure.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| **按依赖分包不按功能**:`osm.py`/`geom.py` 纯 Python,其余可 import `bpy` | `osmassets/__init__.py:1-12` |
|
||||
| 这条线是几何可测试的前提,拆分前只能靠渲染整片区域来验证 | `__init__.py:9-12`, `test_pure.py:5-8` |
|
||||
| 各模块职责一览(geom/osm/mesh/materials/catalog/tree/water/grass/scrub) | 各文件 docstring |
|
||||
| 要素模块统一 `assemble(...)` 签名,返回计数供调用方汇总 | `water.py:7`, `grass.py:7`, `scrub.py:6` |
|
||||
| 要素模块接收裁剪边界参数,自己调 `clip_polygon`,不假设调用方已裁剪 | 三个 `assemble` 的首行 |
|
||||
| `catalog` 声明"是什么"、`materials` 负责"怎么建"——这个拆分让 catalog 能被无 Blender 环境读取 | `materials.py:1-7` |
|
||||
| 新增一种 OSM 要素 = 新增一个模块 + 注册一行,不改 `build()` | `docs/refactor-plan.md` 目标节 |
|
||||
|
||||
### 3.5 `blender/asset-generation.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| `MeshBatch` 是主力:批成一个 mesh datablock,压低对象数和 glTF 节点数 | `mesh.py:1-9` |
|
||||
| 累积几何后调一次 `finish()` | `mesh.py:6-8` |
|
||||
| 树用实例化:import 一次 → bake 朝向 → 每棵树只链一个轻对象复用 datablock | `tree.py:1-8` |
|
||||
| 材质在本地重建而非沿用源文件,因为两个源模型都不可直接用(apple 57% 贴图透明,需 alpha-clip) | `tree.py:12-16` |
|
||||
| `MATERIALS` / `ROAD_LAYERS` 是 list,**顺序决定 GLB 材质索引**,只能追加 | `catalog.py:16-18` |
|
||||
| `kind` 选择构建器:`solid` / `textured`,`procedural` 叠加噪声 | `catalog.py:52-55` |
|
||||
| Cesium 侧的调色覆盖(`cesium` 字段 + `CESIUM_EXPORT`)为什么单独存在 | `catalog.py:139-153` |
|
||||
| Cesium 默认光照偏白,场景内材质普遍手工提亮过;新资产不提亮会显得发黑 | `docs/changelog.md` 2026-07-31 条目 |
|
||||
|
||||
### 3.6 `blender/testing.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| 运行方式:`python3 -m unittest discover blender/tests`,不需要 Blender | `test_pure.py:1-3` |
|
||||
| **期望值必须从几何推导,不能录制当前实现**——录制型测试会把 bug 固化成规范 | `test_pure.py:9-11` |
|
||||
| 每个几何函数都覆盖退化输入(空、单点、共线、重复顶点、零长线段) | `test_pure.py` 各 `test_degenerate_*` |
|
||||
| 覆盖除零守卫要写明针对哪一行代码 | `test_pure.py:76-78` |
|
||||
| 随机采样函数必须验 seed 可复现 | `test_pure.py:135-138` |
|
||||
| 解析器的容错语义:坏节点跳过不致命,缺 bounds 直接抛 | `test_pure.py:343-356` |
|
||||
| 只能测纯 Python 侧;`bpy` 侧的回归靠 parity 校验 | 指向 `guides/artifact-parity-guide.md` |
|
||||
|
||||
### 3.7 `preview/index.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| 无构建步骤:IIFE + `"use strict"`,通过 `window.OSM_ASSET_PREVIEW_CONFIG` 接参 | `cesium-preview.js:1-4` |
|
||||
| HTML 由 `build-area.js:697 cesiumPreviewHtml()` 生成,注入需转义(`escapeHtml` / `escapeScriptJson`) | `build-area.js:759-767` |
|
||||
| DOM 句柄在顶部集中获取,不散在函数里 | `cesium-preview.js:5-20` |
|
||||
| status 分两类消息(场景摘要 vs 瞬时提示),摘要要保留以便瞬时提示可被替换而非摧毁 | `cesium-preview.js:21-25` |
|
||||
| `Cesium.Ion.defaultAccessToken = ""`:不依赖 Ion 服务 | `cesium-preview.js:27` |
|
||||
| 必须用 HTTP 服务打开,`file://` 会被浏览器拦截 | README 预览节 |
|
||||
| 车辆巡航是预览层实验功能,不影响 Blender/GLB 主资产 | README 实验节 |
|
||||
|
||||
### 3.8 `config/index.md`
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| 字段全表与默认值 | `config/examples/template.json`, `build-area.js:74` |
|
||||
| 路径必须绝对 | template.json |
|
||||
| `outputs` 覆盖是逃生舱,默认从 `id` 推导 | README 区域配置节 |
|
||||
| `qgis.*` 各旋钮的物理含义(arrowScale / arrowMergeTriangles / arrowOutlineSimplifyMeters / intersectionCornerSourceMaxDimensionMeters) | README QGIS knobs 节 |
|
||||
| `arrowOutlineSimplifyMeters: 0.05` 这个默认值的来历(去掉两个畸形尾顶点而不动箭头头部) | README |
|
||||
| `intersectionCornerSourceMaxDimensionMeters` 为什么要过滤大多边形(会盖住可行驶路口) | README |
|
||||
| 新增区域:从 `config/examples/template.json` 复制,落到 `config/areas/` | README |
|
||||
| 已沉淀的两个区域配置 | `config/areas/` |
|
||||
|
||||
### 3.9 `guides/artifact-parity-guide.md`(新增)
|
||||
|
||||
| 要写什么 | 取材 |
|
||||
|---|---|
|
||||
| 什么时候需要跑 parity:任何声称"纯重构"的改动 | `docs/refactor-plan.md` 硬约束节 |
|
||||
| 三件套分工:`scene_digest.py`(.blend 结构)/ `glb-digest.js`(GLB 结构)/ `parity.js`(驱动+比对) | refactor-plan 工具表 |
|
||||
| **必须先做 control 实验**(同代码跑两次)确定天然不稳定字段,跳过这步的 parity 校验是假的 | refactor-plan |
|
||||
| 已确定的不稳定字段与原因:blend sha256(内嵌绝对路径+图片打包顺序)、PNG(EEVEE 非位级可复现)、accessor 数(UV 浮点噪声影响去重) | refactor-plan control 结论 |
|
||||
| 忽略名单写在 `parity.js:IGNORED_PATHS` 且必须附原因 | `parity.js:28-32` |
|
||||
| 真正的契约:stage stdout 标记 + .blend 全量结构摘要 + GLB node/mesh/material/image + `<area>.json` | refactor-plan |
|
||||
| 基线落在 gitignore 的 `outputs/_refactor-baseline/`,是本地草稿不是产物 | `parity.js:16-17` |
|
||||
|
||||
### 3.10 `guides/` 现有两篇的本地化
|
||||
|
||||
保留通用内容,把"触发点"清单换成本项目的真实场景:
|
||||
|
||||
- `cross-layer-thinking-guide.md`:加图层表 JS↔Python 双向同步、GeoJSON→gpkg→GeoJSON 往返、材质名跨 `generate_scene.py`/`export_cesium.py` 对接
|
||||
- `code-reuse-thinking-guide.md`:加 `parseArgs` 在三个脚本重复实现、`clip_polygon` 在四个要素模块各调一次
|
||||
|
||||
### 3.11 `spec/index.md`(新增)
|
||||
|
||||
一张路由表:改哪类代码 → 先读哪个包的 index。加一句"跨语言/跨层改动先读 `guides/`"。
|
||||
|
||||
## 4. 风险与对策
|
||||
|
||||
| 风险 | 对策 |
|
||||
|---|---|
|
||||
| 写成"应该怎么做"的理想规范,与代码实际不符 | 每条约定必须能追到 `path:line`;PRD 验收标准里已定"每文件至少 2 处真实引用" |
|
||||
| 把 README 的用法说明搬进 spec,造成两处维护 | spec 只写"怎么改代码",用法一律指向 README |
|
||||
| 删 `frontend/` 时误删 `guides/` | 只删 `.trellis/spec/frontend/` 单个目录,删后立即用 `--mode packages` 验证 |
|
||||
| 行号引用随代码变动失效 | 行号只作定位提示,同时写函数名/常量名;关键处引用注释原文而非行号 |
|
||||
|
||||
## 5. 兼容性
|
||||
|
||||
- 不动 `config.yaml`:单仓模式自动扫描 `spec/` 子目录
|
||||
- 不动 `.template-hashes.json`:只有 2 个条目,均与本任务文件无关,`trellis update` 不会覆盖
|
||||
- 现有任务的 `implement.jsonl` / `check.jsonl`:本任务尚未生成,无需迁移
|
||||
154
.trellis/tasks/00-bootstrap-guidelines/implement.md
Normal file
154
.trellis/tasks/00-bootstrap-guidelines/implement.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# 执行计划:Trellis spec 重建
|
||||
|
||||
> 对应 `prd.md` / `design.md`。按序执行,每步带验证命令。
|
||||
|
||||
---
|
||||
|
||||
## 前置校验
|
||||
|
||||
```bash
|
||||
# 确认当前 spec layers 是错的(预期输出含 frontend)
|
||||
python3 ./.trellis/scripts/get_context.py --mode packages
|
||||
|
||||
# 确认纯 Python 测试基线是绿的(本任务不该改代码,收尾要复验)
|
||||
python3 -m unittest discover blender/tests -v 2>&1 | tail -5
|
||||
```
|
||||
|
||||
记录测试基线的用例数,收尾时比对。
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — 删除错配脚手架
|
||||
|
||||
- [ ] 删除 `.trellis/spec/frontend/`(7 个文件:index + 6 个模板)
|
||||
|
||||
**只删这一个目录**,`guides/` 必须保留。
|
||||
|
||||
```bash
|
||||
rm -rf .trellis/spec/frontend
|
||||
python3 ./.trellis/scripts/get_context.py --mode packages # Spec layers 应为空
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — `pipeline/` 包(4 个文件)
|
||||
|
||||
按依赖顺序写,`layer-registry.md` 是核心,先写它。
|
||||
|
||||
- [ ] 2.1 `pipeline/layer-registry.md` — 取材 `scene-layers.js` 全文 + `catalog.py:1-19,25-47,162-195`
|
||||
- [ ] 2.2 `pipeline/external-tools.md` — 取材 `reimport-gpkg.js` 全文 + `build-area.js:237-311`
|
||||
- [ ] 2.3 `pipeline/cli-and-stages.md` — 取材 `build-area.js:1-50,74-215`
|
||||
- [ ] 2.4 `pipeline/index.md` — 包索引 + 五个 stage 的数据流全景
|
||||
|
||||
**写 2.3 前需补读**:`build-osm2streets-qgis.js`(1468 行,尚未通读)确认 stage 内部
|
||||
细节与 `normalize-lane-arrows.py` 的调用方式。
|
||||
|
||||
验证:
|
||||
```bash
|
||||
grep -c "scripts/" .trellis/spec/pipeline/*.md # 每个文件应 >= 2
|
||||
grep -rn "To fill\|TODO\|待填" .trellis/spec/pipeline/ ; echo "exit=$?" # 应为 1(无匹配)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — `blender/` 包(4 个文件)
|
||||
|
||||
- [ ] 3.1 `blender/module-structure.md` — 取材 `osmassets/__init__.py` + 各模块 docstring
|
||||
- [ ] 3.2 `blender/testing.md` — 取材 `test_pure.py:1-11` + 各 `test_degenerate_*`
|
||||
- [ ] 3.3 `blender/asset-generation.md` — 取材 `mesh.py`, `materials.py`, `tree.py`, `catalog.py` + changelog 2026-07-31
|
||||
- [ ] 3.4 `blender/index.md` — 包索引 + 依赖分层图(纯 Python / bpy 两层)
|
||||
|
||||
**写 3.3 前需补读**:`generate_scene.py`(999 行)与 `export_cesium.py`(624 行)的
|
||||
结构,确认材质名跨文件对接的实际方式。
|
||||
|
||||
验证:
|
||||
```bash
|
||||
grep -c "blender/" .trellis/spec/blender/*.md
|
||||
grep -rn "To fill\|TODO\|待填" .trellis/spec/blender/ ; echo "exit=$?"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — `preview/` 与 `config/`(各 1 个文件)
|
||||
|
||||
- [ ] 4.1 `preview/index.md` — 取材 `cesium-preview.js` + `build-area.js:697-767`
|
||||
- [ ] 4.2 `config/index.md` — 取材 `config/examples/template.json` + `build-area.js:74-142` + README 配置节
|
||||
|
||||
**写 4.1 前需补读**:`cesium-preview.js`(672 行)主体,目前只读了前 30 行。
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — `guides/` 本地化 + 新增
|
||||
|
||||
- [ ] 5.1 新增 `guides/artifact-parity-guide.md` — 取材 `docs/refactor-plan.md` + `parity.js` + `glb-digest.js` + `scene_digest.py`
|
||||
- [ ] 5.2 更新 `guides/cross-layer-thinking-guide.md` 的触发点清单(保留通用内容)
|
||||
- [ ] 5.3 更新 `guides/code-reuse-thinking-guide.md` 的触发点清单
|
||||
- [ ] 5.4 更新 `guides/index.md` 的指南表格,加入新指南
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — 顶层索引与任务元数据
|
||||
|
||||
- [ ] 6.1 新增 `.trellis/spec/index.md` — 四包路由表
|
||||
- [ ] 6.2 修正 `task.json`:`relatedFiles` 改为四个新包目录,`notes` 去掉 "(frontend project)"
|
||||
|
||||
```bash
|
||||
python3 ./.trellis/scripts/task.py set-meta ... # 或直接编辑 task.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 7 — 全量验收
|
||||
|
||||
对照 `prd.md` 验收标准逐条过:
|
||||
|
||||
```bash
|
||||
# 1. spec layers 正确
|
||||
python3 ./.trellis/scripts/get_context.py --mode packages
|
||||
# 预期:Spec layers: blender, config, pipeline, preview
|
||||
|
||||
# 2. 无占位文本
|
||||
grep -rn "To fill\|TODO\|待填\|FIXME\|<!-- fill" .trellis/spec/ ; echo "exit=$? (1=clean)"
|
||||
|
||||
# 3. frontend 已清除
|
||||
test -d .trellis/spec/frontend && echo "FAIL: still exists" || echo "OK: removed"
|
||||
|
||||
# 4. 每个包有 index.md
|
||||
for d in pipeline blender preview config; do
|
||||
test -f ".trellis/spec/$d/index.md" && echo "OK $d" || echo "FAIL $d"
|
||||
done
|
||||
|
||||
# 5. 关键约定可 grep 定位(8 条)
|
||||
grep -rl "COORDINATE_PRECISION" .trellis/spec/ # 约定 3
|
||||
grep -rl "check_layers" .trellis/spec/ # 约定 1
|
||||
grep -rl "PROJ_LIB\|GDAL_DATA" .trellis/spec/ # 约定 4 相关
|
||||
grep -rl "互斥" .trellis/spec/ # 约定 5
|
||||
grep -rl "bpy" .trellis/spec/blender/ # 约定 6
|
||||
grep -rl "parity" .trellis/spec/ # 约定 8
|
||||
|
||||
# 6. 代码未被误改
|
||||
git status --porcelain -- scripts/ blender/ config/ # 应为空
|
||||
python3 -m unittest discover blender/tests 2>&1 | tail -3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 回滚点
|
||||
|
||||
本任务只新增/删除 `.trellis/spec/` 下的文件,且删除的 `frontend/` 是**未提交的
|
||||
未跟踪文件**(`.trellis/` 整体尚未入库)。
|
||||
|
||||
回滚代价:`frontend/` 的 7 个空模板删掉后无法从 git 恢复。但它们是 `trellis init`
|
||||
生成的、内容为纯占位符,可用 `trellis init` 重新生成,或直接接受丢失——PRD 已确认
|
||||
它们对本项目无价值。
|
||||
|
||||
**保险起见**:Step 1 执行前先把 `.trellis/spec/frontend/` 打包到
|
||||
`/tmp/trellis-frontend-backup.tar.gz`,任务归档后再删。
|
||||
|
||||
---
|
||||
|
||||
## 审查门
|
||||
|
||||
- Step 2 完成后暂停,让用户看 `pipeline/layer-registry.md`——这篇最能反映
|
||||
spec 的目标风格。风格若不对,后面 7 个文件不必按同样方式写完再返工。
|
||||
- Step 7 全部通过后再报告完成。
|
||||
73
.trellis/tasks/00-bootstrap-guidelines/prd.md
Normal file
73
.trellis/tasks/00-bootstrap-guidelines/prd.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 补全 Trellis 项目规范文档
|
||||
|
||||
**类型**:docs · **负责人**:dingkang · **创建**:2026-08-03
|
||||
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
`trellis init` 在本仓库生成了 `.trellis/` 脚手架(v0.6.12),但把项目误判成了前端项目:
|
||||
|
||||
- `.trellis/spec/frontend/` 下 6 个文件全是 React/TypeScript 的空模板,状态栏统一写着 "To fill"
|
||||
- 本仓库实际是 **OSM → QGIS/Blender/Cesium 的资产生成管线**,没有任何前端代码
|
||||
- `task.json` 的 `notes` 直接写着 "First-time setup task created by trellis init (frontend project)"
|
||||
|
||||
后果是具体的:`trellis-implement` / `trellis-check` 子代理会按 `implement.jsonl` / `check.jsonl` 自动加载 spec 文件。当前 spec 为空且方向错误,等于子代理在无约束下写代码——而这个项目有大量**违反直觉、必须遵守**的约定(详见下方"关键约定"),一旦被子代理无意破坏,产物会静默出错而不是报错。
|
||||
|
||||
## 目标
|
||||
|
||||
用真实代码中提取的约定,替换错配的 spec 脚手架,使任何 AI 会话在动手前就能拿到本项目的实际工程约束。
|
||||
|
||||
## 非目标
|
||||
|
||||
- **不改动任何业务代码**。本任务只写 `.trellis/` 下的文档
|
||||
- **不修复代码中的已知缺陷**。`docs/refactor-plan.md` 记录的 D1/D2/D3 只做记录,不在此任务修
|
||||
- **不重写 README/changelog**。它们面向人类使用者,spec 面向 AI 执行者,两者共存不合并
|
||||
- **不引入新的检查脚本或 CI**
|
||||
|
||||
## 交付物
|
||||
|
||||
| # | 交付物 | 说明 |
|
||||
|---|---|---|
|
||||
| D1 | 删除 `.trellis/spec/frontend/` | 6 个空的 React 模板文件,全部移除 |
|
||||
| D2 | `.trellis/spec/pipeline/` | Node 构建管线约定,4 个文件 |
|
||||
| D3 | `.trellis/spec/blender/` | Blender Python 约定,4 个文件 |
|
||||
| D4 | `.trellis/spec/preview/` | Cesium 预览层约定,1 个文件 |
|
||||
| D5 | `.trellis/spec/config/` | 区域配置 JSON 约定,1 个文件 |
|
||||
| D6 | `.trellis/spec/guides/` 本地化 | 更新 index,新增产物一致性指南 |
|
||||
| D7 | `.trellis/spec/index.md` | 顶层索引 |
|
||||
| D8 | `task.json` 元数据修正 | `relatedFiles` / `notes` 去掉 frontend 误判 |
|
||||
|
||||
结构详见 `design.md`。
|
||||
|
||||
## 关键约定(必须被 spec 覆盖)
|
||||
|
||||
这些是从代码注释和 `docs/refactor-plan.md` 中确认的、**违反直觉且破坏后果静默**的约束。spec 的价值主要在这里:
|
||||
|
||||
1. **图层表跨语言单一事实源** — 九个 osm2streets 图层的顺序在 `scripts/lib/scene-layers.js`(JS 侧)和 `blender/osmassets/catalog.py`(Python 侧)各存一份,靠 `catalog.check_layers()` 运行时校验。颜色**故意不同步**(QGIS sRGB 调试色 vs Blender 线性场景色)。
|
||||
2. **顺序是承重的** — `ROAD_LAYERS` / `MATERIALS` 是 list 不是 dict,因为材质创建顺序决定导出 GLB 里的材质索引。只能追加。
|
||||
3. **`ogr2ogr` 不能设 `COORDINATE_PRECISION`** — 显式设置会触发 GDAL 的精度裁剪,实测丢失 7 个箭头多边形的 28 个顶点。
|
||||
4. **`ogr2ogr` 导出失败会留下 0 字节文件** — 所以 `reimport` 必须先导到临时目录、全部校验通过才拷回,不能直接写目标目录。
|
||||
5. **`intermediates` 与 `reimport` 互斥** — 前者从 OSM 重建 gpkg,正好抹掉后者要读回的手工修改。代码里是显式抛错,不是警告。
|
||||
6. **`osmassets` 按依赖分包,不按功能** — `osm.py` / `geom.py` 是纯 Python(可用系统 python 测试),其余可以 import `bpy`。这条线一旦被破坏,`blender/tests/test_pure.py` 就跑不起来。
|
||||
7. **测试的期望值必须从几何推导** — `test_pure.py` 开头明确写着"记录当前输出的测试会把 bug 固化成规范"。
|
||||
8. **重构必须过 parity 校验** — `scripts/parity.js` + `glb-digest.js` + `scene_digest.py` 三件套,比对的是结构摘要而非字节。哪些字段天然不稳定已经用 control 实验确定并列入忽略名单。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] `.trellis/spec/frontend/` 已删除,`python3 ./.trellis/scripts/get_context.py --mode packages` 输出的 Spec layers 为 `blender, config, pipeline, preview`
|
||||
- [ ] 每个 spec 文件都包含**至少 2 处指向真实文件的引用**(`path:line` 或 `path` + 函数名),没有假想路径
|
||||
- [ ] 上方"关键约定" 8 条全部落到具体 spec 文件中,可通过 grep 定位
|
||||
- [ ] 没有任何文件残留 "To fill" / "TODO" / 模板占位文本
|
||||
- [ ] 文档语言为中文;标识符、路径、代码示例保持英文原样
|
||||
- [ ] 每个包目录有 `index.md`,且顶层 `.trellis/spec/index.md` 能索引到全部包
|
||||
- [ ] `blender/tests/test_pure.py` 仍能通过(确认本任务未误改代码)
|
||||
|
||||
## 完成后
|
||||
|
||||
```bash
|
||||
python3 ./.trellis/scripts/task.py finish
|
||||
python3 ./.trellis/scripts/task.py archive 00-bootstrap-guidelines
|
||||
```
|
||||
|
||||
归档后,新加入的开发者会拿到 `00-join-<slug>` 引导任务而不是这个 bootstrap 任务。
|
||||
33
.trellis/tasks/00-bootstrap-guidelines/task.json
Normal file
33
.trellis/tasks/00-bootstrap-guidelines/task.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"id": "00-bootstrap-guidelines",
|
||||
"name": "00-bootstrap-guidelines",
|
||||
"title": "Bootstrap Guidelines",
|
||||
"description": "Fill in project development guidelines for AI agents",
|
||||
"status": "in_progress",
|
||||
"dev_type": "docs",
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P1",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-03",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": null,
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
".trellis/spec/index.md",
|
||||
".trellis/spec/pipeline/",
|
||||
".trellis/spec/blender/",
|
||||
".trellis/spec/preview/",
|
||||
".trellis/spec/config/",
|
||||
".trellis/spec/guides/"
|
||||
],
|
||||
"notes": "First-time setup task for project-specific Trellis spec guidelines.",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user