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
65 lines
7.7 KiB
Markdown
65 lines
7.7 KiB
Markdown
# XZBT 0.1 triage — fix log (what was applied, what remains)
|
||
|
||
Record of edits to `docs/XZBT_0-1_Format_Specification.md` (1499-line version, working
|
||
tree = commit `e5ed468`; spec file itself unmodified in git status at time of writing).
|
||
Consolidates the 13 defects of `00-triage.md`. Scope constraint honored: **nothing that
|
||
overlaps the in-flight Phase 3c slice-2 implementation** (16.3 lifecycle, 16.4 release,
|
||
16.5 endings, 16.6 eviction, disposal, traces 16.11.7/9/10/11, or the runtime/schema/test
|
||
files that slice has open) was touched. Doc-text edits only; no code, schema, or test
|
||
changes.
|
||
|
||
---
|
||
|
||
## Applied — 7 of 13 defects
|
||
|
||
| T | Location(s) | Change | Verification |
|
||
| --- | --- | --- | --- |
|
||
| T4 | §7 row `ERR_INVALID_RANGE_ORDER`; 14.12 | Refiled `Semantic / Runtime` with a cause covering both uses: literal paired bounds at import, resolved paired bounds at node instantiation, automation `at` ordering at import. 14.12 now states the literal/resolved split explicitly. 14.12's invalid-case example (`min: 1, max: -1`) remains an import case, consistent. | Code grounding: `audio-graph.js:186` emits the code only when both bounds are literal numbers, i.e. import stage. |
|
||
| T5 | 16.1 "Points." | Added: "A track's point values are resolved once at the owning sound instance's instantiation boundary, sampled from that instance's stream in depth-first, property-document order, with `automation` taken after `nodes` and `routes`." Wording matches 14.4's and 9.3's own vocabulary; `automation` follows `nodes`/`routes` per the 14.3 graph-object field table. | None needed (forward-looking; automation is slice 3c-3). |
|
||
| T6 | 15.14 (limits paragraph); §7 row `ERR_NODE_LIMIT_EXCEEDED` | Automation tracks/points removed from the runtime-ceiling enumeration (voice ceilings remain, with a 16.6 cross-reference) and pointed to 16.1's semantic enforcement instead. §7 cause extended: "...or automation tracks or points per expanded sound". | 16.10 and 15.18 tables do not restate either amended row; no drift. |
|
||
| T10 | 16.2 | Clause added to the node-property paragraph: `override` actions on node fields are barred exactly like `BindingSpec` (14.4), so the `winning override` stage of the pipeline is always absent for node properties — "absent, not an identity hook (8.1)". | — |
|
||
| T11 | 14.9 impulse envelope table | Column relabelled "Value at `p = 1`" → "Value as `p → 1⁻`" with corrected cells `a`, `0`, `a x 0.001` (exponential no longer self-contradicts its `-60 dB` annotation). | Rows checked against the piecewise definition (`0 <= p < 1`, exactly `0` for `p >= 1`). |
|
||
| T12 | 15.16 sounds metadata | Sentence added: name > 128 chars, > 16 tags, or a tag > 32 chars is `ERR_SCHEMA_VALIDATION`. | Grounded: `schema/xzbt-0.1.schema.json` enforces `name` maxLength 128, `tags` maxItems 16, item maxLength 32 (Sound definition). |
|
||
| T13 | 16.2 | Mis-citation fixed: "parameter-masking rule of section 8.1" → masked-override rules of **8.3** (underlying stages keep evaluating while masked) and **8.4** (release resolves against the current lower value recomputed without the releasing override). | 8.3 line 370 and 8.4 `currentLowerValue` text verified as the actual referents. |
|
||
|
||
Net diff: 12 insertions / 10 deletions in 9 regions. Nothing else in the file changed.
|
||
|
||
## Not applied — 6 of 13 defects, with reasons
|
||
|
||
| T | Reason |
|
||
| --- | --- |
|
||
| T1 (bus-gain automation/modulation surface; 8.1/15.17/16.1/16.2/16.11.8) | **(design)** — the triage's own edit list marks it decision-required before an edit can be written. Recommended option (b): give `audio.buses.<id>.gain` an authoring surface and name it in 16.1's target rule. Not in Gemini's slice (automation is 3c-3), so it can be picked up independently, but needs a decision first. |
|
||
| T2 (delete `component` modulation-target row; 15.13/15.11/15.19.4) | Blocked on coordination, not on Gemini's slice per se: the registry row is mirrored in `audio-contract.js`, asserted by a green Phase 3b test (`test/phase3-audio.test.mjs:313`, trace 15.19.4), and 15.19.4 is an *accepted* contract trace. Deleting spec text alone would leave doc contradicting code+test. The runtime and test files are currently open by the slice-2 work; the delete (plus trace amendment and test/registry update) must land as one coordinated change, or be consciously deferred as a contract decision. |
|
||
| T3 (16.6 eviction step 3 frees no slot) | **Gemini's slice** — 16.6 and trace 16.11.10 are being implemented and tested right now. A spec change here would invalidate the in-flight suite and evidence record. After slice 2 lands, reconcile: Gemini's `audio-engine.js` has already made *some* choice for step 3; check it against the triage's two options (recommended: evicted `ACTIVE` one-shot leaves the ceiling count at the moment of eviction, release running outside the budget, with the matching exception added to the 16.6 counting rule). |
|
||
| T7 (16.5 resonator bound over empty retained-mode set) | **Gemini's slice** — 16.5 ending computation and trace 16.11.9. One-sentence fix ("...or zero when no mode is retained") ready to apply after slice 2 lands; check against Gemini's implementation choice for single-mode resonators on a 44.1 kHz device. |
|
||
| T8 (16.5 delay bound under modulation) | **Gemini's slice** + **(design)** + blocked on T9. Alternative fix (exclude modulated bound-contributors from determinable-ending status via `ERR_INDETERMINATE_ONESHOT`) touches 16.5 semantics the slice is implementing. |
|
||
| T9 (oscillator modulation output magnitude undefined; 15.13) | **(design)** — stating a range in the spec would be a behavioral contract change for accepted Phase 3b modulation code (custom-partial normalization) that no implementation performs; the registry and summation code live in files the slice has open. Needs a decision, then coordinated spec + contract-registry change. |
|
||
| T14 (exposed parameter without `min`/`max` has no clamp range) | Conditional on T2 — moot unless T2's option two (live parameter tracking) is chosen. Remains closed while T2 is open. |
|
||
|
||
## Follow-ups recorded, not actioned
|
||
|
||
- **T4 implementation gap (pre-existing):** no instantiation-time range-order check exists.
|
||
`audio-graph.js:186` is the only enforcement site and it guards on both bounds being
|
||
literal numbers (`typeof low === 'number' && typeof high === 'number'`). A document with
|
||
resolved (e.g. random) `sample-hold` bounds that invert at resolution is import-legal and
|
||
currently unchecked at instantiation. The spec now says the check happens there; the
|
||
runtime follow-up belongs to the phase-3a code owner (files open by Gemini's slice).
|
||
- **§8 out-of-scope finding from the triage:** §8.5 trace 6 and §8.3's masked-automation
|
||
sentence are already unimplementable for want of a target exposing both automation and
|
||
override (T1's root cause, independent of §§14–16). Still to be logged against §8; T1
|
||
must not be closed without addressing it.
|
||
- **14.3 canonical example** (`oscillator → gain → output`) is not a legal `oneshot` recipe
|
||
as-is (`ERR_INDETERMINATE_ONESHOT`); noted as editorial, not a defect. Unchanged.
|
||
- **14.7 all-partials-omitted oscillator** deserves one clarifying sentence (Kimi #5 /
|
||
DeepSeek F7 downgrade in the triage); not a Tier-2 defect. Not actioned.
|
||
|
||
## Housekeeping
|
||
|
||
- Edits are **uncommitted** in the working tree (12+/10−, 9 regions, spec only). Recommended:
|
||
land as a dedicated `docs(audio): ...` commit before Gemini's slice-2 commit, per the
|
||
project's contract-before-implementation convention, so the two changes never mix.
|
||
- Verified: no stale "Value at `p = 1`" header remains; §7 rows appear once each; 15.18 and
|
||
16.10 tables unaffected; all new cross-references (15.14 → 16.6/16.1; 16.2 → 8.1/8.3/8.4;
|
||
14.12 → 14.4) resolve. No test suite was run — none is affected by doc-text edits, and the
|
||
slice-2 suite was in flight.
|