chore(task): archive 08-11-asset-package-contract
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
{"file":".trellis/spec/pipeline/cli-and-stages.md","reason":"Verify package stage ordering, manifest freshness, and external-tool boundaries."}
|
||||||
|
{"file":".trellis/spec/config/index.md","reason":"Verify all new output paths remain centralized in area-config."}
|
||||||
|
{"file":".trellis/spec/preview/index.md","reason":"Verify preview remains a consumer of package assets, not part of the published package."}
|
||||||
|
{"file":".trellis/spec/guides/artifact-parity-guide.md","reason":"Assess intentional output-contract changes and asset verification scope."}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# Asset Package Contract Design
|
||||||
|
|
||||||
|
## Product Boundary
|
||||||
|
|
||||||
|
`outputs/<area-id>/` remains the build workspace. Its `package/` child is the only
|
||||||
|
publishable subtree and may be copied unchanged to another project. The package has
|
||||||
|
no dependency on the parent directory, repository checkout, absolute local paths,
|
||||||
|
QGIS, Blender, or the Cesium preview.
|
||||||
|
|
||||||
|
```
|
||||||
|
outputs/<area-id>/
|
||||||
|
package/ # publishable boundary
|
||||||
|
manifest.json # asset-package/v1
|
||||||
|
models/
|
||||||
|
<area-id>.glb # compressed complete static scene
|
||||||
|
roads.glb
|
||||||
|
buildings.glb
|
||||||
|
vegetation.glb
|
||||||
|
water.glb
|
||||||
|
<area-id>-cesium-preview.html # local verification only
|
||||||
|
_preview/ # vehicles, routes, dynamic signal runtime
|
||||||
|
_pipeline/ # staging, manifests and build diagnostics
|
||||||
|
osm2streets_web_out/, *.gpkg, *.qgz, *.blend, *.png
|
||||||
|
```
|
||||||
|
|
||||||
|
The package does not duplicate the GLBs: Cesium export and compression target the
|
||||||
|
package model paths. Build staging lives under `_pipeline/` and is removed before a
|
||||||
|
successful package is published.
|
||||||
|
|
||||||
|
## Manifest v1
|
||||||
|
|
||||||
|
The JSON root uses `schema: "osm-asset-package/v1"`. Required top-level fields are:
|
||||||
|
|
||||||
|
| Field | Contract |
|
||||||
|
|---|---|
|
||||||
|
| `schema`, `packageVersion`, `areaId` | Stable identity and schema evolution point |
|
||||||
|
| `coordinateSystem` | Literal local ENU contract: X east, Y north, Z up, meters |
|
||||||
|
| `placement` | WGS84 anchor longitude/latitude/height plus heading correction degrees |
|
||||||
|
| `bounds` | WGS84 `minLon`, `minLat`, `maxLon`, `maxLat` |
|
||||||
|
| `assets` | Deterministic list of declared publishable assets |
|
||||||
|
| `sceneStats` | Optional descriptive OSM-derived counts, not loading-critical |
|
||||||
|
|
||||||
|
Each asset has `id`, `role`, `category`, `uri`, and `defaultLoad`. `uri` is a
|
||||||
|
forward-slash relative path inside `package/`; it must not be absolute, start with
|
||||||
|
`/`, contain `..`, or resolve outside the package. Roles are `scene` for the complete
|
||||||
|
static scene and `layer` for separately loadable semantic subsets. Categories are
|
||||||
|
fixed in v1: `scene`, `roads`, `buildings`, `vegetation`, `water`.
|
||||||
|
|
||||||
|
`models/<area-id>.glb` is the only `scene` entry and defaults to load. Layer GLBs are
|
||||||
|
optional alternatives for selective loading and default off; consumers must not load
|
||||||
|
both the complete scene and overlapping layers unless intentionally composing them.
|
||||||
|
|
||||||
|
The manifest deliberately excludes `source_osm`, `source_geojson`, arbitrary Cesium
|
||||||
|
JavaScript, vehicle routes, vehicle models, dynamic signal states, countdown models,
|
||||||
|
preview runtime paths, build timestamps and desktop paths. File digests and sizes may
|
||||||
|
be added under an optional `integrity` object only after they are computed from final
|
||||||
|
compressed files.
|
||||||
|
|
||||||
|
## Pipeline Design
|
||||||
|
|
||||||
|
### 1. Static export seed
|
||||||
|
|
||||||
|
`blender/export_cesium.py` continues to own static GLB generation, WGS84 bounds,
|
||||||
|
anchor and semantic collection selection. It must emit data suitable for a manifest
|
||||||
|
seed, not a preview metadata document. Static traffic-signal geometry already in the
|
||||||
|
main scene remains part of the static scene; animated traffic signal and countdown
|
||||||
|
collections are not package assets.
|
||||||
|
|
||||||
|
### 2. Package staging and compression
|
||||||
|
|
||||||
|
The build orchestrator owns output paths through `normalizeAreaConfig()`. It adds
|
||||||
|
explicit package paths and exports static GLBs to a package staging directory beneath
|
||||||
|
`_pipeline/`. Compression works only on staged package files and rewrites the staged
|
||||||
|
manifest's main GLB URI after successful compression. It never needs to copy or alter
|
||||||
|
preview HTML.
|
||||||
|
|
||||||
|
After path validation, file existence checks, and manifest validation, the package
|
||||||
|
stage promotes the whole staging directory to `outputs/<area-id>/package/`. Promotion
|
||||||
|
is directory-level and replaces a previous package only after the new one is valid.
|
||||||
|
On failure, the previous published package remains usable and staging is retained or
|
||||||
|
reported for diagnosis according to existing pipeline failure conventions.
|
||||||
|
|
||||||
|
### 3. Preview adapter
|
||||||
|
|
||||||
|
The existing Cesium preview remains a verification tool outside the package. It reads
|
||||||
|
the package manifest via its relative path, then loads preview-only route, vehicle and
|
||||||
|
dynamic-signal descriptors from `_preview/`. Dynamic traffic assets are declared in a
|
||||||
|
preview-specific descriptor, never appended to package `assets`. This preserves
|
||||||
|
existing high-precision cruise validation without making it a downstream requirement.
|
||||||
|
|
||||||
|
### 4. Stage and compatibility behavior
|
||||||
|
|
||||||
|
Canonical order becomes `intermediates/reimport -> blender -> cesium -> compress ->
|
||||||
|
package -> preview`. `package` is included in the full default build and is callable
|
||||||
|
explicitly to validate/publish existing staged static exports. `preview` stays an
|
||||||
|
optional/verification stage, not a package dependency.
|
||||||
|
|
||||||
|
Existing `npm run build:area -- --config ... --stages ...` remains supported. Root
|
||||||
|
level legacy GLB/JSON/HTML files are not deleted by the migration; they are not read
|
||||||
|
as a fallback by the new package contract. A clean full build produces the package as
|
||||||
|
the canonical downstream asset source.
|
||||||
|
|
||||||
|
## Consumer Examples
|
||||||
|
|
||||||
|
Examples live in repository source, outside individual packages:
|
||||||
|
|
||||||
|
- Cesium: fetch `manifest.json`, derive the ENU frame from `placement`, apply heading
|
||||||
|
correction, then load `assets` by `uri`.
|
||||||
|
- Three.js: load the selected model URL relative to the manifest URL; expose the same
|
||||||
|
ENU placement object to the host application's georeferencing adapter. It must not
|
||||||
|
imply that Three.js alone converts ENU to WGS84.
|
||||||
|
|
||||||
|
Both examples load the complete scene and demonstrate selecting a single `layer`.
|
||||||
|
They validate that URLs are resolved relative to the manifest rather than the current
|
||||||
|
page or repository root.
|
||||||
|
|
||||||
|
## Validation and Rollback
|
||||||
|
|
||||||
|
Unit tests validate schema fields, category/role legality, package-relative URI rules,
|
||||||
|
and rejection of omitted/extra files. An integration fixture constructs a minimal
|
||||||
|
package and verifies that Cesium and Three.js example resolvers choose identical
|
||||||
|
relative URLs and placement values. A target-area package test checks final compressed
|
||||||
|
GLB parsing and manifest references.
|
||||||
|
|
||||||
|
The package stage writes a stage manifest containing only final published records and
|
||||||
|
their integrity. Diagnostic checks distinguish missing package, invalid package, and
|
||||||
|
stale package. Rollback is to the prior `package/` directory; legacy preview outputs
|
||||||
|
remain untouched throughout rollout.
|
||||||
|
|
||||||
|
## Deferred Decisions
|
||||||
|
|
||||||
|
- Rich per-feature semantics, routing graph delivery and simulation inputs are not in
|
||||||
|
v1; they should be introduced through a later schema version only when a downstream
|
||||||
|
consumer requires them.
|
||||||
|
- Asset coverage improvements are downstream of this contract work.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{"file":".trellis/spec/pipeline/cli-and-stages.md","reason":"Stage ordering, manifests, external-command boundary, and compression contracts."}
|
||||||
|
{"file":".trellis/spec/config/index.md","reason":"Area output-path normalization and configuration contract."}
|
||||||
|
{"file":".trellis/spec/preview/index.md","reason":"Preview config injection and browser runtime compatibility."}
|
||||||
|
{"file":".trellis/spec/guides/cross-layer-thinking-guide.md","reason":"Blender-to-Node-to-browser coordinate and artifact contract risks."}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
# Asset Package Contract Implementation Plan
|
||||||
|
|
||||||
|
## Phase 0: Contract Lock-In
|
||||||
|
|
||||||
|
- [ ] Add a package-contract module that owns v1 schema constants, allowed roles and
|
||||||
|
categories, URI containment validation, manifest construction and validation.
|
||||||
|
- [ ] Add focused unit fixtures for valid manifests and each invalid condition:
|
||||||
|
missing schema/placement/bounds, malformed coordinates, invalid role/category,
|
||||||
|
absolute or traversing URI, duplicate asset ID, missing primary scene, and referenced
|
||||||
|
file outside the package.
|
||||||
|
- [ ] Document `package/` as the sole downstream boundary in README and pipeline/config
|
||||||
|
specs; retain a clear distinction between release assets and preview artifacts.
|
||||||
|
|
||||||
|
Gate: manifest v1 can be created and structurally validated without invoking Blender,
|
||||||
|
Cesium or QGIS.
|
||||||
|
|
||||||
|
## Phase 1: Package Paths and Static Export
|
||||||
|
|
||||||
|
- [ ] Extend `scripts/lib/area-config.js` with paths for `packageDir`, package manifest,
|
||||||
|
package model directory, primary GLB and semantic layer GLBs; keep all path derivation
|
||||||
|
in this module.
|
||||||
|
- [ ] Change `blender/export_cesium.py` metadata output to a static manifest seed:
|
||||||
|
bounds, ENU placement and static scene/layer declarations only. Remove local source
|
||||||
|
paths and inline Cesium source code from the published data.
|
||||||
|
- [ ] Direct static GLB output to package staging paths and retain dynamic signal/countdown
|
||||||
|
output as preview-only paths outside package staging.
|
||||||
|
- [ ] Update `build-area.js`, semantic asset checks, stage manifests and diagnostics to
|
||||||
|
consume the new path contract rather than constructing paths locally.
|
||||||
|
|
||||||
|
Gate: a Cesium export produces a valid static manifest seed and every declared static
|
||||||
|
asset exists under package staging; no preview-only asset appears in it.
|
||||||
|
|
||||||
|
## Phase 2: Compression and Atomic Publication
|
||||||
|
|
||||||
|
- [ ] Refactor the default compression stage to operate on staged package files,
|
||||||
|
preserving the final manifest shape while replacing only the primary GLB bytes and
|
||||||
|
integrity data.
|
||||||
|
- [ ] Add a `package` stage after `compress`; validate every asset and atomically promote
|
||||||
|
staging to `outputs/<area-id>/package/`.
|
||||||
|
- [ ] Update canonical stage ordering, `all`, interactive CLI labels and defaults.
|
||||||
|
- [ ] Ensure a failed compression/package validation never replaces an existing published
|
||||||
|
package; record diagnostics sufficient to identify the failed source/staging path.
|
||||||
|
|
||||||
|
Gate: a full build creates one publishable package with compressed primary GLB and no
|
||||||
|
duplicate static GLBs at the area root.
|
||||||
|
|
||||||
|
## Phase 3: Preview Adapter and Compatibility
|
||||||
|
|
||||||
|
- [ ] Change preview HTML generation to reference `package/manifest.json` relative to
|
||||||
|
the area output root.
|
||||||
|
- [ ] Move route/vehicle/dynamic-signal discovery into a preview-only descriptor beneath
|
||||||
|
`_preview/`, and make `cesium-preview.js` merge it after loading the package manifest.
|
||||||
|
- [ ] Preserve existing preview controls and graceful behavior when preview-only data is
|
||||||
|
absent; preview must still render the package static scene.
|
||||||
|
- [ ] Update `diagnose:area`, `check:area` and stage manifest freshness to distinguish
|
||||||
|
package artifacts from preview-only files.
|
||||||
|
|
||||||
|
Gate: the local Cesium preview loads the published package and continues to show
|
||||||
|
optional cruise/dynamic preview content without adding either to package manifest.
|
||||||
|
|
||||||
|
## Phase 4: Downstream Consumption Proof
|
||||||
|
|
||||||
|
- [ ] Add Cesium example code that resolves the manifest URL, validates placement and
|
||||||
|
loads the full scene or selected layers.
|
||||||
|
- [ ] Add Three.js example code with a manifest-relative resolver and an explicit ENU
|
||||||
|
placement handoff to the host's georeferencing integration.
|
||||||
|
- [ ] Add automated resolver tests so neither example can regress to page-relative,
|
||||||
|
desktop-absolute or repository-relative URLs.
|
||||||
|
- [ ] Publish consumer documentation including overlap rules for complete scene vs layers.
|
||||||
|
|
||||||
|
Gate: examples run from a copied `package/` directory and require no files outside it.
|
||||||
|
|
||||||
|
## Phase 5: Full Verification and Migration
|
||||||
|
|
||||||
|
- [ ] Run focused Node tests for package schema, stage resolution, compression metadata,
|
||||||
|
preview behavior, diagnostics and asset budgets.
|
||||||
|
- [ ] Run the full default build for the primary area, then `check:area` and package
|
||||||
|
integrity validation.
|
||||||
|
- [ ] Inspect the packaged GLB structure and validate the Cesium example in browser;
|
||||||
|
verify Three.js resolver output with the same manifest.
|
||||||
|
- [ ] Capture expected intentional output-contract changes in docs/changelog and update
|
||||||
|
relevant Trellis pipeline/config/preview specs.
|
||||||
|
- [ ] Preserve legacy root-level artifacts during rollout; document that downstream
|
||||||
|
consumers must migrate to `package/manifest.json` rather than treating legacy files
|
||||||
|
as fallback.
|
||||||
|
|
||||||
|
## High-Risk Boundaries
|
||||||
|
|
||||||
|
- `blender/export_cesium.py` to Node: static metadata fields and semantic asset file
|
||||||
|
names are a cross-runtime contract.
|
||||||
|
- Node packaging to preview runtime: preview-only dynamic data must never silently enter
|
||||||
|
the package manifest.
|
||||||
|
- Compression to publication: paths must remain package-relative and a partial write must
|
||||||
|
not replace the last valid package.
|
||||||
|
- Consumers: ENU axes and heading correction are load-bearing; examples must not create
|
||||||
|
a second, incompatible georeferencing convention.
|
||||||
|
|
||||||
|
## Validation Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run test:build-stages
|
||||||
|
npm run test:compress-glb
|
||||||
|
npm run test:preview-assets
|
||||||
|
npm run test:budgets
|
||||||
|
npm run test:preflight
|
||||||
|
npm run check:area -- --config config/areas/nantaizi-lake-innovation-valley.json
|
||||||
|
node scripts/glb-digest.js outputs/nantaizi-lake-innovation-valley/package/models/nantaizi-lake-innovation-valley.glb
|
||||||
|
```
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Reusable asset package contract
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
将当前面向 Cesium 预览的区域输出升级为可由多个下游项目稳定消费的静态资产包。资产包
|
||||||
|
必须有版本化 manifest、仅使用包内相对引用,并明确发布资产与本项目调试/预览产物的边界。
|
||||||
|
|
||||||
|
## Confirmed Facts
|
||||||
|
|
||||||
|
- `blender/export_cesium.py` 已生成 `<area>.json`,包含主 GLB、roads/buildings/
|
||||||
|
vegetation/water 分层 GLB、WGS84 anchor、ENU 坐标约定、heading correction 和 OSM bounds。
|
||||||
|
- 该 JSON 同时包含桌面绝对 `source_osm` / `source_geojson` 路径、Cesium 代码片段,以及
|
||||||
|
动态信号灯和倒计时预览资产;因此不是可发布的下游契约。
|
||||||
|
- `outputs/<area>/` 还包含 QGIS、GeoJSON、Blender、Cesium HTML/runtime、车辆巡航和自检文件;
|
||||||
|
它是构建工作目录,不是干净的发布目录。
|
||||||
|
- 当前默认 Cesium GLB 已在构建末端压缩,且 metadata 中的资产 URL 使用同目录相对文件名。
|
||||||
|
- 项目目标是生成可复用资产;交通仿真、跟车和信号调度属于下游运行时能力,不属于资产包首版。
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- R1:定义一个版本化 `manifest.json` v1,描述区域 ID、WGS84 anchor、ENU 轴向与 heading
|
||||||
|
correction、WGS84 bounds、发布资产、语义类别和包内相对路径。
|
||||||
|
- R2:资产包只含可复用的静态交付资产;主场景和道路、建筑、植被、水体等分层模型必须有
|
||||||
|
明确的角色、加载语义和默认行为。
|
||||||
|
- R3:manifest 和包内文件不得包含桌面绝对路径、构建临时目录、Cesium HTML/runtime、
|
||||||
|
QGIS、GeoJSON、`.blend`、车辆巡航或动态交通信号调度依赖。
|
||||||
|
- R4:在不破坏现有区域预览、诊断和构建中间产物的前提下,增加明确的资产包发布阶段。
|
||||||
|
- R5:提供 Cesium 与 Three.js 的最小加载示例,均从 manifest 读取包内相对 URL,并按相同的
|
||||||
|
WGS84/ENU 契约放置主场景或分层资产。
|
||||||
|
- R6:定义发布资产、可选静态资产和本项目仅检查产物的分类规则,并由测试验证。
|
||||||
|
- R7:完整构建后的资产包应可独立复制到其他项目,而无需本仓库的 `outputs` 目录结构或本地路径。
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] 目标区域生成一个可独立分发的资产包目录,其中仅有 manifest 和 manifest 引用的发布资产。
|
||||||
|
- [ ] manifest 的 schema version、坐标契约、bounds、所有资产类别和 URL 可由程序校验。
|
||||||
|
- [ ] 所有 manifest URL 都是安全的包内相对路径;不得含绝对路径、`..` 或未声明文件。
|
||||||
|
- [ ] 主 GLB 与每个发布分层资产都能在 Cesium 和 Three.js 示例中按 manifest 正确放置与加载。
|
||||||
|
- [ ] 车辆、巡航路线、Cesium preview HTML/runtime、QGIS/GeoJSON/`.blend` 和动态信号调度资产
|
||||||
|
不会进入发布包。
|
||||||
|
- [ ] 既有 `outputs/<area>/` 预览工作流继续可用,现有非交互 build 命令保持兼容。
|
||||||
|
- [ ] 发布包缺文件、manifest 路径越界、坐标字段无效或资产类别不合法时,构建/校验非零退出。
|
||||||
|
|
||||||
|
## Proposed Delivery Phases
|
||||||
|
|
||||||
|
1. 契约与目录边界:冻结 manifest v1 schema、发布目录结构、资产角色和坐标定义。
|
||||||
|
2. 资产包发布阶段:从现有 Cesium 导出与压缩结果收集、校验并写入独立包目录。
|
||||||
|
3. 下游消费证明:Cesium / Three.js 示例仅依赖 manifest 与包内容,并覆盖主场景和按类别加载。
|
||||||
|
4. 质量门与迁移:增加结构、路径隔离、坐标和加载验证;保留旧预览输出并记录迁移规则。
|
||||||
|
|
||||||
|
## Key Decision
|
||||||
|
|
||||||
|
- 发布包根目录固定为 `outputs/<area-id>/package/`。该目录是可整体复制给下游项目的唯一
|
||||||
|
发布边界;GLB 和 manifest 直接生成或移动到这里,避免与工作目录再保留一套大模型副本。
|
||||||
|
本项目的预览页可通过包内相对路径读取发布资产,但 HTML/runtime 本身不属于发布包。
|
||||||
|
|
||||||
|
## Out Of Scope
|
||||||
|
|
||||||
|
- 交通流、车辆行为、信号相位控制、路口调度和其他运行时仿真。
|
||||||
|
- 在本任务中扩展 OSM 到建筑、路灯、标志、植被等资产覆盖率或生成质量。
|
||||||
|
- 删除既有 `outputs/<area>/` 中由用户保留的历史调试产物。
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"id": "asset-package-contract",
|
||||||
|
"name": "asset-package-contract",
|
||||||
|
"title": "Reusable asset package contract",
|
||||||
|
"description": "",
|
||||||
|
"status": "completed",
|
||||||
|
"dev_type": null,
|
||||||
|
"scope": null,
|
||||||
|
"package": null,
|
||||||
|
"priority": "P2",
|
||||||
|
"creator": "dingkang",
|
||||||
|
"assignee": "dingkang",
|
||||||
|
"createdAt": "2026-08-11",
|
||||||
|
"completedAt": "2026-08-12",
|
||||||
|
"branch": null,
|
||||||
|
"base_branch": "main",
|
||||||
|
"worktree_path": null,
|
||||||
|
"commit": null,
|
||||||
|
"pr_url": null,
|
||||||
|
"subtasks": [],
|
||||||
|
"children": [],
|
||||||
|
"parent": null,
|
||||||
|
"relatedFiles": [],
|
||||||
|
"notes": "",
|
||||||
|
"meta": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user