Files
XZBT/docs/evidence/phase4/2026-09-06-phase4a-contract.md
T
LabyricornandClaude Opus 5 3e27a668e2 docs(visual): specify the phase 4a scene, primitive, and appearance contract
Open the Visual subsystem contract at Format Specification revision 0.5 with
section 17, covering PRD 69-76: the renderer-neutral pipeline, canonical units
on a single degrees convention, the visuals container, layers, the scene model
with three coordinate spaces and three fit modes, 2.5D depth with a fixed sign,
stable sorting, parallax, perspective factor and per-object fog, the fourteen
primitives of Visual Primitive Set 0.1, common visual properties, a normative
transform composition order, appearance with the eight-mode safe blend set and
gradient paint, paths and splines with independently addressable points, text
restricted to the three generic font families, and the once-at-instantiation
resolution boundary for visual ValueSpec fields.

Visual objects are keyed rather than listed and carry no id field, matching the
audio node-identity rule that a Phase 3a blocking defect established. No visual
property becomes externally addressable in this slice; a binding, set, or
override naming one remains ERR_UNSUPPORTED_TARGET, and section 8.1 is
unchanged until section 19.1 adds its rows.

Add five diagnostic codes to the section 7 table, record the eight-slice Phase 4
delivery plan, mark the section 11 Visuals register row in progress, and refresh
the implementation status, which had not been updated since the 3c-1 contract.

Documentation only; no runtime, schema, fixture, or test file is touched.
npm test passes 102 tests with zero failures.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GwmTQU6zLwh3qbBvq5zf5B
2026-09-06 03:57:46 +00:00

121 lines
7.6 KiB
Markdown

