Files
XZBT/reviews/00-pre-phase6-reconciliation.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

9.8 KiB
Raw Blame History

Pre-Phase 6 Reconciliation Plan

Status: draft — not yet actioned. Nothing in this plan has been executed; it records what needs to happen and in what order before Phase 6 (scenario director) work begins.

Why this exists: two sessions worked in this repo on 2026-09-06. Committed history (main @ 0af58da) carries only Phase 4 through slice 4d. Everything past that — slices 4e/4f/4g and a full Phase 5 (events/cadence) implementation, reported as 229/229 tests green — exists only as uncommitted working-tree changes, and is not in git history. Two independent review passes against that uncommitted tree (reviews/02-triage.md, Phase 4d4g; reviews/03-phase5-triage.md, Phase 5) found confirmed defects, some Tier-1. Phase 6 is defined against a working scenario director sitting on top of the visual engine and the cadence/event subsystem, so it cannot be started on an unreconciled, unfixed foundation.

This plan does not re-derive those findings — it sequences fixing and landing them. See the two triage docs for full technical detail; only what's needed for sequencing is repeated here.


0. Preconditions (verify before anything else)

  1. Confirm no session is still writing to the tree: find . -path ./.git -prune -o -type f -newermt '-10 minutes' -print, twice, a minute apart. If anything is changing, stop.
  2. Confirm current state matches this plan's assumptions: git log --oneline -5 should show 0af58da at HEAD of main; git status --short should show the modified/untracked set described in claude/status.md.
  3. Get explicit sign-off from the user before committing any of the uncommitted tree under a new session's authorship — this was called out as a standing rule and isn't relaxed by this plan existing.

1. Fix Tier-1 defects in the uncommitted tree, before it is treated as done

These are correctness/security-boundary bugs, not style. Fix them in place in the working tree, in this order, then re-run the full suite before moving to reconciliation:

Priority Source Defect Fix
1 Phase 5 F1+F2 actions.js uses an invented diagnostic code (ERR_SOUND_USAGE_MISMATCH) and its underlying permission check has a logic bug (permitsAction short-circuits on "the sound allows some action context" instead of "the sound allows this caller's context") — a scenario-only sound is currently playable from a manual action. Replace with if (isActionCaller && !allowedUsage.includes(callerUsage)) throw ERR_UNSUPPORTED_TARGET; delete permitsAction. Add the two missing test cases (manual-only invoked from scenario, scenario-only invoked from manual).
2 Phase 4 C1 Production render path never creates compositing surfaces; a masked group or non-opaque layer throws, is caught in app.js, and permanently deactivates the visual subsystem. Pass a real surface factory from VisualSubsystem.render (per R2's fix, not R3's guard-and-skip). Add a subsystem-level render test for a masked group and a non-opaque layer.
3 Phase 4 C2 System-level behaviors arrays skip semantic validation (validateBehaviors only runs for object hosts), so six classes of invalid document fail at activation/runtime instead of import. Run validateBehaviors at system scope during import, with options.fields set from system context.
4 Phase 5 F3 Second invented diagnostic code, ERR_UNKNOWN_PARAMETER, for a check §20.11 doesn't actually require. Either drop the check, or rename to ERR_UNKNOWN_FIELD (the spec's existing convention) and document the new normative surface in §20.11.
5 Phase 5 F4+F5 Traces 710 of the Phase 5 acceptance suite exercise triggerSound()/calculateEligiblePool(), a dead duplicate scheduler with no production call site — not advance()fireClass(), the only path a real exhibit runs. The two implementations disagree on recency-history semantics (F5), undetected because nothing calls both. Rewrite Traces 710 to drive update()/advance() with a seeded RNG, matching Traces 1114's existing pattern. Then delete triggerSound()/calculateEligiblePool() as dead code — don't reconcile them.

Remaining Phase 4 defects (C3C20, B1, S1, and the P3 list in 02-triage.md) are real but not blocking in the same way — see §2 below for how they're triaged, not skipped.

2. Triage the remaining Phase 4 findings (C3C20, B1, S1, P3s)

02-triage.md's own "Recommended correction order" table is the working list — don't re-litigate it, execute it, with one exception: promote anything from it that touches a code path Exhibit E or the scenario director will exercise (ownership/cleanup of visual instances, remove action semantics — C20 — and non-integer resolved counts — C18 — are the two most likely to matter early, since Phase 6 does spawn/cleanup accounting). Everything else in that table can land after Phase 6 starts, tracked as follow-up debt, provided it's written down as such rather than silently dropped.

