Repository navigation
Compare stored automation bits across the browser and native hosts #1669
Description
Compare stored automation bits across the browser and native hosts
Proposed by Research: render stored session automation in the engine, identically on every
platform (#1058), answer A5, under decision 15 D15-16
(docs/rulings/live-updates-seamless-swaps-and-one-control-plane-2026-10-05.md). A draft for root
to file. Code anchors verified on 6ee64f484. Batch Q.
Product outcome
One fixture session automates every row the engine renders, with every shape, and is seeked once
while it plays. The shipped browser artifact (wasm simd128) and the native browser host on
x86-64 (AVX2) render it to the same bits, and the C ABI renders the same bits as the browser host.
A second fixture does the same for matrix automation. This is the browser and x86-64 half of the
evidence that stored automation renders identically on every platform; #1670 adds AArch64 and
seek-time invariance on the same fixtures. It adds no new digest owner: it extends the direct
oracle's existing pins. Batch Q.
Context
The existing owners.
- The G5 corpus is the single owner of the kernels' cross-target digests
(tools/wasm-gate-corpus/src/lib.rs:1-20), run natively bywasm-gatesand under wasmtime.
Compile stored automation into per-cell events in node time #1637 adds the evaluator's event values to it. - The browser direct oracle renders fixed sessions through the shipped
simd128artifact
(hosts/host-web/tests/browser-v1/direct-oracle.mjs:547-679). Each leg asserts its PCM digest
equals a native pin before anything prints (the identity leg,:571-583; the command timeline,
:584-601; the observation timeline,:602-654). - Each native pin is written by a host-web test that renders the same session and transcript
throughAudioWorkletEngineHoston the host CPU and reads the pin fromexpected.json
(native_identity_session_digest_pins_the_wasm_parity,hosts/host-web/src/tests.rs:1632;
the command and observation twins at:1751and:6690; the pin readerserde_pin,
:2255-2300). - CI runs the oracle in the
artifact-gatesjob throughscripts/check-web-audioworklet.shand
scripts/check-browser-expected-resources.py --artifacts
(.github/workflows/qualification.yml:331-343).
What the oracle drives today. The command timeline feeds constant PCM and drives live
commands (direct-oracle.mjs:373-454). No leg has stored automation or a session seek.
The C ABI. No test compares a C ABI render with the browser host's today. #1399 adds the
cross-host harness hosts/host-web/tests/strip_cells_cross_host.rs.
Decisions frozen for this slice
- D1. Two fixtures, beside the existing ones in
hosts/host-web/tests/browser-v1/:automation-session.json: two tracks and one submix at 48 kHz, quantum 128. Track 1 automates
fader, mute, pan, trim, polarity, HPF and LPF on its lanes (onebothentry and one
single-lane entry among them), and has a pre-fader route into the submix with
follows_mute. Its inserts carry every span-driven launch effect (compressor, delay with its
time automated, gate/expander, multiband compressor, soft clip, transient shaper, true-peak
limiter) and a parametric EQ, each with at least one automatedBlockparameter. Track 2 has
the same chain with no automation, so a bank holds automated and plain lanes.- Across the entries:
step,linearandexponentialsegments (exponential only where a rule
allows it: Validate builtin automation targets against their rows at preparation #1645's for the input HPF and LPF, Validate builtin automation targets against their rows at preparation #1645's shape rule for an effect frequency, time or
ratio row), a gap, a step on a sample that is not a grid
sample, and a segment that starts before the seek target. automation-matrix-session.json: one matrix strip whose four coefficients are automated.
- D2. One transcript. Both fixtures render 96 blocks of PCM generated by an integer formula
that is exact inf32in Rust and in JavaScript, for example
x[i] = ((i·40503) mod 65536 − 32768) / 65536. At block 40 the host makes one session seek to
timeline 30,000 (Seek the timeline and every source from the browser module export and the headless SDK #1643's export in the oracle, the same control-plane call natively). - D3. The browser leg.
direct-oracle.mjsgainsrunAutomationTimelinefor each fixture. It
asserts each digest equalsexpected.directOracle.nativeAutomationPcmF32leSha256and
nativeAutomationMatrixPcmF32leSha256before any print, as the existing legs do. The pins are
written by two new host-web tests beside:1632, whichserde_pinextends to read. Compare stored automation bits on AArch64 and across seek times #1670
reuses these two tests and pins. - D4. The C ABI equals the browser host. In Report live_values_superseded in the browser status and prove both hosts drain strip cells alike #1399's cross-host test, both fixtures and the
transcript render through the C ABI (Seek the timeline and every source in one C ABI call #1642'smiso_engine_v1_session_seek) and through
AudioWorkletEngineHost, and the two outputs are compared bit for bit in the test. No digest. - D5. One-ulp evidence (PR evidence, not committed). Plant a one-ulp change in Compile stored automation into per-cell events in node time #1637's
value_atresult. Record that the two native pin tests, the oracle'ssimd128legs, the
cross-host test (when the plant reaches only one host's path, as a check of the comparison) and
the G5 corpus each turn red, then revert.
Deliverables
- D1-D2's fixtures and transcript.
- D3: the oracle legs, the two native pin tests and the
expected.jsonpins. - D4's test cases.
- D5's record in the PR.
Authorized paths
hosts/host-web/tests/browser-v1/(the two fixtures,direct-oracle.mjs,expected.json).hosts/host-web/src/tests.rs(two pin tests andserde_pin).hosts/host-web/tests/strip_cells_cross_host.rs(D4's cases).
Non-goals
- Any engine change. A leg that disagrees is a defect for its own issue, recorded here with its
first differing sample. - AArch64 and seek-time invariance (Compare stored automation bits on AArch64 and across seek times #1670).
- A new digest owner, or a digest of a rendered session outside
expected.json. - Timing (Build the stored-automation console benchmark row #1671, Record the stored-automation console benchmark baseline #1672). Listening tests.
- Live edits during the fixture: Classify fader automation edits as carried rebuilds #1648, Compose VCA offsets with stored fader automation #1649, Write a following send's route cell from the shared commit #1653, Render stored pan and matrix automation #1657, Render stored input HPF and LPF automation #1660, Classify and carry effect automation edits #1665 and Render stored parametric EQ automation #1667 gate them.
Hazards
- Pin discipline. A pin is written only from a native render the
simd128leg already equals
(the oracle asserts before it prints). Never mint a pin from one side. - The
browserjob. Its Playwright legs replayexpected.json; a new key must not break
scripts/check-browser-expected-resources.py's two-class rule (pins exact, resources
ceilinged). - Hot files.
hosts/host-web/src/tests.rsandexpected.jsonare stream H's. Root sequences
the merge.
Objective gates
- Browser equals native.
mkdir -p target/ci/qualification-artifacts target/ci/qualification-named-twin && bash scripts/build-web-audioworklet.sh --named-twin target/ci/qualification-named-twin target/ci/qualification-artifacts,
then
bash scripts/check-web-audioworklet.sh --without-metadata-regeneration target/ci/qualification-artifacts target/ci/qualification-named-twin/miso-engine-v1-audio-worklet.simd128.named.wasm
andpython3 -B scripts/check-browser-expected-resources.py --artifacts target/ci/qualification-artifacts
pass with both automation legs. - Native pins.
cargo test --locked -p host-web --features test-supportpasses, the two new
pin tests and D4's cross-host cases included. - One ulp turns every leg red (D5, PR evidence).
- Workspace. The
test-debug-aworkspace step ofqualification.yml;
cargo test --locked --release -p lane -p math -p wasm-gates --features math/lane(G5);
cargo fmt --all -- --check;
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings.
Test value
- The automation legs turn red if any row's events, designs or ramps differ between wasm and
native: a platform transcendental in the evaluator, a fused multiply-add, an FP environment left
unpinned at preparation (finding F11), or a grid on the render clock. - The cross-host test turns red if the C ABI and the browser host prepare or seek a session
differently, which no test compares today.
Dependencies
Batch Q. Direct dependencies:
- Write a following send's route cell from the shared commit #1653 Write a following send's route cell from the shared commit (it brings Render stored mute automation on the strip #1651 and Follow an automated mute on following sends in render #1652).
- Render stored pan and matrix automation #1657 Render stored pan and matrix automation.
- Render stored input trim and polarity automation #1658 Render stored input trim and polarity automation.
- Render stored input HPF and LPF automation #1660 Render stored input HPF and LPF automation.
- Render stored parametric EQ automation #1667 Render stored parametric EQ automation.
- Report live_values_superseded in the browser status and prove both hosts drain strip cells
alike (Report live_values_superseded in the browser status and prove both hosts drain strip cells alike #1399): the cross-host harness.
#1651, #1642 Seek the timeline and every source in one C ABI call, #1643 Seek the
timeline and every source from the browser module export and the headless SDK and #1637
Compile stored automation into per-cell events in node time (D5's plant, G5's case) arrive
through those drafts. #1670 Compare stored automation bits on AArch64 and across seek times
depends on this draft.
Amendment (controls coordinator, 2026-10-14)
Checked against 12d4a4f9d.
- The cross-host harness is
hosts/host-web/tests/control_parity.rs(Prove that both hosts give the same result for the same control edits #1560);
strip_cells_cross_host.rsis gone. Report live_values_superseded in the browser status and prove both hosts drain strip cells alike #1399 has landed. - The fixtures add a fader offset (Store a hand move on an automated fader as a dB offset #1650), a hand mute over a mute curve (Render stored mute automation on the strip #1651 amended) and a send
ride (Render stored send gain, mute and matrix automation #1654); depend on Store a hand move on an automated fader as a dB offset #1650 and Render stored send gain, mute and matrix automation #1654. - Native pin tests in
hosts/host-web/src/tests.rshave moved; re-read at filing.
Amendment (controls coordinator, batch 20, 2026-10-17): narrowed to the delivered rows
Checked against e7722bd19. The owner narrowed this issue on 2026-10-17. This amendment replaces
D1-D5, the authorized paths, the gates, the test value and the dependencies above, and the
amendment of 2026-10-14.
Product outcome (narrowed)
One fixture session automates the rows that the engine renders today: the strip fader, the strip
mute, the VCA offset, the VCA mute, and a following send that tracks its source's mute and its
VCA's mute. It uses every shape that each row accepts, and it is seeked once while it plays. The
shipped simd128 artifact (the direct oracle), the native browser host on x86-64
(AudioWorkletEngineHost) and the C ABI render the same bits. There is no new digest owner. The
oracle leg adds one pin beside the existing pins in expected.json.
What the code accepts (anchors at e7722bd19)
- Grammar. An entry is
{id, target, segments, offset}(crates/session/src/parse.rs:1569-1604).
The target is{owner, owner_id, section, control, lane}(:1606-1646). A segment is
{shape, start_sample, end_sample, start_value, end_value, unit}(:1690). Sample times are
JSON strings. - Rows. Strip fader:
strip,builtins, control 5. Strip mute: control 6
(crates/controls/src/builtin_rows.rs:29-30). VCA offset:vca,own, control 1. VCA mute:
control 2 (crates/controls/src/vca.rs:14-15). Only these four rows compile to cells
(crates/controls/src/automation.rs:394-408). A route-row entry is kept but inert (Render stored send gain, mute and matrix automation #1654). - Shapes.
stepis always valid.linearneeds a continuous row.exponentialneeds a
continuous row above 0 that is not in dB (crates/controls/src/automation.rs:255-266). So the
fader and the VCA offset takestepandlinear, the two mutes takesteponly (unit
linear, values 0 and 1), andexponentialis refused on all five rows with
control.automation.shape. - Structure (
crates/session/src/validate.rs). Segments are ordered and do not overlap
(:1023,:1031). Gaps are valid. The jumps of one entry are at least 64 samples apart
(:1070-1134). One entry per lane, andbothclaims the two lanes (:1141-1185). The hold
rule is indocs/SESSION_SCHEMA_V1.md:339-345: astepholdsstart_valueand takes
end_valueatend_sample. - Offsets. The stored hand-move offset (Store a hand move on an automated fader as a dB offset #1650) is
offset.{left_db,right_db}. A lane that the
entry drives on the fader or VCA offset row takes a value in[-144, 24]dB. Every other lane
holds exactly+0.0(docs/SESSION_SCHEMA_V1.md:363-371). - Known-good shapes.
fixtures/session/v1/builtins-automation.json(fader:174-197, VCA
offset:294-318, VCA members:106-118, a following send:129-148). Mute entries:
hosts/host-web/tests/stored_mute_automation.rs:184-207. VCA mute:
crates/host-core/tests/stored_vca_automation.rs:161-184.
D1 (replaced). One fixture: hosts/host-web/tests/browser-v1/automation-session.json
Copy the frame of command-session.json (48 kHz, quantum 128, profiles, main-out, default
smoothing). Then:
- Sources.
src-t1andsrc-t2, 2 channels,32f,frames"48000". A seek clamps a
source to[0, frames](crates/host-core/src/source.rs:37-39), so the frames must be more
than 37,168. - Tracks.
t1onsrc-t1andt2onsrc-t2. No console slot, no insert, no input
filter. Static faders at 0 dB, all hand mutesfalse. - Submix.
bus, with the plain builtins ofbuiltins-automation.json:68-118. - VCA.
vca, members["t1", "t2"], staticfader.left_db-2.0(the static offset on the
left lanes), all other static values zero orfalse. - Routes.
t1-mainandt2-main(post_pantomain-out).t1-bus(pre_fadertobus,
follows_mute: true).t2-bus(pre_fadertobus,follows_mute: false, the
non-following contrast).bus-main(post_pantomain-out). - Entries (values in dB for the dB rows, 0 or 1 for the mutes):
t1-fader,t1control 5, laneboth, offset{left_db: -1.5, right_db: 0.0}:
linear 256-2304, 0 to -12; a gap; step 3001-3601, -6 then -9 (3001 and 3601 are not grid
samples); linear 29000-33000, -9 to +3; step 34000-35000, 0 then -3.t1-mute,t1control 6, laneleft: step 0-1000, 0 then 1; step 1600-4200, 0 then 1;
step 4800-29800, 0 then 1; step 30600-33500, 0 then 1; step 34000-36000, 0 then 0. Muted over
1000-1600, 4200-4800, 29800-30600 and 33500-34000.t2-fader,t2control 5, laneright, offset{left_db: 0.0, right_db: 0.0}: linear
1024-4096, -3 to 0; linear 29900-32000, 0 to -18.vca-offset,vcacontrol 1, laneright, offset{left_db: 0.0, right_db: -0.5}: linear
512-3584, 0 to -6; step 4096-4352, +2 then 0; linear 29500-31500, -4 to +2; step 33000-35500,
-3 then -3.vca-mute,vcacontrol 2, laneboth: step 0-2000, 0 then 1; step 2400-30200, 0 then 1;
step 30400-35000, 0 then 1; step 35500-36000, 0 then 0. Muted over 2000-2400, 30200-30400
and 35000-35500 (review fold 1, M1: the seek target 30,000 and the step at 3001 are outside
every VCA mute hold, so their landings are heard).
- What this covers. A
bothentry and single-lane entries. Lanes driven by their own curve,
by a VCA curve, by both, and plain lanes. Linear segments, steps on and off the grid, gaps, a
hold before the first segment and after the last one, and non-zero stored offsets. Each entry
has a segment that starts before the seek target 30,000 and ends after it, and events after the
seek. The following send closes for the strip mute (left lane only) and for the VCA mute. The
non-following send stays open. - Dropped. The matrix fixture, effect inserts, and every other row (phase 2, below).
D2 (replaced). One transcript
- 96 blocks of 128 frames. Blocks 0-39 render timeline 0-5,119. Before block 40 renders, the host
makes one plain session seek: generation 2, timeline 30,000. Blocks 40-95 render timeline
30,000-37,167. - Before each render, submit exactly one 128-frame chunk per source (the oracle's ring holds one
quantum,direct-oracle.mjs:96). Blockk < 40: generation 1, start framek*128. Block
k >= 40: generation 2, start frame30000 + (k-40)*128.finalis always false. Do not
submit a generation-1 chunk for block 40. A seek discards stale chunks and needs contiguous new
chunks from the seek frame (crates/source/src/lib.rs:1162-1168,:1355-1381). - PCM at source frame
f:((f*m) mod 65536 - 32768) / 65536, withm= 40503 (src-t1left),
30011 (src-t1right), 52153 (src-t2left), 18749 (src-t2right). The value is exact in
f32. In Rust, compute(f as u32).wrapping_mul(m) & 0xffffin integers, then subtract 32768
and divide by 65536.0 (plaini32multiplication overflows). In JavaScript,
(Math.imul(f, m) >>> 0) & 0xffffgives the same integer. - The seek:
miso_engine_web_v1_session_seek(handle, 2, 30000n)in the oracle
(hosts/host-web/src/ffi.rs:3351),host.session_seek(None, 2, 30000, None)natively
(hosts/host-web/src/lib.rs:3756), andmiso_engine_v1_session_seek(session, 2, 30000)on the
C ABI (crates/capi/src/ffi.rs:660). All three reachSessionState::session_seek
(crates/control-plane/src/control.rs:4327). A plain seek declares a discontinuity and
publishes a successor plan, on every host alike. Every seek and every submit must return 0.
D3 (replaced). One oracle leg and one pin
direct-oracle.mjsgainsrunAutomationTimeline. It bootsautomation-session.json, runs D2
and digests the PCM as the other legs do (pcmSha256, every left block then every right block).
It recordsactual.automationTimeline = {blocks: 96, seekBlock: 40, seekTimelineSample: 30000, beforeDisposeStatus, pcmF32leSha256}. Before the print branch, it asserts that the digest
equalsexpected.directOracle.nativeAutomationPcmF32leSha256, as the other legs do
(:493-576).- The pin key is
directOracle.nativeAutomationPcmF32leSha256. PutautomationTimelineand
the pin afterobservationTimelineinexpected.json. - The native pin test is
native_automation_timeline_digest_pins_the_wasm_parityin
hosts/host-web/src/tests.rs, beside its twin at:2016. It copies that twin:include_str!
of the fixture,AudioWorkletEngineHost::bootwithsource_ring_frames: QUANTUM,
submit_source,render_next, the same digest. It asserts against both pins. serde_pin(:2120-2164) gains two fields: the text after"nativeAutomationPcmF32leSha256":,
and the"pcmF32leSha256":after the anchor"automationTimeline".scripts/check-browser-expected-resources.pyadds("automationTimeline", "pcmF32leSha256")
toDIGEST_PATHS(:121-125) and says four PCM digests in its docstring (:33-35). The two-class
rule covers resource rows only, so the new key needs no class. The oracle (:599) and the
script (:274-283) compare the whole document, soexpected.json, the oracle and the script
change in one commit. No other reader breaks:qualification/qualification.js:1131-1132and
run.mjs:204-207read only the identity pins.
D4 (replaced). One cross-host case in hosts/host-web/tests/control_parity.rs
the_automation_fixture_renders_alike_on_both_hosts_across_one_session_seek. The browser side
boots the fixture bytes throughRig::boot(tests/common/mod.rs:363-385). The C ABI side
parses the same bytes withparse_session_jsonand buildsCAbi::new
(control_parity.rs:922-975).- It runs D2 with
CAbi::session_seek(:4949-4972) and direct submits, as
a_composed_stored_mute_renders_alike_on_both_hostsdoes (:3694-3741). Do not usestep():
it hard-codes generation 1 (common/mod.rs:454-475). - It compares every block's two planes with
bits()(common/mod.rs:287-289) andassert_eq!.
No digest. The case is undertest-support.
D5 (replaced). The plants (PR evidence, not committed)
A plain one-ulp change to the result of value_at alone is not valid. The program builder
compares value_before with value_at to find jumps (crates/automation/src/program.rs:330), so
the change adds jumps and can make preparation refuse the session. Use these three plants, one at
a time, and record each leg's result:
- P1, the evaluator (every row). Put
f32::from_bits(v.to_bits() + 1)on every return of
value_at(crates/automation/src/evaluate.rs:18-44) and ofvalue_before
(crates/automation/src/program.rs:338-358). The jumps stay the same. A mute value of 0.0
becomes the least subnormal, so every open mute span, VCA mute span and follow gate closes
(value != 0.0:crates/builtins-compiler/src/lib.rs:3252;
crates/graph/src/runtime.rs:1480-1481,:2196). The FP environment keeps subnormals on every
target (crates/lane/src/fpenv.rs:518-530). Expected red: the native pin test, the oracle leg,
and G5 (g5_native_digests_match_pinsand the wasm leg;crates/automation/src/corpus.rs:245).
Expected green: D4 (the path is shared). - P2, the dB rows. On a dB row a P1 ulp can disappear (in
db_gain, or in
vca_compose_db). Putnext_upon the output ofdb_gain
(crates/builtins/src/lib.rs:6472-6479). It reaches every fader and VCA offset lane. Expected
red: the native pin test and the oracle leg. - P3, one host only (does D4 compare?). After
state.renderreturnsOkin
miso_engine_v1_render_f32_planar(crates/capi/src/ffi.rs:1133), flip the low bit of the
first left sample whenabsolute_sample >= 5120. Expected red: D4 at block 40. Expected green:
the pin test and the oracle leg.
Hand-written tests that compute their expected values with value_at stay green under P1 (for
example crates/host-core/tests/stored_fader_automation.rs:578). Do not count them.
Authorized paths (replaced)
hosts/host-web/tests/browser-v1/automation-session.json(new),direct-oracle.mjs,
expected.json.hosts/host-web/src/tests.rs(one pin test,serde_pin).hosts/host-web/tests/control_parity.rs(D4).scripts/check-browser-expected-resources.py(DIGEST_PATHSand the docstring only).
Objective gates (replaced)
- Browser equals native. As on main (
.github/workflows/qualification.yml:132,:345-348):
mkdir -p target/ci/qualification-artifacts target/ci/qualification-named-twin && bash scripts/build-web-audioworklet.sh --named-twin target/ci/qualification-named-twin target/ci/qualification-artifacts,
then
bash scripts/check-web-audioworklet.sh --without-metadata-regeneration target/ci/qualification-artifacts target/ci/qualification-named-twin/miso-engine-v1-audio-worklet.simd128.named.wasm
andpython3 -B scripts/check-browser-expected-resources.py --artifacts target/ci/qualification-artifacts
pass with the automation leg.python3 -B scripts/check-browser-expected-resources.py --self-test
passes. - Native pin and cross-host.
cargo test --locked -p host-web --features test-supportpasses,
with the new pin test and the D4 case. - Plants (D5, PR evidence): P1, P2 and P3 each give the expected red legs.
- Workspace. The
test-debug-astep (qualification.yml:631-638); G5,
cargo test --locked --release -p lane -p math -p wasm-gates --features math/lane(:705-706);
cargo fmt --all -- --check;
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings.
Test value (replaced)
- The oracle leg and its pin turn red if the
simd128artifact renders an event, a
composition (fader with VCA offsets, mute OR, the follow gate) or the landing of a plain session
seek differently from x86-64 native. Today the only artifact-versus-native renders have empty
automation (session.json:62,command-session.json:141,observation-session.json:159). - The D4 case turns red if the C ABI and the browser host prepare the whole fixture or land
its seek differently. Today the only cross-host case with a seek automates the mute row only
(control_parity.rs:3571), and the VCA cases do not seek (:6916-7395).
Dependencies (replaced): all on main
- Compile stored automation into per-cell events in node time #1637 and Hold the automation jump lengths in a plan cell #1639 (PR Controls batch 13b: stored-automation start (#1635-#1639), core-owned observation addressing and limits (#1676-#1678) #1687), Validate builtin automation targets against their rows at preparation #1645 (PR Controls batch 14a: exact-byte observation admission, automation target checks at preparation, master strip after boot (#1685, #1645, #1686, #1683) #1692), Seek the timeline and every source in one C ABI call #1642 and Seek the timeline and every source from the browser module export and the headless SDK #1643 (PR Controls batch 16b: seek the session in one step on both hosts, behind a publish fence #1708), Prepare stored fader automation and render it flat #1646-Store a hand move on an automated fader as a dB offset #1650 (PR
Controls batch 17: stored fader automation renders on both hosts, with VCA offsets and hand moves #1712), Render stored mute automation on the strip #1651-Write a following send's route cell from the shared commit #1653 (PR Controls batch 18: stored mute automation, and following sends that track it in render #1715), Render stored VCA offset and mute automation #1655 (PR Controls batch 19b: stored VCA offset and mute automation, composed with each member's own curves #1719). The harness work Report live_values_superseded in the browser status and prove both hosts drain strip cells alike #1399 and Prove that both hosts give the same result for the same control edits #1560 is closed.
All of these issues are closed on GitHub. - The fixture has no live edit. A stored offset (Store a hand move on an automated fader as a dB offset #1650) is a field of the entry. A hand mute
(Render stored mute automation on the strip #1651) is the staticfader.*_muteand would OR to a constant mute, so the fixture keeps it
false. The live hand mute over a curve is already compared across hosts at:3571. - Compare stored automation bits on AArch64 and across seek times #1670 depends on this issue. Its spec names two fixtures and two pin tests; it needs a matching
amendment (one fixture, one pin test).
Phase-2 extensions (not in this issue)
- The matrix fixture
automation-matrix-session.jsonand pan and matrix automation (Render stored pan and matrix automation #1657). - Input trim and polarity (Render stored input trim and polarity automation #1658), input HPF and LPF (Render stored input HPF and LPF automation #1660), parametric EQ (Render stored parametric EQ automation #1667), and every
other effect-parameter row, with effect inserts in the fixture. - Send-row (route-row) automation (Render stored send gain, mute and matrix automation #1654, behind Land a removed send row exactly across a live move #1718).
- A following send at a latent tap (an insert with latency) in the oracle fixture.
- AArch64 and seek-time invariance stay in Compare stored automation bits on AArch64 and across seek times #1670.
Decision record: T1+T2 (batch 20)
- D1 shipped as written.
hosts/host-web/tests/browser-v1/automation-session.jsonhas the
amendment's sources, tracks, submix, VCA, five routes and five entries with no departure. Every
value was accepted: the "0 then 0" and "-3 then -3" steps, the 64-sample jump spacing and the
VCAbothmute lane all parse, validate and prepare (the native pin test boots the file
verbatim). Track pan isleft -1.0, right 1.0, smoothing_samples 0and the bus matrix is the
identity withsmoothing_samples 0, as incommand-session.jsonandbuiltins-automation.json.
The twocontentdigests are placeholders of the valid form (the engine streams the PCM). - D2. One transcript helper,
automation_transcriptinhosts/host-web/src/tests.rs, and its
JS twin inrunAutomationTimeline: the same integer formula and chunk schedule. Every seek,
submit and render returns 0 and is asserted on both sides. - D3. Pin test
native_automation_timeline_digest_pins_the_wasm_parity;serde_pinreads
nativeAutomationPcmF32leSha256and thepcmF32leSha256after"automationTimeline". The test
also asserts the automation is heard: the same session withautomationcleared renders other
bits before the seek (blocks 0-39) and after it (blocks 40-95). - Pin discipline. The native digest and the simd128 oracle digest were read independently
before any pin was written (the oracle run against a scratch copy ofexpected.jsonwith a
probe pin). Both are
6f82e4668836ea2c7b977f2c322882aea98d73c0dd285caf41e13ccd18186cb6. The leg's
beforeDisposeStatus.memoryBytesis 2,949,120 (one 64 KiB page above the other legs; the
seek's successor plan is control work). - Script.
DIGEST_PATHSgains("automationTimeline", "pcmF32leSha256"); the docstring and the
comment above it say four digests. - Gates (all green).
cargo fmt --all;cargo clippy --locked -p host-web --all-targets --all-features -- -D warnings;cargo check --locked -p host-web --all-targets;
cargo test --locked -p host-web --features test-support native_(the four pin tests);
bash scripts/check-web-audioworklet.sh --without-metadata-regeneration ...;
python3 -B scripts/check-browser-expected-resources.py --artifacts target/ci/qualification-artifacts
and--self-test(32 red mutations);node direct-oracle.mjsin compare mode.
T3
- D4 shipped.
the_automation_fixture_renders_alike_on_both_hosts_across_one_session_seekin
hosts/host-web/tests/control_parity.rs(undertest-support). The browser side boots the
fixture bytes withRig::boot; the C ABI side buildsCAbi::newfromparse_session_jsonof
the same bytes. Both run the D2 schedule with direct submits andsession_seek; every seek,
submit and render returns OK, and each block's left and right planes are compared withbits().
Both hosts agree on all 96 blocks. - Ring.
Rig::bootandlimits()both use a ring of two quanta, not one; the transcript
submits one quantum per block, so the ring size does not change what renders. - Probe (not committed). Flipping the low bit of the first C ABI sample at blocks >= 40 in the
test's read path turns the case red at block 40, left plane.
Review fold 1
- M1. At timeline 30,000 every member lane was inside a closed mute (VCA mute 29900-30100;
t1 left 29800-30600). A mute hold only remembers a seek's value (docs/SESSION_SCHEMA_V1.md,
the fader-row paragraph), so the fader and VCA-offset landings were never heard, and the step
at 3001 sat inside the VCA unmute hold. Thevca-mutesegments are now step 0-2000, 2400-30200,
30400-35000 and 35500-36000 (D1 above is edited in place); t1 left still lands inside a closed
mute. Re-minted pin, measured on both sides independently and equal:
a81d883b3f83eaf629bd78db149d1a39825c821c6cb2e9a53506341a97ed1363(native pin test, and the
oracle against the unchanged artifact). The pin test now also asserts the landing is heard:
two copies whoset1-faderholds -6 dB or +20 dB over 30000-30064 only render other bits in
block 40. It is red on the fixture before this fold and green after it. The expected-resources self-test gains theautomationTimelinedigest mutation.
Activity