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

73 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).