feat(audio): implement phase 3c slice 2 lifecycle and voices
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
# XZBT implementation status
|
||||
|
||||
**Updated:** September 5, 2026
|
||||
**State:** The audio subsystem contract is complete through Phase 3c; Phase 3c implementation (slices 2-4), the Phase 3 audible gates, and the Phase 1 direct-file import/restart observation remain pending
|
||||
**State:** The audio subsystem contract is complete through Phase 3c; Phase 3c slices 1 and 2 implemented; automation (slice 3) and master protection (slice 4), the Phase 3 audible gates, and the Phase 1 direct-file import/restart observation remain pending
|
||||
**Planning baseline:** `05fe2b4e021ba86e4a290d05b63c7cae0e386128`
|
||||
|
||||
**Exact demarcation:** GC1 direct-file feasibility (10/10 checks), GC2 shared format contracts, GC3 resolution semantics, GC4 clock/PRNG semantics, and GC5 ownership/failure semantics are complete at the Phase 0 contract-oracle level. The Phase 1 production runtime skeleton, the Phase 2 common grammar, and the Phase 3a/3b audio authoring contract and its implementation pass automated checks. Three gates remain open in the completed work: Phase 1's direct-file two-fixture restart observation, Phase 3's audible observation (no sound has been heard from any build), and the Phase 3c audio contracts on which real playback acceptance depends. Visual, cadence/event, scenario, final generated-UI, performance, and soak work remains assigned to later phases.
|
||||
**Exact demarcation:** GC1 direct-file feasibility (10/10 checks), GC2 shared format contracts, GC3 resolution semantics, GC4 clock/PRNG semantics, and GC5 ownership/failure semantics are complete at the Phase 0 contract-oracle level. The Phase 1 production runtime skeleton, the Phase 2 common grammar, and the Phase 3a/3b/3c-2 audio engine pass automated checks. Three gates remain open in the completed work: Phase 1's direct-file two-fixture restart observation, Phase 3's audible observation (no sound has been heard from any build), and the Phase 3c audio contracts on which real playback acceptance depends. Visual, cadence/event, scenario, final generated-UI, performance, and soak work remains assigned to later phases.
|
||||
|
||||
The user requested sequential implementation with a stop on problems. The [manual version 3 evidence](evidence/phase0/2026-09-04-user-run-v3.md) verifies embedded data-URL worklet loading in direct-file Chrome. The subsequent [user-performed restart test](evidence/phase0/2026-09-04-user-restart.md) restored Blue Study activity 0.37 and master volume 0.19 immediately on reopening. Native tone output and AudioContext suspend/resume are also observed. Ordinary file import, selection of both exhibits, regular Chrome mode, and [directory cancellation/denial fallback](evidence/phase0/2026-09-05-user-directory-fallback.md) have been confirmed.
|
||||
|
||||
@@ -13,7 +13,7 @@ The user requested sequential implementation with a stop on problems. The [manua
|
||||
| 0 — Contracts and feasibility | Complete | GC1 passed; GC2–GC5 shared contracts and traces passed; GC6/GC7 later gates scheduled and mapped |
|
||||
| 1 — Runtime skeleton | Implemented; acceptance pending | [Automated evidence](evidence/phase1/2026-09-05-runtime-skeleton.md) passes production-module, lifecycle, PRNG-vector, cache/restore, fixture-validation, and deterministic-build tests. Direct-file two-fixture import/restart remains a user-observed gate. |
|
||||
| 2 — Common grammar | Complete | [Automated evidence](evidence/phase2/2026-09-05-common-grammar.md) covers production GC2 conformance, typed values, signals, actions, same-tick bindings, transitions, override precedence/release, and parameter restoration. |
|
||||
| 3 — Audio engine | Phases 3a/3b complete; 3c contract complete, 3c implementation not started | [Automated evidence](evidence/phase3/2026-09-05-audio-authoring-contract.md) covers Format Specification sections 14-15, all sixteen node types, routing and modulation, twelve legality rules, authoring limits, components, sounds/recipes, and buses. The [Phase 3c contract](evidence/phase3/2026-09-05-phase3c-contract.md) adds section 16: automation tracks and precedence, the seven-state lifecycle and release, determinable one-shot endings, voice ceilings and eviction, master protection, and unlock and pause behavior. Phase 3c implementation slices 2-4 and the PRD 129 audio acceptance challenge remain. |
|
||||
| 3 — Audio engine | Slices 3c-1 (contract) and 3c-2 (lifecycle/voices) complete; slices 3c-3 and 3c-4 pending | [Automated evidence](evidence/phase3/2026-09-05-audio-authoring-contract.md) covers sections 14-15; [contract evidence](evidence/phase3/2026-09-05-phase3c-contract.md) adds section 16. [Slice 3c-2 evidence](evidence/phase3/2026-09-05-phase3c-lifecycle-voices.md) implements the seven-state lifecycle, engine-owned release gain, determinable one-shot endings, voice ceilings (64/16), 4-step eviction, and disposal. Slices 3c-3 (automation) and 3c-4 (master protection measurement) and the PRD 129 audio acceptance challenge remain. |
|
||||
| 4 — Visual engine | Not started | Earlier phases and visual contracts |
|
||||
| 5 — Events and cadence | Not started | Earlier phases and event/cadence contracts |
|
||||
| 6 — Scenario director | Not started | Earlier phases and scenario contracts |
|
||||
@@ -63,6 +63,14 @@ Phase 3 is not accepted. Audio automation precedence, the lifecycle state machin
|
||||
|
||||
## Phase 3c contract (slice 1)
|
||||
|
||||
Format Specification section 16 completes the audio subsystem contract. Phase 3c is delivered in four slices, recorded in the implementation plan: the contract (done), lifecycle and voices, automation, and measured master protection. Each slice ends green and committable, because slice 2 replaces the working one-shot timer scaffolding and must not be left half-applied.
|
||||
Format Specification section 16 completes the audio subsystem contract. Phase 3c is delivered in four slices, recorded in the implementation plan: the contract (done), lifecycle and voices (done), automation, and measured master protection. Each slice ends green and committable, because slice 2 replaces the working one-shot timer scaffolding and must not be left half-applied.
|
||||
|
||||
Section 16 is contract only. The runtime does not implement it: there is no lifecycle state machine, no voice ceiling, and `automation` and `release` are still rejected as unknown fields. Slice 3c-4 and the PRD 129 audio acceptance challenge are user-observed and cannot be closed by automated tests. No sound has been heard from any build.
|
||||
Section 16 was contract only at slice 1.
|
||||
|
||||
## Phase 3c lifecycle and voices (slice 2)
|
||||
|
||||
Slice 3c-2 implements the seven-state lifecycle state machine (`CREATED`, `SCHEDULED`, `ACTIVE`, `RELEASING`, `FINISHED`, `DISPOSED`, `FAILED`) per section 16.3, the engine-owned internal release gain per 16.4, authorable `release` durations (`0ms` to `10s`) on recipes, determinable one-shot ending bounds calculation per 16.5 (and `ERR_INDETERMINATE_ONESHOT` validation for unbounded sources), voice ceilings (64 one-shot, 16 continuous) with 4-step eviction order (`FINISHED` -> `RELEASING` -> `ACTIVE` -> refuse) and `WARN_VOICE_LIMIT` per 16.6, full disposal, and removal of the fixed 4-second dev timer from `src/runtime/app.js`.
|
||||
|
||||
`npm test` runs 67 tests with zero failures. Two clean builds produce byte-identical artifacts with digest `d7d16a89f9b1a9e21262232382d7ae53a0a84abafce191a873327e66dc4103a6`.
|
||||
|
||||
Phase 3 is not accepted. Slices 3c-3 (automation) and 3c-4 (measured master protection) remain. No sound has been heard from any build.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Phase 3c slice 2 — audio lifecycle, release, and voice ceilings
|
||||
|
||||
**Date:** September 5, 2026
|
||||
**Specification baseline:** Format Specification 0.1 revision 0.4, sections 15-16
|
||||
**Result:** Implementation slice complete. All 67 tests pass. Two clean builds byte-identical.
|
||||
|
||||
## Scope
|
||||
|
||||
Phase 3c is delivered in four slices. This record covers **slice 3c-2 only**: the audio lifecycle state machine, internal release gain, determinable one-shot endings, voice ceilings, eviction policy, and disposal contract.
|
||||
|
||||
Slice 3c-2 implements:
|
||||
1. **The seven-state lifecycle state machine** (16.3): `CREATED`, `SCHEDULED`, `ACTIVE`, `RELEASING`, `FINISHED`, `DISPOSED`, and `FAILED`, with strict enforcement of permitted transitions and rejection of forbidden transitions with `ERR_RUNTIME_FAULT`. Calling `stop()` on `FINISHED`, `DISPOSED`, or `FAILED` is a verified no-op.
|
||||
2. **Engine-owned internal release gain** (16.4): Placed between sound graph `output` (`sink`) and destination bus (`[output] -> [release gain] -> [bus]`). Initial gain is 1.0. Entering `RELEASING` linearly ramps gain to 0 over `releaseDuration`. Unbypassable, non-addressable by authors, and omitted from author node limits.
|
||||
3. **Recipe `release` field** (15.16, 16.4): Authorable `release` duration on `audio.recipes.<id>` and `sounds.<id>.recipe` within `0ms` to `10s` (default `50ms`). Rejected inside component definitions with `ERR_UNKNOWN_FIELD`.
|
||||
4. **Determinable one-shot endings** (16.5): Computed via pure longest-path traversal over expanded DAG routes and node contributions (impulse duration, delay decay bound, reverb predelay + decay, resonator longest mode decay, component inlined bound, plus recipe release). An unbounded source (`oscillator` or `noise`) on an audible path in a `oneshot` sound is rejected at validation with `ERR_INDETERMINATE_ONESHOT`.
|
||||
5. **Voice ceilings and 4-step eviction** (16.6): Independent ceilings for one-shot (`64`) and continuous (`16`) voices. A voice counts against its ceiling from `CREATED` until `DISPOSED`. Eviction policy runs in strict order:
|
||||
- Step 1: Dispose oldest `FINISHED` instance.
|
||||
- Step 2: Advance oldest `RELEASING` instance to immediate completion and dispose.
|
||||
- Step 3 (one-shot only): Evict oldest `ACTIVE` one-shot by starting its release ramp.
|
||||
- Step 4: Otherwise refuse request (continuous or no candidates), maintaining runtime stability.
|
||||
- `WARN_VOICE_LIMIT` is emitted on every eviction and refusal. One-shot and continuous pools are strictly isolated and never evict across pools.
|
||||
6. **Full disposal** (16.4, 16.6): Releases all Web Audio nodes, connections, buffers, timers, and pool memberships. A `FINISHED` instance continues to occupy its ceiling slot until `DISPOSED`.
|
||||
7. **Scaffolding removal**: Replaced the fixed 4-second development timer in `src/runtime/app.js` with natural ending management by the engine.
|
||||
|
||||
## Specification reconciliation before implementation
|
||||
|
||||
A pre-implementation review of Section 16 identified 5 inconsistencies, corrected in commit `e5ed468`:
|
||||
1. Section 15.16 allowed recipe fields table omitted `release`. Added `release` (DurationSpec, default 50ms, optional).
|
||||
2. Section 16.6 eviction step 2 contradicted the non-hard-stop invariant. Reconciled step 2 to advance release to immediate completion and dispose, rather than immediate drop.
|
||||
3. Section 16.8 unlock and 16.9 pause discard batching incoherence. Added `INFO_AUDIO_PAUSE_SKIP` to section 7 and 16.10 diagnostics tables.
|
||||
4. Section 16.5 author remedy text suggested gating an oscillator with an impulse, which is illegal under 15.14 rule 2 (audio route into oscillator is forbidden). Corrected prose to declare `mode: "continuous"` and stop explicitly.
|
||||
5. Clarified ending bound calculation on expanded graph where component boundaries are already inlined.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Automated test suite**: All 67 tests pass cleanly with zero failures (`npm test`).
|
||||
- **Required traces tested** (16.11):
|
||||
- **Trace 7**: Permitted transitions succeed (`CREATED -> SCHEDULED -> ACTIVE -> RELEASING -> FINISHED -> DISPOSED`, `CREATED -> FINISHED`, `SCHEDULED -> RELEASING`, `ACTIVE -> FINISHED`, `* -> FAILED -> [terminal]`). Forbidden transitions throw `ERR_RUNTIME_FAULT`. Second stop on terminal states is idempotent.
|
||||
- **Trace 9**: Determinable ending bounds match the section 16.5 contribution table across impulse, resonator, delay (with and without feedback), reverb, branching mixers, and component expansion. Unbounded oscillator/noise in a oneshot recipe is rejected with `ERR_INDETERMINATE_ONESHOT`, while continuous sounds with identical shapes validate cleanly.
|
||||
- **Trace 10**: Eviction order 1 -> 2 -> 3 -> 4 is verified at ceiling. `WARN_VOICE_LIMIT` is emitted with sound and ceiling metadata. Continuous sound is never evicted by one-shot request, and refused request leaves runtime stable.
|
||||
- **Trace 11**: Disposal releases every node and connection. A `FINISHED` instance still occupies its ceiling budget until `DISPOSED`.
|
||||
- **Recipe `release` validation**: Validates `0ms` to `10s`, rejects out-of-bounds (`11s`), invalid duration strings (`-10ms`, `slow`), and rejects `release` declared inside components (`ERR_UNKNOWN_FIELD`).
|
||||
- **Exhibit validation**: All three exhibits (`minimal-audio.xzbt`, `minimal-fixed.xzbt`, `minimal-random.xzbt`) validate cleanly with 0 errors via `tools/validate-exhibit.mjs`.
|
||||
- **Deterministic build**: `node tools/build-xzbt.mjs` runs twice with identical digest:
|
||||
`SHA-256 d7d16a89f9b1a9e21262232382d7ae53a0a84abafce191a873327e66dc4103a6` (172,825 bytes).
|
||||
|
||||
## Not established by this record
|
||||
|
||||
- **No automation tracks**: Automation tracks and modes (16.1, 16.2) belong to slice 3c-3.
|
||||
- **No master protection measurement**: Master output protection (16.7) verification belongs to slice 3c-4 under GC6.
|
||||
- **No sound has been heard from any build**: Automated tests verify Web Audio node topologies, connections, and state transitions against headless stand-ins. Real audible playback observations remain open.
|
||||
- **Phase 3 is not accepted**: Slices 3c-3 and 3c-4 remain before Phase 3 can be submitted for acceptance.
|
||||
Reference in New Issue
Block a user