Section 20 in full: the automatic scheduling algorithm with its eligible-pool
filtering, cooldown and overlap exclusion, weight evaluation, the anti-repetition
multiplier table applied by recency-queue position, pool relaxation when total
effective weight reaches zero, and reschedule by uniform sample divided by
intensity; the priority clocks and minimum-gap servicing of 20.6 with deferred
classes retained; intensity clamping and the pause threshold of 20.7, under
which ambient voices keep running; the 1024-unit dispatch budget and sixteen
levels of event nesting; and manual SAMPLE evaluation in an isolated stream that
does not perturb cadence scheduling.
Two defects found by the section 20 review triage are fixed here rather than
shipped. A sound action's usage check tested whether the target sound permitted
*some* action context instead of the caller's own, so a scenario-only sound was
playable from a manual action; it now checks the caller's context and rejects
with ERR_UNSUPPORTED_TARGET, the code 20.2.2 and 20.12 actually name, and the
two cases the previous test never exercised — manual-only from scenario, and
scenario-only from manual — are covered.
Traces 7 through 10 drove `triggerSound()` and `calculateEligiblePool()`, a
duplicate scheduler with no production call site, rather than the
`advance()`/`fireClass()` path a real exhibit runs. The two implementations
disagreed on recency-history semantics: 20.5.9 requires a plain queue of the
last four firings, and the duplicate moved an existing entry to the front
instead. Nothing caught it because nothing called both. Those traces now drive
`update()`/`advance()` with a seeded RNG, as traces 11 through 14 already did,
and the duplicate is deleted rather than reconciled.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
Fourteen visual challenge fixtures and the first visuals for reference exhibits
A through D, all executing without a line of subject-specific renderer code —
which is the claim slice 4g exists to test. A subject the engine needs special
handling for is a subject the format cannot express.
The standalone CLI validator no longer disagrees with the production one. It
had been falling through to ERR_UNSUPPORTED_TARGET for every `visuals.*` binding
target, so legal exhibits — including the committed minimal-visual fixture —
failed the CLI while passing the runtime. The four section 8.1 visual target
families are now recognized in both, and a test runs the CLI validator across
every exhibit and challenge fixture so the two paths cannot drift apart again.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
Visual automation in both of its scopes — exhibit-scope tracks measured from
activation and system-scope tracks measured from an instance's own
instantiation, so a track written against spawn-relative time behaves the same
whether the spawn happens at four seconds or at four minutes — together with the
spawned-system lifecycle, the camera, and the seven post-effects of 19.4.
Automation on a missing target object now raises ERR_INVALID_REFERENCE rather
than an unguarded TypeError, per 19.1. Post-effect channel math is clamped
explicitly before assignment and the device blur radius is capped against a
pixel budget, so a large projected radius cannot turn a legal exhibit into a
frame-long stall. Trail fade tapers per segment from the item's own head opacity
to the tail factor, which is what 18.8 describes; the previous flat alpha
ignored the item's ramped opacity entirely. The canvas backend consumes the
per-object buffer grants the engine allocates, rasterizing a buffered node once
and compositing it once under its own blend and alpha, rather than compositing
fill, stroke, glow, and filter separately and double-blending the overlap. Glow
is drawn as a halo around the result rather than painted over it, and text now
gets the glow branch it was silently missing.
Traces 19.7.3 and 19.7.4 are implemented as specified rather than approximated:
the two-spawn four-second offset assertion, and the four negative target cases
that separate ERR_INVALID_REFERENCE from ERR_UNSUPPORTED_TARGET.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
The normative coherent noise of 18.7 (ordered gradients, a 255-sample
Fisher-Yates permutation, octave normalization, and curl as the explicit
perpendicular of the potential's gradient, with published tolerances), the nine
distributions with their normative draw-order table, all seventeen behaviors
with their field contracts and the accumulating-versus-fresh split, component
expansion independent of group nesting depth, particles, emitters, repeaters,
trails, and links. Traces 1 through 19 of 18.10 are automated.
The renderer core this builds on is corrected here rather than separately,
because 4e is what exercises it: the production render path now passes a real
compositing surface factory, so a masked group or a non-opaque layer composites
instead of throwing and permanently deactivating the visual subsystem;
system-level `behaviors` arrays run `validateBehaviors` at import with field
context, so the six classes of invalid document that used to fail at activation
now fail where an author can see them; velocity-accumulating behaviors integrate
on object and repeater hosts; `morph` guards both sides of the z delta rather
than poisoning perspective projection with NaN; `face-motion` initializes its
follow state lazily and holds the previous rotation at zero velocity; a `ring`
with equal start and end angles draws nothing instead of a radial spoke; a
resolved non-integer creation count raises ERR_TYPE_MISMATCH at the boundary
instead of being rounded; boolean leaves are type-checked; per-type required
fields and the static half of the unbounded-emission rule are enforced at
import; and a repeater rejects the emitter-only fields 18.5 says it has none of.
A duration is now the authored literal or a non-negative finite number already
in milliseconds, resolving the one design question the review triage left open.
Runtime, validator, and specification agree on it.
A guard test asserts that no two bundled modules declare the same top-level
identifier: the bundler concatenates into one scope, so a private helper name
collision is a SyntaxError in the artifact while every unit test still passes.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
The first visual code that draws. Sections 17.4 through 17.14 are implemented
against Format Specification revision 0.8, and the standalone artifact now has a
stage canvas that renders a declared scene.
The renderer is split so that the automated traces of 17.16 can run without a
display, which is what those traces require. visual-engine.js resolves an
exhibit's objects once at their instantiation boundary, composes the
scene-to-device chain, sorts by depth, applies fog and the compositing order,
and emits a **frame plan** in device pixels; visual-canvas2d.js turns a plan
into drawing calls. A plan carries the numeric oracles the traces ask for - a
known scene point at a known display point, a perspective factor, a fog
fraction, a sort order - where a canvas carries only pixels.
visual-math.js implements the affine matrices, the normative local transform of
17.11, the directed arc sweep of 17.9 with its bound checked before
normalization, and section 2 color parsing with the fog and ramp arithmetic of
17.6 and 18.2. Colors outside the four documented forms are ERR_TYPE_MISMATCH:
exact components are what make per-object fog renderer-independent.
visual-geometry.js reduces all fourteen primitives to subpaths of lines and
cubic Beziers, so an affine map carries geometry exactly rather than
approximately. It implements the local extents and anchors of 17.9 - a
rectangle anchored top-left, circular primitives centered - the uniform cardinal
form of catmull-rom with its open-duplication and closed-wrap index rules, the
straight closing segment of a closed bezier spline, and endpoint-parameterized
elliptical arcs.
The composition chain of 19.3 is implemented as written: the fit matrix carries
the contain and cover centering offsets, the camera center is mapped into CSS
coordinates before the translation is formed, perspective acts about the
projection center, and the device-pixel multiplier is applied exactly once and
drops below 1 on a display larger than 4096. Scalars with no axis - stroke
widths, radii, dash lengths - take the single uniform factor g, so a nonuniform
stretch never distorts a stroke.
Depth follows 17.6: effective depth accumulates z and translate.z up the tree,
sortable units order farthest-first with the documented tie-break, a point's own
z projects that point without making it a sortable unit, and an object at or
behind the eye is culled with no diagnostic. Compositing follows 17.12: opacity
multiplies down the tree while layer opacity applies once at the layer, and the
sixteen buffer allocations per frame are granted nearest-first so refusals fall
on the far content, each diagnosed under the 19.5 cadence rather than omitted
silently.
visual-validation.js gains the object tree: the fifteen object types and their
declared fields, no `id` and no `layer` on an object, a declared fill on a
stroke-only primitive, a mask only on a group and only naming its own child,
path legality, spline modes and point counts, gradient stop order, and every
authoring limit of 19.5 that applies to a drawn object.
While implementing V10 I corrected the buffer-accounting rule I had written into
17.12: counting buffers as concurrently live made 19.5's farthest-first shedding
nearly unreachable, since group nesting is already capped at 8. The rule is now
16 allocations per frame, which is the per-frame reading "pass budget" has
carried since 17.5 first used it. The arc-sweep prose is likewise corrected to
normalize the signed delta, so 350 -> 10 clockwise is the 20-degree sweep the
text always claimed rather than 340 the long way round.
test/phase4-renderer.test.mjs adds 22 tests covering traces 1 through 13 of
17.16 plus buffer shedding and the backend's call order. npm test goes from 131
to 153 passing. Traces 15 and 16 remain user-observed, and no procedural system,
automation track, or post-effect executes yet - 4e and 4f own those.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
Stage 0 of the five-stage plan in reviews/02-application-code-triage.md: the
shared pre-renderer alignment that has to land before slice 4d writes renderer
code, so the runtime foundation and Format Specification revision 0.8 cannot
drift while three slices are built on top of them. Nothing here draws.
The JSON Schema's `visuals` definition was a Phase 0 stub of `camera`,
`systems`, and `passes`. It is replaced by the real container - scene, layers,
systems, fields, camera, effects, and the exhibit-scope `automation` array that
17.3 previously rejected while 19.1 authorized. Fourteen new definitions cover
visual objects, paints, styles, transforms, behaviors, distributions, trails,
links, automation tracks, the spawn container, and visual components, and
`components.visual` is no longer an unconstrained object. Structural exclusions
carry the contract's own prohibitions: no `id` on a visual object, no `links` on
an emitter, no `trail` on a render object, and none of the four spawn-only
lifecycle names at a system's top level.
src/runtime/visual-contract.js is new and plays the role audio-contract.js
plays for sections 14-16: the primitive, system, behavior, field, distribution,
blend, filter, and post-effect vocabularies; the post-effect parameter tables
with their ranges and pass costs; the centralized ceiling table of 19.5 split
into authoring bounds and runtime ceilings; and matchVisualTarget, which
resolves a path against the four section 8.1 visual target families and
distinguishes a dangling reference from a target that exposes no capability.
src/runtime/visual-validation.js is new and validates the shared surface: the
visuals container, the scene model including the conditional viewport `fit`
rule, layers including the rule that a present layer map makes a system's
`layer` required, the common system fields and the `spawn` container,
procedural fields including the conditional noise `direction`, the post-effect
chain, and visual automation with its two declaration scopes, its automatable
registry, its loop modes, and its authoring bound. Type-specific system fields
are carried through unvalidated and are tightened by 4d, 4e, and 4f.
The resolution engine now exposes the four visual families. `target()` returns a
capability record with a per-family stage table, replacing the hardcoded
`namespace === 'buses'` test for the automation and modulation stages, so a
boolean system `visible` correctly has neither. Visual bases sample once from
the `visual` stream domain at the exhibit-scope instantiation boundary, fall
back to their documented defaults - including the scene center for an
unauthored camera position - and clamp through the shared 8.1 safety stage, so
a `focalLength` that resolves below 1 becomes 1 rather than dividing by zero.
`requireAudioStage` becomes `requireStage(path, stage)` with the old name kept
as its automation wrapper.
The validator's binding-target check is no longer a regex over two families. It
reports ERR_INVALID_REFERENCE for an undeclared layer, system, or effect index
and ERR_UNSUPPORTED_TARGET for everything outside the four rows - per-object
properties, field strengths, emitter rates - which is the distinction trace 14
of 17.16 and trace 4 of 19.7 both check.
exhibits/minimal-visual.xzbt is a new fixture exercising the aligned surface:
two layers, a graphic system with system-scope automation, a repeater over a
component, a particle system reading a declared field, a spawned emitter with
its spawn container, two post-effects, and three bindings reaching three of the
four target families.
test/phase4-visual-contract.test.mjs adds 29 tests. `npm test` goes from 102 to
131 passing with zero failures; no existing test changed.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
Format Specification revision 0.8 closes the thirty repair packages
(V1-V30) and three additional defects (A1-A3) of reviews/01-triage.md
before slice 4d writes any renderer code. Every Tier-1/2/3 design
decision adopts the triage's own recommended fix; reviews/05-visual-fix-log.md
records each choice, its reason, and the sections it touched.
Contradictory surfaces first. `visuals.automation` is added to the 17.3
allowed-field table that previously rejected it. Trace 17.16.14 is
rewritten around the four target families that now exist rather than
asserting a table that changed. `fill` and `stroke` accept
ValueSpec<color>, which is what makes 18.1's own component example legal,
with three limits stated so a ValueSpec can never return a paint object.
The repeater automation registry loses its nonexistent `step` block. An
infinite loop is legal in every scope, bounded by whatever owns the
track.
Spawned-instance lifecycle moves into a `spawn` container. A top-level
`lifetime` is now unambiguously per item and `spawn.lifetime` per
instance, so a spawned emitter expresses both and a spawned repeater
takes an instance lifetime without contradicting 18.5. Component inputs
get one canonical location, the `component` object's own `inputs`, and
the system-level `inputs` on emitters and repeaters is removed.
The composition chain is written out in named spaces. The fit matrix
carries the contain and cover centering offsets it was missing, the
camera center is mapped into CSS coordinates before the translation is
formed, and the chain B x P x V x F x M applies the device-pixel
multiplier exactly once. Local extents and anchors are fixed for all
fourteen primitives, arc sweep is directed with its bound checked before
normalization, catmull-rom is a uniform cardinal spline with its equation
given, and a closed bezier spline closes with a line.
Compositing gets a normative eight-stage order. Layer opacity applies
once, at the layer, not a second time per object, and a separate release
factor initialized to 1 means release never rewrites an authored opacity.
The sixteen offscreen buffers are one pool shared by layers and objects,
with allocation order, reuse, and farthest-first shedding stated, and
buffer refusal named as a diagnosed exception to 17.1.
Sorting units are defined for emitters and repeaters, not only particles:
a procedural system is atomic, with a representative depth and internal
ordinal ordering. Depth fog fixes its blend space and fogs gradient stops
before the paint is built. Coherent noise becomes an algorithm - ordered
gradients, a 255-sample Fisher-Yates shuffle, the full lattice hash,
octave normalization, and curl as the explicit perpendicular of the
potential's gradient - with published tolerances. Distributions get their
equations and an explicit per-distribution draw list, replacing "field
order". All seventeen behaviors get complete field contracts, waveform
equations, an accumulating-versus-fresh rule, and channel write sets.
Live automation totals separate from authoring bounds: a spawn that would
cross the live budget is refused atomically, consuming no ordinal, rather
than being admitted with tracks dropped. One diagnostic cadence covers
every ceiling and every shed. The centralized table gains the ceilings it
was missing and two new authoring bounds - 64 declared systems and 16384
expanded static objects - that close the unbounded static draw load.
`focalLength` gains a real lower bound of 1 so the clamp has a value to
clamp to. The backing store cap wins over the multiplier floor on
displays wider than 4096. Parallax 0 is pinned against camera
translation, not exempt from zoom and rotation.
tools/verify-spec-contract.py commits the contract harness that was
previously run ad hoc. Its post-edit run reports 46 diagnostic codes
declared, 107 distinct cross-references all resolving, zero unresolved
references, 170 balanced fence markers, and 112 well-formed tables.
Documentation only: no runtime, schema, fixture, or test file was
touched, and npm test still passes 102 tests with zero failures. Every
19.5 value, including the two new static bounds, remains provisional
pending the slice 4h GC6 measurement.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
Format Specification revision 0.7 adds section 19, the third and final
visual contract section, covering PRD 85-89 and 119-120.
Visual automation reuses the audio track shape of 16.1 and adds only
`loop`. It is declared in two scopes: `visuals.automation`, measured from
activation, and `visuals.systems.<id>.automation`, measured from that
system's instantiation boundary, so a track on a spawned system behaves
identically however late the spawn happens.
Section 8.1 gains exactly four visual rows, all system-level: camera
fields, layer opacity, system visibility, and post-effect parameters. No
per-object geometry, transform, or style property becomes externally
addressable in 0.1, so the statements in 17.14 and trace 19 of 18.10
survive unchanged. This is the decision 17.14 and 18.6 both deferred.
Systems are persistent or spawned by an explicit `lifecycle` enum. A
spawned system is a template, instantiated only by a spawn action, with a
five-state machine plus FAILED, a `0ms` default release, and a spawn
ceiling that refuses rather than evicts.
The camera matrix is normative, including that parallax multiplies the
camera translation only. `projection` is authored once and is neither
automatable nor bindable.
Seven post-effects, applied in normative array order with a stated
approximation boundary. `grain` is explicitly exempt from reproducibility
and consumes no procedural stream.
Section 19.5 is the centralized ceiling table PRD 120 requires. It
separates authoring bounds, which reject an exhibit at import, from
runtime ceilings, which shed work by a documented deterministic rule and
keep the exhibit running, and it restates every ceiling first fixed in
sections 10 and 14 through 18. Its aggregate values are provisional
pending the slice 4h GC6 measurement.
Two diagnostic codes added: ERR_INVALID_EFFECT_TYPE and
WARN_VISUAL_CEILING. ERR_AUTOMATION_CONFLICT widens to cover a visual
scope and the behavior collision rather than minting a second code.
Documentation only: no runtime, schema, fixture, or test file was
touched. The visual contract now contains no unresolved forward
reference, and npm test still passes 102 tests with zero failures.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AzX3848PwqYwzdUCWvjegL
Format Specification section 18 (PRD 77-84) closes slice 4b: visual
components and their inputs scope, particle systems with a normative
integrator and life ramps, the nine placement distributions, emitters
with exact fractional-accumulator emission timing, repeaters and the
copy-scoped repeat.* namespace, the seventeen-behavior vocabulary and
its channel set, the six procedural fields with a normative coherent
noise function, and trails, ribbons, and links.
Seven diagnostic codes are added to the section 7 table. Section 17 is
amended in four places the new section requires: the visuals.fields
container, the component visual object type beside the closed fourteen
primitives, the now-declared behaviors field, and the widened visual
limit row. Revision 0.5 -> 0.6.
Documentation only; no runtime, schema, fixture, or test file changed.
npm test remains 102 passing.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019dTNHWyTdFobdevrKspoV6
Open the Visual subsystem contract at Format Specification revision 0.5 with
section 17, covering PRD 69-76: the renderer-neutral pipeline, canonical units
on a single degrees convention, the visuals container, layers, the scene model
with three coordinate spaces and three fit modes, 2.5D depth with a fixed sign,
stable sorting, parallax, perspective factor and per-object fog, the fourteen
primitives of Visual Primitive Set 0.1, common visual properties, a normative
transform composition order, appearance with the eight-mode safe blend set and
gradient paint, paths and splines with independently addressable points, text
restricted to the three generic font families, and the once-at-instantiation
resolution boundary for visual ValueSpec fields.
Visual objects are keyed rather than listed and carry no id field, matching the
audio node-identity rule that a Phase 3a blocking defect established. No visual
property becomes externally addressable in this slice; a binding, set, or
override naming one remains ERR_UNSUPPORTED_TARGET, and section 8.1 is
unchanged until section 19.1 adds its rows.
Add five diagnostic codes to the section 7 table, record the eight-slice Phase 4
delivery plan, mark the section 11 Visuals register row in progress, and refresh
the implementation status, which had not been updated since the 3c-1 contract.
Documentation only; no runtime, schema, fixture, or test file is touched.
npm test passes 102 tests with zero failures.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GwmTQU6zLwh3qbBvq5zf5B
Triage of three independent reviews of sections 14-16 (reviews/00-triage.md)
confirmed 13 distinct defects. Seven are doc-only and land here; the rest are
held for design decisions or for reconciliation with the slice 3c-2 runtime.
- T4 ERR_INVALID_RANGE_ORDER refiled Semantic / Runtime in section 7, covering
both sample-hold min/max (literal at import, resolved at instantiation)
and automation `at` ordering (import). 14.12 states the split.
- T5 16.1 documents the sampling boundary and order for automation point
values, satisfying 9.3's requirement of a documented boundary.
- T6 15.14 no longer classes the automation track/point limits as runtime
ceilings; section 7's ERR_NODE_LIMIT_EXCEEDED cause list extended.
- T10 16.2 notes that the override stage is always absent for node properties.
- T11 14.9's impulse envelope column relabelled "Value as p -> 1-" with the
pre-fade values, resolving the exponential row's self-contradiction.
- T12 15.16 names ERR_SCHEMA_VALIDATION for the name and tags caps, which the
schema already enforces on definitions/Sound.
- T13 16.2's masking cross-reference corrected from 8.1 to 8.3/8.4.
Committed path-scoped on main: other modified files are in-flight slice 3c-2
runtime work and are deliberately left in the working tree.
Follow-up: T4 is now spec-mandated but unimplemented. audio-graph.js guards the
range-order check on both bounds being literal numbers, so procedural bounds
pass silently and no instantiation-time check exists.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TvjMnfLaSNVVvzKJbdm6Wj
Close four specification gaps found during pre-implementation review of section 16.
Add the missing \
elease\ field to the recipe graph object table in 15.16, completing the allowed-field table for the container introduced in 16.4.
Reconcile the 16.6 eviction policy: step 2 previously called for evicting an instance in RELEASING without specifying how an already-releasing voice could be evicted under the non-hard-stop rule. Clarify that evicting an already-releasing voice advances its release ramp to immediate completion and disposes it, guaranteeing that the eviction policy terminates and reclaims resources in all cases.
Resolve the incoherence between 16.8 unlock and 16.9 pause discard batching by adding INFO_AUDIO_PAUSE_SKIP to section 7 and 16.10, and recording that resume discards report their own batch rather than sharing an unlock batch.
Clarify that 16.5 ending bound computation operates on the expanded audio graph, resolving paths through component inputs and internal sources deterministically across feed-forward structures, and remove the impossible author remedy of gating an oscillator through an impulse.
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
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
Review Phase 3a before building on it, then implement Phase 3b.
The Phase 3a draft had four blocking defects: nodes were described as a
keyed map while every documented example carried an inline `id` field,
so under the strict unknown-field policy each minimal example would have
failed its own acceptance trace; no section said where a node lives; the
`audioMaxFrequency` ceiling was declared a semantic-stage error while
depending on a live AudioContext sample rate; and the sample-hold PRNG
child key that section 9.3 requires was undocumented. Close all four,
plus nine further gaps in noise seeding, spectral definitions, impulse
decay math, Nyquist handling, missing-field codes, LFO phase origin, the
units table, node-type staging, and a duplicated diagnostics table.
Add Format Specification section 15 for Phase 3b: nine processing and
routing node contracts, the component instance node, audio routing and
modulation with an explicit modulatable-property registry, twelve graph
legality rules, authoring limits, components with a component-scoped
`inputs.*` namespace, sound definitions and recipes, and buses.
Implement the subsystem in three modules. audio-contract.js holds the
declarative node, limit, and modulation tables every consumer reads.
audio-graph.js validates, expands components, and checks legality
without ever opening an AudioContext. audio-engine.js resolves node
fields once from the seeded stream, clamps frequencies to the live
device ceiling, realizes the graph through Web Audio, and owns the
runtime AudioSubsystem. Extend the schema, delegate the standalone
validator's audio checks to the shared module rather than carrying a
second implementation, and add a generic audio fixture.
Phase 3 is not accepted. Automation precedence, the lifecycle state
machine, unlock behavior, voice ceilings, and master protection are
Phase 3c. No sound has been heard from any build, so the audio
acceptance challenge, peak and finite-sample capture, and listening
observations remain open.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011FWPdCqKaaDnP9NC3JAwh6
- Record user evidence for directory fallback to complete GC1 (10/10 checks passed)
- Expand Format Specification 0.1 to Revision 0.2 with normative shared contracts
- Author JSON Schema Draft-07 at schema/xzbt-0.1.schema.json
- Implement zero-dependency semantic validator at tools/validate-exhibit.mjs
- Create 12-case conformance fixture suite and automated test runner (12/12 passing)
- Update implementation status, verification gates, and gap closure decisions
- Add devlog entry covering stall recovery and Phase 0 current state