Files
XZBT/docs/evidence/phase3/2026-09-05-phase3c-contract.md
T
LabyricornandClaude Opus 5 50fb72c0e8 docs(audio): close three defects in the phase 3c contract
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
2026-09-05 23:29:23 +00:00

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 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.

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:

  1. 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.
  2. The 16.3 state machine had no exit from CREATED for a stop arriving before scheduling — only FAILED, which would have misreported an ordinary cancellation as a fault. CREATED -> FINISHED is now permitted, and the text says why it differs from SCHEDULED -> RELEASING: a created instance is connected to nothing, so there is no signal to ramp down.
  3. 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. at is 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 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.