Re-read section 16 before handing the implementation slice onward. Three defects, all of the same classes the Phase 3a review turned up. The 16.5 ending-bound table gave a contribution for every node type except the one that contains other nodes, so a one-shot whose tail lived inside a component had no defined bound. Components now contribute the bound of their own graph by the same rule, terminating on the existing nesting cap. The 16.3 state machine offered no exit from CREATED for a stop arriving before scheduling except FAILED, which would have reported an ordinary cancellation as a fault. Permit CREATED -> FINISHED, and say why it differs from SCHEDULED -> RELEASING: a created instance is connected to nothing, so there is no signal to ramp down. Automation point ordering was a stage conflation. Points had to be in strictly increasing `at` order while `at` was a DurationSpec, which section 6.2 permits to be a procedural TimeSpec resolved at instantiation — so the ordering rule could not have been enforced at the semantic stage where it was filed. This is structurally the same defect as the audioMaxFrequency one closed in Phase 3a. Fix `at` as a duration literal; point values remain full ValueSpecs. Still contract only. No runtime change, and no sound has been heard from any build. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_011FWPdCqKaaDnP9NC3JAwh6
5.4 KiB
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
BindingSpecto a node field is stillERR_UNSUPPORTED_TARGET.audio.buses.<id>.gainremains the single audio target in the shared registry. - One track per property, but modulation still sums.
ERR_AUTOMATION_CONFLICTmirrorsERR_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
oneshotwhose audible path begins at anoscillatorornoiseisERR_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_SKIPrather 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
NaNin 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.
Post-review corrections
Section 16 was re-read before handing the implementation slice onward. Three defects were found in it and fixed in a follow-up commit. All three are the same classes the Phase 3a review turned up, which is why the review step exists rather than being a formality:
- The 16.5 ending-bound table omitted
component. Every node type had a contribution except the one that contains other nodes, so a one-shot whose tail lived inside a component had no defined bound. Components now contribute the bound of their own graph, computed by the same rule; the recursion terminates on the 15.14 nesting cap. - The 16.3 state machine had no exit from
CREATEDfor a stop arriving before scheduling — onlyFAILED, which would have misreported an ordinary cancellation as a fault.CREATED -> FINISHEDis now permitted, and the text says why it differs fromSCHEDULED -> RELEASING: a created instance is connected to nothing, so there is no signal to ramp down. - Automation point ordering was a stage conflation. Points had to be in strictly increasing
atorder whileatwas a DurationSpec, which section 6.2 permits to be a proceduralTimeSpecresolved at instantiation — so the ordering rule could not have been enforced at the semantic stage where it was filed. This is structurally the same defect as theaudioMaxFrequencyone closed in Phase 3a.atis now a duration literal only; point values remain full ValueSpecs.
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
automationorreleaseis currently rejected withERR_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.