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
121 lines
7.6 KiB
Markdown
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.
|