docs(audio): specify the phase 3c contract

Phase 3c is delivered in four slices so an interrupted phase never leaves
the runtime worse than it started: contract, lifecycle and voices,
automation, and measured master protection. Slice 2 replaces working
scaffolding, and slice 4 cannot close without user-observed measurement.
Record that split in the implementation plan.

This commit is slice 1, the contract. Format Specification section 16
adds automation tracks with three modes and four interpolation curves,
their placement in the shared resolution pipeline, the seven-state
lifecycle with its permitted transitions, the engine-owned internal
release gain, a per-node table for computing determinable one-shot
endings, voice ceilings with an eviction order that always releases
rather than hard-stops, the master protection contract, and unlock and
pause behavior for audio.

Automation reuses the modulation registry rather than introducing a
second answer to which properties vary over time, and a track is
declared inside the graph that owns its target, so section 14.4 stands:
automation does not widen the external surface of a node property. Close
the container gap the new fields opened by adding `automation` to the
graph object in 14.3 and `release` to the recipe object in 15.16.

Master protection is specified in shape and provisional in value.
Finite-sample handling is normative because a NaN in the output buffer
is unacceptable at any ceiling; the peak ceiling, numerical tolerance,
and release behavior await GC6 measurement.

No runtime change. There is no lifecycle state machine, no voice ceiling
is enforced, and `automation` and `release` are still rejected as
unknown fields. No sound has been heard from any build.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011FWPdCqKaaDnP9NC3JAwh6
This commit is contained in:
2026-09-05 23:20:01 +00:00
co-authored by Claude Opus 5
parent cc36878a0f
commit 42e4b32fd6
5 changed files with 313 additions and 12 deletions
@@ -0,0 +1,33 @@
# Phase 3c slice 1 — automation, lifecycle, and protection contract
**Date:** September 5, 2026
**Specification baseline:** Format Specification 0.1 revision 0.4, section 16
**Result:** Contract slice complete. No runtime change; no implementation claimed.
## Scope
Phase 3c is delivered in four slices, recorded in the implementation plan. This record covers **slice 3c-1 only**: the contract. Section 16 now specifies automation tracks and their place in the shared resolution pipeline (PRD 54), the seven-state lifecycle and release behavior (PRD 57), determinable one-shot endings, voice ceilings and eviction, master output protection (PRD 58, 120), and unlock and pause behavior for audio (PRD 117-118).
## Decisions worth recording
- **Automation reuses the modulation registry.** A track may target only a property in the 15.13 modulatable registry. A property is either time-varying or it is not; two mechanisms disagreeing about which would be a defect waiting to happen.
- **Automation does not widen the external surface.** A track is declared inside the graph that owns the property, so 14.4 stands unchanged: an external `BindingSpec` to a node field is still `ERR_UNSUPPORTED_TARGET`. `audio.buses.<id>.gain` remains the single audio target in the shared registry.
- **One track per property, but modulation still sums.** `ERR_AUTOMATION_CONFLICT` mirrors `ERR_CONFLICTING_BINDING`: two writers to one scalar has no defined answer, whereas summation is modulation's defined answer.
- **Determinable endings are decided at import.** Section 16.5 gives a concrete per-node contribution table and computes a finite bound from the resolved graph. A `oneshot` whose audible path begins at an `oscillator` or `noise` is `ERR_INDETERMINATE_ONESHOT` — a semantic error, because it is decidable from the document, and the alternative is a voice that never frees itself.
- **Eviction always releases.** No path stops a voice by disconnecting a running source, which keeps the click surface to one testable code path. One-shot and continuous budgets are independent; neither steals from the other.
- **Exponential automation degrades rather than fails.** A zero or sign-crossing endpoint falls back to linear with `WARN_AUTOMATION_FALLBACK`, because a legal base value can resolve to zero at instantiation.
- **Unlock reports once per batch.** A long pre-unlock interval raises a single counted `INFO_AUDIO_UNLOCK_SKIP` rather than flooding the panel with one entry per skipped one-shot.
- **Master protection is specified in shape, provisional in value.** Finite-sample handling is normative now because a `NaN` in the output buffer is never acceptable at any ceiling. The peak ceiling, numerical tolerance, and release behavior carry provisional values and are confirmed by GC6 measurement.
## Verification
This slice changes documentation only. The full suite still runs 62 tests with zero failures and all three exhibit fixtures still validate, confirming no regression, not that section 16 is implemented. Section cross-references resolve with no dangling targets, and every diagnostic code section 16 uses appears in the single section 7 table.
## Not established by this record
- **No implementation.** Sound instances have no lifecycle state machine, no voice ceiling is enforced, and the runtime shell still releases a one-shot on a fixed development timer. A document declaring `automation` or `release` is currently rejected with `ERR_UNKNOWN_FIELD`; those fields become authorable in slices 3c-2 and 3c-3.
- **No measurement.** The peak ceiling, numerical tolerance, and release behavior of 16.7 are provisional. Traces 15 through 17 of 16.11 — measured peak across worst-case overlapping recipes, listening observations, and the PRD 129 audio acceptance challenge — are user-observed and remain open.
- **No sound has been heard from any build.**
- **The GC4 audio long-stall bound** referenced by 16.9 is still unspecified and is fixed with the GC4 lookahead policy.
Phase 3 is not accepted. Slices 3c-2, 3c-3, and 3c-4 remain.