# Phase 4a evidence — Visual subsystem contract, part I (Format Specification section 17)
**Date:** September 6, 2026
**Slice:** 4a — Contract I (documentation only; no runtime change)
**Baseline:** `main` at `6aab663` (Phase 3c slice 4)
**Specification revision:** 0.4 → 0.5
**PRD coverage:** 69-76
## What this slice fixes
Section 17 opens the Visual contract required by section 11. It covers the visual pipeline and its
renderer-neutral scope, canonical units, the `visuals` container, layers, the scene model and the
three coordinate spaces, 2.5D depth, the fourteen geometry primitives of Visual Primitive Set 0.1,
common visual properties, the transform model, appearance and paint, paths and splines and text, and
the resolution boundary for visual ValueSpec fields.
Sections 18 (Phase 4b) and 19 (Phase 4c) are named throughout as the owners of procedural systems and
of automation, lifecycle, camera, post-effects, and the centralized ceilings. Those forward references
are deliberate and mirror how section 14 referenced sections 15 and 16 before they were written; they
are the only unresolved numeric references in section 17 and they close when 4b and 4c land.
## Decisions taken, so 4d does not relitigate them
1. **Angles are degrees everywhere**, `0` along `+x`, positive turning toward `+y`. No visual field is
authored in radians or turns. This matches the audio contract's `phase` field (14.7).
2. **Increasing `z` is farther from the camera.** Depth sorting draws greater `z` first and breaks ties
by document key order, using the same document-order rule sections 9.3 and 14.4 already rely on.
Perspective scaling is `focalLength / (focalLength + z)`; `orthographic` leaves `z` affecting sorting,
parallax, and fog but never scale.
3. **Visual objects are keyed, not listed.** `content` and `children` are objects keyed by ID and a
visual object carries no `id` field. This is the same node-identity rule section 14.3 adopted after
the contradictory version was one of the four blocking defects the Phase 3a review closed; adopting
it up front here avoids repeating that defect in a second subsystem.
4. **Transform composition order is normative:**
`M_local = T(position + translate) x T(origin) x R(rotation) x K(skew) x S(scale) x T(-origin)`,
with `M_parent x M_local` down a group hierarchy. Trace 3 pins it with a case where rotation and
non-uniform scale do not commute, so a renderer cannot fold the order differently and pass.
5. **Visual ValueSpec fields resolve once, at their object's instantiation boundary**, exactly as
section 14.4 fixes for audio node fields. Rendering consumes no procedural stream, so procedural
decisions stay identical across render rates and machines. Time variation comes from behaviors
(18.6), visual automation (19.1), and the section 8.1 rows that 19.1 adds — from nothing else.
6. **No visual property is externally addressable in this slice.** A binding, `set`, or `override`
naming one is `ERR_UNSUPPORTED_TARGET`, and the section 8.1 table is unchanged. Section 1.3 reserves
the `visuals.systems.*` namespace; reserving a namespace does not grant a capability.
7. **`layer` is a system property, not an object property.** Letting siblings inside one transform
hierarchy composite into different layers would make the hierarchical transform meaningless.
8. **Depth fog is per object, not per pixel**, so it is exact on any renderer and raises no diagnostic.
The conic gradient is the *only* appearance fallback in 0.1, and it raises `WARN_VISUAL_APPROXIMATION`
once per paint instance rather than once per frame.
9. **`font` is restricted to the three generic CSS families.** Section 13.3 requires the standalone
artifact to make no external request, and 0.1 ships no font file.
10. **Degenerate geometry fails validation rather than being transformed.** A zero-radius `arc` is
`ERR_OUT_OF_BOUNDS`, not a silently substituted line, per PRD 89.
## Deliberate scope deferral
**Live numeric readouts are not in 0.1.** Because `text` resolves once at instantiation, it renders
authored strings and static labels only. The instrument and radar displays of PRD 130 item 7 and
Exhibit D are to be built from generic geometry driven by state. The reason is recorded in 17.13: a live
readout needs a number-to-string formatting contract (precision, rounding, locale, unit suffixes) that
PRD 72 does not specify and that would introduce the first subject-shaped construct into the visual set.
**Slice 4g revisits this** if the Exhibit D visuals cannot be built without it. This is the one place in
section 17 where a later slice may have to reopen the contract.
## New diagnostic codes
Five codes were added to the section 7 table, which remains the single authoritative list:
`ERR_INVALID_SYSTEM_TYPE`, `ERR_INVALID_PRIMITIVE_TYPE`, `ERR_INVALID_PATH`,
`ERR_VISUAL_LIMIT_EXCEEDED`, and `WARN_VISUAL_APPROXIMATION`. Section 17.15 repeats them for locality,
exactly as 15.18 and 16.10 do.
`ERR_INVALID_RANGE_ORDER`, `ERR_OUT_OF_BOUNDS`, `ERR_UNKNOWN_FIELD`, `ERR_SCHEMA_VALIDATION`,
`ERR_INVALID_REFERENCE`, `ERR_INVALID_ID`, and `ERR_UNSUPPORTED_TARGET` are reused rather than
duplicated under visual-specific names.
## Authoring limits fixed in this slice
| Limit | Bound | Diagnostic |
| --- | --- | --- |
| Layers per exhibit | 16 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| Group nesting depth | 8 (matches audio component nesting, 15.15) | `ERR_VISUAL_LIMIT_EXCEEDED` |
| `polyline` / `polygon` vertices | 512 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| `path` commands | 512 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| `spline` points | 256 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| Gradient stops | 16 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| `filters` entries | 4 | `ERR_VISUAL_LIMIT_EXCEEDED` |
| `strokeDash` entries | 8 | `ERR_SCHEMA_VALIDATION` |
| `text` length | 256 characters | `ERR_SCHEMA_VALIDATION` |
Runtime ceilings — active particles, emission rate, active spawned systems, link count, trail history,
blur radius, post-processing passes, and rendering resolution (PRD 89, 120) — belong to slice 4c and are
not set here.
## Verification performed
This slice changes documentation only. No runtime source, schema, fixture, or test file was touched.
- Every diagnostic code used in section 17 resolves to a row in the section 7 table (checked
programmatically; zero unresolved).
- Every numeric cross-reference in section 17 resolves to an existing heading, except the intended
forward references to 18.1, 18.2, 18.4, 18.5, 18.6, 18.8, 19.1, 19.2, 19.3, 19.4, and 19.5.
- `npm test` was run to confirm the existing suite is unaffected; the result is recorded in the commit.
- The section 11 contract register's Visuals row now reads **In progress (Rev 0.5 / Phase 4a)** and names
what remains for 4b and 4c.
## Test boundary
Traces 1-14 of section 17.16 are automated and belong to slice 4d, where the renderer exists to run them.
Traces 15 and 16 — the PRD 130 visual challenge judged on a real display, and the early combined GC6
benchmark at `1920 x 1080` — are user-observed and close slice 4h. Phase 4 is not accepted until both do.
## State at this checkpoint
Section 17 is contract only. No visual runtime code exists; `src/runtime` has no renderer module and the
JSON Schema has no visual definitions. Nothing has been drawn from any build. Phase 3 also remains
unaccepted while its own user-observed gates (traces 15-17 of section 16.11) and the Phase 1 direct-file
restart observation are open; no Phase 4 slice depends on them, and no Phase 4 slice can close them.
Whether section 17-19 passes a multi-model review before slice 4d begins — the pass that found thirteen
defects in sections 14-16, nine of which any single reviewer would have missed — remains an open decision.