# 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//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 ```