Files
XZBT/reviews/04-followup-debt.md
T
LabyricornandClaude Opus 5 c4332363a9 docs: raise the format specification to revision 0.9 and land the reconciliation
Revision 0.9 adds section 20, the cadence and event subsystems contract, and
carries two corrections the implementation forced. Section 6.1 now states that a
duration is the authored literal or a non-negative finite number already in
milliseconds, since a DurationSpec may be the resolved output of a ValueSpec or
a bounded TimeSpec, with the one documented exception of an automation track's
`at`, which 19.1 keeps literal-only so that point ordering stays decidable at
import. Section 20.11 documents the rejection of an undeclared input name in an
event action's `with` map as ERR_UNKNOWN_FIELD — the section's own convention
for that shape of error, replacing an invented code that appeared nowhere in the
registry.

The review record is committed with the code it describes: the two code triages
that found these defects, the reconciliation plan that sequenced the fixes, and
a follow-up debt record listing what was deliberately left open — the unchecked
JSON Schema artifact, degenerate path arcs, post-effect transient allocation,
the window-traffic fixture's per-copy wrap bounds, and the unstated
`ownership: "persistent"` value on a sound action. None of the five blocks phase
6; all five are written down rather than dropped.

Devlog entries are backfilled for the two milestones that had none: phase 3c
slice 2, the audio lifecycle and voice ceilings, and slice 4d, the renderer
core. The implementation status summary now reflects the reconciled state rather
than the in-flight one.

231 tests pass. tools/verify-spec-contract.py reports 46 declared diagnostic
codes with every used code resolving and its two long-standing unresolved
cross-references unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
2026-09-06 21:54:09 +00:00

5.7 KiB
Raw Blame History

Follow-up debt after the pre-Phase 6 reconciliation

Status: current as of the reconciliation commits landing on main (2026-09-06). This is the written-down remainder that 00-pre-phase6-reconciliation.md §2 asks for: findings from the two triages that were not dropped silently, recorded here so Phase 6 can start without losing them.

What was closed

Every Tier-1 finding of both triages is fixed in the code that shipped in these commits, and each is covered by a test that drives the production path rather than a duplicate of it:

Finding Source Closed by
F1 + F2 — invented ERR_SOUND_USAGE_MISMATCH, and the permitsAction short-circuit that let a scenario-only sound play from a manual action 03-phase5-triage.md actions.js now checks allowedUsage.includes(callerUsage) against the caller's own context and raises ERR_UNSUPPORTED_TARGET per §20.2.2/§20.12. permitsAction is deleted.
F3 — the second invented code, ERR_UNKNOWN_PARAMETER 03-phase5-triage.md Resolved as the rename option, not the drop: the check raises ERR_UNKNOWN_FIELD, the section's own convention, and §20.11 documents the behavior as normative surface.
F4 + F5 — Traces 710 certifying a duplicate scheduler that disagreed with the shipping one on recency semantics 03-phase5-triage.md Traces 710 now drive CadenceSubsystem.update()/advance() with a seeded RNG, as Traces 1114 already did. triggerSound() and calculateEligiblePool() are deleted rather than reconciled.
C1 — production render path never created compositing surfaces; the first masked group permanently deactivated the visual subsystem 02-triage.md VisualSubsystem.render passes a real createSurface factory (OffscreenCanvas, falling back to a detached canvas element), per R2's fix rather than R3's guard-and-skip.
C2 — system-level behaviors arrays skipped semantic validation, so six classes of invalid document failed at activation instead of import 02-triage.md validateBehaviors runs at system scope during import with options.fields set from the system context.

The two items §2 asked to be promoted because Phase 6 will exercise them are also closed: C20 (remove on an unknown instance ID now returns refused, not executed) and C18 (a resolved non-integer count or burst count now raises ERR_TYPE_MISMATCH at the boundary instead of being rounded). Both touch the spawn/cleanup accounting the scenario director's ownership work depends on.

C5 — the one open design question — was decided by the user rather than guessed: a DurationSpec accepts the authored duration literal or a non-negative finite number already in milliseconds. The numeric form exists because a DurationSpec may be the resolved output of a ValueSpec or a bounded TimeSpec. Runtime (types.js), validator (visual-validation.js), and specification (§6.1) now agree, with the single documented exception of an automation track's at, which §19.1 keeps literal-only so point ordering stays decidable at import.

Beyond the reconciliation plan's required set, the working tree also carries fixes for C3, C4, C6, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C19, B1, S1, and P3.1. These were verified present in the source before the reconciliation commits; they are not separately re-certified here.

What remains open

None of the following blocks Phase 6. Each is real, and each should be picked up rather than forgotten.

  1. C7 — the JSON Schema is not a checked artifact. The schema has no consumer: nothing in src/, tools/, or test/ validates against it, so it can drift from the validator without any test noticing (P3.5 makes the same point from the other direction). The concrete fix is to validate the exhibit fixtures against the schema in CI; until then, treat validator.js as the single source of truth and the schema as documentation.
  2. P3.2 — degenerate path arcs. A coincident-endpoint arc forces acos(0) and emits a phantom bulge; a negative radius is drawn mirrored rather than raising ERR_OUT_OF_BOUNDS. Early-return on coincident endpoints and check raw radii before Math.abs.
  3. P3.3 — post-effect transient memory. Each blur pass allocates full-frame copies at up to 4096 device pixels, with no tie-in to the §19.5 pass budget. The device radius is now capped at 128, which bounds the work but not the allocation. Tiling the blur is the real fix.
  4. P3.4 — the window-traffic challenge fixture. Per-copy wrap bounds are ±30px around each copy's own origin, so cars cycle in place instead of crossing the window. Either use the window rect as bounds, or document the cell-stutter as intended. The 4g suite only asserts finiteness and equality, so it passes either way.
  5. F6 — ownership: "persistent" on a sound action. The schema and cadence-validation.js accept it; §20.12 documents only "performance" and "scenario". This is probably deliberate carry-over from the §10.1 ownership vocabulary, but it is currently unstated. One line in §20.12 settles it either way — and it is worth settling before Phase 6, which is where scenario ownership becomes load-bearing.

Still user-observed, unchanged by this reconciliation

Carried forward verbatim from the project status, because nothing automated can close them: the slice 4h / GC6 hardware measurement (every §19.5 aggregate stays provisional until trace 21 of §19.7 runs on recorded hardware), the PRD 130 visual challenge judged on a real display, Phase 3's audible acceptance — no sound has yet been heard from a production build — and Phase 1's direct-file two-fixture restart observation.