One open design question blocks nothing but should be decided, not deferred indefinitely: C5, whether spawn.lifetime/action lifetime accepts numeric milliseconds or the spec is restricted to the literal string form parseDuration currently requires. Flag it for the user; don't guess.

3. Correct the documentation claims that outran the code

  • docs/IMPLEMENTATION_STATUS.md and the Phase 5 evidence doc (docs/evidence/phase5/2026-09-06-phase5-events-cadence.md) currently present ERR_UNKNOWN_PARAMETER and ERR_SOUND_USAGE_MISMATCH as normative contract surface (F7). Correct both once §1's fixes land — this is downstream cleanup, not a separate defect to fix independently.
  • The working tree's docs/XZBT_0-1_Format_Specification.md claims revision 0.9 (adding §20) while committed history is at 0.8. Confirm 0.9 is intentional and ready to be the committed revision once the tree lands — it should not be committed with the F1/F3 invented codes still described as normative.
  • Devlog entries are missing for slice 3c-2 (lifecycle and voices) and slice 4d. Per the standing rule in claude/status.md, the public-facing write-up (.labyricorn/project/contents.lr, the Claude project description) still waits for Phase 3 completion — do not re-offer that separately. Per-milestone devlog entries are not covered by that hold and should be backfilled for 3c-2 and 4d before or alongside this reconciliation, so the devlog record isn't missing entries for work that's about to be several phases behind HEAD.
  • Two devlog entries (visual-contract-before-the-renderer citing 245af6e, closing-the-visual-contract citing d3cd688) cite source_commit values that aren't yet ancestors of the pushed branch, per the devlog's own AGENTS.md rule. This resolves naturally once main is pushed (§5) but is worth a final check afterward.

4. Land the reconciled tree

Once §13 are done and npm test (all phase suites) is green against the fixed code:

  1. Re-run tools/verify-spec-contract.py against the spec text to confirm it's still internally consistent after any §20 corrections.
  2. Stage and commit in slices that mirror the phase boundaries already in use elsewhere in this repo, rather than one giant commit — e.g. one commit for the 4e slice (noise/distributions/behaviors/fields/systems/motion/particles/trails/links), one for 4f (execution/bundling), one for 4g (challenges/exhibits), one for Phase 5 (cadence/events), one for the spec revision to 0.9. This matches the existing commit granularity (1bc4901, 6587d3e, 699492f, 0af58da) and keeps git bisect useful.
  3. Use git -c user.name='Labyricorn' -c user.email='[email protected]' for authorship, per the working-environment notes.
  4. New untracked directories not part of the runtime (.abacusai/, "Claude outputs/", .labyricorn/devlog/second-test-entry/) should be reviewed individually — confirm with the user whether each belongs in the commit, in .gitignore, or should be deleted, rather than committing them by default via a blanket git add.

5. Push and close out

  1. main is currently 10 commits ahead of origin/main, unpushed, even before this reconciliation's new commits. Confirm with the user before pushing — this plan doesn't assume permission to push on its own.
  2. Push using the Gitea token in the gitignored .env via GIT_ASKPASS; never echo the values.
  3. After push, re-check the two devlog source_commit citations from §3 — they should now resolve as ancestors.
  4. Update docs/IMPLEMENTATION_STATUS.md's top-line state summary to reflect the corrected, committed state (Phase 4 through 4g, Phase 5 complete, defects fixed) rather than the current draft language.

6. Only then: Phase 6 entry criteria

Phase 6 (per docs/XZBT_0-1_Implementation_Plan.md) can start once:

  • §1's Tier-1 fixes are committed and covered by tests that exercise the real production code path (not a duplicate/dead one).
  • The visual engine (through 4g) and cadence/event subsystem (Phase 5) are on main, not just in a working tree.
  • GC5 ownership/failure semantics are ready to be re-run "with real resource counters" per the Phase 6 plan entry — confirm the counters Phase 6 needs actually exist post-reconciliation, since several of the Phase 4 fixes (C1, C20) touch instance lifecycle/removal accounting that Phase 6's ownership and cleanup work will depend on.

Not required before Phase 6 starts (tracked separately, per claude/status.md's "still user-observed" list): the Phase 4h GC6 hardware measurement, the PRD 130 visual challenge judged on a real display, and Phase 3's audible acceptance. Those are real open items but don't block scenario-director work the way the Tier-1 fixes above do.


No files were changed in producing this plan. §15 above are proposed actions awaiting the user's go-ahead per this project's standing rule (summary + explicit permission before acting on the repo).