Revision 0.9 adds section 20, the cadence and event subsystems contract, and carries two corrections the implementation forced. Section 6.1 now states that a duration is the authored literal or a non-negative finite number already in milliseconds, since a DurationSpec may be the resolved output of a ValueSpec or a bounded TimeSpec, with the one documented exception of an automation track's `at`, which 19.1 keeps literal-only so that point ordering stays decidable at import. Section 20.11 documents the rejection of an undeclared input name in an event action's `with` map as ERR_UNKNOWN_FIELD — the section's own convention for that shape of error, replacing an invented code that appeared nowhere in the registry. The review record is committed with the code it describes: the two code triages that found these defects, the reconciliation plan that sequenced the fixes, and a follow-up debt record listing what was deliberately left open — the unchecked JSON Schema artifact, degenerate path arcs, post-effect transient allocation, the window-traffic fixture's per-copy wrap bounds, and the unstated `ownership: "persistent"` value on a sound action. None of the five blocks phase 6; all five are written down rather than dropped. Devlog entries are backfilled for the two milestones that had none: phase 3c slice 2, the audio lifecycle and voice ceilings, and slice 4d, the renderer core. The implementation status summary now reflects the reconciled state rather than the in-flight one. 231 tests pass. tools/verify-spec-contract.py reports 46 declared diagnostic codes with every used code resolving and its two long-standing unresolved cross-references unchanged. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
409 lines
25 KiB
Markdown
409 lines
25 KiB
Markdown
# XZBT 0.1 Format Specification §§14–16 — review triage
|
||
|
||
Inputs: `01-grok-4.6.md`, `02-kimi-k3.md` (two outputs, same seven findings), `03-deepseek-v4-flash.md`.
|
||
GLM review not received.
|
||
|
||
Every claim below was checked against `docs/XZBT_0-1_Format_Specification.md` as it stands on disk
|
||
(1499 lines). Line numbers are that file's. Nothing in the spec was edited.
|
||
|
||
**Result: 13 distinct defects. All 21 reported findings are real** — none is a false positive —
|
||
but only **4 of 13 were found by all three reviewers**, and **5 of 13 were found by exactly one**.
|
||
Four proposed fixes are wrong or incomplete and are corrected below. Two defects that no reviewer
|
||
found are added.
|
||
|
||
---
|
||
|
||
## Scorecard
|
||
|
||
| | Grok 4.6 | Kimi K3 | DeepSeek v4 Flash |
|
||
| --- | :---: | :---: | :---: |
|
||
| Findings reported | 6 | 7 | 8 |
|
||
| Real | 6 | 7 | 8 |
|
||
| Overstated | 0 | 0 | 1 (D8) |
|
||
| Unique catches | 0 | 1 | 2 |
|
||
| Of the 13 confirmed | 6 | 7 | 8 |
|
||
| Proposed fix wrong/incomplete | 2 | 1 | 2 |
|
||
|
||
DeepSeek is the strongest pass: it is the only reviewer to unify the bus-gain defect (T1) instead of
|
||
splitting it, and the only one to catch the eviction defect (T3) and the modulated-delay bound (T8).
|
||
Kimi is the only one to catch the component-parameter defect (T2), which is the second-largest hole
|
||
in the section. Grok found nothing the other two missed, and split T1 into two half-findings whose
|
||
fixes contradict each other.
|
||
|
||
The overlap pattern is the argument for having run multiple models: **9 of 13 defects would have been
|
||
missed by any single reviewer.**
|
||
|
||
---
|
||
|
||
## Tier 1 — Unimplementable: a required acceptance trace cannot pass as written
|
||
|
||
### T1. Bus gain claims automation and modulation with no authoring surface; no target in the document exposes both automation and override; trace 16.11.8 cannot be implemented
|
||
|
||
*Reported by: DeepSeek F1 (complete). Grok #4 and #5 are the same defect split in two. Kimi missed it.*
|
||
|
||
**Confirmed.** Three independent statements are orphaned:
|
||
|
||
- 8.1 (line 314) gives `audio.buses.<id>.gain` Automation = Yes and Additive modulation = Yes.
|
||
15.17 (line 1230) and 16.2 (line 1330) repeat both claims.
|
||
- Automation tracks live only in a graph object's `automation` array (14.3 line 606, 16.1 line 1265).
|
||
Graph objects exist at exactly three places (lines 610–612); a bus is not one of them, and 15.17's
|
||
bus table (line 1228) allows only `gain`, so an `automation` key on a bus is `ERR_UNKNOWN_FIELD`
|
||
under the strict unknown-field policy.
|
||
- 16.1 line 1286 restricts `target` to `<node-key>.<property>` "resolved in the same graph", and
|
||
line 1293 restricts it to the 15.13 registry. A bus is not a node and bus gain is not in that
|
||
registry (lines 1073–1085). **No legal `target` can name a bus.**
|
||
- Modulation has the same problem: the only modulation syntax is a 15.12 route whose `to` is
|
||
`<node-key>.<property>` in the same graph. **Nothing can modulate a bus gain either.**
|
||
|
||
Consequences:
|
||
|
||
1. 16.2's second consequence (line 1332, override masks automation, releases to the track's current
|
||
value) describes a situation no legal document can produce. Node properties take automation
|
||
(16.1) but are barred from override (14.4 line 631, `ERR_UNSUPPORTED_TARGET`); `parameters.<id>`
|
||
and `state.<id>` take override but have Automation = No (8.1 lines 312–313); bus gain is the only
|
||
row with both, and its automation is unauthorable. **No target exposes both stages.**
|
||
2. Required trace **16.11.8** (line 1485) is therefore unimplementable, and Phase 3c cannot be
|
||
accepted as written.
|
||
|
||
**Fix — all three reviewers get this wrong.**
|
||
|
||
- Grok #4 proposes keeping override-vs-automation "only for `audio.buses.<id>.gain`". That fails for
|
||
the same reason: bus gain has no automation surface.
|
||
- Grok #5 offers "add an `automation` array on the bus object, or strike automation from 16.2" and
|
||
says not to leave both standing — correct as far as it goes, but it treats only the automation half
|
||
and leaves the modulation half untouched.
|
||
- DeepSeek F1 correctly identifies both halves and both options, then says **"Option (a) is the
|
||
smaller change."** *That is wrong.* Deleting additive modulation from bus gain would orphan
|
||
**§8.5 required trace 6** (line 409, "A target has legal additive modulation → Modulation follows
|
||
the winning override; safety clamp runs last"), because bus gain is the **only** row in the entire
|
||
8.1 table with Additive modulation = Yes. Option (a) does not shrink the problem; it moves it into
|
||
§8, a contract §11 line 513 already marks **Complete (Rev 0.3 / GC3)**.
|
||
§8.3 line 370 ("Underlying binding and **automation** stages continue to evaluate while masked")
|
||
is orphaned by the same gap.
|
||
|
||
**Recommended fix:** option (b). Give `audio.buses.<id>.gain` a real authoring surface for automation
|
||
and modulation, and make 16.1's target rule name it. Concretely: allow an `automation` array on the
|
||
bus object with `target` fixed to `gain`, and add a bus-addressed modulation form. This keeps 8.1,
|
||
8.3, 8.5, 15.17, 16.2 and traces 16.11.8 and 8.5-6 all consistent, and it is the only option that
|
||
does not reopen a completed contract.
|
||
|
||
**Out of scope but worth recording:** §8.5 trace 6 and §8.3's masking sentence are *already*
|
||
unimplementable today, independent of §§14–16. All three reviewers scoped to 14–16 and so could not
|
||
see this. It should be logged against §8.
|
||
|
||
---
|
||
|
||
### T2. Component exposed parameters are legal modulation and automation targets with no defined effect; trace 15.19.4 cannot be implemented
|
||
|
||
*Reported by: Kimi #1 only. Grok and DeepSeek both missed it.*
|
||
|
||
**Confirmed.** 15.13 line 1085 lists `component` / `<exposed-parameter-id>` in the modulatable
|
||
registry; 15.11 line 1045 repeats it; 16.1 line 1293 inherits it for automation. But the only path by
|
||
which a component's internals read a parameter is `{ "ref": "inputs.<id>" }` in a node field
|
||
(15.15 line 1166), and 14.4 line 629 resolves every node field **once** at instantiation, "constant
|
||
for that node instance's lifetime". 15.11 line 1039 resolves the supplied `values` once as well.
|
||
|
||
So a modulation sum or automation curve applied to an exposed parameter changes a value that nothing
|
||
ever reads again. Required trace **15.19.4** (line 1250, "an exposed parameter is a legal modulation
|
||
target") cannot be satisfied without inventing behavior.
|
||
|
||
**Fix — Kimi offers two options and correctly says the first is smaller. It is also the only correct
|
||
one, for a reason Kimi does not give.** Option two (make `{ "ref": "inputs.<id>" }` fields track the
|
||
parameter live, as an exception to 14.4) would let a modulation route reach *any* internal node field
|
||
through a parameter — including `reverb.decay`, `compressor.threshold`, `waveshaper.amount` and every
|
||
other property 15.13 line 1087 deliberately excludes ("Merely being numeric does not grant modulation
|
||
support"). That silently defeats the registry's whole purpose and breaks 15.11's encapsulation claim.
|
||
|
||
**Recommended fix:** delete the `component` row from the 15.13 registry (line 1085), delete the
|
||
modulation-target sentence in 15.11 (line 1045), and drop the exposed-parameter clause from trace
|
||
15.19.4.
|
||
|
||
---
|
||
|
||
### T3. 16.6 eviction step 3 frees no budget slot; the outcome is undefined and trace 16.11.10 is ambiguous
|
||
|
||
*Reported by: DeepSeek F2 only.*
|
||
|
||
**Confirmed.** Line 1406: "A voice counts against its ceiling from `CREATED` until `DISPOSED`."
|
||
The eviction policy (lines 1408–1413) "stops at the first candidate":
|
||
|
||
1. Dispose the oldest `FINISHED` instance — frees a slot.
|
||
2. Evict the oldest `RELEASING` instance by advancing its ramp to completion **and disposing it** —
|
||
frees a slot.
|
||
3. For a one-shot request only: evict the oldest `ACTIVE` one-shot **by starting its release** —
|
||
moves it `ACTIVE` → `RELEASING`, which still counts (line 1406, reinforced by line 1372 and trace
|
||
16.11.11). **Frees nothing.**
|
||
4. Otherwise refuse.
|
||
|
||
With the ceiling full of `ACTIVE` one-shots, the policy stops at step 3 having freed no slot.
|
||
Admitting the new instance puts the count at 65; refusing it contradicts having stopped before step 4.
|
||
Neither is defined. Step 2's explicit "and disposing it" makes step 3's omission conspicuous rather
|
||
than incidental.
|
||
|
||
A weak defense exists — line 1399 calls the ceilings "approximate" — but line 1406's counting rule and
|
||
trace 16.11.11 both insist on exact accounting, so this does not resolve it.
|
||
|
||
**Fix — DeepSeek offers two options without ranking them; the first is correct.** Making step 3
|
||
behave like step 2 (complete the release immediately and dispose) contradicts line 1415, "Eviction
|
||
always releases; it never hard-stops an active voice" — an instant ramp on an audible voice *is* the
|
||
click that 16.4's single-code-path design exists to prevent. Step 2 does it only to voices already
|
||
decaying.
|
||
|
||
**Recommended fix:** state that an `ACTIVE` one-shot evicted under step 3 stops counting against the
|
||
ceiling at the moment of eviction, its release running outside the budget, so the new instance is
|
||
admitted and the ceiling is never exceeded. Add the matching exception to line 1406.
|
||
|
||
---
|
||
|
||
## Tier 2 — Real defects with clear fixes
|
||
|
||
### T4. `ERR_INVALID_RANGE_ORDER` is filed Semantic-only but the sample-hold rule needs instantiation-time values
|
||
|
||
*Reported by: all three (Grok #1, Kimi #2, DeepSeek F4). Unanimous, and unanimously right.*
|
||
|
||
**Confirmed.** 14.12 lines 815–816 make `min`/`max` full ValueSpecs in 14.4 scope — resolved once at
|
||
instantiation. Line 819 makes inverted resolution `ERR_INVALID_RANGE_ORDER`. §7 line 286 files that
|
||
code **Semantic** only, with a cause that says "after resolution" — the table concedes the problem in
|
||
its own text. 14.5 line 645 states semantic validation checks only values that resolve to a literal
|
||
and never opens an `AudioContext`; 9.3 line 445 puts the root seed at performance start, not import.
|
||
|
||
`{ "min": { "random": {...} }, "max": { "random": {...} } }` is import-legal and its order is
|
||
undecidable at the only stage the code is filed under.
|
||
|
||
**Fix:** all three converge and all three are right. Refile as `Semantic / Runtime` in §7 (mirroring
|
||
`ERR_OUT_OF_BOUNDS`, line 272, which is already dual-filed), and state in 14.12 that literal bounds
|
||
are rejected at import and resolved bounds at instantiation.
|
||
|
||
**Note:** §7's cause text mentions only `sample-hold` `min`/`max`. 16.1 line 1299 uses the same code
|
||
for automation `at` ordering, which *is* purely semantic because `at` is a literal by construction
|
||
(line 1297). The revised cause text must cover both without implying `at` is a runtime check.
|
||
|
||
---
|
||
|
||
### T5. Automation point `value` draws from a seeded stream with no documented sampling boundary or order
|
||
|
||
*Reported by: all three (Grok #3, Kimi #4, DeepSeek F6).*
|
||
|
||
**Confirmed.** 16.1 line 1289 makes each point `{ "at": <literal>, "value": ValueSpec<number> }`, and
|
||
line 1297 says "A track's *values* remain full ValueSpecs and may be random."
|
||
|
||
9.3 line 457 requires sampling at "the containing object's **documented** instantiation or invocation
|
||
boundary". No such documentation exists for `automation`:
|
||
|
||
- 14.4 line 629 documents the boundary for fields on **node objects**. A track is on the graph object.
|
||
- 15.12 line 1067 documents the order for route `depth` only.
|
||
- 14.12 line 825 is the only documented child key, and it is `sample-hold` only.
|
||
|
||
Two conforming implementations can consume the sound instance's stream in different orders and
|
||
diverge for the same seed, breaking 9.3's reproducibility promise and 14.6's restatement of it.
|
||
16.8 line 1445's guarantee that a partially elapsed continuous sound has "a procedural sequence
|
||
identical to an unbroken run" has no defined meaning for automated tracks.
|
||
|
||
**Fix:** all three propose the same one-sentence addition to 16.1 and all are adequate. Kimi's and
|
||
DeepSeek's are the more precise, because they fix the position of `automation` in the depth-first
|
||
order relative to `nodes` and `routes`, which Grok's leaves open:
|
||
|
||
> A track's point values are resolved once at the owning sound instance's instantiation boundary,
|
||
> sampled from that instance's stream in depth-first, property-document order, with `automation`
|
||
> taken after `nodes` and `routes`.
|
||
|
||
---
|
||
|
||
### T6. 15.14 calls the automation track/point limits runtime ceilings; 16.1 enforces them with a Semantic code
|
||
|
||
*Reported by: all three (Grok #6, Kimi #3, DeepSeek F5).*
|
||
|
||
**Confirmed.** Line 1132 groups automation tracks (`64`) and points (`256`) with the voice ceilings as
|
||
"runtime ceilings rather than document properties". Line 1318 makes exceeding either
|
||
`ERR_NODE_LIMIT_EXCEEDED`, filed **Semantic** at §7 line 285, and trace 16.11.6 (line 1483) sits in
|
||
the "Automated, and executable without an audio device" group. Track and point counts are decidable
|
||
after component expansion, which trace 15.19.7 confirms runs with no `AudioContext`. The voice
|
||
ceilings in the same sentence *are* correctly runtime.
|
||
|
||
**Fix — Grok's first option is wrong.** Grok #6 offers "move tracks/points into the authoring-limit
|
||
table with expanded nodes/routes". That table is headed "The authoring-time limits enforced in
|
||
**Phase 3b**" (line 1122), and automation is Phase 3c — 16.1 line 1261 states that the current
|
||
validator rejects any document declaring `automation` with `ERR_UNKNOWN_FIELD`. Putting them in the
|
||
Phase 3b table asserts enforcement that cannot exist. DeepSeek F5 offers the same wrong option
|
||
alongside the right one.
|
||
|
||
**Recommended fix (Kimi's):** delete "automation tracks (`64`), and automation points (`256`)" from
|
||
line 1132, leaving the voice ceilings. Optionally add a pointer that 16.1 enforces them semantically.
|
||
Separately, extend §7 line 285's cause parenthetical — it currently reads "(oscillator partials,
|
||
resonator modes, expanded nodes or routes per sound)" and omits the automation limits entirely.
|
||
|
||
---
|
||
|
||
### T7. 16.5's resonator contribution is undefined when every mode is omitted at instantiation
|
||
|
||
*Reported by: all three (Grok #2, Kimi #5, DeepSeek F7).*
|
||
|
||
**Confirmed.** 16.5 line 1387 gives a resonator "the longest `decay` among its **retained** modes".
|
||
15.10 line 1024 omits, at instantiation and with no diagnostic, any mode whose resolved frequency
|
||
exceeds `audioMaxFrequency`. Mode entries are omitted rather than clamped — 14.7 line 690 is explicit
|
||
that omission "is not the `WARN_AUDIO_RATE_CLAMP` case of 14.5, which applies to the node's own
|
||
`frequency`".
|
||
|
||
A single-mode resonator can therefore retain nothing, and "longest decay" becomes a maximum over an
|
||
empty set — feeding the one-shot ending bound, which 16.5 line 1376 requires to be computable "from
|
||
the resolved graph alone".
|
||
|
||
All three examples check out arithmetically. The cleanest is Grok's: a mode with absolute
|
||
`frequency: 20000` is import-legal against the device-independent ceiling `24000` (14.5 line 645) and
|
||
omitted on a 44.1 kHz device, where `audioMaxFrequency = min(24000, 19845) = 19845`.
|
||
|
||
**Fix:** DeepSeek's wording is the tightest — extend the row to "the longest `decay` among its
|
||
retained modes, **or zero when no mode is retained**".
|
||
|
||
**Downgrade:** Kimi #5 and DeepSeek F7 also raise the all-partials-omitted custom oscillator. That one
|
||
is materially weaker: an empty sum of partials is silence by construction, and `oscillator` is
|
||
**unbounded** in the 16.5 table regardless, so no bound is left undefined. Worth one clarifying
|
||
sentence in 14.7, not a Tier 2 defect.
|
||
|
||
---
|
||
|
||
### T8. The 16.5 ending bound is not an upper bound when `delay.time` is modulated
|
||
|
||
*Reported by: DeepSeek F3 only.*
|
||
|
||
**Confirmed.** 16.5 line 1376 defines "determinable" as a finite upper bound computed at instantiation
|
||
"from the resolved graph alone"; line 1385 computes the delay contribution from the **resolved**
|
||
`time`. But `delay.time` is modulatable (15.6 line 943; 15.13 line 1082) and 15.6 line 949 clamps a
|
||
modulated delay only to `[0ms, 10s]`. A legal `oneshot` may route an `lfo` or `sample-hold` at
|
||
`delay.time`; the actual feedback tail can then run far past the computed bound, and the runtime tears
|
||
the instance down while it is still ringing — contradicting 16.3 line 1360, which asserts that at a
|
||
determinable ending "the envelope has already returned to zero". Trace 16.11.9 passes only for graphs
|
||
whose bound-contributing properties are unmodulated.
|
||
|
||
`delay.feedback` is not modulatable (line 944), so `time` is the only exposure.
|
||
|
||
**Fix — DeepSeek's is incomplete, and T9 is why.** It proposes bounding the contribution by the
|
||
largest reachable `time`, "source outputs are bounded — `lfo` by its resolved amplitude, `sample-hold`
|
||
by its resolved `min`/`max`". That list omits `oscillator`, which 15.13 line 1089 also permits as a
|
||
modulation source and whose output magnitude the spec never states (see T9). Until T9 is fixed, the
|
||
proposed bound cannot be computed for an oscillator-modulated delay.
|
||
|
||
**Recommended fix:** fix T9 first, then bound the delay contribution over the property's reachable
|
||
range given its modulation routes. Alternatively — and this is the genuinely smaller change — exclude
|
||
a `oneshot` whose bound-contributing property is modulated from determinable-ending status, i.e.
|
||
`ERR_INDETERMINATE_ONESHOT`. Note that an *automated* `delay.time` is exactly boundable once T5 lands,
|
||
since `at` values are literals and point values resolve at instantiation; only modulation is open.
|
||
|
||
---
|
||
|
||
### T9. An `oscillator` used as a modulation source has no defined output magnitude
|
||
|
||
*Not reported by any reviewer.*
|
||
|
||
**Confirmed.** 15.13 line 1089 permits a modulation route's `from` to be "a control source
|
||
(`constant`, `lfo`, `sample-hold`) **or an `oscillator` used at audio rate** (PRD 41)". The summation
|
||
rule at line 1094 is `value = clamp(b + sum(s_i x d_i), ...)`, and line 1097 defines `s_i` only for
|
||
control sources: "**A control source's** output is its own value in its own units before scaling: an
|
||
`lfo` with `amplitude: 1` and `polarity: "bipolar"` contributes `[-d, +d]`."
|
||
|
||
An `oscillator` is not a control source (14.7 line 678; 15.14 rule 5 lists only `constant`, `lfo`,
|
||
`sample-hold`), and 14.7 gives it no amplitude field and no stated output range. For a `custom`
|
||
waveform with up to 64 partials at `gain: 1` each (line 685), the peak is not even conventionally
|
||
`[-1, 1]`. So `s_i` is undefined for the one source type the registry explicitly admits alongside the
|
||
control sources.
|
||
|
||
**Recommended fix:** state the oscillator's modulation output range in 15.13 — e.g. that a non-`custom`
|
||
oscillator contributes `[-d, +d]`, and a `custom` oscillator's output is normalized to peak `1` before
|
||
scaling by `depth`. Normalization is the safer choice; without it, `depth` means something different
|
||
for every harmonic table.
|
||
|
||
---
|
||
|
||
## Tier 3 — Editorial and low-severity
|
||
|
||
### T10. 16.2's "For a node property" pipeline includes an override stage that is always absent
|
||
*Grok #4's residue, after T1 absorbs the rest.* Line 1322 introduces the pipeline diagram at line 1325
|
||
with "For a node property:", and the diagram includes `winning override`. 14.4 line 631 makes an
|
||
override on a node field `ERR_UNSUPPORTED_TARGET`, and 16.2 line 1330 reaffirms it for binding but is
|
||
silent on override. Per 8.1 line 308 the stage is "absent, not an identity hook", so the diagram
|
||
should say so. **Fix:** annotate the diagram or add one clause to line 1330 noting that the override
|
||
stage is absent for node properties.
|
||
|
||
### T11. 14.9's "Value at `p = 1`" column contradicts the exponential row's own annotation
|
||
*DeepSeek F8 — real, but overstated.* Line 741 defines the envelope over `0 <= p < 1`; line 749 then
|
||
says "The envelope is exactly `0` for `p >= 1`", which makes the column's three zeros defensible for
|
||
the piecewise function. The genuine inconsistency is narrower and internal to one row: the
|
||
`exponential` row's Envelope cell is annotated "(`-60` dB at `p = 1`)", i.e. `0.001a`, while its
|
||
"Value at `p = 1`" cell says `0`. The same table then supports line 749's "Because `flat` and
|
||
`exponential` do not reach zero on their own" — which is false of a column reporting `0` for both.
|
||
No implementation ambiguity survives, because the terminal fade is normative either way.
|
||
**Fix:** relabel the column "Value as `p → 1⁻`" with `a`, `0`, `a x 0.001`, or delete it.
|
||
|
||
### T12. `sounds.<id>.name` and `tags` length caps name no diagnostic
|
||
*Kimi #6.* Lines 1197–1198 cap `name` at 128 characters and `tags` at 16 entries of 32 characters
|
||
with no code. Every other quantitative limit in §§14–16 names one, and no §7 entry covers string or
|
||
array lengths: `ERR_INVALID_ID` (line 268) is identifier-scoped, `ERR_OUT_OF_BOUNDS` (line 272) is
|
||
numeric min/max, and `ERR_SCHEMA_VALIDATION` (line 265) covers "malformed top-level shapes", which
|
||
`sounds.<id>` is not. **Fix:** name the code — `ERR_SCHEMA_VALIDATION` is the closest fit.
|
||
|
||
### T13. 16.2 line 1332 mis-cites §8.1
|
||
*Kimi #7.* The cited "parameter-masking rule of section 8.1" is not in 8.1 — its only masked-override
|
||
text (line 318) is about the UI override indicator. The behavior lives in **8.3** (line 370, masked
|
||
stages continue) and **8.4** (line 392, `currentLowerValue` recomputed every tick), with the trace at
|
||
8.5 line 406. **Fix:** cite 8.3/8.4.
|
||
|
||
### T14. An exposed component parameter with no `min`/`max` has no clamp range
|
||
*Not reported by any reviewer.* 15.15 line 1163 makes `min` and `max` optional on an exposed
|
||
parameter, but 15.13 line 1094 clamps a modulated property to "the property's declared range from its
|
||
node contract". For `{ "type": "number", "default": 220 }` there is no such range.
|
||
**Moot if T2's recommended fix lands** (deleting the `component` row removes the only path here); if
|
||
option two is chosen instead, this must be fixed alongside it.
|
||
|
||
---
|
||
|
||
## Findings checked and cleared
|
||
|
||
- **Class 1 (prose vs JSON in the same section):** all three reviewers reported none, and that holds.
|
||
Every example and invalid case in 14.3–14.13, 15.2–15.17 and 16.1 matches its section's tables.
|
||
One editorial note nobody raised: 14.3's canonical graph example (lines 589–600) is
|
||
`oscillator → gain → output`, which is **not** a legal `oneshot` recipe — as a recipe it would be
|
||
`ERR_INDETERMINATE_ONESHOT` (16.5 line 1393), and `mode` defaults to `oneshot` (line 1208). It is a
|
||
bare graph-object example, so this is not a defect, but it is an unfortunate thing to copy.
|
||
- **Class 2 (field missing from its container's allowed-field table):** none, confirmed. The 15.13
|
||
registry matches the "Modulatable" columns of 15.2–15.10 exactly; T1's bus-gain case is a missing
|
||
*surface*, not a missing table row.
|
||
- **Diagnostic codes used but absent from §7:** none. All codes in §§14–16 appear in the §7 table, and
|
||
the 15.18/16.10 tables match it. Mis-staging is T4 and T6; an incomplete cause list is folded into T6.
|
||
- **Cross-references:** all internal references resolve. The only defect is a *mis*-reference, T13.
|
||
- **Non-termination:** 16.5's longest-path terminates on the acyclic expanded graph (15.14 rules 7 and
|
||
11). The delay formula `ceil(log(1/1000)/log(feedback))` is well-defined on the legal `(0, 0.95]`
|
||
and correctly branches at `feedback > 0`.
|
||
- **Modulation-only `oscillator` and the one-shot bound:** an oscillator used purely as a modulation
|
||
source has no audio-route path to `output`, and 16.5 line 1393 keys `ERR_INDETERMINATE_ONESHOT` to
|
||
the *audible* path, so it does not make a `oneshot` indeterminate. Correct as written.
|
||
- **Deliberate-design exclusions** (node `id`, the 14.4 bindable surface, noise/impulse
|
||
non-reproducibility, provisional master-protection values, absent `audio.master`, literal automation
|
||
`at`, the GC4 stall bound, bus processing beyond gain) were respected by all three reviewers and are
|
||
not defects.
|
||
|
||
---
|
||
|
||
## Recommended edit list
|
||
|
||
Ordered by severity. Items marked **(design)** need a decision before an edit can be written.
|
||
|
||
| # | Location | Change | Kind |
|
||
| --- | --- | --- | --- |
|
||
| T1 | 8.1, 15.17, 16.1, 16.2, 16.11.8 | Give bus gain an automation/modulation authoring surface and name it in 16.1's target rule | **(design)** |
|
||
| T2 | 15.13 line 1085, 15.11 line 1045, 15.19.4 | Delete the `component` modulation-target row and its two restatements | Delete |
|
||
| T3 | 16.6 lines 1406, 1412 | Evicted `ACTIVE` one-shot leaves the ceiling count immediately | One sentence |
|
||
| T4 | §7 line 286, 14.12 | Refile `ERR_INVALID_RANGE_ORDER` as `Semantic / Runtime`; split literal vs resolved | Restage |
|
||
| T5 | 16.1 | Document the automation point `value` sampling boundary and order | One sentence |
|
||
| T6 | 15.14 line 1132, §7 line 285 | Remove the two automation limits from the runtime-ceiling sentence; extend the cause list | Delete + edit |
|
||
| T7 | 16.5 line 1387 | "…or zero when no mode is retained" | Clause |
|
||
| T8 | 16.5 line 1385 | Bound the delay contribution over the reachable `time`, or exclude modulated bound-contributors | **(design)**, blocked on T9 |
|
||
| T9 | 15.13 line 1097 | State an `oscillator`'s modulation output magnitude and `custom` normalization | **(design)** |
|
||
| T10 | 16.2 lines 1325, 1330 | Note that the override stage is absent for node properties | Clause |
|
||
| T11 | 14.9 lines 743–747 | Relabel or delete the "Value at `p = 1`" column | Editorial |
|
||
| T12 | 15.16 lines 1197–1198 | Name the diagnostic for the `name`/`tags` caps | Editorial |
|
||
| T13 | 16.2 line 1332 | Cite 8.3/8.4 instead of 8.1 | Editorial |
|
||
| T14 | 15.15 line 1163 / 15.13 line 1094 | Only if T2 takes option two | Conditional |
|
||
|
||
**Outside §§14–16, log separately:** §8.5 trace 6 and §8.3's masked-automation sentence are already
|
||
unimplementable for want of a target with those stages (see T1).
|