Add OSM area preflight

This commit is contained in:
2026-08-04 11:58:12 +08:00
parent 34153a31ab
commit e1f5207e97
13 changed files with 434 additions and 5 deletions

View File

@@ -12,6 +12,7 @@
| `scripts/build-osm2streets-qgis.js` | intermediates 阶段的实现 | 由 build-area 调起;`npm run build:qgis` 可单跑 |
| `scripts/reimport-gpkg.js` | reimport 阶段的实现 | 由 build-area 调起 |
| `scripts/diagnose-area.js` | 快速区域诊断只读配置、OSM 和已有产物 | `npm run diagnose:area` |
| `scripts/preflight-area.js` | OSM 构建前预检;只读配置和 OSM并写成功预检记录 | `npm run preflight:area` |
| `scripts/check-area.js` | 区域质量门;复用诊断事实源并给出 PASS/FAIL 退出码 | `npm run check:area` |
`scripts/parity.js``scripts/glb-digest.js` 是校验工具,不属于构建链,见
@@ -121,6 +122,73 @@ npm run compress:glb -- --input outputs/a/a.glb --output outputs/a/a-compressed-
---
## OSM 预检命令
### 1. Scope / Trigger
`preflight:area` 用于手工编辑 OSM 后、运行 QGIS / Blender / Cesium 前的快速结构门槛。
它不是构建阶段,不进入 `build-area --stages`,不会启动外部工具或写场景产物。
### 2. Signatures
```bash
npm run preflight:area
npm run preflight:area -- --config config/areas/<area>.json
```
### 3. Contracts
- 通过 `readAreaConfig()` 读取区域配置,只读取配置文件和 OSM XML。
- OSM 解析和错误分类来自 `scripts/lib/area-diagnostics.js`,不得另建 XML 解析器。
- `<node>``<way>``<relation>``action="delete"` 时属于历史删除对象,解析统计和
几何检查必须忽略;否则旧 OSM 导出会把已删除的建筑误报为损坏面。
- 无效 bounds、任意 way 缺失 node、破损 building way、破损 building multipolygon、
不可解析为正米数的显式 building `height` 都是 error并以非零退出。
- 不填 `height` / `building:levels` 合法;无效 `building:levels` 是 warning。
- 仅在 error 为零时原子写 `<areaDir>/_pipeline/stages/preflight.manifest.json`。失败不覆盖
上次成功 manifest。manifest 记录 config / OSM 文件摘要、预检 summary、errors、warnings
和耗时。
- `diagnose:area` 显示该 manifest`check:area` 仅在 manifest 存在时检查其有效性和
freshness故采用前不会使旧区域质量门失败。
### 4. Validation & Error Matrix
| 条件 | 结果 |
|---|---|
| 无效 bounds、缺失 node、破损建筑几何、坏显式 height | 输出 error非零不覆盖旧 manifest |
| 无效 `building:levels` | 输出 warning仍可成功写 manifest |
| `action="delete"` 的节点 / way / relation | 忽略,不计入当前 OSM 或报错 |
| OSM / config 不存在 | `readAreaConfig()` 或文件读取抛错,非零 |
### 5. Good/Base/Bad Cases
- Good: 手工编辑后预检 PASS再运行 `build-area` 的任意重型阶段。
- Base: 未运行过预检的旧区域,`check:area` 仍可按既有规则通过。
- Bad: 预检失败后仍更新 manifest或把预检加入 `all` 导致每次构建修改验证记录。
### 6. Tests Required
- `npm run test:preflight`
- `npm run preflight:area -- --config config/areas/nantaizi-lake-innovation-valley.json`
- `npm run diagnose:area -- --config config/areas/nantaizi-lake-innovation-valley.json`
- `npm run check:area -- --config config/areas/nantaizi-lake-innovation-valley.json`
### 7. Wrong vs Correct
Wrong:
```js
const xml = fs.readFileSync(area.input, "utf8");
const missingNodes = xml.match(/<nd[^>]*ref=/g).length;
```
Correct:
```js
const osm = parseOsm(fs.readFileSync(area.input, "utf8"));
const preflight = analyzeOsmPreflight(osm);
```
## 区域诊断命令
### 1. Scope / Trigger
@@ -300,8 +368,8 @@ const gate = classifyAreaQuality(result);
### 1. Scope / Trigger
Stage manifest 是构建阶段完成后的机器可读产物契约。它覆盖完整区域链:
`intermediates``reimport``blender``cesium``preview``compress`
Stage manifest 是区域构建阶段或独立验证通过后的机器可读产物契约。它覆盖预检记录与完整区域链:
`preflight``intermediates``reimport``blender``cesium``preview``compress`
它用于诊断产物是否存在、是否 stale、体量是否超预算以及后续 `check:area` /
增量构建判断。
@@ -316,6 +384,7 @@ Manifest 路径固定:
当前会写:
```text
<areaDir>/_pipeline/stages/preflight.manifest.json
<areaDir>/_pipeline/stages/intermediates.manifest.json
<areaDir>/_pipeline/stages/reimport.manifest.json
<areaDir>/_pipeline/stages/blender.manifest.json
@@ -362,6 +431,15 @@ File records use this shape:
}
```
`preflight` manifest:
- `inputs.config`
- `inputs.osm`
- `outputs` 固定为空对象(预检不拥有场景产物)
- `summary`bounds、node / way / relation、building way / multipolygon 与问题计数
- `errors` 固定为空数组(只有通过的预检会写 manifest`warnings`
- manifest 不存在时不算质量门失败;存在但 input 摘要漂移或 JSON 损坏时,`check:area` 失败
`intermediates` manifest:
- `inputs.config`