# Specification review — 2026-09-06 (America/Los_Angeles) ## Scope - **Local date:** 2026-09-06 (America/Los_Angeles, PDT / UTC−7). Written 2026-09-06 17:38 UTC. - **Branch:** `main` - **HEAD:** `0af58da89dd6095fa9ca3ed546a2e48d7c7971b7` (`feat(visual): implement the slice 4d renderer core`) - **Today’s commits (since 2026-09-06 07:00 UTC):** `1bc4901` (spec §§17–19 rev 0.8), `6587d3e` (schema/validator/resolution), `699492f` (standalone bundle), `0af58da` (4d renderer). - **Uncommitted work:** Phase 4e–4g runtime (`src/runtime/visual-*.js`, engine/actions/app/resolution/performance), tests, exhibits, evidence. **Git cannot date uncommitted files;** they are in scope as the current tree. - **Authoritative sources:** `docs/XZBT_0-1_Format_Specification.md` rev **0.8**, especially §§6, 8.1, 9.1, 10.1–10.2, **17–19** (19.1–19.7). Supporting: `docs/XZBT_0-1_Implementation_Plan.md` Phase 4 slice table. PRD cited only where the spec restates it. - **Not used:** any file under `/reviews`. - **Limitations:** Action Model (spawn/remove *shapes*) is explicitly not fixed in §19.2; Phase 6 scenarios and 4h/GC6 (traces 20–21) are deferred and not treated as defects. Display judgment not run. ## Traceability (today’s visual work → spec) | Item | Spec | Implementation | Status | | --- | --- | --- | --- | | Scene / fit / primitives / compositing | 17.4–17.13 | `visual-engine.js`, `visual-geometry.js`, `visual-canvas2d.js` | **Satisfied** (4d tests 17.16.*) | | Camera matrix, parallax, perspective, focalLength clamp | 19.3 | `cameraMatrix`, `planFrame` | **Satisfied** (static + execution tests) | | Components, particles, emitters, repeaters, behaviors, fields, trails, links | 18.1–18.8 | `visual-systems.js`, `visual-behaviors.js`, `visual-fields.js`, `visual-distributions.js` | **Satisfied** (18.10 traces in `phase4-procedural.test.mjs`) | | Exhibit + system automation, shared curves/modes, live vs authoring budgets | 19.1, 16.1 | `resolution.js`, `visual-automation.js`, `audio-automation.js` | **Partial** (curves/modes/budgets tested; local-track target walk unsafe; 19.7.3/4 coverage incomplete) | | Lifecycle, spawn/remove, ownership, release factor | 19.2 | `visual-lifecycle.js`, `VisualEngine.spawn/remove/cleanup` | **Partial** (`DurationSpec` after evaluation vs `parseDuration`; action lifetime not specified in §19) | | Post-effects chain, grain isolation, pass ceiling | 19.4 | `visual-effects.js`, `effectPlan` | **Partial** (pixel tests exist; radius/energy vs 19.4 table not fully asserted) | | Aggregate ceilings + cadence | 19.5–19.6 | `enforcePopulations`, `visual-diagnostics.js` | **Satisfied** for automated 19.7.18 cases; **unverified** vs measured 4h values (provisional by spec) | | 19.7 traces 1–19 | 19.7 | `test/phase4-execution.test.mjs` | **Partial** (many named tests; 19.7.3/4/8/13 not all matching the prose) | | 19.7 traces 20–21 | 19.7 | — | **Deferred** (4h / display); not a defect | ## Findings (confirmed gaps) ### 1. `spawn.lifetime` / action lifetime after evaluation is not a duration literal - **Priority:** P1 - **Spec:** §6.1 — durations are unit strings converted internally to milliseconds. §19.2 — `spawn.lifetime` and `spawn.release` are **DurationSpec**; instance duration is that logical duration from instantiation. - **Impl:** `visual-engine.js:466-468` always `parseDuration(sampleTree(...))`, which requires `typeof value === 'string'` (`types.js:55-56`). `actions.js:48-50` may `evaluateValue(action.lifetime)` first. - **Expected:** Authored DurationSpec remains a duration literal through sampling, then converts to ms. If evaluation yields a number (ms), it must still be accepted or rejected with `ERR_TYPE_MISMATCH`, not `ERR_INVALID_DURATION`. - **Actual:** Any non-string (including a resolved number) throws `ERR_INVALID_DURATION` and aborts spawn. - **Trigger:** `spawn` action with evaluated `lifetime`, or a DurationSpec that the value resolver does not leave as a string. - **Impact:** Legal instance lifetimes fail at runtime; §19.2 “absent means until remove” path is the only reliably tested path. - **Correction:** Convert DurationSpec with `parseDuration` only when the value is still a string; if already a finite number, treat as milliseconds (or reject per strict coercion ban §2 — pick one and match §6.1). ### 2. Local automation target walk throws `TypeError` instead of `ERR_INVALID_REFERENCE` - **Priority:** P1 - **Spec:** §19.1 — target naming an undeclared object is `ERR_INVALID_REFERENCE`; outside the registry is `ERR_UNSUPPORTED_TARGET`. Import should reject; runtime must not invent a third failure mode. - **Impl:** `visual-automation.js:11-13`: `while (object?.children.some(...))` — if `find` returns `undefined`, `.some` is called on `undefined`. - **Expected:** Validator fault at import, or runtime `RuntimeFault` with those codes. - **Actual:** Uncaught `TypeError` during `createSystem` / instantiate (outside the per-tick `try` in `advance`). - **Trigger:** Dangling graphic-object key on a system `automation` track, or exhibit-scope fallback path `visual-engine.js:403-406`. - **Impact:** Tick/activation abort rather than a documented diagnostic. - **Correction:** Guard `object?.children?.some`; if missing, throw `RuntimeFault('ERR_INVALID_REFERENCE', ...)`. ### 3. Required traces 19.7.3 and 19.7.4 are not implemented as specified - **Priority:** P2 - **Spec:** §19.7 items 3–4 (lines ~3255–3258 of the format spec): (3) system-scope `at` from instantiation — two spawns 4s apart produce identical curves offset by 4s; (4) cross-scope / undeclared / out-of-registry targets raise `ERR_INVALID_REFERENCE` vs `ERR_UNSUPPORTED_TARGET` as specified. - **Impl:** `test/phase4-execution.test.mjs` “19.7.3” only checks one exhibit-scope stream; “19.7.4” only checks behavior/automation `ERR_AUTOMATION_CONFLICT`. - **Expected:** The behaviors named in 19.7.3–4 actually run (spec: “a parsed stub is never a passed runtime trace”). - **Actual:** Adjacent properties are tested; the named traces are not. - **Trigger:** Acceptance of slice 4f against 19.7. - **Impact:** Spawn-relative automation offset and target-error taxonomy can regress without a failing test. - **Correction:** Add the two-spawn 4s offset assertion and the four negative target cases from 19.7.4. ### 4. Blur/bloom radius vs 19.4 “32 scene units” is not enforced in the pixel filter - **Priority:** P3 - **Spec:** §19.5 authoring table / 19.4 — blur and bloom radius **32 scene units**; pipeline clamp of 8.1 on effect parameters. - **Impl:** `visual-effects.js:4-5` caps box-blur radius at `max(width,height)` **pixels** (device radius from `effectPlan`). Contract numeric clamp is in `effectPlan` via `POST_EFFECTS`; the filter can still run at huge projected radii. - **Expected:** Authored/resolved radius in scene units stays in the 19.4 table; device radius is a projection of that, not an unbounded pixel kernel. - **Actual:** Device kernel can equal the long edge of the backing store. - **Trigger:** Large `zoom` × `deviceRadius` with radius still inside 32 scene units. - **Impact:** Frame hitch; not a silent spec violation of the authored 32 if `effectPlan` clamps scene units — **partial**. Confirm `POST_EFFECTS` max is 32 and that tests assert it (19.7.15 does not). - **Correction:** Assert 19.4 ranges in execution tests; cap device radius by a pixel budget derived from the scene-unit max. ## Specification ambiguities (not defects) 1. **§19.2 vs Action Model:** spawn/remove *action shapes* are explicitly not fixed in 19.2. Whether `action.lifetime` is DurationSpec, ValueSpec\, or either is **undecided**. Finding 1 is a defect only for `spawn.lifetime` after `sampleTree`; action-lifetime typing needs a decision in the Action Model (Phase 5/6), not a silent assumption. 2. **DurationSpec vs TimeSpec (§6.2):** 19.2 names DurationSpec, not the random TimeSpec object. Whether `spawn.lifetime: { "random": { "min": "1s", "max": "2s" } }` is legal is **unspecified**. Implementation would currently fail `parseDuration` on an object. 3. **19.5 values** are provisional until 4h/trace 21; using 8192 particles / 2048 emitters in tests matches the *current table*, not a measured GC6 result. 4. **`instances.*` addressing** is runtime-only (19.2 / 8.1). Tests use `instances.s#N`; the Action Model still owns the public `remove` target grammar. ## Verification - Read spec §§6, 17–19.7 and traced `spawn`, `advance`, automation, lifecycle, effects, resolution `visualValues`. - `node --test test/phase4-*.test.mjs test/phase1-runtime.test.mjs`: **116 pass, 0 fail** (prior turn). Tests are evidence of implemented behavior, not of 19.7.3/4 completeness. - **Not verified:** real-display 19.7.20, GC6 19.7.21, full Action Model document, audio 16.11 cross-check of every visual curve sample. Actionable specification/implementation gaps exist (P1–P3 above). Traces 20–21 remain deferred by the spec itself.