diff --git a/.github/ISSUE_SPECS/1339-give-the-delay-a-live-bypass-shunt.md b/.github/ISSUE_SPECS/1339-give-the-delay-a-live-bypass-shunt.md index 862ee986f..34a313b7b 100644 --- a/.github/ISSUE_SPECS/1339-give-the-delay-a-live-bypass-shunt.md +++ b/.github/ISSUE_SPECS/1339-give-the-delay-a-live-bypass-shunt.md @@ -37,7 +37,7 @@ the lift is heard with the tail already in place. carrying non-finite or runaway values downstream. A bypassed delay's output is that dry block, which is already in range. Zeroing it is a dropout of a valid signal, caused by wet state nobody hears. The test `the_delay_keeps_its_prepared_bypass_because_a_shunt_would_move_a_bit` - (`crates/graph-compiler/tests/bypass_shunt_identity.rs:798-858`) pins exactly that dropout: a + (`crates/graph-compiler/tests/bypass_shunt_identity.rs:798-858`; deleted by TA5) pinned exactly that dropout: a 1 ms delay at `0.95` feedback fed `9e29` trips the ring check, and the prepared bypass zeroes the block. So this correctness reason does not hold, and decision 15 D15-13 E4 gives the delay a live shunt. @@ -173,7 +173,7 @@ the lift is heard with the tail already in place. block equals a reference that runs A and lifts the delay's bypass live at block 7. #1282's gate-3 delay leg is deleted, and its multiband leg stays. 7. **Deleted, superseded:** `the_delay_keeps_its_prepared_bypass_because_a_shunt_would_move_a_bit` - (`bypass_shunt_identity.rs:798-858`), whose claim gate 1 now reverses. Update the red-mutation + (`bypass_shunt_identity.rs:798-858`; deleted by TA5), whose claim gate 1 now reverses. Update the red-mutation doc of `the_never_banked_list_is_exactly_the_launch_effects_that_decline_a_bank` (`:754-760`). 8. **Click against the mute baseline** (root, 2026-10-05, from #1055). The bypass crossfade's click is measured against #1055's mute baseline, at the session's `muteMs` default, diff --git a/.github/ISSUE_SPECS/1340-give-the-multiband-compressor-a-live-bypass-shunt.md b/.github/ISSUE_SPECS/1340-give-the-multiband-compressor-a-live-bypass-shunt.md index 13a9a075f..5440a9c2f 100644 --- a/.github/ISSUE_SPECS/1340-give-the-multiband-compressor-a-live-bypass-shunt.md +++ b/.github/ISSUE_SPECS/1340-give-the-multiband-compressor-a-live-bypass-shunt.md @@ -43,8 +43,8 @@ bits. This closes decision 14's F4 for the multiband compressor. issue does not change that. - **Tests that pin today's behaviour.** - `crates/graph-compiler/tests/bypass_cohorts.rs:716` (`a_mixed_bypass_multiband_cohort_keeps_its_prepared_bypass`) - and `:794` (`a_hot_bypassed_multiband_lane_leaves_its_neighbours_bits_unchanged`, whose - positive control is the whole-bank recovery under #1087's lowering). + and, until TA5 deleted it, `:794` (`a_hot_bypassed_multiband_lane_leaves_its_neighbours_bits_unchanged`, + whose positive control was the whole-bank recovery under #1087's lowering). - `crates/effect-compiler/tests/native_session.rs:516-528` asserts the multiband's prepared bypass and the list. - `crates/multiband-compressor/tests/nonfinite.rs:168` (`the_boundary_is_the_shared_limit_and_a_bank_shares_its_reset`) @@ -162,10 +162,11 @@ bits. This closes decision 14's F4 for the multiband compressor. `initial_bypass == true`, `metadata.bypass == false` and a lane; the cohort binds `TRACKS / lanes()` banks; the render is bit-identical to today's prepared-bypass lowering (`todays_lowering`) and to `Backend::Scalar` at music levels. -3. **A hot bypassed lane in a bound bank.** `a_hot_bypassed_multiband_lane_leaves_its_neighbours_bits_unchanged` - keeps its name and assertion (zero neighbour taps moved), now with the hot lane inside a bound - mixed bank (assert the bank binds). Its in-test positive control under #1087's lowering is - removed, because the lowering is now the production path; D1's red mutation replaces it. +3. **A hot bypassed lane in a bound bank.** A new test (TA5 deleted the old + `a_hot_bypassed_multiband_lane_leaves_its_neighbours_bits_unchanged`) asserts that zero neighbour + taps move with the hot lane inside a bound mixed bank (assert the bank binds). It needs no + positive control under #1087's lowering, because that lowering is now the production path; + D1's red mutation replaces it. 4. **Lowering.** `native_session.rs` asserts that the bypassed multiband entry is lowered (`initial_bypass`, `!metadata.bypass`, a lane), and that every launch descriptor lowers. 5. **A live lift is heard, bit-exactly.** In `crates/host-core/tests/live_delta.rs`: the classifier diff --git a/.github/ISSUE_SPECS/1713-carry-a-following-routes-column-moves-exactly-into-a-six-word-successor.md b/.github/ISSUE_SPECS/1713-carry-a-following-routes-column-moves-exactly-into-a-six-word-successor.md index d50d5102d..8602e6d22 100644 --- a/.github/ISSUE_SPECS/1713-carry-a-following-routes-column-moves-exactly-into-a-six-word-successor.md +++ b/.github/ISSUE_SPECS/1713-carry-a-following-routes-column-moves-exactly-into-a-six-word-successor.md @@ -54,7 +54,7 @@ six-word. Costs and limits: The conservative flag: `PlanStateInventory::carries_a_following_route_into_a_six_word_route`, its field and its join line, the control plane's `follow_into_six_word` term, and the gates -`a_rebuild_that_drops_a_following_route_to_six_words_reports_a_fallback` (capi), +`a_rebuild_that_drops_a_following_route_to_six_words_reports_a_fallback` (capi; deleted by TA5), `a_rebuild_that_drops_a_following_route_to_six_words_reports_the_fallback_alike` (host-web) and `the_join_flags_a_following_route_carried_into_a_six_word_one` (host-core), replaced by gate 3. diff --git a/.github/ISSUE_SPECS/1733-close-the-batch-2-mutation-survivor-gaps.md b/.github/ISSUE_SPECS/1733-close-the-batch-2-mutation-survivor-gaps.md new file mode 100644 index 000000000..b5087c041 --- /dev/null +++ b/.github/ISSUE_SPECS/1733-close-the-batch-2-mutation-survivor-gaps.md @@ -0,0 +1,30 @@ +# Close the batch 2 mutation-survivor gaps + +## Mission + +The batch 2 mutation sample (measured at 81a3074fc, read at ad5c7ae86) found six product or gate behaviours that change under a mutant while no test turns red. It also found one engine contract that has no engine caller. This issue adds one small test per gap and decides the dead contract. Each test has to name the defect it catches, as the "Test value" rule in AGENTS.md requires. + +## Scope + +One row per item. Lines are at ad5c7ae86. + +1. **Section-header names on the control list.** `SectionRecord::name`, crates/host-core/src/control_provider.rs:225. Mutant: the body returns `""`. Unchecked behaviour: every `ControlSectionHeader.name` on the wire is `own`, `builtins` or the console-slot/insert ID. Existing catalog walks match `SectionHeader(_)` and never read `name`. Smallest test: in the existing host-core catalog walk (control_provider.rs, near :2802), assert each section header's `name` against `own`/`builtins`/`address.slot_id`. This is one `assert_eq!` per arm on a session that has one console slot and one insert. +2. **Effect-count cap.** `count_effects`, crates/host-core/src/prepare.rs:6765. Mutant: `Ok(0)`. Unchecked behaviour: `check_counts` refuses a session whose console-plus-insert effect count is above `caps.maximum_effects` with `host.resource.count`. `PreparedReport.effect_count` and `HostShape.effect_count` also report the real count. Every caps test covers tracks, submixes, VCAs or reach pairs only. Smallest test: in crates/host-core/tests (next to submix_caps.rs), one track with two inserts. It prepares at `maximum_effects: 2` and is refused with `host.resource.count\t$\n` at `maximum_effects: 1`. +3. **Effect-order edit refusal.** `apply_session_edit` (`SetTrackEffectOrder`), crates/protocol/src/model.rs:799. Mutant: `||` -> `&&`. Unchecked behaviour: an order list that is a strict subset of the rack's effects is refused with `InvalidEffectOrder`. Under the mutant it succeeds and silently drops the unlisted effect. No test triggers `InvalidEffectOrder` at all. Smallest test: in crates/protocol/tests, a rack `[a, b]` with `SetTrackEffectOrder [b]`. Assert `Err(InvalidEffectOrder)` and that the rack is still `[a, b]`. Add one same-length case with a duplicated ID (`[a, a]`), also refused. +4. **Peak-heap window measures something.** `record_peak_window`, tools/bench-support/src/alloc.rs:159. Mutant: the body is a no-op. Unchecked behaviour: `current_thread_peak()` tracks live and peak bytes. Its two readers (parameter-metadata/tests/control_command_heap.rs, control-plane/tests/observation_bindings.rs) assert only ceilings, which a constant 0 passes, so the #1615 heap gates cannot fail. Smallest test: in bench-support, call `current_thread_peak_reset()`, allocate a `Vec` of 4096 bytes, and assert `peak_bytes >= 4096`. Then drop it and assert `live_bytes == 0` and `peak_bytes >= 4096`. +5. **Lowercase hex rule in the fixture audit.** `json_object_hex`, tools/audit/src/fixture_builtins.rs:2934. Mutant: `&&` -> `||`. Unchecked behaviour: a JSONL hex field (`start`, `handle`, `reset_generation`, `sequence`) in uppercase is refused. Under the mutant it is accepted. Smallest test: a unit test in fixture_builtins.rs that calls `json_object_hex` on a one-key object. `"00000000000000ab"` gives Ok(0xab), and `"00000000000000AB"` gives the lowercase-hex error. +6. **PCM mismatch index (low value; the implementer may decline it with a reason).** `verify_pcm_words`, tools/audit/src/fixture_builtins.rs:2627. Mutant: `!=` -> `==` in `position`. Unchecked behaviour: the error names the first word that differs, not the first word that is equal. Ok/Err is not affected. Smallest test: write a temp file with words `[1, 2, 3]`, expect `[1, 9, 3]`, and assert the error contains `word=1`. +7. **Dead contract: document-decimal lattice matching.** `ExactDecimal::parse` and `lattice_index_for_decimal`, crates/effect-contract/src/step.rs:731 and :873 (mutants at :774 and :775, `||` -> `&&`, which accept `.5` and non-digit text). No crate, host or C ABI path calls `lattice_index_for_decimal`. Its only non-test caller is the `lattice_oracle` SDK cross-check tool, which passes canonical renderings only. The module comment says persisted values are matched on document text, but no engine path does that. Decision required: either (a) delete `ExactDecimal`, `lattice_index_for_decimal` and their tests, and have `lattice_oracle` use an exact match on `points[i].canonical` instead, or (b) if a product path must match document text, record that as its own issue. Do not add parse tests to code that has no caller. + +## Non-goals + +- No test for the equivalent or unreachable survivors: `scheduling_barrier` (lane/src/fpenv.rs:504, no instructions, codegen-only), `distinct_planes_mut` (graph/src/runtime.rs:3646, the staged fallback gives the same bits), the `BankStage::begin_block` default (rack/src/lib.rs:502, same body), and `is_strictly_jury_stable` (dsp-reference/src/svf.rs:186, every caller stays at or below 0.45 fs). +- No rewrite of the heap-gate ceilings, the caps model or the fixture corpus. +- No new benchmark or harness. + +## Gates + +- Each new test is red on its listed mutant and green on the tree. Record each red run in the PR body, not in a committed file. +- Every test has a one-sentence test-value answer naming the defect. +- Item 7: the decision is in the PR body. If (a), the crate and tool still build, and `lattice_oracle` output stays byte-identical to its pre-change output (one-time PR evidence, not a committed test). +- The qualification `lint` job steps pass on the branch. diff --git a/.github/ISSUE_SPECS/1734-delete-the-batch-2-redundant-tests.md b/.github/ISSUE_SPECS/1734-delete-the-batch-2-redundant-tests.md new file mode 100644 index 000000000..d71e51e63 --- /dev/null +++ b/.github/ISSUE_SPECS/1734-delete-the-batch-2-redundant-tests.md @@ -0,0 +1,261 @@ +# Delete the redundant tests of the batch 2 sample (test audit TA5) + +Owner approval: option A, relayed by root on 2026-10-20: delete what batch 1 measured redundant +(TA4, #1731), sample batch 2, and end the audit with one PR (TA5) from that sample. This is that +PR, the last of the 2026-10 test audit. Branch `codex/batch-test-policy-4`, from `main` at +`ad5c7ae86` (TA1 to TA4 merged). + +## Method (batch 2) + +Batch 2 is agent B2's 2026-10-20 run at base `81a3074fc` (8.3 h; method and data kept with the +audit's working notes, `b2/README.md`). Pool: the 3,516 batch 1 KEEP tests minus the 9 TA3 +deletions and the 239 never-delete tests (`candidates.tsv` flags plus a name rule: `alloc`, `abi`, +`layout`, `golden`, `wire`, `g5`, `regression`/`reproducer`, `fuzz`), 3,268 tests. Draw: +`random.Random(20261020).sample(sorted(ids), 200)`. Mutants: cargo-mutants 27.1.0, from functions +each sampled test covers, up to 4 catches or 12 viable tries per test (median 12); each mutant ran +every sampled test that covers its function, then the covering KEEP tests (fail-fast, first red +test recorded). 414 mutants, 321 viable, 12 survivors. + +## Result + +- MEASURED-REDUNDANT (every caught mutant also red in a KEEP test): **162 of 200, 81.0%, 95% + Wilson 75.0% to 85.8%**. The other 38: 11 CLAIM-KEPT, 5 HELD-RANDOMIZED, 6 UNIQUE, 14 THIN, 2 + WEAK. +- The projection onto the pool (about 2,647 tests) is an upper bound per test, not a sum: deleting + many pool tests at once removes catchers of each other. The 162 are safe together because no + sampled test was a catcher of another. + +## The blind spot, and how it was handled + +Mutation cannot see allocation counts, exact count claims or ceilings, and a sample of about 12 +random mutants per test can miss a claim. B2 read the 178 mutation-redundant bodies (regex triage +for allocation, counts, ceilings, bytes, reproducers, randomness) and held 11 as CLAIM-KEPT and 5 as +HELD-RANDOMIZED; those are not in the 162. This PR then read each of the 162 and answered the +AGENTS.md question, "which plausible defect turns this red that no remaining test catches?". A +test is kept when the answer names a real edge case that the measured mutants could not reach and +no remaining test asserts. Every DELETE answer names the claim and the remaining test, by its full +name, that asserts it; every KEEP answer names the remaining tests checked. The first pass named +siblings only by file for 73 DELETE answers; the TA5 verifier found that 5 of them were the only +defenders of their claims, so all 73 were read again (and one more was restored on re-check) and kept wherever no remaining test could be +named. Reading also found what the triage missed: a randomized differential named `run_seeds`, an +allocation audit inside a macro, tests that a `MUTATIONS.md` records as the only red test of a +row, and one test that `scripts/lib/aarch64-known-defects.py` lists as a known AArch64 failure. + +## What this change does + +1. Deletes 97 of the 162 tests and keeps 65 by reading (list below). None of the 162 had moved + or gone since `81a3074fc`; nothing was skipped. +2. Deletes 31 helper items (465 lines) only after `cargo clippy --all-targets --all-features` + reported them unused, looped until it reported nothing; no `#[allow(dead_code)]` was added. + No test file is left empty. +3. Updates the references: each `MUTATIONS.md` row that names a deleted test names a remaining + test that can see the row's mutation, or says "(deleted by TA5; no catcher recorded)". No list of deleted tests is added to a tracked file. Code + comments and open specs (#1339, #1340, #1713) note a deleted name only where it would + otherwise be a stale reference. Recorded log output and dated records (`docs/handoffs`, + `docs/audits`, `artifacts/`) are not edited. +4. Gives the `qualification` job `test-debug-a` ("workspace debug tests (minus DSP crates and + evidence tools)") `timeout-minutes: 22` in place of 15: 1.5 times the slowest recent green run + (14:41). This refers to #1728 and does not close it; #1728's gate (ten consecutive green runs + with at least 25% margin) stays open. No other timeout moves. + +## Per package + +| package | deleted | kept by reading | deleted test lines | +|---|---|---|---| +| audit | 0 | 1 | 0 | +| automation | 1 | 0 | 30 | +| bench-support | 1 | 0 | 5 | +| builtins | 4 | 3 | 349 | +| builtins-compiler | 0 | 1 | 0 | +| capi | 7 | 3 | 501 | +| compressor | 2 | 1 | 165 | +| console-workload | 2 | 0 | 83 | +| control-plane | 0 | 1 | 0 | +| controls | 2 | 1 | 78 | +| delay | 1 | 0 | 12 | +| dsp-reference | 1 | 1 | 15 | +| effect-compiler | 0 | 3 | 0 | +| effect-contract | 2 | 1 | 46 | +| effect-runtime | 4 | 2 | 80 | +| engine | 3 | 0 | 139 | +| gate-expander | 0 | 2 | 0 | +| graph | 3 | 1 | 180 | +| graph-compiler | 7 | 0 | 590 | +| host-core | 20 | 13 | 735 | +| host-web | 2 | 6 | 142 | +| lane | 3 | 2 | 72 | +| math | 1 | 2 | 6 | +| multiband-compressor | 1 | 2 | 83 | +| parametric-eq | 3 | 4 | 244 | +| protocol | 3 | 4 | 152 | +| rack | 4 | 2 | 248 | +| realtime-policy | 11 | 2 | 177 | +| session | 1 | 2 | 21 | +| soft-clip | 2 | 0 | 126 | +| source | 3 | 0 | 115 | +| transient-shaper | 1 | 3 | 44 | +| true-peak-limiter | 2 | 2 | 63 | +| **total** | **97** | **65** | **4,501** | + +Lines are the deleted test functions with their doc comments, at `ad5c7ae86`. Shortstat against `ad5c7ae86`: 82 files changed, 350 insertions(+), 5,143 deletions(-). + +## Kept by reading (65) + +- audit `fixture_builtins::tests::check_rejects_owned_jsonl_tuple_mutations`: a field or record + change in an owned JSONL after the manifest is regenerated; the format test only deletes, + appends a byte or empties. +- builtins `a_long_matrix_move_stays_inside_its_endpoints`: the #1408 reproducer at the matrix + call site; the D11 reference test never overshoots and the lane test checks the law only. +- builtins `a_windowed_move_is_monotone_and_lands_exactly_on_its_target`: the D11 exact-assignment + leg; the endpoint and partition siblings pass without it. +- builtins-compiler `composite_drain_applies_the_other_stages_value_when_one_stage_is_refused`: the + acked-batch question on the fused fader+matrix drain; the sibling covers the input drain only. +- capi `capi_retained_bytes_charge_every_byte_the_compile_retains`: a resource-charge claim over + four sessions, and the only caller of `assert_host_owners_are_charged`. +- control-plane `no_room_for_the_end_refuses_the_removal_and_changes_nothing`: the acked-batch + question in the control plane (commit and drop the end event); the only one there. +- dsp-reference `gate_expander::tests::a_level_inside_the_hysteresis_band_keeps_reloading_the_hold`: + the only red test of gate-expander `MUTATIONS.md` row 3 (the in-band reload). +- effect-compiler `a_session_bypass_lowers_to_an_enabled_effect_and_a_bypassed_lane`: the only pin + of the constants `NEVER_BANKED_EFFECTS`, `PREPARED_BYPASS_EFFECTS` and the lowered set; no + mutant edits a constant. +- effect-contract `a_drain_emits_the_contract_canonical_span_order`: the only red test of + effect-contract `MUTATIONS.md` 140-1; the block validator is not on the render path. +- effect-runtime `subnormal_targets_are_hoisted_without_flushing`: the denormal rule; the siblings + have no subnormal word. +- gate-expander `passes_effect_contract_conformance`: the conformance macro's `process.allocation` + audit, the crate's only render allocation check. +- gate-expander `a_moving_ramp_word_past_its_domain_is_refused`: the one-ulp domain edge with + `effect.state.parameter`; no other gate-expander test refuses with that code. +- host-core `a_bus_renders_the_bits_of_a_track_fed_its_sum`: a randomized differential (32 seeds of + drawn strips, effects and routes); the only bus-equals-track-fed-its-sum check. +- host-core `a_hand_move_on_an_automated_fader_writes_the_lanes_offsets_cell`: the D6 summation + order (hand offset first, then the VCAs by ID); a reorder is not a mutant. +- host-core `the_session_shape_measures_the_longest_vca_id`: the only assertion of + `longest_vca_id_bytes`, a staging-size ceiling. +- host-web `ffi::live_response_ffi_tests::live_response_owners_name_console_slots_inserts_and_input_filters`: + the browser ABI's rack codes 0, 2 and 4 and the refusal of the retired 1 and 3. +- host-web `tests::each_boot_option_rule_has_its_own_typed_refusal`: the `struct_size` and + `reserved0` ABI refusals; other tests cover `abi_version` and the sizes only. +- host-web `tests::the_meter_frame_carries_a_peak_pair_and_a_gain_word_per_submix`: the meter + frame's `3(T + S) + 3` word layout with submixes, which the worklet reads. +- lane `g4_silence_skip_block_saturates_a_long_trailing_count`: the 2^24 clamp, reachable only + with a 2^24 + 3 frame block. +- math `m2_exp2_lane_identity`: a known AArch64 release failure (LANE-3, #1019) named in + `scripts/lib/aarch64-known-defects.py`; x86 mutants cannot reach it. +- parametric-eq `the_low_shelf_fixed_point_reaches_exact_rest`: #1328 gate 2, the reproducer of the 10 Hz + slope-0.1 shelf stuck at 6.01e-20, and a ceiling claim (rest within `REST_BOUND_SAMPLES`); the + named defender plants +-1e-15 with every band disabled (restored on re-check). +- parametric-eq `a_non_finite_input_block_is_zeroed_counted_once_and_leaves_the_next_block_clean`: + the count claim (one block on one channel, not one per sample). +- parametric-eq `svf_words_match_the_independent_oracle_on_the_complete_grid`: the only gate on the + A1 storage (parametric-eq `MUTATIONS.md`, recorded failures 1 and 1b); its 10 Hz, Q = 18, + 88.2 kHz row is on no other grid. +- protocol `controller::tests::canonical_json_snapshots_reparse_before_and_after_commit_across_utf8_split_pages`: + snapshot pages are byte ranges that may split a UTF-8 sequence; the only such test. +- protocol `controller::tests::the_end_needs_room_with_the_commit_and_a_dropped_token_releases_it`: + the acked-batch question for the end event's reservation, release and `Unencodable`. +- rack `re_equal_words_after_a_desymmetrised_episode_do_not_re_engage`: the only negative of + `collapse_channels_agree`; the siblings assert re-engagement. +- realtime-policy `drain::outer::an_item_that_declares_the_collection_root_refuses_the_drain`: the + reproducers of verdict rows r01 and b06. +- realtime-policy `render_wrap::an_unwrapped_entry_outside_the_named_exceptions_is_a_finding`: the + only test that produces `UnwrappedNotPermitted`. +- session `route_mute_is_a_required_boolean`: a schema rule (a missing `mute` must not parse as + on); the only test of the key. +- transient-shaper `a_moving_ramp_word_past_its_domain_is_refused`: the one-ulp edge; the sibling + refuses gross values only. +- true-peak-limiter `every_case_is_finite_and_not_vacuous`: the guard of the limiter's G5 corpus, + which a digest pin cannot give (NaN payloads are canonicalised on wasm). +- true-peak-limiter `production_tracks_the_f64_oracle`: the only independent `f64` oracle of the + limiter gain law (E5); E4 bounds the peak only. + +Added by the re-reading and the review fold: + +- builtins `an_enable_from_rest_jumps_the_recursion_only_when_the_integrators_are_zero`: an enable from rest jumps the recursion, restored integrators ramp; no remaining test enables from rest. +- capi `runtime::live_tests::a_live_edit_on_a_pending_candidate_completes_at_the_swap`: a live edit on a pending candidate completes at the swap; the remaining candidate test checks lanes and bits, not the watermark. +- capi `runtime::live_tests::a_removed_fader_ride_releases_to_the_static_fader`: a removed ride releases to a fresh static-fader plan; the remaining removal tests compare host with host. +- compressor `a_statically_bypassed_bank_collapses_to_the_dual_bits`: a prepared-bypass bank collapses to the dual bits; the only one (compressor MUTATIONS 985-M4). +- controls `the_effect_lane_follows_the_effect_rows`: an insert or console slot attaches the effect lane; the remaining lane test covers route and input rows. +- effect-compiler `every_builtin_row_declares_a_lawful_lattice_at_every_launch_rate`: every builtin row has a lawful lattice at every launch rate; the others check three rows. +- effect-compiler `prepare::owner_tests::invalid_edit_poison_survives_valid_overwrite_until_discard`: a valid write does not clear a poisoned candidate; the sibling writes nothing after the poison. +- effect-runtime `the_ratio_sets_the_slope`: ratio 1 is a bit-exact identity and a ratio below 1 expands; no other test uses a ratio below 1. +- graph `runtime::tests::the_host_planes_are_the_arena_oracles_master_bit_for_bit_at_every_stride`: the only red test of graph MUTATIONS rows 916-1, 916-1b, 916-6 and 916-15 (restored after review). +- host-core `a_repointed_route_does_not_carry_its_line_at_every_rate_and_width`: a repointed route does not carry its PDC line; the sibling covers the send value only. +- host-core `a_seek_step_after_the_unmute_ramps_end_in_its_block_still_lands`: a seek step after the unmute ramp's end in the same block lands (#1647 MAJOR-4). +- host-core `a_submix_strip_fader_mute_and_pan_are_live`: a submix pan is a live record at the bus ID; fader and mute are covered elsewhere, pan is not. +- host-core `a_successor_at_another_rate_or_quantum_starts_a_fresh_timeline`: a successor at another rate or quantum gets a fresh timeline producer (the D3 guard). +- host-core `handles_list_tracks_then_submixes_and_file_bus_effects`: strip handle order, per-track meters and bus effect channels and observation handles (host-core MUTATIONS 1211-M5). +- host-core `send_records_are_the_folded_target_of_the_post_commit_values`: a gain edit on a muted send gives no record and the unmute carries it; no other test edits a muted send. +- host-core `spectrum_carry::a_continuous_capture_carries_and_its_reader_keeps_receiving`: a continuous spectrum capture reads across a swap with no gap; the siblings cover one-shot captures. +- host-core `submix_effect_params_are_live`: a submix console-slot parameter is a record at the console address; the sibling covers an insert bypass. +- host-core `two_per_lane_target_writes_that_agree_in_one_block_keep_the_lane`: #1345 D3 positive arm, in host-core (restored after review; console-workload's twin stays deleted). +- host-core `vca_and_follow_records_take_the_ramp_of_the_edit_that_moved_them`: VCA, membership and strip-own records take their edit's ramp on non-automated lanes. +- host-web `tests::selected_observation_reads_keep_same_track_owner_windows_and_sequences`: two effects of one track keep their own observation windows and sequences. +- host-web `tests::source_seek_keeps_the_meter_epoch_and_absolute_peak_clock`: a source seek keeps the meter epoch and the absolute peak clock. +- host-web `tests::the_seek_exports_refuse_a_host_with_no_control_half_and_change_nothing`: the seek exports' lifecycle refusals and `source_seek_report_ptr` returning 0 when not ready, an ABI rule (restored after review). +- lane `any_state_word_in_the_band_arms_the_block`: any state word of any section in the band arms the block; the siblings plant one word. +- math `f1_gain_from_db_subsample`: the only per-PR check of the GAIN_MAX_DB bound; the full sweep is nightly (restored after review). +- multiband-compressor `each_channel_counts_its_own_input`: #1328 A9 exact per-channel silence counts (restored after review). +- multiband-compressor `shim::tests::the_smoother_has_exact_ends`: the smoother's exact ends (coefficient 0 arrives, 1 freezes); the sibling uses fixed coefficients. +- parametric-eq `padded_banks::a_padded_lane_fed_positive_zero_writes_positive_zero_at_rest`: a padded EQ lane fed +0.0 writes exactly +0.0 in every schedule. +- protocol `controller::tests::b3b1_btlv_telemetry_echo_and_counters_are_typed_and_nondestructive`: BTLV telemetry configure echo, idempotence, non-resetting counter reads, NotFound selector. +- protocol `model::tests::effects_and_parameters_follow_exact_key_rules`: a repeated (parameter, channel) key leaves one entry with the last value. +- rack `run_hands_the_blocks_snapshot_to_every_active_slot_in_every_block`: each block's snapshot reaches every active slot, silent blocks too (the watermark must not run early). +- session `insignificant_whitespace_and_shuffled_keys_canonicalize`: shuffled keys and whitespace canonicalize to the canonical bytes (canonical JSON rule). +- transient-shaper `a_padded_request_binds_and_still_validates_every_lane`: a padded transient-shaper bank request validates its clones; the conformance probes use full masks. +- transient-shaper `the_bank_is_partition_invariant`: the transient-shaper bank partition invariance, the crate's only one. + +## Deleted helpers (compiler-reported) + +- `crates/capi/src/runtime/live_tests.rs`: `live_alone` +- `crates/controls/tests/monitor.rs`: `FADER_DB` +- `crates/dsp-reference/src/svf.rs`: `IMPULSE_FRAMES` +- `crates/engine/src/realtime/spsc.rs`: `fail_if_stalled`, `STALL_DEADLINE`, `EndedOnDrop` and its + `Drop` +- `crates/host-core/src/prepare.rs`: `instance`; `tests/browser_successor.rs`: + `session_without_eq1`; `tests/spectrum.rs`: `render_window` +- `crates/lane/tests/f64_lane.rs`: `square_mismatches`, `square_pool`, `oracle_square_bits`; + `tests/fader_matrix.rs`: `fused_select_free_width`, `FUSED_FRAMES`, + `fused_select_free_differences`, `FusedDifferences` and its `record`, `FUSED_MUTES`, + `FUSED_GAINS`, `fused_family_source` +- `crates/math/tests/m2_lane_identity.rs`: `exp2_caller_edges`, `FastGain` and its `LaneFn` +- `crates/multiband-compressor/tests/crossover.rs`: `rms`, `complex_gain`, `CROSSOVERS` +- `crates/parametric-eq/tests/carry.rs`: `same_bits` +- `crates/rack/src/lib.rs`: `WrongWidthPlanes` and its `BankMembers` + +The lesson for any later pool-wide cut is the last section of this spec. + +## Objective gates + +Every `run:` step of the qualification `lint` job (fmt, workspace clippy `-D warnings`, +`RUSTDOCFLAGS='-D warnings' cargo doc --locked --workspace --no-deps`, the hermetic policy gates), +and `cargo test --locked --all-features -p ` for every touched package. + +## Evidence + +The per-test list (package, test, location, the one-line answer, and the KEEP catchers batch 2 +recorded) is too long for an issue body: per-test list with catchers: issue comments ("TA5 +per-test list, part 1/3" to "part 3/3"). The PR diff is the list of what went. + +## Survivor gaps + +Batch 2 left 12 mutants that no sampled and no covering KEEP test turned red. Agent T5S read each +at `ad5c7ae86`: 3 equivalent, 1 unreachable, 2 dead code, 6 real gaps. The six real gaps (one +small test each) and the decision on the dead contract are the successor spec +`1733-close-the-batch-2-mutation-survivor-gaps.md`. + +## Lesson for any later pool-wide cut + +**The redundancy measurement over-reports on its own.** Of batch 2's 162 MEASURED-REDUNDANT +tests, reading kept 65. Some carry a claim that another record states and the name triage did not +read: the only red test of a `MUTATIONS.md` row (gate-expander row 3, effect-contract 140-1, +parametric-eq recorded failures 1 and 1b, graph 916-1 to 916-15), a known AArch64 release failure +in `scripts/lib/aarch64-known-defects.py` (`m2_exp2_lane_identity`, #1019), and a randomized +differential named `run_seeds` (host-core `a_bus_renders_the_bits_of_a_track_fed_its_sum`). +Others were the only test of a claim that only reading against named siblings shows; a first pass +that cited siblings only by file deleted five of those, and review restored them. B2's +projection of about 2,647 deletable pool tests therefore does not stand. If a pool-wide cut is +ever reopened, its brief must first match every candidate against the `MUTATIONS.md` +sole-catcher rows, the known-defect lists and the seeded-differential helpers, and every DELETE +answer must name, by its full name, the remaining test that asserts the same claim. diff --git a/.github/workflows/qualification.yml b/.github/workflows/qualification.yml index fe2649270..5f7c56072 100644 --- a/.github/workflows/qualification.yml +++ b/.github/workflows/qualification.yml @@ -606,7 +606,8 @@ jobs: needs: route if: needs.route.outputs.route == 'full' runs-on: ubuntu-24.04 - timeout-minutes: 15 + # 1.5 times the slowest recent green run (14:41), #1728. + timeout-minutes: 22 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 diff --git a/crates/automation/src/events.rs b/crates/automation/src/events.rs index fafa384cc..f9e600f6a 100644 --- a/crates/automation/src/events.rs +++ b/crates/automation/src/events.rs @@ -897,35 +897,4 @@ mod tests { .map(|event| (event.offset, event.kind)) .collect() } - - /// #1646 D2: a cell seeded with its prepared value emits nothing on a flat curve at that - /// value, while a fresh cell retargets at its first grid point; a seed at another value still - /// retargets. - /// - /// Red if `seed_target` does not set the target: the first grid event of every prepared lane - /// would then retarget the lane to the value it already holds. - #[test] - fn a_seeded_target_suppresses_the_first_retarget_to_the_same_bits() { - let program = flat(-7.25); - assert_eq!( - first_block(&program, &mut CellState::new()), - [(0, EventKind::Grid)] - ); - - let mut seeded = CellState::new(); - seeded.seed_target(-7.25); - assert_eq!( - seeded.target().map(f32::to_bits), - Some((-7.25_f32).to_bits()) - ); - assert_eq!(first_block(&program, &mut seeded), []); - - let mut other = CellState::new(); - other.seed_target(-7.0); - assert_eq!(first_block(&program, &mut other), [(0, EventKind::Grid)]); - assert_eq!( - other.target().map(f32::to_bits), - Some((-7.25_f32).to_bits()) - ); - } } diff --git a/crates/builtins/tests/MUTATIONS.md b/crates/builtins/tests/MUTATIONS.md index 5ce51eaa5..b3e079c5d 100644 --- a/crates/builtins/tests/MUTATIONS.md +++ b/crates/builtins/tests/MUTATIONS.md @@ -12,7 +12,7 @@ Command form: `cargo test -p builtins --test -- --exact`. | M1 | `let denominator = 1.0 + t1;` → `1.0 - t1` | `builtins/src/lib.rs` (`SvfSection::design`) | T1 `prepared_sections_match_reference_coefficients` | FAILED, `rate=44100, cutoff=10, high_pass=true` | | M2 | drop the D7 flush of `s1`, joint arm included: `self.s1 = if rest { 0.0 } else { flush(n1) }` → `self.s1 = n1` (#1328; before it, `self.s1 = flush(n1)` → `n1`, red at `index=3670`). Dropping only the per-word arm (`else { n1 }`) stays green: this signal never leaves `n1` below `FLUSH_EPS` beside an `n2` at or above `REST_EPS` | `dsp-reference/src/tpt.rs` | T2 `scalar_stage_is_bit_identical_to_reference_recurrence` | FAILED, `rate=44100, signal=1, index=2645` (re-run for #1328) | | M2b | drop only the per-word arm of the D7 flush (#1328): `self.s1 = if rest { 0.0 } else { flush(n1) }` → `else { n1 }`, and separately the same for `s2` | `dsp-reference/src/tpt.rs` | T2b `scalar_stage_is_the_reference_recurrence_where_the_per_word_flush_fires` (T2 stays green on both: its signals reach rest through the joint arm) | FAILED, `rate=44100, index=257` (`s1`) and `rate=44100, index=276` (`s2`) | -| M3a | every bank lane takes lane 0's coefficients (`zip(sections)` → `sections[0]`) | `builtins/src/lib.rs` (`svf_coef`) | T3 `bank_is_bit_identical_to_scalar_stage_at_every_width` | FAILED, `width=4, members=3, lane=1, frame=0` | +| M3a | every bank lane takes lane 0's coefficients (`zip(sections)` → `sections[0]`) | `builtins/src/lib.rs` (`svf_coef`) | T3 `bank_is_bit_identical_to_scalar_stage_at_every_width` (deleted by TA5; catcher `randomized::the_banks_render_their_scalar_sections_under_random_retargets`) | FAILED, `width=4, members=3, lane=1, frame=0` | | M3c | report counters sum every lane, not only the members (`take(self.members)` → `take(L::WIDTH)`) | `builtins/src/lib.rs` (`InputStage::members_sum`) | T3, padding-lane arm | FAILED, `width=4, members=1` | | M4 | high-pass mix `m1 = -k` → `-k * 1.001` | `builtins/src/lib.rs` (`SvfSection::design`) | T1, T2 **and** the determinism corpus | all three FAILED | | M5 | the fixture oracle drops the identity-section `-0.0` mapping | `tools/audit/src/fixture_builtins.rs` | `issue064_checked_corpus_is_read_only_complete_and_has_no_authoring_reachability` | FAILED at the PCM semantics check | @@ -200,7 +200,7 @@ what the rows below record. | # | mutation | site | suite | verdict | |---|---|---|---|---| | C-1 | the retarget writer `set_trim_signed` drops its refresh | `builtins/src/lib.rs` | `input_liveness_mono` (3 tests) | RED — `the cached channel-symmetry flag is stale for lane 0`, on `an_asymmetric_retarget_declines_the_lane_on_the_admitting_block`, `re_equalising_the_words_restores_the_designed_term_and_nothing_more` and `a_retarget_between_a_collapsed_block_and_the_disengage_survives_the_copy`. This is the drain's own invalidation, and it is the one a live-words cache exists to have | -| C-2 | the **dual** ramping arm of `process` drops its refresh | `builtins/src/lib.rs` | `host-core::input_liveness_live_controls` (2 tests) | RED — `stale for lane 2`, on `re_equalising_after_a_disengaging_drain_holds_the_never_collapsed_bits` and `the_collapse_census_follows_the_commands`. A ramp advances the compared words on every block it runs, with no record drained: a drain-only invalidation is **not** sufficient, and this row is the proof | +| C-2 | the **dual** ramping arm of `process` drops its refresh | `builtins/src/lib.rs` | `host-core::input_liveness_live_controls` (2 tests) | RED — `stale for lane 2`, on `re_equalising_after_a_disengaging_drain_holds_the_never_collapsed_bits` (deleted by TA5; catcher `the_collapse_census_follows_the_commands`) and `the_collapse_census_follows_the_commands`. A ramp advances the compared words on every block it runs, with no record drained: a drain-only invalidation is **not** sufficient, and this row is the proof | | C-3 | the **collapsed** ramping arm of `process_mono` drops its refresh (after `mirror_trim_ramp`) | `builtins/src/lib.rs` | — (green across `builtins`, `rack`, `host-core`, `console-workload`, `parametric-eq`, `builtins-compiler`, `graph`) | **EQUIVALENT, and kept anyway.** `mirror_trim_ramp` assigns channel `1`'s whole record from channel `0`'s, so every compared ramp word is equal when it returns -- and it was equal on entry too, which `debug_assert!(self.trim_ramp_channels_agree())` at the top of `process_mono` states. The comparison therefore lands where it already was. The refresh is kept because the equivalence rests on the mirror being *total*: a mirror that ever became partial or conditional would make this row red, and the cost is one walk on a ramping collapsed block | ### Row count @@ -367,10 +367,3 @@ restored. Before attempt 2 both S-1 rows were green, because the safety net moved both seeds at once and either half refused the commit. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `settled_matrix_takes_the_select_free_arm_only_without_an_identity_lane`: no plausible same-crate KEEP catcher recorded -- `fused_fader_matrix_takes_the_select_free_arm_only_without_an_identity_lane`: no plausible same-crate KEEP catcher recorded diff --git a/crates/builtins/tests/contract.rs b/crates/builtins/tests/contract.rs index 321dcee55..82e2cbe18 100644 --- a/crates/builtins/tests/contract.rs +++ b/crates/builtins/tests/contract.rs @@ -216,82 +216,6 @@ fn parameter_descriptors_have_complete_stable_contracts() { ); } -#[test] -fn descriptor_domains_are_exhaustive_at_launch_rates() { - for rate in [44_100, 48_000, 88_200, 96_000] { - for descriptor in BUILTIN_PARAMETER_DESCRIPTORS { - assert!(descriptor.domain.contains(descriptor.default, rate)); - assert!(!descriptor.domain.contains(f32::NAN, rate)); - assert!(!descriptor.domain.contains(f32::INFINITY, rate)); - assert!(!descriptor.domain.contains(f32::NEG_INFINITY, rate)); - } - for descriptor in [ - BUILTIN_PARAMETER_DESCRIPTORS[2], - BUILTIN_PARAMETER_DESCRIPTORS[3], - ] { - let maximum = builtin_filter_cutoff_maximum_hz(rate) - .expect("launch rate has an exact cutoff maximum"); - let successor = f32::from_bits(maximum.to_bits() + 1); - let nyquist = rate as f32 / 2.0; - let just_below_maximum = f32::from_bits(maximum.to_bits() - 1); - assert!(descriptor.domain.contains(0.0, rate)); - assert!(!descriptor.domain.contains(-0.0, rate)); - assert!(!descriptor.domain.contains(9.999, rate)); - assert!(descriptor.domain.contains(10.0, rate)); - assert!(descriptor.domain.contains(just_below_maximum, rate)); - assert!(descriptor.domain.contains(maximum, rate)); - assert!(!descriptor.domain.contains(successor, rate)); - assert!(!descriptor.domain.contains(nyquist, rate)); - } - } - for boolean in [ - BUILTIN_PARAMETER_DESCRIPTORS[0], - BUILTIN_PARAMETER_DESCRIPTORS[5], - ] { - assert!(boolean.domain.contains(0.0, 48_000)); - assert!(boolean.domain.contains(1.0, 48_000)); - assert!(!boolean.domain.contains(-0.0, 48_000)); - assert!(!boolean.domain.contains(0.5, 48_000)); - } - for decibels in [ - BUILTIN_PARAMETER_DESCRIPTORS[1], - BUILTIN_PARAMETER_DESCRIPTORS[4], - ] { - assert!(decibels.domain.contains(-144.0, 48_000)); - assert!(decibels.domain.contains(24.0, 48_000)); - assert!(!decibels.domain.contains(-144.001, 48_000)); - assert!(!decibels.domain.contains(24.001, 48_000)); - } - // Bounded, not open-ended: issue #210 phase 2 appended `delay_samples` after the matrix rows, - // and an open `[6..]` would have quietly swept it into the matrix contract. - for matrix in &BUILTIN_PARAMETER_DESCRIPTORS[6..10] { - assert!(matrix.domain.contains(-1.0, 48_000)); - assert!(matrix.domain.contains(1.0, 48_000)); - assert!(!matrix.domain.contains(-1.001, 48_000)); - assert!(!matrix.domain.contains(1.001, 48_000)); - } - let delay = BUILTIN_PARAMETER_DESCRIPTORS[10]; - assert_eq!(delay.name, "delay_samples"); - for rate in [44_100, 48_000, 88_200, 96_000] { - // A flat integer range: rate-independent, unlike the two cutoff rows above. - assert!(delay.domain.contains(0.0, rate)); - assert!(delay.domain.contains(1.0, rate)); - assert!(delay.domain.contains(48_000.0, rate)); - assert!(!delay.domain.contains(48_001.0, rate)); - assert!(!delay.domain.contains(-1.0, rate)); - assert!(!delay.domain.contains(f32::NAN, rate)); - assert!(!delay.domain.contains(f32::INFINITY, rate)); - } - let pan = BUILTIN_PARAMETER_DESCRIPTORS[11]; - assert_eq!(pan.name, "pan"); - assert!(pan.domain.contains(-1.0, 48_000)); - assert!(pan.domain.contains(1.0, 48_000)); - assert!(!pan.domain.contains(1.01, 48_000)); - // The descriptor maximum and the session schema maximum being *one* number rather than two - // that agree today is gated in `builtins-compiler`, which is the crate that can see - // both without this one taking a session dependency it has no other reason to have. -} - /// Owner ruling R5 (#1036): the former extended research rates (176.4-384 kHz) have no cutoff /// domain and no fallback; they refuse exactly like any other non-launch rate. #[test] diff --git a/crates/builtins/tests/fader_ramp.rs b/crates/builtins/tests/fader_ramp.rs index 274cec22d..9f80c81ef 100644 --- a/crates/builtins/tests/fader_ramp.rs +++ b/crates/builtins/tests/fader_ramp.rs @@ -1099,73 +1099,6 @@ fn a_repeated_mute_leaves_the_stage_as_it_was() { } } -/// D2: the held flag follows the mute ramp. It is set by a windowed mute change, cleared the -/// frame the countdown ends, cleared by a live retarget during an unmute ramp, and carried -/// across a plan swap's lane export and import. -#[test] -fn the_held_flag_follows_the_mute_ramp() { - let mut bank = match Subject::bank(Backend::Simd4) { - Subject::Bank(bank) => bank, - Subject::Scalar(_) => unreachable!(), - }; - let block = |bank: &mut BuiltinFaderBank, frames: u32| { - let mut left = vec![0.5_f32; frames as usize * 4]; - let mut right = left.clone(); - bank.process(&mut left, &mut right, frames); - }; - // A mute that repeats the lane's state starts no ramp (batch 13b), so mute it first. - bank.set_mute(0, BuiltinLaneSelector::Left, true, 0) - .expect("lane"); - bank.set_mute(0, BuiltinLaneSelector::Left, false, 40) - .expect("lane"); - assert_eq!( - bank.gain_held(0, 0), - Some(true), - "an unmute ramp holds the gain" - ); - assert_eq!( - bank.gain_held(0, 1), - Some(false), - "the right channel is free" - ); - block(&mut bank, 39); - assert_eq!(bank.ramp_remaining(0, 0), Some(1)); - assert_eq!(bank.gain_held(0, 0), Some(true), "one frame left"); - - // A plan swap carries the flag. - let state = bank.export_lane(0).expect("member"); - let mut successor = match Subject::bank(Backend::Simd4) { - Subject::Bank(bank) => bank, - Subject::Scalar(_) => unreachable!(), - }; - successor.import_lane(1, &state).expect("member"); - assert_eq!(successor.gain_held(1, 0), Some(true), "carried by the swap"); - - block(&mut bank, 1); - assert_eq!( - bank.gain_held(0, 0), - Some(false), - "cleared as the countdown ends" - ); - - bank.set_mute(0, BuiltinLaneSelector::Left, true, 0) - .expect("lane"); - bank.set_mute(0, BuiltinLaneSelector::Left, false, 40) - .expect("lane"); - bank.set_fader_db(0, BuiltinLaneSelector::Left, -6.0, 8) - .expect("domain"); - assert_eq!( - bank.gain_held(0, 0), - Some(false), - "a live retarget ends an unmute ramp" - ); - bank.set_mute(0, BuiltinLaneSelector::Left, true, 0) - .expect("lane"); - assert_eq!(bank.gain_held(0, 0), Some(true), "muted"); - assert_eq!(bank.gain_held(3, 0), None, "a padding lane"); - assert_eq!(bank.gain_held(0, 2), None, "no third channel"); -} - /// The scalar fader's lane queries answer `None` for a lane above `1`, as the bank's do for a /// channel above `1`. /// diff --git a/crates/builtins/tests/stage.rs b/crates/builtins/tests/stage.rs index bc67aac7b..4aa862d22 100644 --- a/crates/builtins/tests/stage.rs +++ b/crates/builtins/tests/stage.rs @@ -311,133 +311,6 @@ fn scalar_stage_is_the_reference_recurrence_where_the_per_word_flush_fires() { } } -/// T3: a bank is the scalar stage at another width, and a padding lane changes nothing. -#[test] -fn bank_is_bit_identical_to_scalar_stage_at_every_width() { - for (backend, width) in banks() { - let lanes = width.lanes() as usize; - for members in [1, lanes - 1, lanes] { - let mut scalar: Vec = (0..members) - .map(|index| prepared_input(48_000, parameters_for(index))) - .collect(); - let bank_inputs: Vec = (0..members) - .map(|index| prepared_input(48_000, parameters_for(index))) - .collect(); - let mut bank = BuiltinInputBank::new(backend, width, bank_inputs).expect("bank"); - assert_eq!(bank.active_lanes(), members); - - const FRAMES: usize = 257; - let mut rng = Rng(0xB00B_5EED ^ members as u64 ^ lanes as u64); - let planar: Vec> = (0..members) - .map(|_| (0..FRAMES * 2).map(|_| rng.next_sample()).collect()) - .collect(); - - // Padding lanes are pre-filled with the bit patterns that would poison a recurrence. - const POISON: [u32; 4] = [0x7FC0_0000, 0x7F80_0000, 0x8000_0000, 0x0000_0001]; - let mut left = vec![0.0_f32; FRAMES * lanes]; - let mut right = vec![0.0_f32; FRAMES * lanes]; - for frame in 0..FRAMES { - for lane in 0..lanes { - let (l, r) = if lane < members { - (planar[lane][frame], planar[lane][FRAMES + frame]) - } else { - let poison = f32::from_bits(POISON[(frame + lane) % POISON.len()]); - (poison, poison) - }; - left[frame * lanes + lane] = l; - right[frame * lanes + lane] = r; - } - } - let bank_report = bank.process(&mut left, &mut right, FRAMES as u32); - - let mut scalar_report = BuiltinProcessReport::default(); - for (lane, input) in scalar.iter_mut().enumerate() { - let mut scalar_left = planar[lane][..FRAMES].to_vec(); - let mut scalar_right = planar[lane][FRAMES..].to_vec(); - let report = input.process( - DualMonoBlock::new(&mut scalar_left, &mut scalar_right, 0).expect("block"), - ); - scalar_report.sanitized_input += report.sanitized_input; - scalar_report.recovered_left_state += report.recovered_left_state; - scalar_report.recovered_right_state += report.recovered_right_state; - for frame in 0..FRAMES { - assert_eq!( - left[frame * lanes + lane].to_bits(), - scalar_left[frame].to_bits(), - "width={lanes}, members={members}, lane={lane}, frame={frame}, left" - ); - assert_eq!( - right[frame * lanes + lane].to_bits(), - scalar_right[frame].to_bits(), - "width={lanes}, members={members}, lane={lane}, frame={frame}, right" - ); - } - assert_eq!( - test_support::bank_lane_state_words(&bank, lane), - test_support::input_state_words(input), - "width={lanes}, members={members}, lane={lane}, state" - ); - } - assert_eq!( - bank_report, scalar_report, - "width={lanes}, members={members}" - ); - - // Padding lanes stay exactly `+0.0` in state, whatever was left in the scratch. - for lane in members..lanes { - assert_eq!( - test_support::bank_lane_state_words(&bank, lane), - [0; 8], - "width={lanes}, members={members}, padding lane={lane}" - ); - } - - // A padding lane whose *state* is non-finite is excluded from the boundary check and - // from every counter. Sanitisation already makes a padding lane's samples inert, so - // this is the only way its exclusion is load-bearing -- and it is: without the - // `active` mask, one padding lane would zero the whole block's member output. - if members < lanes { - let fresh = || { - BuiltinInputBank::new( - backend, - width, - (0..members) - .map(|index| prepared_input(48_000, parameters_for(index))) - .collect(), - ) - .expect("fresh bank") - }; - let mut bank = fresh(); - let mut control = fresh(); - let mut poisoned = test_support::bank_lane_state_words(&bank, members); - poisoned[0] = f32::NAN.to_bits(); - test_support::set_bank_lane_state_words(&mut bank, members, poisoned); - let mut poisoned_left = left.clone(); - let mut poisoned_right = right.clone(); - let mut control_left = left.clone(); - let mut control_right = right.clone(); - let poisoned_report = - bank.process(&mut poisoned_left, &mut poisoned_right, FRAMES as u32); - let control_report = - control.process(&mut control_left, &mut control_right, FRAMES as u32); - assert_eq!( - poisoned_report, control_report, - "width={lanes}, members={members}, padding-lane counters" - ); - for frame in 0..FRAMES { - for lane in 0..members { - assert_eq!( - poisoned_left[frame * lanes + lane].to_bits(), - control_left[frame * lanes + lane].to_bits(), - "width={lanes}, members={members}, lane={lane}, frame={frame}" - ); - } - } - } - } - } -} - /// T6: the block boundary check is per lane and per block, and it never crosses lanes. #[test] fn boundary_check_is_lane_local_per_block() { diff --git a/crates/builtins/tests/tail_contract.rs b/crates/builtins/tests/tail_contract.rs index cbb598a9d..892c34ed4 100644 --- a/crates/builtins/tests/tail_contract.rs +++ b/crates/builtins/tests/tail_contract.rs @@ -2744,89 +2744,6 @@ fn fixed_design_stall_is_the_module_stall_rounded_up_and_covers_the_flush_floor( } } -/// #1465 F2(c), and the both-disabled branch of preparation (root's named exception, 2026-10-08). -/// A design with both filters disabled states `D = 0`, `G_p = G_t = ceil_mB(|trim|)` for a -/// power-of-two trim (0 dB, `|trim| = 2`) and `ceil_mB(|trim| (1 + u))` otherwise (+6 dB, whose -/// word lies below `10^(6/20)`, so the two differ), and one underflow as both stalls, through both -/// `input_section_bound` and `input_section_bounds`; with the channels' trims different, the larger -/// gain; and one disabled channel beside an enabled one still leaves the design stated. -#[test] -fn a_design_with_filters_disabled_states_its_trim_gain() { - let rate = 48_000; - // `+6.0206 dB`: the `f32` gain word is exactly 2. - let two_db = 6.020_6_f32; - let underflow = ceil_mb(f64::from(f32::MIN_POSITIVE)); - for (trim_db, exact) in [(0.0_f32, true), (two_db, true), (6.0, false), (-3.0, false)] { - let strip = parameters(0.0, 0.0, trim_db, false); - let kernel = input(rate, 0.0, 0.0, trim_db, false); - let trim = trim_gain(&kernel); - let expected = if exact { - ceil_mb(trim) - } else { - ceil_mb(trim * (1.0 + U)) - }; - if trim_db == two_db { - assert_eq!(trim, 2.0, "the +6.0206 dB word"); - } - if !exact { - assert_ne!( - expected, - ceil_mb(trim), - "{trim_db} dB: the rounding moves the value" - ); - } - let single = input_section_bound(rate, strip).expect("bound"); - let session = input_section_bounds(rate, [strip]).expect("bounds")[0]; - for (path, value) in [ - ("input_section_bound", single), - ("input_section_bounds", session), - ] { - let what = format!("{path} at {trim_db} dB"); - assert_eq!(value.tail, TailSamples::Finite(0), "{what}"); - assert_eq!(value.rest, RestBound::Bounded(RestSamples::ZERO), "{what}"); - assert_eq!( - composition_values(value, &what), - (0, expected, expected, underflow, underflow), - "{what}" - ); - } - } - // Different trims, both disabled: the larger gain, on both paths. - let channel = |trim_db: f32, lpf_hz: f32| ChannelParameters { - trim_db, - lpf_hz, - ..ChannelParameters::default() - }; - let strip = BuiltinParameters { - left: channel(0.0, 0.0), - right: channel(12.0, 0.0), - ..BuiltinParameters::default() - }; - let louder = ceil_mb(f64::from(math::pow(10.0, 12.0 / 20.0) as f32) * (1.0 + U)); - let single = input_section_bound(rate, strip).expect("bound"); - let session = input_section_bounds(rate, [strip]).expect("bounds")[0]; - for (path, value) in [ - ("input_section_bound", single), - ("input_section_bounds", session), - ] { - let (_, peak, tail, ..) = composition_values(value, path); - assert_eq!( - (peak, tail), - (louder, louder), - "{path}: the louder channel's gain" - ); - } - // One channel disabled, the other enabled: stated, at least the disabled channel's gain. - let mixed = BuiltinParameters { - left: channel(24.0, 0.0), - right: channel(0.0, 1_000.0), - ..BuiltinParameters::default() - }; - let (_, peak, ..) = - composition_values(input_section_bound(rate, mixed).expect("bound"), "mixed"); - assert!(peak >= ceil_mb(f64::from(math::pow(10.0, 24.0 / 20.0) as f32))); -} - // ---- #1466: the live input section's decay, peak gain and stalls (gate 1, L4; L3 above) ----- /// The live composition values at `rate`, as the gates read them: `math::tail`'s accessor at the diff --git a/crates/capi/src/runtime/live_tests.rs b/crates/capi/src/runtime/live_tests.rs index 1042951ad..656f33064 100644 --- a/crates/capi/src/runtime/live_tests.rs +++ b/crates/capi/src/runtime/live_tests.rs @@ -5331,134 +5331,6 @@ mod set_control { blocks } - /// One rig of one document takes `edits`: one revision, the plan epoch unchanged, no candidate, - /// and the next blocks are heard to differ from an untouched second rig. The effect rows' - /// render bits are pinned against the direct host-core lane by - /// `live_effect_parameter_edits_render_like_the_browsers_lane` and - /// `live_effect_bypass_edits_render_like_a_rebuild`. - fn live_alone(document: &str, edits: &[SessionEdit], label: &str) { - let mut rig = Rig::new(document); - let mut untouched = Rig::new(document); - for block in 0..window(rig.latency(), 0, rig.quantum) { - assert_eq!( - bits(&rig.step()), - bits(&untouched.step()), - "{label}: warm-up {block}" - ); - } - let (revision, _, epoch, _) = rig.summary(); - assert_eq!(rig.apply(edits), crate::RESULT_OK, "{label}"); - let (after, _, after_epoch, pending) = rig.summary(); - assert_eq!( - (after, after_epoch, pending), - (revision + 1, epoch, 0), - "{label}: one revision, the same plan, no candidate" - ); - let heard = (0..8).any(|_| bits(&rig.step()) != bits(&untouched.step())); - assert!(heard, "{label}: the edit changes the output"); - } - - /// Gate 1: each value the classifier makes live is live through `SET_CONTROL`, and a write of - /// its one row renders the bits of the same change written as the whole struct that holds it. - /// - /// Red if a row write touches another field, lane or value than the one it names (the left - /// lane for a both-lane write, the mute in place of the fader, a matrix coefficient written - /// without its mode switch), or reaches the plan through a path the whole-struct write does - /// not. - #[test] - fn a_set_control_on_a_live_value_is_live_and_renders_like_the_whole_struct_write() { - let document = long_session(10, 48_000); - let model = parse_session_json(&document).expect("model"); - let track = model.tracks[0].clone(); - let name = track.id.as_str(); - let fader = |left_db, right_db, mute: bool| DualMonoFader { - left_db, - right_db, - left_mute: mute, - right_mute: mute, - }; - - live_twin( - &document, - &[set(builtin(name, FADER_DB, Lane::Left), -6.0, None)], - &fader_edit( - name, - DualMonoFader { - left_db: -6.0, - ..track.fader.clone() - }, - ), - "fader, left lane", - ); - live_twin( - &document, - &[set(builtin(name, FADER_DB, Lane::Both), -3.0, None)], - &fader_edit(name, fader(-3.0, -3.0, false)), - "fader, both lanes", - ); - live_twin( - &document, - &[set(builtin(name, MUTE, Lane::Both), 1.0, None)], - &fader_edit( - name, - DualMonoFader { - left_mute: true, - right_mute: true, - ..track.fader.clone() - }, - ), - "mute", - ); - - let pan_edit = set(builtin(name, PAN, Lane::Both), 0.5, None); - let panned = applied(&document, core::slice::from_ref(&pan_edit)).tracks[0] - .matrix_or_pan - .clone(); - live_twin( - &document, - &[pan_edit], - &matrix_edit(&id(name), panned), - "pan", - ); - - // A matrix coefficient follows its mode switch in the same transaction. - let matrix = [ - set(own(name, MATRIX_MODE, Lane::Both), 1.0, None), - set(builtin(name, MATRIX_LL, Lane::Both), 0.5, None), - ]; - let switched = applied(&document, &matrix).tracks[0].matrix_or_pan.clone(); - assert!(matches!(switched, MatrixOrPan::Matrix { ll, .. } if ll == 0.5)); - live_twin( - &document, - &matrix, - &matrix_edit(&id(name), switched), - "matrix after a mode switch", - ); - - // An effect parameter and an effect bypass: an insert's and a console slot's. - let document = effect_session(10, 48_000); - let model = parse_session_json(&document).expect("model"); - let first = model.tracks[0].id.as_str(); - let last = model.tracks[model.tracks.len() - 1].id.as_str(); - live_alone( - &document, - &[ - set(insert(first, "comp", 1, Lane::Left), -30.0, None), - set(insert(first, "comp", 6, Lane::Both), 6.0, None), - set(console(last, "clip", 1, Lane::Both), 12.0, None), - ], - "effect parameters", - ); - live_alone( - &document, - &[ - set(insert(first, "comp", 0, Lane::Both), 1.0, None), - set(console(last, "clip", 0, Lane::Both), 1.0, None), - ], - "effect bypass", - ); - } - /// Gate 2: a value the classifier leaves to a rebuild is a rebuild through `SET_CONTROL`. /// /// Red if a rebuild-only value is acked as live (a candidate not prepared, a cell written). @@ -6413,50 +6285,6 @@ mod set_control { ); } - /// Gate 4 (#1557): a transaction of a valid send gain and an out-of-domain matrix value is - /// refused whole: no send cell is written and the revision does not move. - /// - /// Red if the gain is written before the matrix value is refused. - #[test] - fn a_send_transaction_with_an_out_of_domain_value_writes_no_cell() { - let document = stateless_bus_document(); - let mut rig = Rig::new(&document); - for _ in 0..4 { - rig.step(); - } - let (revision, _, epoch, pending) = rig.summary(); - let (status, diagnostics) = refusal( - &mut rig, - &[ - set(route("eq0-bus", ROUTE_GAIN_DB), -6.0, None), - set(route("eq0-bus", ROUTE_MATRIX_LR), 100.0, None), - ], - ); - assert_ne!( - status, - protocol::StatusCode::Ok, - "the out-of-domain value is refused" - ); - assert_eq!(diagnostics.len(), 1); - assert_eq!(diagnostics[0].1, 1, "the matrix edit, the second"); - assert_eq!( - (rig.summary().0, rig.summary().2, rig.summary().3), - (revision, epoch, pending), - "no revision, no candidate" - ); - assert_eq!( - rig.current_route_cells(), - vec![0], - "no send cell was written" - ); - assert_eq!( - rig.apply(&[set(route("eq0-bus", ROUTE_GAIN_DB), -6.0, None)]), - crate::RESULT_OK, - "the valid half applies alone" - ); - assert_eq!(rig.current_route_cells(), vec![1]); - } - /// Gate 1, effect family on a submix strip: a console slot's parameter, an insert's /// parameter and an insert's bypass commit live and render the bits of the direct host-core lane /// (host-core records pushed to the bus's own producers at the same block). @@ -8469,47 +8297,6 @@ mod set_control { } } - /// U3 fold, MAJOR 1 (reviewer C's case). A VCA move in the same transaction as a - /// structural edit (the transaction rebuilds) reaches the carried automated lane as the - /// join's offsets record, with the edit's own length: every block equals the same move - /// sent alone (`live`), with its own 4,096 samples and with the session's length. - /// - /// Test value: red if the join writes no offsets record (the successor's `S` reaches the - /// lane by the adoption rule, over the fader length, from the block's curve), or the - /// carried lane composes its first block with the new `S` as if it had heard it. - #[test] - fn a_vca_move_inside_a_rebuild_keeps_its_own_length() { - bench_support::alloc::assert_installed(); - for ((ride, document), (length, ramp)) in - [("moving ride", riding()), ("flat ride", flat())] - .into_iter() - .flat_map(|document| { - [ - ("its own 4,096 samples", Some(4_096)), - ("the session's length", None), - ] - .map(|length| (document.clone(), length)) - }) - { - let label = &format!("{ride}, {length}"); - let model = parse_session_json(&document).expect("model"); - let mut rigs = warm(&document); - let mut edits = vec![vca_move(-6.0, ramp)]; - edits.extend(add_muted_track(&model, "added")); - send(&mut rigs[0], &edits, protocol::EditPath::Rebuild, label); - send( - &mut rigs[1], - &[vca_move(-6.0, ramp)], - protocol::EditPath::Live, - label, - ); - let (first, heard) = lockstep(&mut rigs, 44); - assert_eq!(rigs[0].summary().3, 0, "{label}: the successor is adopted"); - assert_eq!(first, None, "{label}: first difference (block, sample)"); - assert!(heard, "{label}: the move is heard"); - } - } - /// A hand move (#1650b) of `document`'s first track's fader to `db` on both lanes over /// `ramp`: on an automated fader it is stored as the ride's offset and moves `S`. fn hand_move(document: &str, db: f32, ramp: Option) -> SessionEdit { @@ -9026,23 +8813,6 @@ mod set_control { } } - /// #1711 R19-1 on the C ABI. A VCA or hand move heard 1 and 12 blocks (3,872 and 2,464 - /// samples left, both at least `J` = 960) whose target a table-only rebuild moves: the - /// move's ramp runs to its end as the uninterrupted engine runs it, then the cell jumps - /// over `J`; every sample is bit-equal to the fresh plan with that jump at the move's - /// first free sample. - /// - /// Test value: red if the adoption retargets the move at the swap rather than deferring - /// the jump to the ramp's end. - #[test] - fn a_moved_target_lets_a_live_move_longer_than_the_jump_end_when_it_was_due() { - for hand in [false, true] { - for heard in [1, 12] { - moved_target_case(hand, heard, &[], 0); - } - } - } - /// #1711 U1 fold 1 (MAJOR-1) on the C ABI. A VCA or hand move heard 1 and 4 blocks on /// the ride flat at -3 dB, then a table-only rebuild to -5 dB up to 2,000, a linear -8 to /// -14 dB over 2,000 to 8,000, then -14 dB: the move's target moves, so its jump is @@ -10416,150 +10186,6 @@ fn follow_document(entry: bool, muted: bool) -> String { session::canonical_session_json(&model).expect("canonical follow session") } -/// #1652 U2a fold 2 (MAJOR-A, conservative; #1713 deletes the flag). A rebuild whose send join -/// carries a following route into a six-word one (it removes `eq0`'s mute entry while `eq0-b` -/// follows it) completes as the transition fallback: the C ABI watermark that covers it reads -/// `OUTCOME_TRANSITION_FALLBACK`, count 1. The removal is sent at block 8 (sample 1,024), while the -/// send's columns ramp toward the mute the curve stepped on at 1,000 (480 samples). A rebuild that -/// keeps the entry (the following route stays following, seven -> seven) and a rebuild of a -/// session with no following route (no mute entry) complete as `OUTCOME_EXACT`, count 0. A second -/// rebuild that automates `eq0`'s fader in the block after the first one's adoption (inside `J`) -/// completes `OUTCOME_EXACT` too, count still 1: the flag marks its own candidate only. -/// -/// Test value: red if the control plane does not mark a seven -> six rebuild (the six-word -/// successor's re-timed column move then completes exact), or if it marks a rebuild whose -/// following routes stay following, or one with no following route (the flag must stay narrow), -/// or if the flag outlives its own candidate (the fader rebuild after it then reports the -/// fallback). -#[test] -fn a_rebuild_that_drops_a_following_route_to_six_words_reports_a_fallback() { - let remove = SessionEdit::RemoveAutomation { - automation_id: StableId::parse("eq0-mute").expect("automation ID"), - }; - let fallback = crate::OUTCOME_TRANSITION_FALLBACK; - let exact = crate::OUTCOME_EXACT; - for (label, entry, remove_entry, expected) in [ - ("seven -> six, a column mid-move", true, true, fallback), - ("seven -> seven", true, false, exact), - ("no following route", false, false, exact), - ] { - let document = follow_document(entry, false); - let model = parse_session_json(&document).expect("model"); - let edits = if remove_entry { - vec![remove.clone()] - } else { - // A muted copy of `eq0` with its own route to the output: a rebuild that leaves - // `eq0-b` and `eq0`'s mute entry as they are. - let mut track = model.tracks[0].clone(); - track.id = StableId::parse("added").expect("track ID"); - (track.fader.left_mute, track.fader.right_mute) = (true, true); - let mut route = model - .routes - .iter() - .find(|route| route.id.as_str() == "eq0-main") - .expect("the direct route") - .clone(); - route.id = StableId::parse("added-main").expect("route ID"); - route.source = RouteSource::Track { - track_id: track.id.clone(), - tap: session::SendTap::PostPan, - }; - vec![ - SessionEdit::UpsertTrack { track }, - SessionEdit::UpsertRoute { route }, - ] - }; - let mut rig = Rig::new(&document); - for _ in 0..8 { - rig.step(); - } - let bytes = rig.transaction(&edits); - let (result, response) = rig.send(&bytes); - assert_eq!(result, crate::RESULT_OK, "{label}"); - assert_eq!( - edit_path_of(&response), - protocol::EditPath::Rebuild, - "{label}" - ); - let revision = rig.summary().0; - for _ in 0..4 { - rig.step(); - } - assert_eq!(rig.summary().3, 0, "{label}: the successor is adopted"); - let (result, watermark) = crate::ffi::test_plan_watermark(rig.plan); - assert_eq!(result, crate::RESULT_OK); - assert_eq!( - ( - watermark.revision, - watermark.outcome_flags, - watermark.transition_fallback_count - ), - (revision, expected, u64::from(expected == fallback)), - "{label}: the rebuild's revision, outcome flags and transition-fallback count" - ); - } - // Fold-2 NIT-1: the flag marks its own candidate only. The seven -> six rebuild above is - // flagged, and a second rebuild that automates a fader in the block after its adoption - // (inside `J` = 240 samples of it) completes exact; the count stays 1. - let document = follow_document(true, false); - let mut rig = Rig::new(&document); - for _ in 0..8 { - rig.step(); - } - let bytes = rig.transaction(&[remove]); - let (result, response) = rig.send(&bytes); - assert_eq!(result, crate::RESULT_OK); - assert_eq!(edit_path_of(&response), protocol::EditPath::Rebuild); - let first = rig.summary().0; - rig.step(); - let (result, watermark) = crate::ffi::test_plan_watermark(rig.plan); - assert_eq!(result, crate::RESULT_OK); - assert_eq!( - (watermark.revision, watermark.first_sample), - (first, 8 * rig.quantum as u64), - "the flagged successor is adopted at the next block" - ); - let ride = session::Automation { - id: StableId::parse("eq0-ride").expect("automation ID"), - target: session::ControlAddress { - owner: session::Owner::Strip(StableId::parse("eq0").expect("strip ID")), - section: session::Section::Builtins, - // The fader row (builtin parameter 5). - control: 5, - lane: session::ParameterChannel::Both, - }, - segments: vec![session::AutomationSegment { - shape: session::AutomationShape::Linear, - start_sample: 0, - end_sample: SOURCE_FRAMES, - start_value: 0.0, - end_value: -12.0, - unit: session::ParameterUnit::Db, - }], - offset: session::AutomationOffset::default(), - }; - let bytes = rig.transaction(&[SessionEdit::UpsertAutomation { automation: ride }]); - let (result, response) = rig.send(&bytes); - assert_eq!(result, crate::RESULT_OK); - assert_eq!(edit_path_of(&response), protocol::EditPath::Rebuild); - let revision = rig.summary().0; - for _ in 0..4 { - rig.step(); - } - assert_eq!(rig.summary().3, 0, "the second successor is adopted"); - let (result, watermark) = crate::ffi::test_plan_watermark(rig.plan); - assert_eq!(result, crate::RESULT_OK); - assert_eq!( - ( - watermark.revision, - watermark.outcome_flags, - watermark.transition_fallback_count - ), - (revision, crate::OUTCOME_EXACT, 1), - "a fader rebuild inside a flagged follow rebuild's landing finds no level move" - ); -} - /// #1653: sends `edits` on `rig`, which must answer `live`, and renders `blocks` blocks from the /// next block on. Returns that block's first sample `T` (the first block that begins after the /// submit returns, which applies the transaction's records) and the blocks, `T`'s first. diff --git a/crates/capi/src/runtime/supersede_tests.rs b/crates/capi/src/runtime/supersede_tests.rs index bd92805b6..0f27d753b 100644 --- a/crates/capi/src/runtime/supersede_tests.rs +++ b/crates/capi/src/runtime/supersede_tests.rs @@ -137,111 +137,6 @@ fn revision(children: &CompiledChildren) -> u64 { children.session.test_controller().session().revision().0 } -/// Gate 1: three structural transactions submitted without a render between them each commit, -/// and the plan the last one publishes renders exactly what one transaction of all three edits -/// renders; the watermark completes the first two as superseded. -/// -/// P0 has tracks `t1`-`t4` on the fixture source, `t2` and `t3` with a compressor insert. T1 adds -/// source `s` with its track and a compressor on `t1`, and moves `t4`'s fader; T2 replaces `t2`'s -/// compressor; T3 removes `t3`'s. `s` is fed between T1 and T2, so its ring is the withdrawn -/// candidate's and moves by the donation; `t4` carries from P0 with its fader retargeted at T1's -/// own ramp length. -/// -/// Test value: red if any of T1-T3 is refused, if the replacement carries from the withdrawn -/// candidate's identity while P0 runs (the carry finds no predecessor and the fixture source and -/// `t2` restart), if it is prepared against the current model instead of P0's (`t4`'s fader is -/// then no change, and `t4` keeps P0's), if the retarget forgets T1's ramp length, if `s`'s acked -/// PCM is lost with the withdrawn candidate, or if the superseded count is off. -#[test] -fn a_superseding_replacement_renders_as_one_combined_transaction() { - let mut model = stateless_session(48_000); - model.tracks[1].inserts.effects.push(compressor()); - model.tracks[2].inserts.effects.push(compressor()); - // `t4` is untouched but for a fader change T1 carries: it carries from P0 in every plan. - let mut t4 = model.tracks[0].clone(); - t4.id = id("t4"); - let mut route = model.routes[0].clone(); - route.id = id("t4-main"); - let RouteSource::Track { track_id, .. } = &mut route.source else { - panic!("track route") - }; - *track_id = t4.id.clone(); - model.tracks.push(t4); - model.routes.push(route); - let fader = session::DualMonoFader { - left_db: -6.0, - right_db: -9.0, - left_mute: false, - right_mute: false, - }; - // The fader edits carry their own ramp length (#1394), which the replacement's base keeps - // across the withdrawn candidate (root ruling B15-Q3). - let mut fader_edits = protocol::control_core::fader_edits(&id("t4"), &fader); - for edit in &mut fader_edits[..2] { - let SessionEdit::SetControl { ramp_samples, .. } = edit else { - panic!("a control edit") - }; - *ramp_samples = Some(1); - } - let first: Vec = add_source_track(&model) - .into_iter() - .chain([put(&model, 0, compressor())]) - .chain(fader_edits) - .collect(); - let second = [put(&model, 1, gate())]; - let third = [remove(&model, 2)]; - let combined: Vec = first.iter().chain(&second).chain(&third).cloned().collect(); - - let run = |superseding: bool| { - let mut children = compile(&model, limits()); - submit_direct(&mut children, &[FIXTURE], 0); - let mut blocks = vec![render_direct(&mut children, 0)]; - let before = children.plan.queries().watermark().expect("watermark"); - if superseding { - for (request, (base, edits)) in [(42, &first[..]), (43, &second[..]), (44, &third[..])] - .into_iter() - .enumerate() - { - commit(&mut children, request as u64 + 1, base, edits); - if request == 0 { - // `s` is fed while T1's candidate waits, into the candidate's own ring. - submit_direct(&mut children, &[ADDED], 0); - submit_direct(&mut children, &[ADDED], 1); - } - } - assert_eq!(revision(&children), 45); - } else { - commit(&mut children, 1, 42, &combined); - submit_direct(&mut children, &[ADDED], 0); - submit_direct(&mut children, &[ADDED], 1); - } - submit_direct(&mut children, &[FIXTURE], 1); - blocks.push(render_direct(&mut children, 1)); - let adopted = children.plan.queries().watermark().expect("watermark"); - for block in 2..9 { - submit_direct(&mut children, &[FIXTURE, ADDED], block); - blocks.push(render_direct(&mut children, block)); - } - (blocks, before, adopted) - }; - let (superseded, before, adopted) = run(true); - let (twin, _, _) = run(false); - for (block, (actual, expected)) in superseded.iter().zip(&twin).enumerate() { - assert!( - expected.iter().any(|sample| *sample != 0.0), - "block {block}: the twin plays" - ); - assert_eq!(bits(actual), bits(expected), "block {block}"); - } - assert_eq!(adopted.revision, 45); - assert_eq!( - adopted.outcome_flags, - engine::realtime::OUTCOME_EXACT | engine::realtime::OUTCOME_SUPERSEDED - ); - assert_eq!(adopted.superseded, before.superseded + 2); - assert_eq!(adopted.exact, before.exact + 1); -} - /// The lifecycle counters every constructed owner and every reservation are balanced in. fn assert_balanced(label: &str, counters: TestOwnerCounters) { assert_eq!( diff --git a/crates/capi/src/runtime/tests.rs b/crates/capi/src/runtime/tests.rs index b5db761c7..50da17278 100644 --- a/crates/capi/src/runtime/tests.rs +++ b/crates/capi/src/runtime/tests.rs @@ -5361,62 +5361,6 @@ fn configuring_an_unserved_counter_is_refused_and_changes_nothing() { crate::ffi::test_session_destroy(c_session); } -/// Issue #1351 gate 4 (D1, D6): the provider serves every counter of its fixed set at 0 from -/// construction, `TRANSITION_REPREPARE_REFUSALS` among them, and a configuration may name it. -/// -/// Test value: red if the new counter is missing from the registry decoder or the served set, so -/// that a host's read of it is `NOT_FOUND` or its configuration is refused. -#[test] -fn every_served_counter_reads_zero_on_a_fresh_session() { - let (c_session, c_plan) = boxed_c_children(SESSION); - let all = counters_get_c(c_session, 1, &[]).expect("all served counters"); - assert_eq!( - all.iter().map(|value| value.id).collect::>(), - vec![ - protocol::CounterId::TelemetryCoalesced, - protocol::CounterId::TelemetryDropped, - protocol::CounterId::LiveValuesSuperseded, - protocol::CounterId::TransitionReprepareRefusals, - ] - ); - assert!(all.iter().all(|value| value.value == 0)); - assert_eq!( - counters_get_c( - c_session, - 2, - &[protocol::CounterId::TransitionReprepareRefusals] - ), - Ok(vec![protocol::CounterValue { - id: protocol::CounterId::TransitionReprepareRefusals, - value: 0, - }]) - ); - let configure = counter_telemetry( - 3, - vec![protocol::CounterId::TransitionReprepareRefusals], - 1, - Vec::new(), - ); - let (result, response) = command_c(c_session, &configure); - assert_eq!( - (result, response_status(&response)), - (crate::RESULT_OK, StatusCode::Ok) - ); - render_c(c_plan, 0); - assert_eq!(crate::ffi::test_service(c_session), crate::RESULT_OK); - let snapshots = lossy_counter_snapshots(c_session); - assert_eq!(snapshots.len(), 1); - assert_eq!( - snapshots[0].values, - vec![protocol::CounterValue { - id: protocol::CounterId::TransitionReprepareRefusals, - value: 0, - }] - ); - crate::ffi::test_plan_destroy(c_plan); - crate::ffi::test_session_destroy(c_session); -} - /// Issue #1348 gate 4 (D7): a published candidate scheduled `NoEarlierThan` 64 blocks ahead /// survives 1,000 service steps after a rendered block: render still adopts it, exactly at the /// block that starts at its sample, its provider stays pending until then, no plan or provider is diff --git a/crates/compressor/tests/MUTATIONS.md b/crates/compressor/tests/MUTATIONS.md index 0b5b71fbd..27966e7de 100644 --- a/crates/compressor/tests/MUTATIONS.md +++ b/crates/compressor/tests/MUTATIONS.md @@ -368,17 +368,8 @@ file was restored byte for byte from a saved copy. | # | mutation | test | result | |---|---|---|---| -| 994-C1 | `knee_coefficients` without its `is_finite` test (the pre-#994 design) | `knee_overflow` | RED, 4 of 5: the prepare, automation, restore and bank tests. First failure `prepare: W 3e-45 (0x00000002) R 4 frame 0: 0.11473124 vs f64 reference 1` — the NaN target clamped to -100 dB and a 0.1 ms attack duck the very first full-scale sample by 18.8 dB. The automation test is red although both of its endpoints (0 and `1e-38`) are outside the overflow band: the `Linear 64` ramp passes through it | +| 994-C1 | `knee_coefficients` without its `is_finite` test (the pre-#994 design) | `knee_overflow` | RED, 4 of 5: the prepare, automation, restore (`a_restored_overflowing_knee_does_not_duck`, deleted by TA5; no catcher recorded) and bank tests. First failure `prepare: W 3e-45 (0x00000002) R 4 frame 0: 0.11473124 vs f64 reference 1` — the NaN target clamped to -100 dB and a 0.1 ms attack duck the very first full-scale sample by 18.8 dB. The automation test is red although both of its endpoints (0 and `1e-38`) are outside the overflow band: the `Linear 64` ramp passes through it | | 994-C2 | the rule as a constant bound one ulp too low: `knee_db >= f32::from_bits(0x0010_0000)` | `knee_overflow` | RED, 2 of 5: the prepare and bank tests, the two whose widths include `2^-129` itself | `the_narrowest_soft_knees_do_not_duck_a_sample_at_the_threshold` stays green under both: it is a preservation gate for widths the rule must not move, not a red gate. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `the_collapsed_body_renders_the_dual_bodys_left_plane`: compressor `mono_collapse::mono_reopen_drives_the_next_render_from_the_copied_state` -- `bank_matches_scalar_per_lane_bits`: no plausible same-crate KEEP catcher recorded -- `block_partitions_are_invariant`: no plausible same-crate KEEP catcher recorded -- `bypass_preserves_exact_dry_bits_at_sample_zero`: no plausible same-crate KEEP catcher recorded diff --git a/crates/compressor/tests/knee_overflow.rs b/crates/compressor/tests/knee_overflow.rs index 912481222..75e5644c1 100644 --- a/crates/compressor/tests/knee_overflow.rs +++ b/crates/compressor/tests/knee_overflow.rs @@ -24,7 +24,7 @@ use effect_contract::{InitialParameterValue, ParameterChannel, PreparedAutomatio use support::{ PARAMETER_COUNT, bind_bank, native_bank_width, prepare, render_bank, render_scalar, request, - restore, snapshot, values_with, + values_with, }; /// Positive widths whose `f32` reciprocal `1 / (2 W)` overflows: the smallest subnormal, the @@ -200,38 +200,6 @@ fn an_automated_knee_ramp_through_the_overflow_band_does_not_duck() { } } -/// Restoring a state payload whose knee is 2.8e-45 into an instance prepared at the default 6 dB -/// knee renders exactly as the hard knee. -/// -/// Red mutation (MUTATIONS.md row 994-C1): drop the `is_finite` test in `knee_coefficients`. -#[test] -fn a_restored_overflowing_knee_does_not_duck() { - let knee = f32::from_bits(0x0000_0002); - for ratio in [4.0_f32, 20.0] { - let hard = render_full_scale(&values(0.0, ratio), &[]); - let donor = prepare(request(&values(knee, ratio))); - let (left_payload, right_payload) = snapshot(donor.as_ref()); - let receiver_values = values(6.0, ratio); - let mut receiver = prepare(request(&receiver_values)); - restore( - receiver.as_mut(), - support::STATE_VERSION, - &left_payload, - &right_payload, - ) - .expect("a valid payload restores"); - let mut left = vec![1.0_f32; FRAMES]; - let mut right = vec![1.0_f32; FRAMES]; - let report = render_scalar(receiver.as_mut(), &mut left, &mut right, 128, 128, &[]); - assert_eq!( - report.nonfinite_left_blocks + report.nonfinite_right_blocks, - 0 - ); - assert_undocked(&left, &hard, knee, ratio, "restore"); - assert_undocked(&right, &hard, knee, ratio, "restore"); - } -} - /// A homogeneous bank at this build's SIMD width, one knee per lane — every overflowing width, /// the hard knee and the narrowest soft knees side by side — renders every lane exactly as the /// scalar hard knee. diff --git a/crates/compressor/tests/padding.rs b/crates/compressor/tests/padding.rs index b16817eee..ff9a48dc2 100644 --- a/crates/compressor/tests/padding.rs +++ b/crates/compressor/tests/padding.rs @@ -318,141 +318,6 @@ fn the_fixtures_render_through_a_padded_bank_as_they_do_per_node() { } } -/// Gate 4, the P1 verdict's M2: a bypassed lane fed a tripping value moves no bank-mate's bit. -/// -/// A session bypass keeps its track in the bank (#1087): the effect runs the lane with prepared -/// `bypass = false`, and the rack's `BypassShunt` copies the dry words back over that lane's -/// output, so the bypassed lane's wet path still runs and still meets D7. Here the bypassed lane -/// carries a legal gain of +24 dB (ratio 1, makeup +24) and is fed `1e29` on some blocks, a legal -/// sample below the `1e30` bound that its wet block pushes past it. The test drives the real -/// `BypassShunt` the same way `rack::LiveControlEffectBankStage` does: capture the dry block, run -/// the bank, restore the bypassed lane. -/// -/// For every active count `2..=W` (full banks too) and the first and last member bypassed: -/// * every enabled member renders the bits and reports of the render in which the bypassed lane -/// was fed ordinary noise instead, and of its own per-node instance; -/// * the bypassed lane's output is its dry input, bit for bit; -/// * its wet block really was rejected (the report is the non-vacuity check), and no other lane -/// reports anything. -/// -/// Red for the pre-#1090 whole-bank recovery: every enabled member of the bank is silenced for as -/// long as the bypassed lane stays hot (Sol's probe measured 43,008 of 43,008 words). -#[test] -fn a_bypassed_lane_fed_a_tripping_value_moves_no_bank_mates_bit() { - let Some((backend, width)) = native_bank_width() else { - println!("scalar-only build: no bank width"); - return; - }; - let lanes = width.lanes() as usize; - const BLOCKS: usize = 8; - const TRIPPING_BLOCKS: [usize; 3] = [2, 3, 5]; - let partitions = vec![QUANTUM as usize; BLOCKS]; - let frames = QUANTUM as usize * BLOCKS; - let hot = values_with(&[(0, 0.0), (1, 1.0), (2, 0.0), (5, 24.0), (6, 1.0)]); - let cool: Vec = (0..lanes).map(console_values).collect(); - for members in 2..=lanes { - for bypassed in [0, members - 1] { - let values: Vec<&Values> = (0..members) - .map(|member| { - if member == bypassed { - &hot - } else { - &cool[member] - } - }) - .collect(); - let requests: Vec<_> = values.iter().map(|values| request(*values)).collect(); - let noise = |member: usize, channel: u64| { - support::noise(frames, 0x1090_0000 + member as u64 * 2 + channel, 0.5) - }; - let benign: Vec = (0..members) - .map(|member| Planes { - left: noise(member, 0), - right: noise(member, 1), - }) - .collect(); - let mut tripping: Vec = (0..members) - .map(|member| Planes { - left: noise(member, 0), - right: noise(member, 1), - }) - .collect(); - for block in TRIPPING_BLOCKS { - let range = block * QUANTUM as usize..(block + 1) * QUANTUM as usize; - tripping[bypassed].left[range.clone()].fill(1.0e29); - tripping[bypassed].right[range].fill(-1.0e29); - } - let shunted = |inputs: &[Planes]| { - let mut bank = bind( - backend, - width, - &lane_requests(&requests, lanes), - &members_first(members, lanes), - ); - banked( - bank.as_mut(), - width, - inputs, - &partitions, - |shunt, left, right, frames| { - // `LiveControlEffectBankStage`'s restore: the bypassed lane's dry words, by - // copy. - let (dry_left, dry_right) = shunt.dry(); - for frame in 0..frames { - let word = frame * lanes + bypassed; - left[word] = dry_left[word]; - right[word] = dry_right[word]; - } - }, - ) - }; - let hot_render = shunted(&tripping); - let cool_render = shunted(&benign); - let oracle = per_node(&requests, &tripping, &partitions); - let context = format!("{members} of {lanes}, lane {bypassed} bypassed"); - for member in 0..members { - if member == bypassed { - let dry: Vec = tripping[member] - .left - .iter() - .chain(&tripping[member].right) - .map(|sample| sample.to_bits()) - .collect(); - assert_eq!( - hot_render[member].0, dry, - "{context}: the bypassed lane is dry" - ); - let rejected: u64 = hot_render[member] - .1 - .iter() - .map(|report| report.nonfinite_left_blocks + report.nonfinite_right_blocks) - .sum(); - assert!( - rejected >= 2 * TRIPPING_BLOCKS.len() as u64, - "{context}: the bypassed lane's wet block was not rejected ({rejected})" - ); - continue; - } - assert_eq!( - hot_render[member], cool_render[member], - "{context}: enabled member {member} moved with the bypassed lane's input" - ); - assert_eq!( - hot_render[member], oracle[member], - "{context}: enabled member {member} is not its per-node render" - ); - assert!( - hot_render[member] - .1 - .iter() - .all(|report| *report == ProcessReport::default()), - "{context}: enabled member {member} was reported" - ); - } - } - } -} - /// A padded lane is not a track: a state payload call that names one is `effect.state.track`, /// exactly as a lane past the width is, while every member's payload round-trips. /// diff --git a/crates/controls/tests/monitor.rs b/crates/controls/tests/monitor.rs index a615b89ff..65c87e746 100644 --- a/crates/controls/tests/monitor.rs +++ b/crates/controls/tests/monitor.rs @@ -3,14 +3,13 @@ mod common; -use common::{RATE, fixture, id, strip_builtin, strip_own}; +use common::{RATE, fixture, id, strip_own}; use controls::{ ControlError, Lane, MonitorOverlay, MonitorRow, MonitorWrite, Owner, Section, check_monitor, - effective, set, + effective, }; const SOLO: u32 = 2; -const FADER_DB: u32 = 5; fn write(strip: &str, soloed: bool, ramp: Option) -> MonitorWrite { MonitorWrite { @@ -21,75 +20,6 @@ fn write(strip: &str, soloed: bool, ramp: Option) -> MonitorWrite { } } -/// A solo is checked like any write, by its row: a track's row takes exactly 0 or 1 on `both` -/// with an optional ramp, a submix has no solo row, and a model row is not a monitor write. -/// -/// Red if a submix becomes soloable, a malformed solo is accepted, a model row is taken for a -/// monitor write, or the write drops its ramp. -#[test] -fn a_solo_write_is_checked_by_its_row() { - let model = fixture(); - let check_solo = |strip: &str, lane, value, ramp| { - check_monitor(&model, &strip_own(strip, SOLO, lane), value, ramp, RATE) - }; - assert_eq!( - check_solo("vocal", Lane::Both, 1.0, Some(480)), - Ok(Some(write("vocal", true, Some(480)))) - ); - assert_eq!( - check_solo("guitar", Lane::Both, 0.0, None), - Ok(Some(write("guitar", false, None))) - ); - // A step is a length, not an absent one. - assert_eq!( - check_solo("vocal", Lane::Both, 1.0, Some(0)), - Ok(Some(write("vocal", true, Some(0)))) - ); - assert_eq!( - check_solo("bus", Lane::Both, 1.0, None), - Err(ControlError::AddressUnknown), - "a submix is solo-safe: it has no solo row" - ); - assert_eq!( - check_solo("nobody", Lane::Both, 1.0, None), - Err(ControlError::AddressUnknown) - ); - assert_eq!( - check_solo("vocal", Lane::Left, 1.0, None), - Err(ControlError::Lane) - ); - for value in [0.5, -0.0, 2.0, f32::NAN] { - assert_eq!( - check_solo("vocal", Lane::Both, value, None), - Err(ControlError::Domain), - "{value}" - ); - } - // A model row is for `set`: the writer says so without judging its value. - assert_eq!( - check_monitor( - &model, - &strip_builtin("vocal", FADER_DB, Lane::Both), - 99.0, - None, - RATE - ), - Ok(None) - ); - // And `set` refuses the monitor row, whatever transport reaches it. - let mut model = model; - assert_eq!( - set( - &mut model, - &strip_own("vocal", SOLO, Lane::Both), - 1.0, - None, - RATE - ), - Err(ControlError::Monitor) - ); -} - /// The overlay after a transaction's writes: in order, the last write of a strip wins, a strip the /// model no longer has is dropped, and the ramp is that of the last write that changed a strip. /// diff --git a/crates/controls/tests/row_descriptor.rs b/crates/controls/tests/row_descriptor.rs index 5c897a9b0..0f7cb573d 100644 --- a/crates/controls/tests/row_descriptor.rs +++ b/crates/controls/tests/row_descriptor.rs @@ -89,14 +89,3 @@ fn effect_sections_and_unknown_ids_have_no_descriptor() { ); assert_eq!(Section::Own.kind(), SectionKind::Own); } - -/// A rate-keyed row is resolved at the rate given. -#[test] -fn a_rate_keyed_row_follows_the_rate() { - let at = |rate| { - row_descriptor(OwnerKind::Strip, SectionKind::Builtins, 3, rate) - .expect("hpf_hz") - .maximum - }; - assert!(at(96_000) > at(44_100)); -} diff --git a/crates/delay/tests/MUTATIONS.md b/crates/delay/tests/MUTATIONS.md index 2d3dad0f1..61e62c4e8 100644 --- a/crates/delay/tests/MUTATIONS.md +++ b/crates/delay/tests/MUTATIONS.md @@ -56,9 +56,3 @@ left `M7c`, `M9` and `M10` alive, and each survivor was a real gap rather than a **Two mutations fail by panicking rather than by asserting.** `M7b` underflows `transition_remaining` and `M15` reaches the test's own `panic!`. Both are unambiguous reds, and both are recorded as what they are rather than dressed up as assertion failures. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `a_mid_ramp_restore_continues_bit_identically`: no plausible same-crate KEEP catcher recorded diff --git a/crates/delay/tests/randomized.rs b/crates/delay/tests/randomized.rs index 11bd8fa5e..f5b85e2b2 100644 --- a/crates/delay/tests/randomized.rs +++ b/crates/delay/tests/randomized.rs @@ -15,16 +15,3 @@ conformance::randomized_effect_test!( banks_natively: false, witness: true, ); - -/// #1278 D2a: the plan-swap carry restores every lane it carries, so a restore must accept every -/// state the effect itself reaches -- here each sampled state of a feedback, mix or cross-feedback -/// ramp to a domain edge, at every launch rate. -/// Since #1409 every ramp word stays between its start and its target, so the strict restore -/// (#1411) admits each snapshot. Red when the render site whose word the snapshot holds leaves a -/// ramp word outside its endpoints at render (a missing or reverted #1409 clamp), or when the -/// restore refuses a valid in-range snapshot. The fix is that clamp or that validation, never a -/// restore slack. -#[test] -fn the_effects_own_edge_ramp_snapshots_restore() { - conformance::EffectDifferential::assert_edge_ramps_restore(Box::new(delay::DelayFactory)); -} diff --git a/crates/dsp-reference/src/svf.rs b/crates/dsp-reference/src/svf.rs index 2bf0696df..ec42bb64f 100644 --- a/crates/dsp-reference/src/svf.rs +++ b/crates/dsp-reference/src/svf.rs @@ -444,7 +444,6 @@ mod tests { const DECIBELS_PER_NEPER: f64 = 8.685_889_638_065_035; /// Flat gate for every row whose design frequency is at or above 1 kHz. const FLAT_DECIBEL_TOLERANCE: f64 = 1e-9; - const IMPULSE_FRAMES: usize = 4_096; /// One RBJ cookbook evaluation plus the terms of its own conditioning bound. #[derive(Clone, Copy, Debug)] @@ -730,22 +729,6 @@ mod tests { ); } - #[test] - fn svf_recurrence_matches_state_space_impulse() { - let mut worst = 0.0_f64; - for row in rows() { - let coefficients = row.coefficients(); - let mut section = ReferenceSvf::new(coefficients); - let modelled = coefficients.state_space().impulse_response(IMPULSE_FRAMES); - for (frame, expected) in modelled.into_iter().enumerate() { - let input = if frame == 0 { 1.0 } else { 0.0 }; - worst = worst.max((section.process(input) - expected).abs()); - } - } - eprintln!("E2 worst_abs={worst:e}"); - assert!(worst <= 1e-12, "recurrence vs state space worst {worst:e}"); - } - #[test] fn zero_gain_bell_and_shelves_are_exact_identity() { for kind in [ diff --git a/crates/effect-contract/src/symmetry.rs b/crates/effect-contract/src/symmetry.rs index c6840227c..699b41c72 100644 --- a/crates/effect-contract/src/symmetry.rs +++ b/crates/effect-contract/src/symmetry.rs @@ -427,35 +427,6 @@ mod tests { ); } - #[test] - fn a_left_channel_parameter_desymmetrises_and_a_both_channel_one_does_not() { - let left = EffectControlRecord::Parameter { - parameter_index: 3, - channel: ParameterChannel::Left, - value: 0.5, - }; - let right = EffectControlRecord::Parameter { - parameter_index: 3, - channel: ParameterChannel::Right, - value: 0.5, - }; - let both = EffectControlRecord::Parameter { - parameter_index: 3, - channel: ParameterChannel::Both, - value: 0.5, - }; - assert_eq!(left.symmetry_event(), SymmetryEvent::Desymmetrize); - assert_eq!(right.symmetry_event(), SymmetryEvent::Desymmetrize); - assert_eq!(both.symmetry_event(), SymmetryEvent::Preserve); - - let mut witness = ChannelSymmetryWitness::SYMMETRIC; - witness.admit(&both); - assert!(witness.eligible(), "a both-channel command must preserve"); - witness.admit(&left); - assert!(!witness.eligible()); - assert_eq!(witness.declined(), ChannelSymmetryWitness::LIVE); - } - #[test] fn a_subscription_never_moves_the_witness() { let mut witness = ChannelSymmetryWitness::SYMMETRIC; diff --git a/crates/effect-contract/tests/lattice.rs b/crates/effect-contract/tests/lattice.rs index 9dfa90242..463e2721b 100644 --- a/crates/effect-contract/tests/lattice.rs +++ b/crates/effect-contract/tests/lattice.rs @@ -65,25 +65,6 @@ fn contains(points: &[LatticePoint], canonical: &str) -> bool { // Endpoints and defaults are lattice members by declaration (ruling B2/B3). // --------------------------------------------------------------------------- -#[test] -fn declared_bounds_and_default_are_always_members() { - // The parametric EQ's frequency row: 20 kHz is the round user-facing extreme, and a pure - // greatest-generated-point-below-max rule would have made it unreachable. - let points = hertz(10.0, 20_000.0, 80.0, 20.0); - assert_eq!(points.first().expect("minimum").canonical, "10.000"); - assert_eq!(points.last().expect("maximum").canonical, "20000.000"); - assert!(points.first().expect("minimum").intrinsic); - assert!(points.last().expect("maximum").intrinsic); - assert!( - points - .iter() - .any(|point| point.canonical == "80.000" && point.intrinsic) - ); - // 20 kHz is exactly spellable, which is the whole point of the amendment. - assert!(lattice_index_for_decimal(&points, "20000.0").is_ok()); - assert!(lattice_index_for_decimal(&points, "20000").is_ok()); -} - #[test] fn geometric_ratio_row_keeps_its_round_maximum_and_meaningful_default() { // The compressor ratio row: 20:1 is the declared maximum, so `set ratio 20` is legal. diff --git a/crates/effect-runtime/tests/MUTATIONS.md b/crates/effect-runtime/tests/MUTATIONS.md index 320faf369..6d7e234ea 100644 --- a/crates/effect-runtime/tests/MUTATIONS.md +++ b/crates/effect-runtime/tests/MUTATIONS.md @@ -247,13 +247,3 @@ The smallest width, `0x0000_0001`, is not by itself a witness: `0.5 * 2^-149` ro its half-width is zero and the knee interval `(-W/2, W/2]` is empty even without the rule. Every list of overflowing widths in these tests therefore also carries `0x0000_0002` (the verification's 2.8e-45), `0x000F_FFFF` and `0x0010_0000`, where the half-width is positive. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `the_step_is_computed_once`: effect-runtime `contract_ramp_identity::linear_smoother_is_bit_identical_to_the_linear_ramp` -- `the_curve_matches_the_paper`: effect-runtime `dynamics::knee_words_follow_the_finite_reciprocal_rule` -- `the_corpus_is_width_independent`: no plausible same-crate KEEP catcher recorded -- `a_knee_whose_reciprocal_overflows_is_a_hard_knee`: effect-runtime `dynamics::knee_words_follow_the_finite_reciprocal_rule` -- `the_narrowest_soft_knees_are_finite_at_the_threshold`: effect-runtime `dynamics::knee_words_follow_the_finite_reciprocal_rule` diff --git a/crates/effect-runtime/tests/partition.rs b/crates/effect-runtime/tests/partition.rs index debd96693..abf6078a8 100644 --- a/crates/effect-runtime/tests/partition.rs +++ b/crates/effect-runtime/tests/partition.rs @@ -124,11 +124,6 @@ fn assert_partition_invariant(width: &str) { } } -#[test] -fn the_composition_is_partition_invariant_at_width_one() { - assert_partition_invariant::("W=1"); -} - #[test] fn the_composition_is_partition_invariant_at_width_four() { assert_partition_invariant::("W=4"); diff --git a/crates/effect-runtime/tests/state_payload.rs b/crates/effect-runtime/tests/state_payload.rs index ae3f1a501..745f2ed86 100644 --- a/crates/effect-runtime/tests/state_payload.rs +++ b/crates/effect-runtime/tests/state_payload.rs @@ -2,8 +2,8 @@ use effect_runtime::state_payload::{ HEADER_WORDS, STATE_LENGTH_CODE, STATE_VERSION_CODE, StateLayout, StatePayloadInput, - StatePayloadOutput, StateWords, StateWordsMut, expected_sizes, read_f32, read_header, read_u32, - restore, snapshot, validate_lengths, write_f32, write_header, write_u32, + StatePayloadOutput, StateWords, StateWordsMut, expected_sizes, read_f32, read_header, restore, + snapshot, validate_lengths, write_f32, write_header, }; const LAYOUT: StateLayout = StateLayout { @@ -31,20 +31,6 @@ fn expected_sizes_account_for_the_header() { assert_eq!(LAYOUT.data_words(), 2 + 2 * 5); } -/// Words are little-endian on every target. -/// -/// Red mutation: `write_u32` uses `to_be_bytes`, or `read_u32` uses `from_be_bytes`. -#[test] -fn words_are_little_endian() { - let mut bytes = [0u8; 8]; - write_u32(&mut bytes, 0, 0x1122_3344); - assert_eq!(&bytes[0..4], &[0x44, 0x33, 0x22, 0x11]); - write_u32(&mut bytes, 1, 0x0000_00ff); - assert_eq!(&bytes[4..8], &[0xff, 0x00, 0x00, 0x00]); - assert_eq!(read_u32(&bytes, 0), 0x1122_3344); - assert_eq!(read_u32(&bytes, 1), 0x0000_00ff); -} - /// `f32` words round-trip by bit pattern, including the signed zeros and a subnormal. #[test] fn float_words_round_trip_by_bits() { @@ -71,52 +57,6 @@ fn float_words_round_trip_by_bits() { } } -#[test] -fn snapshot_then_restore_returns_every_word() { - let (mut common, mut left, mut right) = buffers(); - let source_common = [0xdead_beef_u32, 7]; - let source_left = [1_u32, 2, 3, 4, 5]; - let source_right = [0xffff_ffff_u32, 0, 0x8000_0000, 42, 0x7f80_0000]; - snapshot( - &LAYOUT, - &StateWords { - common: &source_common, - left: &source_left, - right: &source_right, - }, - &mut StatePayloadOutput { - common: &mut common, - left: &mut left, - right: &mut right, - }, - ) - .expect("snapshot into correctly sized buffers"); - - assert_eq!(read_u32(&common, 0), LAYOUT.version, "version word"); - assert_eq!(read_u32(&common, 1), LAYOUT.data_words(), "word count"); - - let mut out_common = [0u32; 2]; - let mut out_left = [0u32; 5]; - let mut out_right = [0u32; 5]; - restore( - &LAYOUT, - &StatePayloadInput { - common: &common, - left: &left, - right: &right, - }, - &mut StateWordsMut { - common: &mut out_common, - left: &mut out_left, - right: &mut out_right, - }, - ) - .expect("restore from a payload this codec wrote"); - assert_eq!(out_common, source_common); - assert_eq!(out_left, source_left); - assert_eq!(out_right, source_right); -} - /// A payload that is one byte short, or one byte long, is rejected — both, and with the same code. /// /// Red mutation: `validate_lengths` compares with `<` instead of `!=`, which accepts a payload diff --git a/crates/effect-runtime/tests/stationary_hoist.rs b/crates/effect-runtime/tests/stationary_hoist.rs index 9d2d4b2ea..291671695 100644 --- a/crates/effect-runtime/tests/stationary_hoist.rs +++ b/crates/effect-runtime/tests/stationary_hoist.rs @@ -22,25 +22,6 @@ fn assert_constant(mut ramp: LinearRamp, expected: f32, count: usize) { assert_eq!(ramp, LinearRamp::fixed(expected)); } -/// Redundant finite retargets settle immediately and keep every rendered word. -#[test] -fn a_redundant_retarget_is_constant_and_settled() { - for value in [ - 0.0_f32, - 1.0, - -1.0, - 0.5, - -24.0, - 1.0e-7, - f32::MIN_POSITIVE, - f32::MAX, - ] { - let mut ramp = LinearRamp::fixed(value); - ramp.set_target(value, 64); - assert_constant(ramp, value, 80); - } -} - /// Negative zero arms: intermediate additions produce +0.0 and the final snap restores -0.0. #[test] fn negative_zero_remains_armed_and_snaps_back_to_its_sign() { diff --git a/crates/engine/src/realtime/latest_cell.rs b/crates/engine/src/realtime/latest_cell.rs index debb67193..81cc593fe 100644 --- a/crates/engine/src/realtime/latest_cell.rs +++ b/crates/engine/src/realtime/latest_cell.rs @@ -1260,47 +1260,6 @@ mod tests { let _ = RevisionGate::pair(GATE_REVISION_MAX + 1); } - /// Root ruling n3 (#1432 D1): the stamp's revision bound is on in every build and a refusal - /// changes nothing. In a release build an unchecked stamp at the published revision would - /// make the in-place rule rewrite the slot render may be reading. - #[test] - fn a_stamp_at_or_below_the_published_revision_or_above_the_ceiling_is_refused_and_changes_nothing() - { - let (gate, mut pin) = RevisionGate::pair(5); - let (cell, dirty) = (LatestCell::<2>::new(), DirtyWord::new()); - let (mut writer, mut reader, mut stage) = ( - CellWriter::<2>::new(), - CellReader::new(), - DirtyReader::new(), - ); - for (revision, reason) in [ - (5, StampRefusal::NotAbovePublished), - (3, StampRefusal::NotAbovePublished), - (GATE_REVISION_MAX + 1, StampRefusal::AboveCeiling), - (u64::MAX, StampRefusal::AboveCeiling), - ] { - assert_eq!( - pin.stamp(revision).map(|_| ()), - Err(StampRefused { - revision, - last_published: 5, - reason - }) - ); - } - assert_eq!(pin.last_published(), 5); - // In a debug build this stamp would panic if a refusal had set `open`. - let stamp = pin.stamp(7).expect("a revision above the published one"); - writer.write(&cell, &dirty, 0, stamp, value_words(7, 0)); - pin.publish(&gate, 7); - let snapshot = gate.snapshot(); - assert_eq!(stage.pending(&dirty), 1); - let CellRead::Applied { words, .. } = reader.read(&cell, snapshot, &mut stage, 0) else { - panic!("the value applies in the first block"); - }; - assert_eq!(words, value_words(7, 0)); - } - #[cfg(debug_assertions)] #[test] #[should_panic(expected = "is not above the last published")] diff --git a/crates/engine/src/realtime/mod.rs b/crates/engine/src/realtime/mod.rs index d641a3603..457b9c88d 100644 --- a/crates/engine/src/realtime/mod.rs +++ b/crates/engine/src/realtime/mod.rs @@ -2174,32 +2174,6 @@ mod tests { (blocks, reports, owner, hooks.load(Ordering::Relaxed)) } - #[test] - fn successor_continues_the_predecessor_state_gap_free() { - let reference = reference(); - let (blocks, reports, owner, hooks) = swap_at_block_five(true); - assert_eq!(blocks, reference); - assert_eq!(hooks, 1); - for (block, report) in reports.iter().enumerate() { - let (swap, carry) = if block == 5 { - (SwapOutcome::Applied, CarryOutcome::Carried) - } else { - (SwapOutcome::None, CarryOutcome::NotRequested) - }; - assert_eq!((report.swap, report.carry), (swap, carry), "block {block}"); - } - assert_eq!( - (owner.carried_count(), owner.carry_mismatch_count()), - (1, 0) - ); - - let (blocks, reports, owner, _) = swap_at_block_five(false); - assert_eq!(blocks[..5], reference[..5]); - assert_ne!(blocks[5], reference[5]); - assert_eq!(reports[5].carry, CarryOutcome::NotRequested); - assert_eq!(owner.carried_count(), 0); - } - #[test] fn a_mismatched_predecessor_is_reported_not_carried() { let hooks = Arc::new(AtomicUsize::new(0)); diff --git a/crates/engine/src/realtime/spsc.rs b/crates/engine/src/realtime/spsc.rs index 0ff69130f..7438d639a 100644 --- a/crates/engine/src/realtime/spsc.rs +++ b/crates/engine/src/realtime/spsc.rs @@ -1512,8 +1512,7 @@ mod tests { use super::{QueueGeneration, bounded_spsc, bounded_spsc_internal}; use core::num::NonZeroUsize; use std::sync::Arc; - use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; - use std::time::{Duration, Instant}; + use std::sync::atomic::{AtomicUsize, Ordering}; struct DropProbe(Arc); @@ -1540,118 +1539,6 @@ mod tests { assert_eq!(drops.load(Ordering::Relaxed), 2); } - /// Sets its flag when dropped, so a peer learns that this thread left its loop however it left - /// it. `engine` cannot use `bench_support::producer::StopOnDrop`: `bench-support` depends on - /// `engine` (#1251 D3). - struct EndedOnDrop(Arc); - - impl Drop for EndedOnDrop { - fn drop(&mut self) { - self.0.store(true, Ordering::Release); - } - } - - /// How long one side of the stress waits on a full or empty queue before it fails. The peer - /// moves the queue within microseconds whenever it is running. - const STALL_DEADLINE: Duration = Duration::from_secs(10); - - /// Fails the side that waits on the queue once its peer has ended, or after - /// [`STALL_DEADLINE`] without progress. `peer_ended` must have been read before the failed - /// queue operation: a peer that ended published its last operation first, so a queue still - /// full or empty after it ended stays that way. - fn fail_if_stalled( - peer_ended: bool, - stalled_since: &mut Option, - side: &str, - peer: &str, - position: u64, - ) { - assert!( - !peer_ended, - "spsc stress: the {peer} ended while the {side} waited at item {position}" - ); - let since = *stalled_since.get_or_insert_with(Instant::now); - assert!( - since.elapsed() < STALL_DEADLINE, - "spsc stress: the {side} made no progress at item {position} within {STALL_DEADLINE:?}" - ); - } - - #[test] - fn concurrent_spsc_stress() { - const ITEMS: u64 = 1_000_000; - let (mut producer, mut consumer) = bounded_spsc( - NonZeroUsize::new(127).expect("capacity"), - QueueGeneration(7), - ) - .expect("queue"); - // Each thread marks its end however it leaves its loop, so a failed assertion on one side - // fails the other's wait instead of leaving it spinning on a full or empty queue (#1251). - let producer_ended = Arc::new(AtomicBool::new(false)); - let consumer_ended = Arc::new(AtomicBool::new(false)); - let (producer_end, consumer_peer) = - (Arc::clone(&producer_ended), Arc::clone(&consumer_ended)); - let producer_thread = std::thread::spawn(move || { - let _ended = EndedOnDrop(producer_end); - let mut next = 0; - let mut stalled_since = None; - while next < ITEMS { - let peer_ended = consumer_peer.load(Ordering::Acquire); - match producer.try_push(next) { - Ok(()) => { - next += 1; - stalled_since = None; - } - Err(full) => { - assert_eq!(full.value, next); - fail_if_stalled( - peer_ended, - &mut stalled_since, - "producer", - "consumer", - next, - ); - std::thread::yield_now(); - } - } - } - producer - }); - let consumer_thread = std::thread::spawn(move || { - let _ended = EndedOnDrop(consumer_ended); - let mut expected = 0; - let mut checksum = 0_u128; - let mut stalled_since = None; - while expected < ITEMS { - let peer_ended = producer_ended.load(Ordering::Acquire); - match consumer.try_pop() { - Ok(value) => { - assert_eq!(value, expected); - checksum = checksum.wrapping_add(u128::from(value)); - expected += 1; - stalled_since = None; - } - Err(_) => { - fail_if_stalled( - peer_ended, - &mut stalled_since, - "consumer", - "producer", - expected, - ); - std::thread::yield_now(); - } - } - } - (consumer, checksum) - }); - let producer = producer_thread.join().expect("producer thread"); - let (consumer, checksum) = consumer_thread.join().expect("consumer thread"); - assert_eq!(producer.success_count(), ITEMS); - assert_eq!(consumer.success_count(), ITEMS); - assert_eq!(checksum, u128::from(ITEMS) * u128::from(ITEMS - 1) / 2); - } - /// The queue layout retains cursor cache-line alignment without pinning resource bytes. #[cfg(target_pointer_width = "64")] #[test] diff --git a/crates/graph-compiler/src/lib.rs b/crates/graph-compiler/src/lib.rs index ade54cdfb..e0fcea04d 100644 --- a/crates/graph-compiler/src/lib.rs +++ b/crates/graph-compiler/src/lib.rs @@ -1947,83 +1947,6 @@ mod tests { } } - #[test] - fn indexed_topo_explicit_controls_preserve_contract() { - let nodes = vec![ - graph_node("z", 0, TailSamples::Finite(0)), - graph_node("a", 0, TailSamples::Finite(0)), - graph_node("m", 0, TailSamples::Finite(0)), - graph_node("b", 0, TailSamples::Finite(0)), - graph_node("q", 0, TailSamples::Finite(0)), - ]; - let edges = vec![ - edge("a-z-1", "a", "z"), - edge("m-z", "m", "z"), - edge("a-z-2", "a", "z"), - edge("b-m", "b", "m"), - ]; - let expected_names: &[(&[&str], u64)] = &[ - (&["submix:a", "submix:b", "submix:q"], 0), - (&["submix:m"], 1), - (&["submix:z"], 2), - ]; - let oracle_accepts = |candidate: &[DependencyLevel]| { - candidate.len() == expected_names.len() - && candidate - .iter() - .zip(expected_names) - .all(|(level, (names, number))| { - level.level == *number - && level.nodes.iter().map(node_text).collect::>() - == names - .iter() - .map(|name| (*name).to_owned()) - .collect::>() - }) - }; - - let actual = topo(&nodes, &edges).expect("explicit DAG is acyclic"); - assert!( - oracle_accepts(&actual), - "independent level oracle rejected topo output" - ); - let mut wrong_result = actual.clone(); - wrong_result[2].level = 1; - assert!( - !oracle_accepts(&wrong_result), - "independent level oracle accepted an incorrect level" - ); - - let mut reversed_nodes = nodes.clone(); - reversed_nodes.reverse(); - let mut reversed_edges = edges.clone(); - reversed_edges.reverse(); - assert_eq!(topo(&reversed_nodes, &reversed_edges), Some(actual.clone())); - assert_eq!(topo(&[], &[]), Some(Vec::new())); - - let cycle = [edge("cycle-a-b", "a", "b"), edge("cycle-b-a", "b", "a")]; - assert_eq!(topo(&nodes, &cycle), None); - assert_eq!(topo(&nodes, &[edge("self-loop", "a", "a")]), None); - assert_eq!( - topo(&nodes, &[edge("dangling-source", "missing", "a")]), - None - ); - assert_eq!( - topo(&nodes, &[edge("dangling-destination", "a", "missing")]), - None - ); - assert_eq!( - topo( - &[ - graph_node("a", 0, TailSamples::Finite(0)), - graph_node("a", 0, TailSamples::Finite(0)), - ], - &[], - ), - None - ); - } - fn caps(maximum_finite_tail_samples: u64) -> GraphCompileCaps { GraphCompileCaps { maximum_nodes: 100, @@ -7506,68 +7429,6 @@ mod tests { ); } - /// A send taken from an elided rack boundary declines the merge, through the second-reader - /// clause rather than the observer one. - /// - /// Issue #181 declined on the *presence* of a `program::Tap`, which made this case and the - /// metered one indistinguishable. They are not the same: a tap is a name, and an edge out of - /// the aliased stage resolves through it to the compressor, so it is counted by - /// `runtime::op_dataflow` as an ordinary second reader of the compressor's output. That clause - /// is what refuses here, and it has to, because a merged chain would send pre-compressor audio. - #[test] - fn a_send_from_a_rack_boundary_declines_the_merge() { - const BLOCKS: u64 = 12; - let Some(width) = BankWidth::for_backend(host_dispatch()) else { - return; - }; - let cohorts = 64 / width.lanes() as u64; - let mut sent = parse_session_json(CONSOLE_SIXTY_FOUR_TRACK_INTENDED_FIXTURE) - .expect("intended fixture"); - let template = sent.routes[0].clone(); - let mut route = template.clone(); - route.id = StableId::parse("ch00-simd1-send").expect("route id"); - route.source = RouteSource::Track { - track_id: StableId::parse("ch00").expect("track id"), - tap: session::SendTap::InsertSend, - }; - sent.routes.push(route); - sent.routes.sort_by(|left, right| left.id.cmp(&right.id)); - - let registry = launch_native_effect_registry().expect("launch registry"); - let artifact = compile_console_model_with_builtins(&sent, 2_040, &[], registry); - let (pcm, transposes, chains, slots, _, redirects, _) = - render_console_builtins_blocks(artifact, BLOCKS, Vec::new()); - assert_eq!( - slots, - STRIP_SLOTS_PER_COHORT * cohorts, - "the send changes no bank's membership" - ); - assert_eq!( - chains, - cohorts + 1, - "ch00's cohort splits at the sent boundary; every other cohort stays one chain" - ); - assert_eq!(transposes, BLOCKS * chains, "G5 on the declining plan"); - let scalar_artifact = compile_console_oracle(&sent, 2_041, &[]); - let (scalar_pcm, ..) = render_console_builtins_blocks(scalar_artifact, BLOCKS, Vec::new()); - assert_pcm_bits_equal(&pcm, &scalar_pcm, "64-track strip with a post-simd1 send"); - assert!( - pcm.iter().flatten().any(|sample| *sample != 0.0), - "the sent strip rendered audio" - ); - // The redirect count is zero for every lane on this fixture since issue #212 -- see - // `the_intended_strip_fuses_the_whole_signal_path_into_one_chain_per_cohort` for why the - // strip's chain now ends in a buffer its consumer already reads in place. What this test - // still says is that a send taken from `PostSimd1` changes nothing at the *far end* of the - // strip: it splits ch00's cohort at the observed boundary, and the scatter accounting on - // every lane, ch00's included, is exactly what it is without the send. - assert_eq!( - redirects, 0, - "a send taken from `PostSimd1` is upstream of the limiter, so it declines the chain \ - merge without touching the scatter accounting at the far end of the strip" - ); - } - /// Mono-collapse M1: the two bank planners classify every track alike, and the proof is the /// thing the merge actually needs -- their banks cover the same lanes in the same order. /// @@ -9223,100 +9084,6 @@ mod tests { ); } - /// A meter on the pre-fader alias splits its cohort's chain there, redirects nothing, and reads - /// the limiter's output. - /// - /// `PostSimd2PreFader` is elided into a `program::Tap` on the limiter's op, so a meter leased - /// there reads the limiter's own buffer. This test was written (issue #202 rec 3) for a - /// `scatter_target` clause that declined a redirect when the last slot's alias was observed, - /// back when the limiter *was* the last slot. Issue #212 made the fader and matrix slots of the - /// same chain, so the alias now sits *inside* it, and the clause that answers is - /// `chains_into`'s observed-alias clause, keyed on the **alias node** -- keying it on the - /// producing node would miss it: nobody observes the limiter, the observer is bound to - /// `ch00/PostSimd2PreFader`. Issue #886 then removed the redirect's observer clauses outright - /// (an observer of a redirected last slot reads the redirected buffer), so no redirect is - /// declined here at all: the split chain's consumer is the fader bank, which the gather-side - /// redirect serves, and every other chain still ends in a buffer its consumer reads in place. - #[test] - fn a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter() { - const BLOCKS: u64 = 12; - let Some(width) = BankWidth::for_backend(host_dispatch()) else { - return; - }; - let cohorts = 64 / width.lanes() as u64; - let intended = parse_session_json(CONSOLE_SIXTY_FOUR_TRACK_INTENDED_FIXTURE) - .expect("intended fixture"); - let meters = vec![MeterRequest { - handle: MeterHandle(NonZeroU64::new(1).expect("constant")), - track_id: "ch00".to_owned(), - tap: MeterTap::PostSimd2PreFader, - config: MeterConfig { - period_frames: NonZeroU32::new(128).expect("constant"), - peak_hold_frames: 0, - peak_decay_db_per_second: 0.0, - queue_capacity: NonZeroUsize::new(64).expect("constant"), - reset_generation: 0, - }, - }]; - let registry = launch_native_effect_registry().expect("launch registry"); - let artifact = compile_console_model_with_builtins(&intended, 2_060, &meters, registry); - let (pcm, transposes, chains, slots, frames, redirects, _) = - render_console_builtins_blocks(artifact, BLOCKS, Vec::new()); - assert_eq!( - slots, - STRIP_SLOTS_PER_COHORT * cohorts, - "the meter changes no bank's membership" - ); - // Issue #212 moved this boundary from the end of the chain to the middle of it. When the - // chain was `builtins -> EQ -> compressor -> limiter`, `PostSimd2PreFader` aliased the - // *last* slot's output and was downstream of every merge, so an observer there declined - // nothing. The fader and the matrix are now slots of the same chain, so that alias sits - // between two of them -- and an observer on it declines the limiter -> fader merge, exactly - // as `chains_into`'s observed-alias clause says it must. - // - // This is the documented cliff, and it is a cost paid only when the observer is there: - // leasing a stage meter at `PostSimd2PreFader` costs that track's cohort one extra - // planar/AoSoA round-trip per block, because its chain can no longer span the stage the - // meter reads. The meter must see pre-fader audio and a merged chain would hand it the - // chain's input, so this is the intended trade -- and both halves of it are pinned here. - assert_eq!( - chains, - cohorts + 1, - "the meter sits on an alias *inside* the chain, so ch00's cohort splits there" - ); - assert_eq!(transposes, BLOCKS * chains); - assert_eq!( - redirects, 0, - "the split chain feeds a banked fader and every other chain ends in a buffer its \ - consumer reads in place, so nothing redirects, metered or not" - ); - - // And the meter reads the limiter's output. The oracle is the same session with every - // effect on the per-node scalar path, where no chain -- and so no redirect -- exists. - let scalar_artifact = compile_console_oracle(&intended, 2_061, &meters); - let (scalar_pcm, _, _, _, scalar_frames, _, _) = - render_console_builtins_blocks(scalar_artifact, BLOCKS, Vec::new()); - assert_pcm_bits_equal( - &pcm, - &scalar_pcm, - "64-track strip with a pre-fader stage meter", - ); - assert!( - !frames.is_empty(), - "the leased meter must publish windows, or this test proves nothing about it" - ); - assert_eq!( - frames, scalar_frames, - "the metered boundary must read the limiter's output, not the previous block's words" - ); - assert!( - frames - .iter() - .any(|frame| frame.left.sample_peak != 0.0 || frame.right.sample_peak != 0.0), - "the metered windows must carry signal" - ); - } - /// A second reader of the last slot's output declines that lane's scatter redirect. /// /// The sole-readership clause, reached the way a session reaches it: a send taken from @@ -9351,8 +9118,8 @@ mod tests { "the send changes no bank's membership" ); // The same boundary move as - // `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter`, through the other - // clause. A send taken from `PostSimd2PreFader` gives ch00's limiter output a second + // `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter` (deleted by TA5), + // through the other clause. A send taken from `PostSimd2PreFader` gives ch00's limiter output a second // reader, and since #212 that alias sits *inside* the chain rather than at its end -- so // `chains_into`'s sole-readership clause declines the limiter -> fader merge and ch00's // cohort splits there. A send from a stage the chain does not span still costs nothing. @@ -9375,78 +9142,6 @@ mod tests { ); } - /// Issue #218: the intended strip folds every route and the whole master reduction into its - /// cohorts' epilogues, and the bits do not move. - /// - /// # Two oracles - /// - /// The standing one is the test-only `Scalar` backend (#1059), where nothing banks, effect or - /// builtin, so it forms no chain and folds no route. Until #1098 it was a registry that put - /// every *effect* on the per-node path while the builtins, fader and matrix still banked and - /// folded all sixty-four routes: an oracle for the effects and not for the fold. A console slot - /// no longer renders per node on a vector backend, so that arm is gone, and its fold count is - /// asserted here as zero rather than assumed. - /// - /// The fold's own oracle is the same session bound with the fold **declined** - /// (`graph::test_only_set_route_fold_declined`). That arm renders the route ops and the D9 - /// reduction the fold replaced, and nothing else about the plan moves, so the two arms differ in - /// exactly the thing under test. Until issue #885 the decline came from a post-matrix meter on - /// ch00; a post-matrix meter now keeps the fold armed - /// (`a_meter_on_the_matrix_keeps_the_route_fold_and_still_meters`), so the decline is explicit. - #[test] - fn the_intended_strip_folds_every_route_into_its_cohorts_epilogue() { - const BLOCKS: u64 = 12; - let Some(width) = BankWidth::for_backend(host_dispatch()) else { - return; - }; - let cohorts = 64 / width.lanes() as u64; - let intended = parse_session_json(CONSOLE_SIXTY_FOUR_TRACK_INTENDED_FIXTURE) - .expect("intended fixture"); - let registry = launch_native_effect_registry().expect("launch registry"); - let artifact = compile_console_model_with_builtins(&intended, 2_180, &[], registry); - let (pcm, transposes, chains, slots, _, _, folds) = - render_console_builtins_blocks(artifact, BLOCKS, Vec::new()); - assert_eq!( - chains, cohorts, - "the whole strip is still one chain per cohort" - ); - assert_eq!(slots, STRIP_SLOTS_PER_COHORT * cohorts); - assert_eq!(transposes, BLOCKS * chains, "G5 is unmoved by the fold"); - assert_eq!( - folds, 64, - "every track's route folds into its cohort's epilogue" - ); - let scalar_artifact = compile_console_oracle(&intended, 2_181, &[]); - let (scalar_pcm, _, _, _, _, _, scalar_folds) = - render_console_builtins_blocks(scalar_artifact, BLOCKS, Vec::new()); - assert_eq!( - scalar_folds, 0, - "the Scalar oracle banks nothing, so it folds nothing" - ); - assert_pcm_bits_equal(&pcm, &scalar_pcm, "64-track strip with the route fold"); - - // The fold's own oracle: the same session, bound with the fold declined. - let unfolded_artifact = - compile_console_model_with_builtins(&intended, 2_188, &[], registry); - graph::test_only_set_route_fold_declined(true); - let (unfolded_pcm, _, _, _, _, _, unfolded_folds) = - render_console_builtins_blocks(unfolded_artifact, BLOCKS, Vec::new()); - graph::test_only_set_route_fold_declined(false); - assert_eq!( - unfolded_folds, 0, - "the declined arm must not fold, or it is not an oracle for it" - ); - assert_pcm_bits_equal( - &pcm, - &unfolded_pcm, - "the folded master against the reduction", - ); - assert!( - pcm.iter().flatten().any(|sample| *sample != 0.0), - "the folded strip rendered audio" - ); - } - /// A second reader of a track's matrix declines the route fold. /// /// The sole-readership clause, reached the way a session reaches it: ch00 is routed to the diff --git a/crates/graph-compiler/tests/MUTATIONS.md b/crates/graph-compiler/tests/MUTATIONS.md index e73e3a687..a25420c2b 100644 --- a/crates/graph-compiler/tests/MUTATIONS.md +++ b/crates/graph-compiler/tests/MUTATIONS.md @@ -366,12 +366,3 @@ deleted or trimmed some tests that rows above name. The rows stay as history; th the owner bytes from `size_of`. It asserts that the three deltas agree, are zero exactly when no instance is controlled, and that the exact caps accept and one byte below refuses. A partial under-charge such as this row's is left to the allocator ceiling in `tests/bypass_resources.rs`. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `direct_graph_report_exposes_zero_output_latency_and_tail_without_identity_change`: no plausible same-crate KEEP catcher recorded -- `dynamic_rack_compressors_bank_and_render_bit_identically_to_the_per_node_path`: no plausible same-crate KEEP catcher recorded -- `console_sixty_four_track_fixture_banks_its_dynamic_compressor_bit_identically`: graph-compiler `tests::add_a_track_keeps_existing_track_bits_and_one_transpose_per_chain` -- `the_estimate_charges_each_lane_its_own_ring`: graph-compiler `track_delay::a_ring_is_a_named_allocation` diff --git a/crates/graph-compiler/tests/bypass_cohorts.rs b/crates/graph-compiler/tests/bypass_cohorts.rs index 4073c8f29..9739c5bd5 100644 --- a/crates/graph-compiler/tests/bypass_cohorts.rs +++ b/crates/graph-compiler/tests/bypass_cohorts.rs @@ -782,55 +782,3 @@ fn a_mixed_bypass_multiband_cohort_keeps_its_prepared_bypass() { "the render is audible" ); } - -/// Issue #1100, gate 3 (#1087 verdict, M2): one bypassed multiband lane fed `6e29` leaves its -/// enabled neighbours' bits unchanged. -/// -/// `6e29` is a legal sample: the input stage passes anything finite below `1e30`. At the -/// multiband's defaults it trips the block-boundary check (D7) of any bank it runs in, and that -/// check zeroes the whole bank. The positive control is #1087's lowering, rebuilt here: there the -/// hot bypassed lane shares a bank with enabled ones and silences them. With the prepared bypass -/// kept, the bypassed instance never shares a bank with an enabled one, and every enabled track -/// renders the same words whatever the bypassed track is fed. -/// -/// Red mutation: drop the multiband from `PREPARED_BYPASS_EFFECTS` -> the enabled neighbours of -/// the hot lane are zeroed. -#[test] -fn a_hot_bypassed_multiband_lane_leaves_its_neighbours_bits_unchanged() { - const TRACKS: usize = 8; - const HOT: u32 = 3; - let model = multiband_console(TRACKS, 1 << HOT); - let neighbours = |rendered: &Rendered| -> BTreeMap<(String, String), Vec> { - rendered - .nodes - .iter() - .filter(|((track, _), _)| track != &format!("ch{HOT:02}")) - .map(|(key, words)| (key.clone(), words.clone())) - .collect() - }; - for lowering in [Lowering::Session, Lowering::P1] { - let quiet = render_with(&model, Backend::current(), lowering, &|_| Feed::Music); - let hot = render_with(&model, Backend::current(), lowering, &|track| { - if track == HOT { Feed::Hot } else { Feed::Music } - }); - let moved = neighbours(&quiet) - .iter() - .zip(neighbours(&hot).iter()) - .filter(|((key, quiet), (_, hot))| { - assert_eq!(quiet.len(), hot.len(), "{key:?}: length"); - folded(quiet) != folded(hot) - }) - .count(); - match lowering { - Lowering::Session => assert_eq!( - moved, 0, - "a hot bypassed multiband lane moved {moved} of its enabled neighbours' taps" - ), - _ => assert!( - moved > 0, - "the positive control: under #1087's lowering the hot lane must reach its \ - bank-mates, or this proves nothing" - ), - } - } -} diff --git a/crates/graph-compiler/tests/bypass_shunt_identity.rs b/crates/graph-compiler/tests/bypass_shunt_identity.rs index 3a46b113c..821ccb826 100644 --- a/crates/graph-compiler/tests/bypass_shunt_identity.rs +++ b/crates/graph-compiler/tests/bypass_shunt_identity.rs @@ -608,181 +608,6 @@ fn a_shunt_bypassed_per_node_instance_is_bit_identical_to_prepared_bypass() { } } -/// Gate 3 with real effects: a live toggle on a session-bypassed banked lane. -/// -/// With live controls attached, the session bypass seeds the lane's live channel -/// (`attach_effect_live_controls` reads `initial_bypass`), so the lane starts bypassed and a live -/// `Bypass(false)` returns the *current* wet signal: its wet path ran all along. The reference is -/// the same lane rendered per node from a prepared-enabled instance and a shunt switched on the -/// same blocks, which is the per-node live path a session-enabled instance has always taken. The -/// limiter carries the longest latency line, so the dry signal after the re-bypass is the delayed -/// one on its first block. -/// -/// Red mutation: the drain leaves `bypass` alone on an `EffectControlRecord::Bypass` record -> -/// lane 1 stays bypassed after block 5 and renders dry where the reference is wet. (That -/// `attach_effect_live_controls` seeds the live lane from the session bypass is pinned in -/// `effect-compiler`'s `native_session` tests.) -#[test] -fn a_live_toggle_on_a_session_bypassed_bank_lane_matches_the_per_node_live_path() { - let registry = launch_native_effect_registry().expect("launch registry"); - let width = width(); - let lanes = width.lanes() as usize; - for effect_id in [ - "miso.true-peak-limiter", - "miso.parametric-eq", - "miso.soft-clip", - ] { - let factory = registry.get_shared_ascii(effect_id).expect("launch effect"); - let descriptor = factory.descriptor(); - let case = cases(descriptor)[0]; - let mut rng = Rng::new(0x1087); - let values: Vec> = (0..lanes) - .map(|_| initial_values(descriptor, &mut rng)) - .collect(); - let requests: Vec> = values - .iter() - .map(|values| request(descriptor, case, false, values)) - .collect(); - let bank = factory - .bind_homogeneous_bank(PrepareEffectBankRequest { - backend: Backend::current(), - width, - requests: &requests, - active_mask: width.full_mask(), - }) - .expect("a well-formed bank request") - .expect("a bankable effect binds at the host width"); - let latency = usize::try_from(bank.metadata.program_key.latency.0).expect("latency fits"); - // Lane 1 is session-bypassed with a live channel; lane 2 is session-bypassed without one. - let (mut producer, live_lane) = effect_control_lane( - EffectLaneSpec { - // A bypass cell alone: this lane's only live value is the shunt switch. - shape: EffectLaneShape::from_live_parameters([], 0), - bypass: true, - observation_depth: 0, - }, - &LiveValuesSuperseded::new(), - ) - .expect("the live lane"); - let (gate, mut pin) = RevisionGate::pair(0); - let mut live_lane = Some(live_lane); - let controls: Vec> = (0..lanes) - .map(|lane| match lane { - 1 => Some(live_lane.take().expect("one live lane")), - 2 => Some(EffectControlLane::without_channel(true)), - _ => None, - }) - .collect(); - let stage = LiveControlEffectBankStage::new( - bank, - width, - QUANTUM, - controls, - (0..lanes).map(|_| None).collect(), - latency, - ) - .expect("stage"); - let mut chain = chain(stage); - // Lane 1's live reference: a prepared-enabled instance and a shunt switched on the same - // blocks. Every other lane's reference is its scalar instance with its session bypass as - // the prepared flag. - let mut live_wet = factory - .prepare(request(descriptor, case, false, &values[1])) - .expect("live reference") - .processor; - let mut live_shunt = effect_contract::BypassShunt::new(QUANTUM as usize, latency); - let mut oracles: Vec> = values - .iter() - .enumerate() - .map(|(lane, values)| { - factory - .prepare(request(descriptor, case, lane == 2, values)) - .expect("scalar oracle") - .processor - }) - .collect(); - let mut signal = Rng::new(0x1087 ^ 0x5eed); - let mut live_bypassed = true; - for block in 0..BLOCKS { - // Un-bypass at block 5 and re-bypass at block 10, each applied at the first sample of - // the block that drains it. - let toggle = match block { - 5 => Some(false), - 10 => Some(true), - _ => None, - }; - if let Some(value) = toggle { - let revision = pin.last_published() + 1; - let stamp = pin.stamp(revision).expect("a legal revision"); - producer - .write( - stamp, - EffectControlRecord::Bypass(effect_contract::BypassSwitch::step(value)), - ) - .expect("a bypass cell"); - pin.publish(&gate, revision); - live_bypassed = value; - } - let mut members = Planes { - left: Vec::new(), - right: Vec::new(), - }; - for lane in 0..lanes { - members - .left - .push(input_block(lane, 0, block, Level::Loud, &mut signal)); - members - .right - .push(input_block(lane, 1, block, Level::Loud, &mut signal)); - } - let mut expected_left = members.left.clone(); - let mut expected_right = members.right.clone(); - chain - .run( - &mut members, - QUANTUM, - block * u64::from(QUANTUM), - gate.snapshot(), - ) - .expect("bank render"); - for lane in 0..lanes { - if lane == 1 { - if live_bypassed || live_shunt.feeds_line() { - live_shunt.capture(&expected_left[lane], &expected_right[lane]); - } - process_scalar( - live_wet.as_mut(), - &mut expected_left[lane], - &mut expected_right[lane], - block, - ); - if live_bypassed { - live_shunt.apply(&mut expected_left[lane], &mut expected_right[lane]); - } - } else { - process_scalar( - oracles[lane].as_mut(), - &mut expected_left[lane], - &mut expected_right[lane], - block, - ); - } - let what = format!("{effect_id} lane {lane} block {block}"); - assert_bits( - &format!("{what} left"), - &members.left[lane], - &expected_left[lane], - ); - assert_bits( - &format!("{what} right"), - &members.right[lane], - &expected_right[lane], - ); - } - } - } -} - /// `NEVER_BANKED_EFFECTS` is exactly the launch effects whose factory declines a well-formed bank /// of default members at the host's width, and every launch effect is in the registry this file /// walks. @@ -827,71 +652,6 @@ fn the_never_banked_list_is_exactly_the_launch_effects_that_decline_a_bank() { assert_eq!(registered, walked, "this file walks every launch effect"); } -/// Why the delay keeps its prepared bypass: a shunt would move a bit. -/// -/// The delay's D7 check reads its feedback ring as well as its output. A 1 ms delay at -/// `0.95` feedback fed `9e29` -- inside the range an effect can receive in a compiled plan -- -/// grows a ring cell past `1e30` within one block, and the check zeroes the block. Under a -/// prepared bypass the zeroed block is the output; a shunt would copy the dry block over it. If -/// this ever renders the same bits, the delay's check no longer reads its state and it may take the -/// shunt like every other effect. -#[test] -fn the_delay_keeps_its_prepared_bypass_because_a_shunt_would_move_a_bit() { - let registry = launch_native_effect_registry().expect("launch registry"); - let factory = registry.get_shared_ascii("miso.delay").expect("the delay"); - let descriptor = factory.descriptor(); - let case = cases(descriptor)[0]; - let by_name = |name: &str| { - descriptor - .parameters - .iter() - .position(|parameter| parameter.display_name == name) - .unwrap_or_else(|| panic!("delay parameter {name}")) as u32 - }; - let mut values = default_values(descriptor); - for (name, value) in [("delay time", 1.0), ("feedback", 0.95), ("damping", 0.0)] { - let index = by_name(name); - for item in values - .iter_mut() - .filter(|item| item.parameter_index == index) - { - item.value = value; - } - } - let mut prepared = factory - .prepare(request(descriptor, case, true, &values)) - .expect("prepared bypass") - .processor; - let mut wet = factory - .prepare(request(descriptor, case, false, &values)) - .expect("prepared enabled") - .processor; - let mut shunt = effect_contract::BypassShunt::new(QUANTUM as usize, 0); - let mut moved = false; - for block in 0..4 { - let mut today = [ - vec![9.0e29_f32; QUANTUM as usize], - vec![9.0e29_f32; QUANTUM as usize], - ]; - let mut shunted = today.clone(); - let [left, right] = &mut today; - process_scalar(prepared.as_mut(), left, right, block); - let [left, right] = &mut shunted; - shunt.capture(left, right); - process_scalar(wet.as_mut(), left, right, block); - shunt.apply(left, right); - moved |= today - .iter() - .flatten() - .zip(shunted.iter().flatten()) - .any(|(a, b)| folded(*a) != folded(*b)); - } - assert!( - moved, - "the delay's prepared bypass and a shunt now agree; it may leave NEVER_BANKED_EFFECTS" - ); -} - // ---- #1341: the bypass crossfade over the session ramp, per node ---------------------------------- /// What a per-node live instance does with its bypass: nothing (W, never bypassed), a session diff --git a/crates/graph/src/program/tests.rs b/crates/graph/src/program/tests.rs index 44189eff2..96c4e5b86 100644 --- a/crates/graph/src/program/tests.rs +++ b/crates/graph/src/program/tests.rs @@ -306,33 +306,6 @@ fn delayed_edge_gets_staging_buffer_and_blocks_in_place() { assert!(delay.staging.0 < program.buffers); } -/// An elided stage is exactly a stage with one undelayed, un-sidechained input: give the same -/// stage a PDC edge and it keeps its op. -#[test] -fn a_delayed_stage_boundary_is_not_elided() { - let (nodes, edges) = plain_track("t", &["r"]); - let (spec, schedule, levels) = build(nodes, edges); - let delayed = InsertedDelay { - node: stage_node("t", TrackStage::PostSimd1), - edge_id: GraphEdgeId::TrackMain { - target: stage_node("t", TrackStage::PostSimd1), - }, - samples: LatencySamples(8), - }; - let program = lower( - &spec, - &schedule, - &levels, - std::slice::from_ref(&delayed), - &[], - ) - .expect("lowers"); - assert_eq!(program.taps.len(), 2); - assert_eq!(program.ops.len(), 7); - let index = node_index(&spec, &stage_node("t", TrackStage::PostSimd1)).expect("node"); - assert!(program.node_op[index as usize].is_some()); -} - /// A dynamic-rack effect is not bank-eligible, so the two stage boundaries after it are pure /// aliases of *its* buffer and the fader downstream still reads that buffer in place. /// diff --git a/crates/graph/src/runtime.rs b/crates/graph/src/runtime.rs index 01b034941..e230c2575 100644 --- a/crates/graph/src/runtime.rs +++ b/crates/graph/src/runtime.rs @@ -10532,7 +10532,7 @@ fn foldable_lane( /// /// * **the association order** -> `route_ids_ordered_against_the_cohorts_decline_the_route_fold`, /// plus `a_leased_stage_meter_declines_the_merge_and_still_meters` and -/// `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter` (named +/// `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter` (deleted by TA5; named /// `an_observed_alias_on_the_last_slot_declines_that_lanes_scatter_redirect` until issue #886, /// the name `crates/graph/tests/MUTATIONS.md` row 218-3 still records). Keeping the length check /// and dropping the element-wise comparison is the unsound direction, and it is the one measured. @@ -12712,82 +12712,6 @@ mod tests { ); } - /// RT-1: real graph arena members gather one buffer set and scatter directly into another. - #[test] - fn arena_members_direct_scatter_preserves_redirected_identity_bits() { - struct Identity; - impl BankStage for Identity { - fn process(&mut self, _block: BankBlock<'_>) -> Result<(), RenderError> { - Ok(()) - } - } - - const FRAMES: usize = 11; - let mut arena = stereo_arena(FRAMES, 8); - let inputs = [1, 2, 3, 4]; - let outputs = [5, 6, 7, 8]; - let mut expected = Vec::new(); - for (lane, input) in inputs.iter().copied().enumerate() { - let left: Vec = (0..FRAMES) - .map(|frame| f32::from_bits(0x7fc0_0000 | ((lane * FRAMES + frame) as u32 + 1))) - .collect(); - let right: Vec = left - .iter() - .map(|word| f32::from_bits(word.to_bits() ^ 0x8000_3990)) - .collect(); - arena.write(0, input).copy_from_slice(&left); - arena.write(1, input).copy_from_slice(&right); - expected.push((left, right)); - } - for output in outputs { - arena.write(0, output).fill(f32::from_bits(0x7f80_3991)); - arena.write(1, output).fill(f32::from_bits(0x7f80_3992)); - } - - let active = vec![true; 4].into_boxed_slice(); - let mut chain = BankChain::new( - AoSoaScratch::new(BankWidth::Four, FRAMES as u32).expect("scratch"), - active.clone(), - vec![BankSlot { - stage: Box::new(Identity), - active_lanes: active, - }], - ) - .expect("chain"); - let mut members = ArenaMembers { - arena: &mut arena, - inputs: &inputs, - outputs: &outputs, - fold: &[], - master: MasterPlanes::Arena(0), - sources: SourceGather::NONE, - }; - chain - .run(&mut members, FRAMES as u32, 0, LiveSnapshot::ALL) - .expect("direct graph run"); - - for (lane, output) in outputs.iter().copied().enumerate() { - let (left, right) = arena.read_stereo(output); - assert_eq!( - left.iter().map(|word| word.to_bits()).collect::>(), - expected[lane] - .0 - .iter() - .map(|word| word.to_bits()) - .collect::>() - ); - assert_eq!( - right.iter().map(|word| word.to_bits()).collect::>(), - expected[lane] - .1 - .iter() - .map(|word| word.to_bits()) - .collect::>() - ); - } - assert_eq!(chain.transposes(), 1); - } - /// The folded epilogue is the route op followed by the D9 reduction, word for word. /// /// The oracle is the shape this replaces, built out of the very kernels the route op and @@ -14031,86 +13955,6 @@ mod tests { assert_ne!(right, twin_right); } - /// E10. The route is two multiplies plus one add per output word, with the gain - /// folded into the coefficients at bind (D3). The oracle is - /// `softfma::unfused_multiply_add_via_f64`, which computes the same multiply-add through `f64` with - /// no dependence on `mix2x2_block`'s vector body; the exact product and the innocuous double - /// rounding of the sum make it bit-identical to the `f32` expression (issue #163 phase 2). - /// - /// Red mutation (`tests/MUTATIONS.md`): compute `gain * (ll * l + lr * r)` instead. - #[test] - fn route_applies_folded_gain_with_frozen_op_order() { - const FRAMES: usize = 4_096; - let transform = (0.707_9f32, 0.9f32, -0.1f32, 0.2f32, 0.8f32); - let folded = [ - transform.0 * transform.1, - transform.0 * transform.2, - transform.0 * transform.3, - transform.0 * transform.4, - ]; - let mut state = 0x1234_5678u32; - let left_in: Vec = (0..FRAMES).map(|_| lcg(&mut state)).collect(); - let right_in: Vec = (0..FRAMES).map(|_| lcg(&mut state)).collect(); - let mut left = left_in.clone(); - let mut right = right_in.clone(); - mix2x2_block::(&mut left, &mut right, folded); - for frame in 0..FRAMES { - let (l, r) = (left_in[frame], right_in[frame]); - let expected_left = - lane::softfma::unfused_multiply_add_via_f64(folded[1], r, folded[0] * l); - let expected_right = - lane::softfma::unfused_multiply_add_via_f64(folded[3], r, folded[2] * l); - assert_eq!( - left[frame].to_bits(), - expected_left.to_bits(), - "frame {frame} left" - ); - assert_eq!( - right[frame].to_bits(), - expected_right.to_bits(), - "frame {frame} right" - ); - } - // Block lengths that are not a multiple of the lane width, so the scalar tail is walked - // and has to agree with the vector body word for word. - for block in [1usize, 3, 7, 63, 65, 129, 511] { - let mut tail_left = left_in[..block].to_vec(); - let mut tail_right = right_in[..block].to_vec(); - mix2x2_block::(&mut tail_left, &mut tail_right, folded); - assert_eq!( - ( - tail_left.iter().map(|s| s.to_bits()).collect::>(), - tail_right.iter().map(|s| s.to_bits()).collect::>() - ), - ( - left[..block] - .iter() - .map(|s| s.to_bits()) - .collect::>(), - right[..block] - .iter() - .map(|s| s.to_bits()) - .collect::>() - ), - "block {block}: the scalar tail must match the vector body" - ); - } - // The fold is not the unfolded form: this is the bit change #98 F4 declares. - let unfolded: Vec = (0..FRAMES) - .map(|frame| { - (transform.0 * (transform.1 * left_in[frame] + transform.2 * right_in[frame])) - .to_bits() - }) - .collect(); - assert_ne!( - left.iter() - .map(|sample| sample.to_bits()) - .collect::>(), - unfolded, - "the folded route is a distinct rounding, not a coincidence" - ); - } - // ----------------------------------------------------------------------------------------- // Issue #885: the route fold stays armed when every track carries a post-matrix meter. // ----------------------------------------------------------------------------------------- diff --git a/crates/graph/tests/MUTATIONS.md b/crates/graph/tests/MUTATIONS.md index eb8b2c944..1d35fc554 100644 --- a/crates/graph/tests/MUTATIONS.md +++ b/crates/graph/tests/MUTATIONS.md @@ -22,8 +22,8 @@ cargo test --locked -p --lib | M15 | fan-in 0 leaves the output buffer untouched instead of zeroing it | `src/runtime.rs` `reduce_plane` | `reduction_is_left_to_right_bit_identical_to_scalar_reference` | RED | | M3 | the slice PDC keeps the block's entry cursor instead of advancing it | `src/runtime.rs` `CompensationDelay::process` | `compensation_delay_is_partition_invariant_and_matches_per_sample_reference` | RED | | M12 | the slice PDC exchanges its two segments in the wrong order | `lane` `kernels::pdc_delay_block` | `compensation_delay_is_partition_invariant_and_matches_per_sample_reference` | RED | -| M4 | the route unfolds the gain and drops the fusion (`ll*l + lr*r`) | `lane` `kernels::mix2x2_block` | `route_applies_folded_gain_with_frozen_op_order` | RED | -| M9 | `mix2x2_block`'s scalar tail uses a different coefficient order than its vector body | `lane` `kernels::mix2x2_block` | `route_applies_folded_gain_with_frozen_op_order` | RED | +| M4 | the route unfolds the gain and drops the fusion (`ll*l + lr*r`) | `lane` `kernels::mix2x2_block` | `route_applies_folded_gain_with_frozen_op_order` (deleted by TA5; no catcher recorded) | RED | +| M9 | `mix2x2_block`'s scalar tail uses a different coefficient order than its vector body | `lane` `kernels::mix2x2_block` | `route_applies_folded_gain_with_frozen_op_order` (deleted by TA5; no catcher recorded) | RED | | M5 | the native executor stages an edge from the wrong producer | `src/runtime.rs` `build_native` | `fifty_random_dag_sessions_render_bit_identically_in_both_executors` | RED | | M6 | the sequential executor reduces before staging its delayed edges | `src/runtime.rs` `execute_op` | `fifty_random_dag_sessions_render_bit_identically_in_both_executors` | RED | | M8 | a bank member's inputs are gathered without their reduction | `src/runtime.rs` `Runtime::execute` | `level_major_w4_builtin_bank_is_analytic_for_three_blocks_in_both_executors` | RED | @@ -100,7 +100,7 @@ mutation at a time over `cargo test -p graph -p graph-compiler |---|---|---|---|---| | 218-1 | the first contributor accumulates instead of storing (`copy_from_slice` becomes `sum_into_block`) | `graph/src/runtime.rs` `ArenaMembers::fold_plane` | `runtime::tests::the_first_contributor_stores_so_a_negative_zero_master_keeps_its_sign` | RED (`+0.0` where `-0.0` is required; bits 0 against 0x8000_0000) | | 218-2 | the fan-in-zero fill is skipped for *every* kind, not only a bound source | `graph/src/runtime.rs` `execute_op` | `runtime::tests::the_fan_in_zero_fill_is_dead_only_under_a_bound_source` | RED (an identity node with no contributors renders the previous block instead of silence) | -| 218-3 | the association proof keeps its length check and drops the element-wise comparison | `graph/src/runtime.rs` `route_fold` | `route_ids_ordered_against_the_cohorts_decline_the_route_fold` | RED, plus `a_leased_stage_meter_declines_the_merge_and_still_meters` and `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter` | +| 218-3 | the association proof keeps its length check and drops the element-wise comparison | `graph/src/runtime.rs` `route_fold` | `route_ids_ordered_against_the_cohorts_decline_the_route_fold` | RED, plus `a_leased_stage_meter_declines_the_merge_and_still_meters` and `a_pre_fader_meter_splits_its_cohorts_chain_and_reads_the_limiter` (deleted by TA5; no catcher recorded) | | 218-4 | the observer clause is dropped from `foldable_lane` | `graph/src/runtime.rs` | `runtime::tests::a_post_matrix_meter_on_every_track_of_a_full_bank_keeps_the_fold_armed` | RED (a meter at `PostFader` no longer declines the fold). Re-run for #885: the original catcher, `the_folded_master_is_the_reductions_own_bits`, relied on a post-matrix meter declining the fold, a premise #885 removed; it now stays GREEN under this mutation. | | 218-5 | the opening chain's own ops are no longer excluded from the in-between master scan | `graph/src/runtime.rs` `route_fold` | `every_standing_workload_folds_one_route_per_track` | RED (nothing folds at all: the session output's colour is track zero's input slot) | | 218-6 | sole readership of a chain's last slot is dropped (`len() != 1` becomes `is_empty()`) | `graph/src/runtime.rs` `foldable_lane` | — | **GREEN.** Reported rather than dressed up: the clause is real but shadowed. A second route from the same tap adds a summand the master's input list carries, so the association proof declines on length first; a sidechain from that tap is read by an op scheduled before the route, so `readers[producer][0]` is not a route and the plain-route clause declines instead. | @@ -702,7 +702,7 @@ host-core/test-support,graph/test-support --test route_mute`); gate 4 is | 1217-4 | an inactive sole input leaves the destination's in-place buffer alone (the `+0.0` store only when `count > 1`) | `graph/src/runtime.rs` `route_segments` | gate 1, in place | RED, 1 of 7: `the muted sole route's bus: plane 0 frame 0: -0.15693776, expected 0.0` -- the raw `post_pan` tap. | | 1217-5 | an active opening run is fill-`+0.0`-then-add instead of today's reduction | `graph/src/runtime.rs` `reduce_gated` | gates 1 and 2 | RED: `r0 open at -0.0, r1 and r2 muted: plane 0 frame 0: 0.0, expected -0.0`; `seed 2, Bus, r1 muted, plane 0: sample 0: 0.0 != -0.0`. | | 1217-6 | the host-master form's later run stores instead of adding | `graph/src/runtime.rs` `reduce_gated_into` | gate 1 | RED, 1 of 7: `seed 0, Output, r0 muted, plane 0: sample 0: -0.0 != 0.0`. | -| 1217-7 | a delayed muted route goes inactive (`&& input.delay.is_none()` dropped) | `graph/src/runtime.rs` `route_activity` | gate 3 | Attempt 1: RED, 1 of 7, by the counter only (`a_muted_delayed_route_stays_active`, 0 mixes against 8). Attempt 2: also RED **on audio**, `a_muted_delayed_routes_line_carries_its_zero_mix` (`plane 0: e's input, d-e's delayed zero mix alone: sample 486: 0.0 != -0.0`), and #1218's `a_fully_follow_muted_delayed_send_stays_active` by its counter. | +| 1217-7 | a delayed muted route goes inactive (`&& input.delay.is_none()` dropped) | `graph/src/runtime.rs` `route_activity` | gate 3 | Attempt 1: RED, 1 of 7, by the counter only (`a_muted_delayed_route_stays_active`, 0 mixes against 8). Attempt 2: also RED **on audio**, `a_muted_delayed_routes_line_carries_its_zero_mix` (`plane 0: e's input, d-e's delayed zero mix alone: sample 486: 0.0 != -0.0`), and #1218's `a_fully_follow_muted_delayed_send_stays_active` (deleted by TA5; no catcher recorded) by its counter. | | 1217-8 | a route destination copies its route inputs to a `Vec` per block | `graph/src/runtime.rs` `execute_op` | gate 5 | RED: `route_activity_renders_without_allocating` aborts (`SIGABRT`) on the armed render audit. | | 1217-9 | bind builds the table whatever the gates | `graph/src/runtime.rs` `build_sequential`, `route_activity` | gate 4 | RED: `a plan without a silencing route builds no route-activity table`. | | 1217-10 | the estimate charges no table | `graph-compiler/src/estimate.rs` `resource_estimate` | gate 4 | RED: `graph_metadata_bytes grew by 0, the bound plan by 237`. | @@ -759,10 +759,3 @@ deleted the last three builtins-compiler scalar-oracle pairing tests. The rows s - 916-16 and 916-17: `actual_scalar_nonadjacent_failed_render_materializes_post_fader_before_error` and `actual_scalar_nonadjacent_ramp_retarget_and_failed_retry_stay_at_original_boundaries` are deleted. The allocation_tracker tests these rows name remain. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `the_driver_fed_gain_pan_row_dispatches_every_unit_but_its_inputs`: no plausible same-crate KEEP catcher recorded -- `a_muted_route_seals_one_route_mute_row_after_its_transform`: no plausible same-crate KEEP catcher recorded diff --git a/crates/host-core/src/control_provider.rs b/crates/host-core/src/control_provider.rs index ad200c9a5..c8b8be76c 100644 --- a/crates/host-core/src/control_provider.rs +++ b/crates/host-core/src/control_provider.rs @@ -3091,115 +3091,6 @@ mod tests { ); } - /// #1650b gate 5 (the catalog). A left-lane fader entry on `eq0` with a `+2.5` dB hand - /// offset lists `eq0`'s left `fader_db` row `automated` with the offset as its value, and the - /// right row (no entry drives it) not `automated`, at its static value. A hand move (the offset - /// moved) keeps the epoch; adding the entry and removing it each advance it, and a client's - /// old epoch is then stale. - /// - /// Test value: red if a client cannot tell that its write on an automated lane is an offset - /// (no flag, or the static value listed), or if the flag can change under a held epoch. - #[test] - fn an_automated_fader_lane_lists_its_offset_and_the_flag_is_a_descriptor() { - let plain = nine_track(); - let (mut provider, _clock) = provider_of(&plain); - let left = fader_address(&plain, "eq0"); - let mut automated = plain.clone(); - automated.automation.push(session::Automation { - id: session::StableId::parse("eq0-ride").expect("ID"), - target: left.clone(), - segments: vec![session::AutomationSegment { - shape: session::AutomationShape::Linear, - start_sample: 0, - end_sample: 4_800, - start_value: 0.0, - end_value: -6.0, - unit: session::ParameterUnit::Db, - }], - offset: session::AutomationOffset { - left_db: 2.5, - right_db: 0.0, - }, - }); - let rows = |provider: &mut SessionControlProvider| { - whole_list(provider, 256) - .into_iter() - .filter(|entry| { - entry.address.owner_id.as_deref() == Some("eq0") - && entry.address.section == ControlSection::Builtins - && entry.address.control == Some(left.control) - }) - .map(|entry| match entry.body { - ControlBody::Control(row) => (entry.address.lane, row.value, row.automated), - _ => unreachable!("a control row"), - }) - .collect::>() - }; - let static_db = [ - plain.tracks[0].fader.left_db, - plain.tracks[0].fader.right_db, - ]; - assert_eq!( - rows(&mut provider), - vec![ - (Some(ParameterChannel::Left), static_db[0], false), - (Some(ParameterChannel::Right), static_db[1], false), - ] - ); - provider.replace_session_catalog( - ControlCatalog::build(&automated, &MonitorOverlay::default(), RATE).expect("catalog"), - 2, - ); - assert_eq!( - provider.structure_epoch(), - 2, - "the flag is a descriptor field" - ); - assert_eq!( - rows(&mut provider), - vec![ - (Some(ParameterChannel::Left), 2.5, true), - (Some(ParameterChannel::Right), static_db[1], false), - ] - ); - // A hand move writes the offset, a value: the epoch holds. - controls::set(&mut automated, &left, -1.5, None, RATE).expect("a hand move"); - assert_eq!( - automated.automation[0].offset.left_db.to_bits(), - (-1.5_f32).to_bits() - ); - assert_eq!( - automated.tracks[0].fader.left_db.to_bits(), - static_db[0].to_bits(), - "the static fader is the lane's fallback" - ); - provider.replace_session_catalog( - ControlCatalog::build(&automated, &MonitorOverlay::default(), RATE).expect("catalog"), - 3, - ); - assert_eq!(provider.structure_epoch(), 2, "a hand move is a value"); - assert_eq!( - rows(&mut provider)[0], - (Some(ParameterChannel::Left), -1.5, true) - ); - provider.replace_session_catalog( - ControlCatalog::build(&plain, &MonitorOverlay::default(), RATE).expect("catalog"), - 4, - ); - assert_eq!(provider.structure_epoch(), 3, "the entry removed"); - assert_eq!( - provider - .control_list(&ControlListRequest { - structure_epoch: 2, - after_handle: 0, - limit: 1, - owner: None, - }) - .err(), - Some(ParameterProviderError::Stale) - ); - } - #[test] fn a_commit_refreshes_values_and_only_a_changed_address_sequence_advances_the_epoch() { let mut model = nine_track(); diff --git a/crates/host-core/src/prepare.rs b/crates/host-core/src/prepare.rs index 23d145d32..b71c080ea 100644 --- a/crates/host-core/src/prepare.rs +++ b/crates/host-core/src/prepare.rs @@ -7455,25 +7455,6 @@ mod tests { ); } - fn instance(effect_id: &str, bypass: bool, threshold: f32) -> session::Effect { - session::Effect { - id: session::StableId::parse("fx").expect("stable id"), - identity: session::EffectIdentity::Native { - effect_id: session::StableId::parse(effect_id).expect("effect id"), - }, - quality: session::EffectQuality::Normal, - bypass, - link_mode: session::LinkMode::DualMono, - params: vec![session::EffectParam { - parameter_id: 1, - channel: session::ParameterChannel::Both, - unit: session::ParameterUnit::Db, - value: threshold, - }], - sidechain: session::SidechainDeclaration::None, - } - } - /// The carry program is built only when some owner may carry, and the effect carry refuses a /// plan without one (`NoEffectCarryProgram`). A strip whose only non-prepared owner is a /// surviving insert must therefore say it may carry; a join that looked at the console slots @@ -7498,52 +7479,6 @@ mod tests { assert!(!chain(super::FamilyJoin::Prepared).may_carry()); } - /// #1280 D1: the one per-instance function says which difference is live. A compressor's - /// bypass and `Block`-rate threshold are live records (the bypass first, with the session's - /// ramp); the delay's bypass is a rebuild-only row, so the join must count it prepared. A join - /// that took any bypass for live would retarget a prepared bypass into a cell the lane lacks. - #[test] - fn the_per_instance_function_separates_live_from_prepared() { - let ramps = controls::LiveRamps::for_session( - &parse_session_json(include_str!("../../../fixtures/session/v1/canonical.json")) - .expect("fixture"), - ); - let records = |before: &session::Effect, after: &session::Effect| { - super::effect_instance_records(before, after, 48_000, ramps) - }; - let compressor = |bypass, threshold| instance("miso.compressor", bypass, threshold); - assert_eq!( - records(&compressor(false, -10.0), &compressor(false, -10.0)), - Ok(None) - ); - let live = records(&compressor(false, -10.0), &compressor(true, -20.0)) - .expect("live") - .expect("records"); - assert_eq!( - live.records.len(), - 3, - "the bypass, then the threshold on both lanes" - ); - assert_eq!( - live.records[0], - effect_contract::EffectControlRecord::Bypass(effect_contract::BypassSwitch { - bypassed: true, - ramp_samples: ramps.for_row(super::LiveRampRow::BypassCrossfade), - }) - ); - assert!( - records( - &instance("miso.delay", false, 0.0), - &instance("miso.delay", true, 0.0) - ) - .is_err(), - "the delay's bypass is prepared" - ); - let mut other = compressor(false, -10.0); - other.quality = session::EffectQuality::High; - assert!(records(&compressor(false, -10.0), &other).is_err()); - } - #[test] fn typed_diagnostic_adapters_preserve_projection_and_bound() { let effects = EffectDiagnosticSet(vec![ diff --git a/crates/host-core/src/spectrum.rs b/crates/host-core/src/spectrum.rs index 81579d24c..afa7be0eb 100644 --- a/crates/host-core/src/spectrum.rs +++ b/crates/host-core/src/spectrum.rs @@ -3274,39 +3274,6 @@ mod tests { (observer, capture) } - /// #1395 D3: only a named pair of captures of one key exchange places; the successor's capture - /// then holds the state the predecessor's held, and nothing else swaps. - #[test] - fn pair_carried_swaps_only_a_named_pair_of_one_key() { - let pair = [super::SpectrumPair { - successor: 0, - predecessor: 0, - }]; - let started = |channels| { - let (_observer, mut capture) = continuous_pair(channels); - capture.start_continuous(48_000, 128).expect("start"); - capture - }; - // A named pair of one key: the successor's fresh capture takes the running stream. - let (_observer, mut next) = continuous_pair(SpectrumChannels::Stereo); - let mut before = started(SpectrumChannels::Stereo); - assert!(next.pair_carried(&mut before, &pair)); - assert_eq!(next.stream_epoch(), Some(1)); - assert_eq!(before.stream_epoch(), None); - // An empty list names nothing. - let (_observer, mut next) = continuous_pair(SpectrumChannels::Stereo); - let mut before = started(SpectrumChannels::Stereo); - assert!(!next.pair_carried(&mut before, &[])); - assert_eq!(next.stream_epoch(), None); - assert_eq!(before.stream_epoch(), Some(1)); - // A list that names captures of another channel mask is a fault, never a pairing. - let (_observer, mut next) = continuous_pair(SpectrumChannels::Left); - let mut before = started(SpectrumChannels::Stereo); - assert!(!next.pair_carried(&mut before, &pair)); - assert_eq!(before.channels(), SpectrumChannels::Stereo); - assert_eq!(before.stream_epoch(), Some(1)); - } - /// Three captures of distinct keys with their observers, as a collection holds them. fn collection_of( keys: &[(&str, SpectrumChannels)], @@ -3572,24 +3539,6 @@ mod tests { assert_eq!(left[0], SPECTRUM_FLOOR_DB); } - #[test] - fn analyzer_calibrates_a_half_amplitude_at_minus_six_dbfs() { - let analyzer = SpectrumAnalyzer::new(); - let mut frequencies = [0.0; SPECTRUM_BIN_COUNT]; - let mut left = [0.0; SPECTRUM_BIN_COUNT]; - let mut right = [0.0; SPECTRUM_BIN_COUNT]; - let mut output = super::SpectrumOutput { - frequencies_hz: &mut frequencies, - left_dbfs: Some(&mut left), - right_dbfs: Some(&mut right), - }; - analyzer - .analyze(&window(0.5), 48_000, &mut output) - .expect("half-amplitude window analyzes"); - assert!((left[0] + 6.0206).abs() < 0.01, "DC dBFS: {}", left[0]); - assert!((right[0] + 6.0206).abs() < 0.01, "DC dBFS: {}", right[0]); - } - #[test] fn analyzer_matches_independent_dft_at_selected_bins_for_launch_rates() { let analyzer = SpectrumAnalyzer::new(); diff --git a/crates/host-core/tests/browser_successor.rs b/crates/host-core/tests/browser_successor.rs index 09dbb11a5..b056811d9 100644 --- a/crates/host-core/tests/browser_successor.rs +++ b/crates/host-core/tests/browser_successor.rs @@ -107,14 +107,6 @@ fn session_b() -> SessionModel { model } -/// A without track `eq1` and its route. -fn session_without_eq1() -> SessionModel { - let mut model = session_a(); - model.tracks.retain(|track| track.id.as_str() != "eq1"); - model.routes.retain(|route| route.id.as_str() != "eq1-main"); - model -} - #[derive(Clone, Copy, Debug)] enum Branch { Single, @@ -506,38 +498,6 @@ fn the_concurrent_selected_meter_entry_forms_no_fused_bank_and_renders_the_same_ ); } -/// Gate 4. A successor whose capture target the new session removed is refused with the typed -/// `host.spectrum.target` diagnostic, on both branches, rather than prepared without its capture. -/// -/// Red if the successor path stops checking the capture target against the new session (the -/// preparation succeeds and a capture handle with no strip is handed to the host), or reports it -/// under another code. The base is borrowed (`&inventory`), so a refusal cannot move the -/// predecessor's state; this test claims nothing about the predecessor. -#[test] -fn a_successor_without_its_spectrum_target_is_refused_with_the_typed_diagnostic() { - let a = Session::compile(session_a()); - let b = Session::compile(session_without_eq1()); - for branch in [Branch::Single, Branch::Collection] { - // The capture targets track `eq1`, which B removed. - let (predecessor, _kept) = prepare(branch, &a, "eq1", None) - .unwrap_or_else(|failure| panic!("{branch:?} predecessor: {failure:?}")); - let edit_ramps = EditRamps::new(); - let refused = prepare( - branch, - &b, - "eq1", - Some(base(&predecessor.inventory, &a.model, &edit_ramps)), - ) - .err() - .unwrap_or_else(|| panic!("{branch:?}: the missing target was accepted")); - assert!( - String::from_utf8_lossy(refused.as_bytes()).contains("host.spectrum.target"), - "{branch:?}: {}", - String::from_utf8_lossy(refused.as_bytes()) - ); - } -} - /// Gate 5. Red if the swap block of a spectrum plan allocates or frees on render. #[test] fn the_spectrum_swap_block_allocates_and_frees_nothing() { diff --git a/crates/host-core/tests/collapse_arming.rs b/crates/host-core/tests/collapse_arming.rs index 32e1edef2..f946d2c29 100644 --- a/crates/host-core/tests/collapse_arming.rs +++ b/crates/host-core/tests/collapse_arming.rs @@ -554,15 +554,6 @@ fn a_live_left_only_polarity_write_on_misaligned_cohorts_renders_the_dual_bits() }); } -#[test] -fn a_live_left_only_trim_write_on_misaligned_cohorts_renders_the_dual_bits() { - assert_live_left_only_write(TrackInputRecord::TrimDb { - lanes: BuiltinLaneSelector::Left, - db: -6.0, - smoothing_samples: 0, - }); -} - // --------------------------------------------------------------------------------------------- // The controls: they pass under both rules, and they keep the fix from disarming too much. // --------------------------------------------------------------------------------------------- diff --git a/crates/host-core/tests/input_liveness_live_controls.rs b/crates/host-core/tests/input_liveness_live_controls.rs index 30b69c166..4cf9cb212 100644 --- a/crates/host-core/tests/input_liveness_live_controls.rs +++ b/crates/host-core/tests/input_liveness_live_controls.rs @@ -334,60 +334,6 @@ fn a_command_moves_exactly_the_addressed_track() { } } -/// Two tracks commanded to different values do not swap. -/// -/// The sharpest form of the lane-index test: a transposing drain renders the same *mix* either -/// way, so the two arms are compared per track. -#[test] -fn two_commands_are_not_interchangeable() { - let session = mono_session(); - let build = |first: usize, second: usize| { - let mut host = prepare_with_live_controls(&session); - push( - &mut host, - first, - TrackInputRecord::TrimDb { - lanes: BuiltinLaneSelector::Both, - db: -144.0, - smoothing_samples: 0, - }, - ); - push( - &mut host, - second, - TrackInputRecord::PolarityInvert { - lanes: BuiltinLaneSelector::Both, - inverted: true, - smoothing_samples: 0, - }, - ); - let _ = render(&mut host, 4); - peaks(&host).clone() - }; - let forward = build(0, 5); - let reversed = build(5, 0); - let names: Vec = forward.keys().cloned().collect(); - assert_ne!( - forward[&names[0]], reversed[&names[0]], - "silencing track {} is not the same as flipping it", - names[0] - ); - assert_ne!( - forward[&names[5]], reversed[&names[5]], - "and the same holds for track {}", - names[5] - ); - // The six tracks nobody addressed are identical in both arms, which is what says the two - // commands went where they were addressed rather than somewhere else consistently. - for index in [1_usize, 2, 3, 4, 6, 7] { - assert_eq!( - forward[&names[index]], reversed[&names[index]], - "track {} was addressed by neither arm", - names[index] - ); - } -} - /// A command takes effect on the **first sample of the block that drains it**. /// /// The drain contract every live-control gate in the tree rests on. With a zero-length window the @@ -727,73 +673,6 @@ fn a_per_lane_record_drained_on_the_disengaging_block_reaches_one_channel() { } } -/// The same window, then put back: re-equalising the two channels neither re-engages the collapse -/// nor moves the bits away from the never-collapsed oracle. -/// -/// The `LIVE` latch and the disengage window interact here, and the interaction is the one that -/// makes the fix's narrower restore rule safe: after the disengage the right channel's ramp record -/// is whatever live controls addressed to it, which is *nothing yet*, and the second record is what -/// puts it where the first put the left one. A copy at the boundary would have made the second -/// record a no-op and hidden the whole episode. -#[test] -fn re_equalising_after_a_disengaging_drain_holds_the_never_collapsed_bits() { - let mut mono = prepare_with_live_controls(&mono_session()); - let mut stereo = prepare_with_live_controls(SESSION); - let _ = render(&mut mono, 2); - let _ = render(&mut stereo, 2); - // One cohort at the eight-lane launch width, two on a four-lane (AArch64 NEON) build (#1017): - // every cohort collapses on both blocks. - let cohorts = (TRACKS / lane::Backend::current().width()) as u64; - let engaged = collapses(&mono)[0]; - assert_eq!( - engaged, - 2 * cohorts, - "every cohort collapses before the ride" - ); - - for host in [&mut mono, &mut stereo] { - push( - host, - 2, - TrackInputRecord::TrimDb { - lanes: BuiltinLaneSelector::Left, - db: -12.0, - smoothing_samples: 64, - }, - ); - } - assert_eq!( - render(&mut mono, 2), - render(&mut stereo, 2), - "the asymmetric episode diverged" - ); - - for host in [&mut mono, &mut stereo] { - push( - host, - 2, - TrackInputRecord::TrimDb { - lanes: BuiltinLaneSelector::Right, - db: -12.0, - smoothing_samples: 64, - }, - ); - } - assert_eq!( - render(&mut mono, 6), - render(&mut stereo, 6), - "the re-equalised episode diverged" - ); - assert_eq!(peaks(&mono), peaks(&stereo), "per-track meters diverged"); - // Only the cohorts track 2 is not in keep collapsing, on each of the eight blocks since. - assert_eq!( - collapses(&mono)[0], - engaged + (cohorts - 1) * 8, - "the ridden chain must not have collapsed again: `LIVE` is a latch, and re-equal words \ - alone do not re-arm it" - ); -} - /// A **symmetric** record drained on a collapsed block does not disengage, and still renders the /// never-collapsed bits. /// diff --git a/crates/host-core/tests/live_delta.rs b/crates/host-core/tests/live_delta.rs index 1cbe967c9..5bb40c3f0 100644 --- a/crates/host-core/tests/live_delta.rs +++ b/crates/host-core/tests/live_delta.rs @@ -1979,64 +1979,6 @@ fn ramps_of_a_move_with( [fader, muted, matrix.smoothing_samples] } -/// #1365 gate 5. Red if the classifier treats `control_smoothing` as structure, or reads the -/// pre-commit lengths for the records of the same transaction: setting, changing and clearing the -/// key are each live, and a fader move beside them carries the lengths of `next`. -#[test] -fn a_control_smoothing_edit_is_live_and_its_lengths_govern_the_same_transactions_records() { - use BuiltinLaneSelector::Left; - let slow = ControlSmoothing { - mute_ms: 5.0, - fader_ms: 15.0, - pan_ms: 25.0, - }; - let fast = ControlSmoothing { - mute_ms: 0.0, - fader_ms: 1.0, - pan_ms: 2.0, - }; - let base = two_tracks(); - // (before, after, the FaderDb length of `after` at 48 kHz). - for (before, after, fader_samples) in [ - (None, Some(slow), 720), - (Some(slow), Some(fast), 48), - (Some(slow), None, 960), - (None, Some(fast), 48), - ] { - let current = with_smoothing(&base, before); - let alone = edited(¤t, |next| next.control_smoothing = after); - let delta = classify_live_delta( - ¤t, - &alone, - LiveRamps::for_session(&alone), - &EditRamps::new(), - ) - .expect("live"); - assert!(delta.strips.is_empty(), "{before:?} -> {after:?}"); - - let moved = edited(¤t, |next| { - next.control_smoothing = after; - next.tracks[0].fader.left_db = -6.0; - }); - let delta = classify_live_delta( - ¤t, - &moved, - LiveRamps::for_session(&moved), - &EditRamps::new(), - ) - .expect("live"); - assert_eq!( - flatten(&delta), - vec![( - track_id(¤t, 0), - vec![fader_db(Left, -6.0, fader_samples)], - None - )], - "{before:?} -> {after:?}" - ); - } -} - /// Gate 3. Red if the classifier keeps a pan window of 0, ignores the session for one row, or maps /// a row to the wrong key: the session's `control_smoothing` (or the default table) is what the /// fader, mute and matrix records carry at 48 kHz, and a pan's own non-zero window still wins. @@ -2867,37 +2809,6 @@ fn filter_records_are_the_preparers_targets_for_the_changed_values() { assert_eq!(case(steady, steady), Ok(Vec::new())); } -/// #1556 D4. Red if a cutoff the filter domain refuses is acked live: above Nyquist, non-finite, -/// below the rate-keyed minimum, or an HPF at or above the LPF. -#[test] -fn filter_values_the_domain_refuses_need_a_rebuild() { - let current = with_filters((0.0, 0.0), (0.0, 0.0)); - let nyquist = current.sample_rate_hz as f32 / 2.0; - for (hpf, lpf) in [ - (nyquist, 0.0), - (f32::NAN, 0.0), - (0.0, f32::INFINITY), - (5.0, 0.0), - (-1.0, 0.0), - (1_000.0, 1_000.0), - (2_000.0, 1_000.0), - ] { - assert_eq!( - classify_input(¤t, |next| set_filters(next, (hpf, lpf), (0.0, 0.0))), - Err(LiveRebuild::Domain), - "{hpf} {lpf}" - ); - } - assert!( - classify_input(¤t, |next| set_filters( - next, - (80.0, 8_000.0), - (10.0, 0.0) - )) - .is_ok() - ); -} - /// #1556 D2. Red if the records of one strip are not trims, then polarities, then filter targets, /// each left before right, or if a track's input values reach another strip. #[test] @@ -3432,26 +3343,6 @@ fn an_eq_hpf_enable_change_carries_targets() { assert_eq!(targets, Some(expected)); } -/// #1265 gate 1(d). Red if the classifier admits an EQ value preparation refuses (a Q above its -/// domain), so that a live commit would leave a committed model its own rebuild refuses. -#[test] -fn an_out_of_domain_eq_q_needs_a_rebuild() { - let current = with_shaped_eq(); - assert_eq!( - eq_entry(¤t, |next| { - inserts(next, 2).push(param(5, ParameterChannel::Left, ParameterUnit::Ratio, 18.5)); - }), - Err(LiveRebuild::Domain) - ); - // The domain's own bound is live. - assert!( - eq_entry(¤t, |next| { - inserts(next, 2).push(param(5, ParameterChannel::Left, ParameterUnit::Ratio, 18.0)); - }) - .is_ok() - ); -} - // Issue #1266: effect bypass through the latency-preserving shunt. /// `with_effects` with the fixture's parametric EQ as a `pre_insert` console slot (`console(0)`, @@ -3547,96 +3438,6 @@ fn a_live_bypass_flip_is_one_record_ahead_of_its_parameters() { ); } -/// #1341 D1. Red if a bypass record carries a ramp other than the session's `mute_ms` length (the -/// fader's or pan's, or a per-edit mute length: the bypass is the one live row with no per-edit -/// length), if a flip with `mute_ms = 0` is not a step, or if a parameter-only edit carries a ramp. -#[test] -fn a_bypass_flip_carries_the_sessions_mute_ramp_and_nothing_else() { - let current = with_bypassable(); - let session_ramps = LiveRamps { - fader_samples: 100, - mute_samples: 300, - pan_samples: 200, - link_samples: 0, - }; - let ramp_of = |ramps: LiveRamps, edit_ramps: &EditRamps, flip: bool| { - let next = edited(¤t, |next| { - if flip { - next.tracks[0].inserts.effects[0].bypass = true; - } else { - inserts(next, 0).push(param(1, ParameterChannel::Left, ParameterUnit::Db, -30.0)); - } - }); - let delta = classify_live_delta(¤t, &next, ramps, edit_ramps).expect("live"); - assert_eq!(delta.effects.len(), 1); - delta.effects[0] - .records - .iter() - .find_map(|record| match record { - EffectControlRecord::Bypass(switch) => Some(switch.ramp_samples), - _ => None, - }) - .unwrap_or(0) - }; - assert_eq!(ramp_of(session_ramps, &EditRamps::new(), true), 300); - assert_eq!(ramp_of(STEP, &EditRamps::new(), true), 0); - assert_eq!(ramp_of(session_ramps, &EditRamps::new(), false), 0); - let mut edit_ramps = EditRamps::new(); - edit_ramps.set( - &EditRampTarget::Strip(current.tracks[0].id.clone()), - EditRampRow::Mute, - Some(50), - ); - assert_eq!( - ramp_of(session_ramps, &edit_ramps, true), - 300, - "no per-edit length" - ); - // A ramp the indexed law cannot spell is a domain refusal, never a record. - let too_long = LiveRamps { - mute_samples: lane::kernels::INDEXED_RAMP_LENGTH_MAXIMUM + 1, - ..session_ramps - }; - let next = edited(¤t, |next| { - next.tracks[0].inserts.effects[0].bypass = true - }); - assert_eq!( - classify_live_delta(¤t, &next, too_long, &EditRamps::new()).map(|_| ()), - Err(LiveRebuild::Domain) - ); -} - -/// #1266 D1 on the EQ. Red if an EQ's bypass record reaches its target designer (which refuses -/// it, so the edit would rebuild) or displaces its parameter edits: the bypass goes first and the -/// targets are the parameter edits' alone. -#[test] -fn an_eq_bypass_beside_a_gain_change_rides_ahead_of_its_targets() { - let current = with_shaped_eq(); - let seeds = prepared_eq_seeds(¤t); - let (records, targets) = eq_entry(¤t, |next| { - next.tracks[0].inserts.effects[2].bypass = true; - inserts(next, 2)[3].value = 5.0; - }) - .expect("live"); - assert_eq!( - records, - vec![ - EffectControlRecord::Bypass(effect_contract::BypassSwitch::step(true)), - record(3, Lane::Left, 5.0) - ] - ); - let expected = designed_targets( - current.sample_rate_hz, - &seeds, - &[EqTargetEdit { - parameter_id: 4, - channel: Lane::Left, - value: 5.0, - }], - ); - assert_eq!(targets, Some(expected)); -} - /// #1266 gate 1, decision 14 F4. Red if a prepared bypass -- the delay's or the multiband /// compressor's -- is classified live in either direction: the record would be acked and never /// heard, because the running plan holds that bypass in its prepared state. @@ -3933,44 +3734,6 @@ fn a_rebuild_only_row_is_a_rebuild_with_its_reason() { ); } -/// Gate 3. Red if a setting produces a record or a rebuild: the pan window alone and the session's -/// ramp lengths alone change what later edits do, and nothing in the running plan. -#[test] -fn a_setting_change_alone_is_live_with_no_record() { - let current = two_tracks(); - assert_eq!( - classify(¤t, |next| { - let MatrixOrPan::Pan { - smoothing_samples, .. - } = &mut next.tracks[0].matrix_or_pan - else { - panic!("the settled tracks pan") - }; - *smoothing_samples = 32; - }), - Ok(Vec::new()) - ); - assert_eq!( - classify(¤t, |next| { - let mut lengths = session::CONTROL_SMOOTHING_DEFAULT; - lengths.fader_ms = 25.0; - next.control_smoothing = Some(lengths); - }), - Ok(Vec::new()) - ); - // The window is read by the records of the same edit: a move beside it uses the new window. - let moved = classify(¤t, |next| { - next.tracks[0].matrix_or_pan = MatrixOrPan::Pan { - left: 0.5, - right: 0.5, - smoothing_samples: 32, - }; - }) - .expect("a pan move is live"); - assert_eq!(moved.len(), 1); - assert_eq!(moved[0].2.expect("a matrix record").smoothing_samples, 32); -} - /// Gate 4. Red if the mask compares resolved values instead of representations, or the reverse: /// a `both` entry rewritten as equal `left` and `right` entries is a different field with the same /// value, so it is live with no record; a different value is a record. diff --git a/crates/host-core/tests/route_mute.rs b/crates/host-core/tests/route_mute.rs index 4a358527a..94cf5add0 100644 --- a/crates/host-core/tests/route_mute.rs +++ b/crates/host-core/tests/route_mute.rs @@ -1386,28 +1386,6 @@ fn a_fully_follow_muted_undelayed_send_is_inactive() { } } -/// #1218 gate 2, delayed. #1217 gate 3's bus with `d-e` open but following `d`, whose two lanes -/// are muted: `d-e`'s edge into `e` carries the limiter's 486-sample compensation (asserted from -/// the compiled plan), so it stays active, mixes `[+0.0; 4]` every block, and the bus renders that -/// gate's oracle. -/// -/// Red if a fully follow-muted delayed send is skipped (its counter stops, and its consumer would -/// stage a buffer this block never wrote) or still mixes its open coefficients. -#[test] -fn a_fully_follow_muted_delayed_send_stays_active() { - let mut model = delayed_bus(true); - assert_eq!(model.tracks[0].id.as_str(), "d"); - let fader = &mut model.tracks[0].fader; - (fader.left_mute, fader.right_mute) = (true, true); - let follow = model - .routes - .iter_mut() - .find(|route| route.id.as_str() == "d-e") - .expect("d-e is declared"); - (follow.mute, follow.follows_mute) = (false, true); - assert_delayed_route_stays_active(&delayed_session_checked(model)); -} - // ---- #1652: a following send of a stored mute --------------------------------------------- /// #1652 (batch 18, #1652c): a send into a submix whose source strip automates its mute holds the diff --git a/crates/host-core/tests/spectrum.rs b/crates/host-core/tests/spectrum.rs index 2641be9ed..e15df8eb8 100644 --- a/crates/host-core/tests/spectrum.rs +++ b/crates/host-core/tests/spectrum.rs @@ -40,86 +40,6 @@ fn caps() -> HostPrepareCaps { } } -fn render_window( - host: host_core::PreparedHost, - mut capture: host_core::SpectrumCapture, -) -> host_core::SpectrumWindow { - capture.arm().expect("first spectrum arm"); - assert_eq!( - capture.try_read().expect_err("window is initially pending"), - SpectrumCaptureReadError::Pending - ); - assert!(capture.arm().is_err(), "one outstanding capture"); - let (mut session, mut sources, _) = host.start_render_session().expect("start render"); - for block in 0..(SPECTRUM_WINDOW_FRAMES / QUANTUM) { - let left = [0.25_f32; QUANTUM]; - let right = [-0.5_f32; QUANTUM]; - sources - .submit( - b"fixture-source", - SourceSubmission { - generation: 1, - start_frame: (block * QUANTUM) as u64, - sample_rate_hz: 48_000, - planes: &[&left, &right], - frames: QUANTUM as u32, - end_of_region: false, - }, - ) - .expect("source block"); - let mut output = [0.0_f32; QUANTUM * 2]; - session - .render_planar(&mut output, 2, QUANTUM, QUANTUM, (block * QUANTUM) as u64) - .expect("render block"); - } - let window = capture.try_read().expect("complete spectrum window"); - assert_eq!(window.first_sample, 0); - assert_eq!(window.end_sample(), Some(SPECTRUM_WINDOW_FRAMES as u64)); - window -} - -#[test] -fn prepared_graph_captures_all_three_real_boundaries_and_analyzes() { - let compiled = compile_host_session(SESSION, &caps()).expect("compiled fixture"); - let targets = [ - SpectrumTarget::TrackPostInputBuiltins("eq0".into()), - SpectrumTarget::TrackPostMatrix("eq0".into()), - SpectrumTarget::Output("main-out".into()), - ]; - for target in targets { - let capture_bytes = spectrum_capture_resources_for(&target).retained_bytes; - let (host, capture) = prepare_host_runtime_with_spectrum( - &compiled, - &caps(), - &SpectrumCaptureRequest { - target, - channels: SpectrumChannels::Stereo, - maximum_capture_bytes: capture_bytes, - }, - ) - .expect("selected target prepares"); - let window = render_window(host, capture); - assert!(window.left.iter().any(|value| *value != 0.0)); - assert!(window.right.iter().any(|value| *value != 0.0)); - - let analyzer = SpectrumAnalyzer::new(); - let mut frequencies = [0.0; SPECTRUM_BIN_COUNT]; - let mut left_dbfs = [0.0; SPECTRUM_BIN_COUNT]; - let mut right_dbfs = [0.0; SPECTRUM_BIN_COUNT]; - let mut output = host_core::SpectrumOutput { - frequencies_hz: &mut frequencies, - left_dbfs: Some(&mut left_dbfs), - right_dbfs: Some(&mut right_dbfs), - }; - analyzer - .analyze(&window, 48_000, &mut output) - .expect("captured window analyzes"); - assert_eq!(frequencies[0], 0.0); - assert!(left_dbfs.iter().all(|value| value.is_finite())); - assert!(right_dbfs.iter().all(|value| value.is_finite())); - } -} - #[test] fn spectrum_capture_refuses_unknown_target_and_small_budget_without_partial_state() { let compiled = compile_host_session(SESSION, &caps()).expect("compiled fixture"); diff --git a/crates/host-core/tests/successor_swap.rs b/crates/host-core/tests/successor_swap.rs index ba83bd3c3..b1799ad7e 100644 --- a/crates/host-core/tests/successor_swap.rs +++ b/crates/host-core/tests/successor_swap.rs @@ -740,30 +740,6 @@ fn a_future_anchor_starts_the_added_stem_on_its_block_at_four_lanes() { future_anchor_starts_the_added_stem_on_its_block(Backend::Simd4); } -/// Gate 2 of #1274: the anchor is two blocks before the swap block, so the render observes the -/// seek late and starts the stem at the swap block's own frame. Red if the lateness is measured -/// on any clock but the plan's absolute render sample, or not added at all. -#[test] -fn a_past_anchor_starts_the_added_stem_in_time() { - const ANCHOR_BLOCK: usize = SWAP_BLOCK - 2; - let kept = Feed::new(SOURCE, 1); - let added = Feed::new(ADDED_SOURCE, 2); - let b = Session::compile(added_source_session()); - let reference_added = spliced(ADDED_SOURCE, &added, |block| { - (block >= SWAP_BLOCK).then_some(block) - }); - for backend in backends() { - let reference = reference_run(&b, &[&kept, &reference_added], backend); - let run = anchored_swap_run(&kept, &added, ANCHOR_BLOCK, SWAP_BLOCK, backend); - assert_eq!( - first_difference(&run, &reference), - None, - "{backend:?}: the stem is in time from the swap block on" - ); - assert!(reference[SWAP_BLOCK].bits.iter().any(|bits| *bits != 0)); - } -} - /// Gate 3 of #1274: two playing sources, each given `seek_at` to one anchor before a different /// render, both jump in the anchor block. Each keeps playing its queued old generation until then. /// Red if a seek applies when observed, if a held seek drops the old generation's queued PCM, or @@ -1569,14 +1545,6 @@ fn a_high_pass_ramp_in_flight_finishes_after_the_swap(backend: Backend) { ); } -/// Gate 2, ramp case, at eight lanes. Red if the coefficient target, step or countdown is not -/// carried: the successor's lane would jump to its prepared coefficients or freeze mid-ramp. -#[cfg(target_feature = "avx2")] -#[test] -fn a_high_pass_ramp_in_flight_finishes_after_the_swap_at_eight_lanes() { - a_high_pass_ramp_in_flight_finishes_after_the_swap(Backend::Simd8); -} - /// Gate 2, ramp case, at four lanes. #[test] fn a_high_pass_ramp_in_flight_finishes_after_the_swap_at_four_lanes() { @@ -6125,12 +6093,6 @@ fn a_changed_control_kind_carries_no_effect_lane(backend: Backend) { ); } -#[cfg(target_feature = "avx2")] -#[test] -fn a_changed_control_kind_carries_no_effect_lane_at_eight_lanes() { - a_changed_control_kind_carries_no_effect_lane(Backend::Simd8); -} - #[test] #[cfg_attr( not(any(target_feature = "neon", target_feature = "simd128")), diff --git a/crates/host-core/tests/withdrawn_successor.rs b/crates/host-core/tests/withdrawn_successor.rs index 500d40cbf..d135bdca0 100644 --- a/crates/host-core/tests/withdrawn_successor.rs +++ b/crates/host-core/tests/withdrawn_successor.rs @@ -1104,51 +1104,3 @@ fn an_owner_a_restarts_or_removes_and_b_reverts_carries_from_p0() { reverted_owner_carries_from_p0(removed(), backend); } } - -/// #1698, sources stay under the host contract: a source declared differently in the newest -/// committed session restarts at generation 1, frame 0 (`CONTROL_PROTOCOL_SEMANTICS.md`). A -/// redeclares or removes P0's `b`, and B declares it as P0 does: `b` is fresh in B, a ring of its -/// own that takes generation 1 from frame 0, while `a`, which A carries from P0, still carries. -/// -/// Test value: red if B's base carries a source A did not carry from P0 (P0's full inventory -/// without the source filter), which would refuse the host's restarted feed of `b`. -#[test] -fn a_source_b_reverts_is_fresh_and_a_source_a_carries_still_carries() { - let backend = Backend::current(); - let p0 = Session::compile(p0_model()); - let signal = signal(); - for (label, a_model) in [ - ("b redeclared", with_b_frames(40_000)), - ("b removed", without(p0_model(), "b", "tb")), - ] { - let a = Session::compile(a_model); - let mut running = running_p0(&p0, backend, &signal); - let mut withdrawn = successor_of(&a, &running.inventory, &p0.model, backend); - withdrawn.sources.adopt_persisting(&mut running.sources); - let base = base_across(&running, &withdrawn); - let mut replacement = successor_of(&p0, &base, &p0.model, backend); - let index = |source: &str| { - replacement - .inventory - .source(source) - .expect("B declares it") - .index as usize - }; - assert!( - replacement.plan.can_prepare_source_seek(index("b")), - "{label}: B's b owns a fresh ring" - ); - assert!( - !replacement.plan.can_prepare_source_seek(index("a")), - "{label}: B's a is vacant, carried from P0" - ); - submit(&mut replacement.sources, "b", &signal[1], 1, 0).unwrap_or_else(|error| { - panic!("{label}: B's b takes generation 1 at frame 0: {error:?}") - }); - assert_eq!( - replacement.sources.adopt_persisting(&mut withdrawn.sources), - 1, - "{label}: a's producer moves from A" - ); - } -} diff --git a/crates/lane/tests/MUTATIONS.md b/crates/lane/tests/MUTATIONS.md index ce13f92f7..3ec59d814 100644 --- a/crates/lane/tests/MUTATIONS.md +++ b/crates/lane/tests/MUTATIONS.md @@ -372,7 +372,7 @@ it; the count exists beside the digests for the same reason `minmax_lowering_mis ## Issue #954 — the select-free fused fader/matrix kernel `fader_matrix_block_without_identity` is `fader_matrix_block`'s second arm with no `L::select` in -the body. Gate 1, `select_free_fused_fader_matrix_matches_both_oracles_when_no_lane_is_identity` +the body. Gate 1, `select_free_fused_fader_matrix_matches_both_oracles_when_no_lane_is_identity` (deleted by TA5; catcher builtins `fused_fader_matrix_shapes_match_the_separate_stages`) (`tests/fader_matrix.rs`), holds it equal to two oracles with no identity lane: oracle A is `fader_matrix_block` with an all-false mask, oracle B is `gain_mute_block` on each plane followed by `matrix2x2_block_without_identity`. It covers five input families (the four hostile ones and an @@ -502,9 +502,3 @@ browser's render-closure trap gate. Host AMD EPYC 7313P, rustc 1.97.1, `x86-64-v | 1219-M11 | the settled frames re-implemented as a private loop, and `mix2x2_block` then flushing its outputs (two edits: a static mix that drifts from the ramp's settled path) | gate 3 alone (`case 2, length 3830 ... left frame 3`, `-0.0` against `mix2x2_block`'s `+0.0`) | RED | | 1219-M12 | attempt 2: `route_mix_ramp_block` back to `let count = left.len(); let right = &mut right[..count];` | `--callgraph probe_ramp` on the probe: `FAIL probe_ramp: unexpected trap owner in the render closure: ...route_mix_ramp_block...`, `closure=5 traps=3`, entry `slice_index_fail` (unmutated: `closure=4 traps=0 trap_owners=[]`). Native gates cannot see it: bits do not move. | RED (probe), GREEN (native) | | 1219-M13 | attempt 2: `route_mix_settled_tail` passes its planes uncut (`mix2x2_block::(left, right, c)`) | `--callgraph probe_ramp`: `FAIL ... unexpected trap owner ...: route_mix_settled_tail`, `closure=5 traps=3` | RED (probe), GREEN (native) | - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `g1_select_max_is_order_free_only_on_the_sanitized_domain`: no plausible same-crate KEEP catcher recorded diff --git a/crates/lane/tests/f64_lane.rs b/crates/lane/tests/f64_lane.rs index 1057c6ca6..03e4524bd 100644 --- a/crates/lane/tests/f64_lane.rs +++ b/crates/lane/tests/f64_lane.rs @@ -404,93 +404,3 @@ fn gate2_add_and_mul_are_exact_on_seeded_random_pairs() { ); }); } - -/// Gate 3's oracle: `x * x` for a finite `x = ±M * 2^E`, as `(M * M) * 2^(2E)`. -/// -/// `M * M` is below `2^48`, so its conversion is exact, and `2E` lies in `[-298, 208]`, so the power -/// of two is a normal `f64` and the product is exact. -fn oracle_square_bits(x: f32) -> u64 { - let bits = x.to_bits(); - let exponent = ((bits >> 23) & 0xFF) as i32; - let mantissa = u64::from(bits & 0x7F_FFFF); - let (significand, scale) = if exponent == 0 { - (mantissa, -149) - } else { - (mantissa | 0x80_0000, exponent - 150) - }; - let power = f64::from_bits(((2 * scale + 1023) as u64) << 52); - ((significand * significand) as f64 * power).to_bits() -} - -/// Gate 3's directed inputs: `±MAX`, `±MIN_POSITIVE`, both subnormal extremes, `1 ± ulp`, both -/// zeros, and `±2^k` for `k` in `-34..=5`. -fn square_pool() -> Vec { - let mut pool: Vec = [ - 0x7F7F_FFFF_u32, - 0xFF7F_FFFF, - 0x0080_0000, - 0x8080_0000, - 0x0000_0001, - 0x8000_0001, - 0x007F_FFFF, - 0x807F_FFFF, - 0x3F80_0001, - 0x3F7F_FFFF, - 0x0000_0000, - 0x8000_0000, - ] - .into_iter() - .map(f32::from_bits) - .collect(); - for k in -34_i32..=5 { - let power = f32::from_bits(((127 + k) as u32) << 23); - pool.push(power); - pool.push(-power); - } - pool -} - -/// `widen(x).mul(widen(x))` at `L::WIDTH` against the integer oracle, lane by lane. -fn square_mismatches(inputs: &[f32]) -> u64 { - let width = L::WIDTH; - let mut src = [0.0f32; MAX_WIDTH]; - let mut mismatches = 0; - let mut index = 0; - while index < inputs.len() { - for (lane, value) in src.iter_mut().enumerate().take(width) { - *value = inputs[(index + lane) % inputs.len()]; - } - let widened = L::load(&src[..width]).widen(); - let square = black_box(widened.mul(widened)); - let mut out = [0.0f64; MAX_WIDTH]; - square.store(&mut out[..width]); - let out = black_box(out); - for lane in 0..width { - mismatches += u64::from(out[lane].to_bits() != oracle_square_bits(src[lane])); - } - index += width; - } - mismatches -} - -#[test] -fn gate3_the_square_of_a_widened_f32_is_exact() { - let mut inputs = square_pool(); - let mut rng = Rng(0x0949_5A0A_2E00_0003); - let mut finite = 0; - while finite < 100_000 { - let x = f32::from_bits(rng.next_u64() as u32); - if x.is_finite() { - inputs.push(x); - finite += 1; - } - } - lane::each_lane!(|L| { - let name = core::any::type_name::(); - assert_eq!( - square_mismatches::(&inputs), - 0, - "gate 3: square witness at {name}" - ); - }); -} diff --git a/crates/lane/tests/fader_matrix.rs b/crates/lane/tests/fader_matrix.rs index d5aaf1f02..474446c15 100644 --- a/crates/lane/tests/fader_matrix.rs +++ b/crates/lane/tests/fader_matrix.rs @@ -3,8 +3,8 @@ use lane::{ CanonicalFpEnv, Lane, kernels::builtins::{ - Matrix2x2Coef, fader_matrix_block, fader_matrix_block_without_identity, gain_mute_block, - mask_from_flags, matrix2x2_block, matrix2x2_block_without_identity, no_lanes, + Matrix2x2Coef, fader_matrix_block, gain_mute_block, mask_from_flags, matrix2x2_block, + matrix2x2_block_without_identity, no_lanes, }, }; @@ -216,213 +216,3 @@ fn select_free_matrix_matches_the_select_form_when_no_lane_is_identity() { let _canonical = CanonicalFpEnv::enter(); lane::each_lane!(|L| select_free_width::()); } - -/// The fused gate's input families: the four hostile families, then overflow. -/// -/// Family 4 is finite, but its words times a gain above one overflow to an infinity, so the -/// matrix then meets `inf * 0.0` and `inf - inf` and produces NaNs of its own. -fn fused_family_source(family: usize) -> [f32; WIDTH] { - if family < 4 { - family_source(family) - } else { - [ - f32::MAX, - -f32::MAX, - 3.0e38, - -2.5e38, - 1.0, - -0.0, - f32::MAX * 0.5, - 1.0e38, - ] - } -} - -/// The fused gate's fader gains, `[set][channel][lane]`: mixed, unity and zero, and large (up to -/// the `+24 dB` ceiling `15.85`, which overflows family 4). -const FUSED_GAINS: [[[f32; WIDTH]; 2]; 3] = [ - [ - [1.25, 0.75, 1.0, 0.5, 1.1, 0.9, 0.8, 1.2], - [0.625, 1.5, 0.25, 1.0, 0.7, 1.3, 0.5, 0.875], - ], - [ - [1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0], - [0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0], - ], - [ - [3.98, 15.85, 1.0, 0.0, 3.98, 0.5, 15.85, 2.0], - [15.85, 3.98, 0.0, 1.0, 2.0, 15.85, 0.25, 3.98], - ], -]; - -/// The fused gate's mute flags, `[set][channel][lane]`: none, mixed, and all. -const FUSED_MUTES: [[[f32; WIDTH]; 2]; 3] = [ - [[0.0; WIDTH], [0.0; WIDTH]], - [ - [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0], - [1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0], - ], - [[1.0; WIDTH], [1.0; WIDTH]], -]; - -/// Words the select-free fused kernel changed against one oracle over one case. -#[derive(Default)] -struct FusedDifferences { - /// The first word that fails [`same_word`], if any. - first: Option, - /// Words that are NaN in both runs with different payloads (allowed by the class statement), - /// against oracle A and oracle B. - nan_payloads: [usize; 2], -} - -impl FusedDifferences { - fn record(&mut self, oracle: usize, planes: [(&str, &[f32], &[f32]); 2]) { - for (plane, new, old) in planes { - for (index, (new, old)) in new.iter().zip(old.iter()).enumerate() { - if !same_word(*new, *old) { - self.first.get_or_insert_with(|| { - format!( - "oracle {} {plane}[{index}] new={:08x} old={:08x}", - ["A", "B"][oracle], - new.to_bits(), - old.to_bits() - ) - }); - } else if new.to_bits() != old.to_bits() { - self.nan_payloads[oracle] += 1; - } - } - } - } -} - -/// Runs the select-free fused kernel over one case against both oracles. -/// -/// Oracle A is [`fader_matrix_block`] over `identity`; oracle B is [`gain_mute_block`] on each -/// plane followed by [`matrix2x2_block_without_identity`]. The select-free kernel sees the same -/// coefficients with no identity lane, which is its precondition. Guard words at both ends are -/// compared too. -fn fused_select_free_differences( - frames: usize, - identity: [f32; WIDTH], - family: usize, - gains: usize, - mutes: usize, -) -> FusedDifferences { - let samples = frames * L::WIDTH; - let source = fused_family_source(family); - let mut left = vec![f32::from_bits(0x42f6_e979); samples + 2]; - let mut right = vec![f32::from_bits(0xc2f6_e979); samples + 2]; - for index in 0..samples { - left[index + 1] = source[index % WIDTH]; - right[index + 1] = source[(index * 3 + 1) % WIDTH]; - } - let gain_left = L::load(&FUSED_GAINS[gains][0][..L::WIDTH]); - let gain_right = L::load(&FUSED_GAINS[gains][1][..L::WIDTH]); - let mute_left = mask_from_flags::(&FUSED_MUTES[mutes][0][..L::WIDTH]); - let mute_right = mask_from_flags::(&FUSED_MUTES[mutes][1][..L::WIDTH]); - let select_form = hostile_matrix::(identity); - let select_free = Matrix2x2Coef { - identity: no_lanes::(), - ..select_form - }; - let (mut a_left, mut a_right) = (left.clone(), right.clone()); - fader_matrix_block( - &mut a_left[1..=samples], - &mut a_right[1..=samples], - frames, - gain_left, - mute_left, - gain_right, - mute_right, - &select_form, - ); - let (mut b_left, mut b_right) = (left.clone(), right.clone()); - gain_mute_block(&mut b_left[1..=samples], frames, gain_left, mute_left); - gain_mute_block(&mut b_right[1..=samples], frames, gain_right, mute_right); - matrix2x2_block_without_identity( - &mut b_left[1..=samples], - &mut b_right[1..=samples], - frames, - &select_free, - ); - fader_matrix_block_without_identity( - &mut left[1..=samples], - &mut right[1..=samples], - frames, - gain_left, - mute_left, - gain_right, - mute_right, - &select_free, - ); - let mut differences = FusedDifferences::default(); - differences.record(0, [("L", &left, &a_left), ("R", &right, &a_right)]); - differences.record(1, [("L", &left, &b_left), ("R", &right, &b_right)]); - differences -} - -const FUSED_FRAMES: [usize; 5] = [1, 3, 8, 9, 128]; - -fn fused_select_free_width() -> [usize; 2] { - let mut nan_payloads = [0; 2]; - for frames in FUSED_FRAMES { - for family in 0..5 { - for gains in 0..FUSED_GAINS.len() { - for mutes in 0..FUSED_MUTES.len() { - let differences = fused_select_free_differences::( - frames, - [0.0; WIDTH], - family, - gains, - mutes, - ); - if let Some(word) = differences.first { - panic!( - "width={} frames={frames} family={family} gains={gains} \ - mutes={mutes}: {word}", - L::WIDTH - ); - } - nan_payloads[0] += differences.nan_payloads[0]; - nan_payloads[1] += differences.nan_payloads[1]; - } - } - } - } - // Negative control: with identity lanes the select form is a different function, which is why - // the arm is keyed on the mask. Unmuted identity lanes pass their scaled inputs through, while - // the select-free arm mixes them. Asserted over the union of frame counts and families. - let mixed = [1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0]; - assert!( - FUSED_FRAMES.iter().any(|&frames| (0..5).any(|family| { - fused_select_free_differences::(frames, mixed, family, 0, 0) - .first - .is_some() - })), - "width={}: the select-free fused kernel must differ from the select form on identity lanes", - L::WIDTH - ); - nan_payloads -} - -/// Issue #954 gate 1: with no identity lane, the select-free fused kernel is `fader_matrix_block`, -/// and it is `gain_mute_block` on each plane followed by `matrix2x2_block_without_identity`. -/// -/// Five input families (the four hostile ones and overflow), three gain sets (mixed, unity and -/// zero, large), three mute sets (none, mixed, all), frame counts `[1, 3, 8, 9, 128]`, guard words -/// included, at `f32`, `Simd4` and `Simd8`. NaN words compare as "both NaN" (see [`same_word`]); -/// the count of NaN-payload differences, which the class statement allows, is printed. Runs in -/// dev and in release, which is the build CI tests `lane` in. -/// -/// Red mutation (issue #954 M3, `crates/lane/tests/MUTATIONS.md`): swap `matrix.lr` and -/// `matrix.rl` in `fader_matrix_block_without_identity`. -#[test] -fn select_free_fused_fader_matrix_matches_both_oracles_when_no_lane_is_identity() { - let _canonical = CanonicalFpEnv::enter(); - let mut counts = Vec::new(); - lane::each_lane!(|L| counts.push(fused_select_free_width::())); - println!( - "NaN-payload differences [oracle A, oracle B] at each width, narrowest first: {counts:?}" - ); -} diff --git a/crates/lane/tests/fp_env.rs b/crates/lane/tests/fp_env.rs index a3cd976e4..ad1bc8143 100644 --- a/crates/lane/tests/fp_env.rs +++ b/crates/lane/tests/fp_env.rs @@ -77,38 +77,6 @@ mod x86 { ); } - /// #1709 (U3 fold, batch 17): the test helper `under_hostile_fp_env` installs the hostile - /// word inside its body and writes the caller's exact word back after it, also when the body - /// panics. The caller's word is itself non-canonical (round up, a sticky flag), so a helper - /// that wrote the canonical word back would be seen. - /// - /// Test value: red if the helper leaves the hostile word on the caller's thread (on return or - /// while unwinding), restores another word than the caller's, or does not install the hostile - /// word, so every #1709 gate built on it would run in the wrong environment. - #[cfg(feature = "test-support")] - #[test] - fn under_hostile_fp_env_restores_the_callers_word() { - let saved = read_mxcsr(); - let _restore = Restore(saved); - let caller = hostile_word(saved); - // SAFETY: `hostile_word` sets FTZ, DAZ, RC and a status flag on a word read from this - // thread, all below bit 16; `_restore` writes `saved` back. - unsafe { write_mxcsr(caller) }; - let inside = fpenv::under_hostile_fp_env(read_mxcsr); - assert_eq!(inside, fpenv::hostile_fp_control_word(caller)); - assert_ne!(inside, caller, "the helper changes the word"); - assert_eq!(read_mxcsr(), caller, "the caller's word comes back"); - let outcome = std::panic::catch_unwind(|| { - fpenv::under_hostile_fp_env(|| panic!("a body that panics")); - }); - assert!(outcome.is_err(), "the body panicked"); - assert_eq!( - read_mxcsr(), - caller, - "the caller's word comes back while unwinding" - ); - } - #[test] fn the_caller_word_survives_an_unwind_through_the_guard() { let saved = read_mxcsr(); diff --git a/crates/math/tests/m2_lane_identity.rs b/crates/math/tests/m2_lane_identity.rs index eaa71df56..b951cf229 100644 --- a/crates/math/tests/m2_lane_identity.rs +++ b/crates/math/tests/m2_lane_identity.rs @@ -173,14 +173,6 @@ impl LaneFn for Log2 { } } -/// `math::fast_db::fast_gain_from_db`. -struct FastGain; -impl LaneFn for FastGain { - fn at(x: L) -> L { - math::fast_db::fast_gain_from_db(x) - } -} - /// Compare every vector width against the scalar oracle, bit for bit: width 4, then width 8 where /// `avx2` is enabled (a 4-lane build has no eight-lane type, issue #1112). fn compare_widths(name: &str, input: &[f32]) -> Vec { @@ -219,42 +211,6 @@ fn check(name: &str, input: &[f32], pinned: &[u8; 32]) { ); } -/// Inputs whose clamp treatment is the load-bearing premise of LANE-4. -fn exp2_caller_edges() -> Vec { - let mut values = vec![ - f32::from_bits(0x7fc0_0000), - f32::from_bits(0x7fc0_0001), - f32::from_bits(0xffc0_0000), - f32::INFINITY, - f32::NEG_INFINITY, - 0.0, - -0.0, - f32::from_bits(0x0000_0001), - f32::from_bits(0x8000_0001), - f32::from_bits(0x007f_ffff), - f32::from_bits(0x807f_ffff), - f32::MIN_POSITIVE, - -f32::MIN_POSITIVE, - ]; - for boundary in [-127.0_f32, -126.0, 126.0, 127.0] { - let bits = boundary.to_bits(); - values.push(f32::from_bits(bits - 1)); - values.push(boundary); - values.push(f32::from_bits(bits + 1)); - } - while !values.len().is_multiple_of(8) { - values.push(0.0); - } - values -} - -#[test] -fn m2_exp2_callers_directed_edges_are_lane_identical() { - let input = exp2_caller_edges(); - compare_widths::("fast_gain_from_db directed edges", &input); - compare_widths::("exp2_lane directed edges", &input); -} - #[test] fn m2_exp2_lane_identity() { let input = corpus(); diff --git a/crates/multiband-compressor/tests/crossover.rs b/crates/multiband-compressor/tests/crossover.rs index 475ef23de..227635b93 100644 --- a/crates/multiband-compressor/tests/crossover.rs +++ b/crates/multiband-compressor/tests/crossover.rs @@ -6,120 +6,10 @@ //! `tests/lr4_two_section_mapping_f64.rs`. This gate is the `f32` production form: the same //! `lr4_step` the render path runs, at `WIDTH = 1`. -use dsp_reference::ReferenceLr4Crossover; use lane::Lane; use multiband_compressor::{Lr4State, lr4_coefficients, lr4_step}; const RATES: [u32; 4] = [44_100, 48_000, 88_200, 96_000]; -const CROSSOVERS: [f32; 3] = [80.0, 1_000.0, 8_000.0]; - -/// Complex gain of `output` relative to `input`, by demodulation over a whole number of periods. -fn complex_gain(input: &[f32], output: &[f32], sample_rate: f64, frequency: f64) -> (f64, f64) { - let step = core::f64::consts::TAU * frequency / sample_rate; - let (mut xr, mut xi, mut yr, mut yi) = (0.0, 0.0, 0.0, 0.0); - for (index, (x, y)) in input.iter().zip(output.iter()).enumerate() { - let (sin, cos) = (step * index as f64).sin_cos(); - xr += f64::from(*x) * cos; - xi -= f64::from(*x) * sin; - yr += f64::from(*y) * cos; - yi -= f64::from(*y) * sin; - } - let norm = xr * xr + xi * xi; - ((yr * xr + yi * xi) / norm, (yi * xr - yr * xi) / norm) -} - -fn rms(values: &[f32]) -> f64 { - (values - .iter() - .map(|value| f64::from(*value) * f64::from(*value)) - .sum::() - / values.len() as f64) - .sqrt() -} - -/// E2. Per-sample agreement with the four-section `f64` oracle, the half-power crossing, and a -/// flat band sum on the frozen one-sixth-octave grid. -/// -/// The per-sample bound is version 1's `2e-5`, kept and not loosened. The flatness bound is new -/// and an order of magnitude tighter than version 1's 0.05 dB RMS check, because `high = ap - low` -/// makes the sum the all-pass by construction rather than by cancellation. -/// -/// Red mutation: swap `a2` and `a3` in the design; drop the `nk2` doubling. -#[test] -fn the_two_stage_split_matches_the_reference_and_recombines_flat() { - let mut worst_band = 0.0f64; - let mut worst_flatness = 0.0f64; - for rate in RATES { - for crossover in CROSSOVERS { - let coefficients = lr4_coefficients::(rate, crossover).expect("design"); - let mut state = Lr4State::::default(); - // The split's input arms its joint flush (issue #1328, amendment A9). - let mut run = 0.0f32; - let mut reference = - ReferenceLr4Crossover::new(f64::from(rate), f64::from(crossover)).expect("oracle"); - let (mut input, mut low_band, mut sum) = (Vec::new(), Vec::new(), Vec::new()); - for index in 0..8_192 { - let sample = - (core::f32::consts::TAU * crossover * index as f32 / rate as f32).sin(); - let rest = lane::silence_step(sample, &mut run, lane::silence_frames(rate) as f32); - let (low, high) = lr4_step(sample, rest, &coefficients, &mut state); - let (expected_low, expected_high) = reference.process_sample(f64::from(sample)); - worst_band = worst_band - .max(f64::from((low - expected_low as f32).abs())) - .max(f64::from((high - expected_high as f32).abs())); - assert!( - (low - expected_low as f32).abs() < 2.0e-5 - && (high - expected_high as f32).abs() < 2.0e-5, - "rate={rate} crossover={crossover} index={index}" - ); - if index >= 4_096 { - input.push(sample); - low_band.push(low); - sum.push(low + high); - } - } - let crossing = 20.0 * (rms(&low_band) / rms(&input)).log10(); - assert!( - (crossing + 6.020_599_913).abs() <= 0.02, - "rate={rate} crossover={crossover} crossing={crossing}" - ); - for index in 0..=60 { - let probe = (20.0 * 2.0f64.powf(f64::from(index) / 6.0)).round(); - if probe > 0.45 * f64::from(rate) { - break; - } - let frames = rate as usize; - let mut state = Lr4State::::default(); - let mut run = 0.0f32; - let step = core::f64::consts::TAU * probe / f64::from(rate); - for frame in 0..frames { - let sample = (step * frame as f64).sin() as f32; - let rest = - lane::silence_step(sample, &mut run, lane::silence_frames(rate) as f32); - let _ = lr4_step(sample, rest, &coefficients, &mut state); - } - let mut input = Vec::with_capacity(frames); - let mut summed = Vec::with_capacity(frames); - for frame in frames..2 * frames { - let sample = (step * frame as f64).sin() as f32; - let rest = - lane::silence_step(sample, &mut run, lane::silence_frames(rate) as f32); - let (low, high) = lr4_step(sample, rest, &coefficients, &mut state); - input.push(sample); - summed.push(low + high); - } - let (real, imaginary) = complex_gain(&input, &summed, f64::from(rate), probe); - let flatness = 20.0 * real.hypot(imaginary).log10(); - worst_flatness = worst_flatness.max(flatness.abs()); - assert!( - flatness.abs() <= 0.01, - "rate={rate} crossover={crossover} probe={probe} flatness={flatness:e} dB" - ); - } - } - } - eprintln!("E2 worst_band_abs={worst_band:e} worst_flatness_db={worst_flatness:e}"); -} /// The design guards its domain and its own half-power self-check. #[test] diff --git a/crates/parametric-eq/tests/MUTATIONS.md b/crates/parametric-eq/tests/MUTATIONS.md index f144fdd3d..2d1eb63a1 100644 --- a/crates/parametric-eq/tests/MUTATIONS.md +++ b/crates/parametric-eq/tests/MUTATIONS.md @@ -459,20 +459,9 @@ it names, the named tests run, and the source restored. |---|---|---|---| | 1328-M4 | the rest threshold always armed (attempt 3's law: `silence_step` returns `REST_EPS`, `silence_armable` always true) | `exact_rest::a_sparse_input_through_four_boosting_shelves_gets_every_boost_at_every_rate` (`44100 Hz, 10 Hz shelves, period 2 … misses the ordinary run by 1.102885e3`), `a_tiny_input_through_four_boosting_shelves_gets_every_boost`, `an_exact_zero_inside_the_cascade_moves_nothing_while_the_input_is_live` | RED | | 1328-M5 | A8's law: armed by a zero *section* input (thresholds from `v0 == 0` in `svf_step_when`, every block armable) | the sparse gate (`… misses the ordinary run by 1.0375549e3`) and the cancellation gate (`DC at 1e-6 … misses the ordinary run by 6.996817e-5 … (peak 7.826055e3)`); the chain gate stays green | RED | -| 1328-M6 | `Channel::commit_track` drops the restored silence word | `carry::a_restore_mid_silence_arms_the_joint_flush_on_the_continuing_lanes_frame`, `carry::a_malformed_silence_word_is_refused` | RED | +| 1328-M6 | `Channel::commit_track` drops the restored silence word | `carry::a_restore_mid_silence_arms_the_joint_flush_on_the_continuing_lanes_frame` (deleted by TA5; catcher `a_malformed_silence_word_is_refused`), `carry::a_malformed_silence_word_is_refused` | RED | | 1328-M7 | `desymmetrize` drops `self.right.silence = self.left.silence` | `mono_collapse::a_desymmetrized_bank_carries_the_collapsed_channels_silence_counter` | RED | | 1328-M8 | the silent fast path earned without every lane armed (`quiet && (armed \|\| true)`) | `exact_rest::a_fixed_point_inside_the_joint_band_is_cleared_once_the_flush_arms` | RED | | 1328-M9 | the silent fast path skips without `silence_advance` | the same test (`the silence counter after 68 silent blocks`) | RED | | 1328-M10 | `rest_plane`'s unarmed branch returns the last written plane instead of the unarmed one | the sparse gate (its train starts after armed silence) | RED | | 1328-M11 | `lane_is_inert` without its pair term | `elision::a_non_inert_state_in_a_dead_section_refuses_elision`, `exact_rest::a_fixed_point_inside_the_joint_band_is_cleared_once_the_flush_arms` | RED | - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `automation_is_partition_invariant`: no plausible same-crate KEEP catcher recorded -- `every_width_matches_the_scalar_instantiation`: no plausible same-crate KEEP catcher recorded -- `the_collapsed_body_renders_the_dual_bodys_left_plane`: no plausible same-crate KEEP catcher recorded -- `disabled_cuts_preserve_all_high_pass_signed_zero_against_four_section_oracle`: parametric-eq `elision::a_discontinuity_reset_mid_ramp_refreshes_the_identity_flag` -- `a_tiny_restored_disabled_cut_state_refuses_elision_but_preserves_old_bands`: parametric-eq `elision::a_discontinuity_reset_mid_ramp_refreshes_the_identity_flag` -- `a_mid_ramp_restore_continues_bit_for_bit_at_every_sample`: no plausible same-crate KEEP catcher recorded diff --git a/crates/parametric-eq/tests/carry.rs b/crates/parametric-eq/tests/carry.rs index 3eca03f71..3e87cf071 100644 --- a/crates/parametric-eq/tests/carry.rs +++ b/crates/parametric-eq/tests/carry.rs @@ -124,10 +124,6 @@ fn continuing(ramp: &Ramp, elapsed: usize) -> PreparedEffect { effect } -fn same_bits(a: &[f32], b: &[f32]) -> bool { - a.iter().zip(b).all(|(x, y)| x.to_bits() == y.to_bits()) -} - /// A restore validates both channels before it commits either: a payload whose left section is a /// mid-ramp snapshot and whose right section is refused leaves the receiver as it was, scalar and /// bank lane alike. @@ -197,103 +193,6 @@ fn bank_lane_snapshot(bank: &PreparedEffectBank, lane: usize) -> Payload { out } -/// Issue #1328, amendment A9: the payload carries the input's silence counter, so a lane restored -/// mid-silence arms its joint flush on the frame the lane it was taken from does. -/// -/// A 10 Hz +24 dB low shelf at 48 kHz takes a `1e-11` impulse; its state then sits inside the joint -/// band (both words below `REST_EPS`, one above `FLUSH_EPS`) for longer than `N_SILENCE` (4,096 -/// frames), so the frame the counter arms is the frame the band's words reach `+0.0`. The payload -/// is taken after eight blocks (counter 1,023) and restored into a fresh instance that has rendered -/// nothing; both render to -/// past the arming frame. Asserted: the band's words are in the joint band before the arming frame -/// and `+0.0` from it on, and the restored instance renders the continuing one's bits on every block. -/// A restore that dropped or reset the counter would arm 1,023 frames late. -#[test] -fn a_restore_mid_silence_arms_the_joint_flush_on_the_continuing_lanes_frame() { - const FRAMES: usize = 128; - const ARMED_AT: usize = 4_096; - let values = support::single_section_values( - parametric_eq::EqBandKind::LowShelf, - 10.0, - 24.0, - core::f32::consts::FRAC_1_SQRT_2, - 1.0, - ); - let mut continuing = ParametricEqFactory - .prepare(request(&values, false)) - .expect("prepare"); - let mut restored = ParametricEqFactory - .prepare(request(&values, false)) - .expect("prepare"); - for block in 0..ARMED_AT / FRAMES + 8 { - let mut left = [0.0_f32; FRAMES]; - if block == 0 { - left[0] = 1.0e-11; - } - let mut right = left; - let (mut restored_left, mut restored_right) = (left, right); - if block == 8 { - let payload = snapshot(&continuing); - assert_eq!( - support::word(&payload.1, support::SILENCE_WORD), - 1_023.0_f32.to_bits(), - "the snapshot carries the left counter" - ); - let sizes = restored.metadata.state_sizes; - restored - .processor - .restore_state_payload( - 1, - StatePayloadInput::new(&payload.0, &payload.1, &payload.2, sizes) - .expect("input"), - ) - .expect("a mid-silence payload restores"); - } - let first = (block * FRAMES) as u64; - continuing.processor.process( - EffectProcessBlock::new(&mut left, &mut right, None, first, &[], 128).expect("block"), - ); - // The restored instance renders nothing before the restore: everything it holds then is - // what the payload wrote. - if block >= 8 { - restored.processor.process( - EffectProcessBlock::new( - &mut restored_left, - &mut restored_right, - None, - first, - &[], - 128, - ) - .expect("block"), - ); - } - if block >= 8 { - assert!( - same_bits(&left, &restored_left) && same_bits(&right, &restored_right), - "block {block}: the restored instance must render the continuing one's bits" - ); - } - let payload = snapshot(&continuing); - let band = [0, 1].map(|word| f32::from_bits(support::band_word(&payload.1, 0, word))); - let end = (block + 1) * FRAMES; - if end == ARMED_AT { - assert!( - band.iter().all(|w| w.abs() < lane::REST_EPS) - && band.iter().any(|w| w.abs() >= lane::FLUSH_EPS), - "the band must sit in the joint band before the counter arms: {band:?}" - ); - } - if end > ARMED_AT { - assert_eq!( - band.map(f32::to_bits), - [0, 0], - "block {block}: the joint flush must fire once the counter arms" - ); - } - } -} - /// The silence word is admitted only as the counter writes it: `+0.0`, or an integer in /// `[1, 2^24]`. Each malformed word is refused and changes nothing (issue #1328, amendment A9). #[test] diff --git a/crates/parametric-eq/tests/contract.rs b/crates/parametric-eq/tests/contract.rs index 96331925a..92008e8ac 100644 --- a/crates/parametric-eq/tests/contract.rs +++ b/crates/parametric-eq/tests/contract.rs @@ -615,69 +615,6 @@ fn a_payload_with_a_stale_header_is_rejected_on_its_own_evidence() { ); } -/// A payload whose words are out of domain or inconsistent with its parameters is rejected whole. -#[test] -fn a_malformed_payload_is_rejected_without_touching_either_channel() { - let values = bell_values(); - let mut effect = ParametricEqFactory - .prepare(request(&values, false)) - .expect("prepare"); - process_zeros(&mut effect, 0, 8, &[]); - let before = snapshot(&effect); - for (word, bits) in [ - (0_usize, f32::NAN.to_bits()), - (2, f32::NAN.to_bits()), - (8, f32::INFINITY.to_bits()), - (14, 65_u32), - (15, 5.0_f32.to_bits()), - (17, 0.0_f32.to_bits()), - ] { - let (common, mut left, right) = before; - left[word * 4..word * 4 + 4].copy_from_slice(&bits.to_le_bytes()); - assert_eq!( - effect.processor.restore_state_payload( - 1, - StatePayloadInput::new(&common, &left, &right, effect.metadata.state_sizes) - .expect("input"), - ), - Err(StatePayloadError { - code: "effect.state.payload" - }), - "word {word}" - ); - assert_eq!(snapshot(&effect), before, "word {word} left a trace"); - } - // A settled band whose stored words disagree with its stored parameters is a forgery. - let (common, mut left, right) = before; - let poisoned = f32::from_bits(band_word(&left, 0, 2)) + 1.0e-3; - left[8..12].copy_from_slice(&poisoned.to_bits().to_le_bytes()); - assert_eq!( - effect.processor.restore_state_payload( - 1, - StatePayloadInput::new(&common, &left, &right, effect.metadata.state_sizes) - .expect("input"), - ), - Err(StatePayloadError { - code: "effect.state.payload" - }) - ); - - // A settled lane must carry exact +0.0 increments. A bank section can still run the ramp - // kernel because a peer lane is moving, so a finite forged step would otherwise drift. - let (common, mut left, right) = before; - left[8 * 4..9 * 4].copy_from_slice(&1.0_f32.to_bits().to_le_bytes()); - assert_eq!( - effect.processor.restore_state_payload( - 1, - StatePayloadInput::new(&common, &left, &right, effect.metadata.state_sizes) - .expect("input"), - ), - Err(StatePayloadError { - code: "effect.state.payload" - }) - ); -} - /// A short or over-long snapshot buffer is refused before a byte is written. #[test] fn snapshot_rejects_bad_output_without_touching_either_lane() { diff --git a/crates/parametric-eq/tests/response.rs b/crates/parametric-eq/tests/response.rs index 8ec0235ef..50809c84c 100644 --- a/crates/parametric-eq/tests/response.rs +++ b/crates/parametric-eq/tests/response.rs @@ -1161,93 +1161,6 @@ fn malformed_requests_preserve_output_sentinels_and_opaque_ids() { assert_eq!(summary.configuration_id, u64::MAX); } -#[test] -fn preparation_validates_full_request_and_owns_source_words() { - let mut source = single_section_values(EqBandKind::Bell, 1_000.0, 6.0, 0.7, 1.0); - let configuration = prepared(&source, false, 48_000); - let frequencies = [0.0_f32, 1_000.0, 12_000.0]; - let mut before_left = [f32::NAN; 3]; - let mut before_right = [f32::NAN; 3]; - query_response_into( - EqResponseRequest { - configuration_id: 1, - configuration: &configuration, - frequencies_hz: &frequencies, - maximum_points: frequencies.len(), - }, - EqResponseOutput { - total_left_db: &mut before_left, - total_right_db: &mut before_right, - sections_left_db: None, - sections_right_db: None, - }, - ) - .expect("source-owned baseline query"); - set_initial(&mut source, 3, ParameterChannel::Left, -24.0); - set_initial(&mut source, 3, ParameterChannel::Right, 24.0); - let mut after_left = [f32::NAN; 3]; - let mut after_right = [f32::NAN; 3]; - query_response_into( - EqResponseRequest { - configuration_id: 2, - configuration: &configuration, - frequencies_hz: &frequencies, - maximum_points: frequencies.len(), - }, - EqResponseOutput { - total_left_db: &mut after_left, - total_right_db: &mut after_right, - sections_left_db: None, - sections_right_db: None, - }, - ) - .expect("source-owned query after mutation"); - assert_eq!(before_left, after_left); - assert_eq!(before_right, after_right); - - let short = &source[..source.len() - 1]; - assert!(matches!( - EqResponseConfiguration::prepare(request_at_rate(short, false, 48_000)), - Err(EqResponseError::Configuration(_)) - )); - - let mut reordered = source.clone(); - reordered.swap(0, 1); - assert!(matches!( - EqResponseConfiguration::prepare(request_at_rate(&reordered, false, 48_000)), - Err(EqResponseError::Configuration(_)) - )); - - let mut wrong_channel = source.clone(); - wrong_channel[0].channel = ParameterChannel::Both; - assert!(matches!( - EqResponseConfiguration::prepare(request_at_rate(&wrong_channel, false, 48_000)), - Err(EqResponseError::Configuration(_)) - )); - - let mut zero_capacity = request_at_rate(&source, false, 48_000); - zero_capacity.limits.maximum_total_state_bytes = 0; - assert!(matches!( - EqResponseConfiguration::prepare(zero_capacity), - Err(EqResponseError::Configuration(_)) - )); - - let mut disabled_nan = values(); - set_initial(&mut disabled_nan, 2, ParameterChannel::Left, f32::NAN); - assert!(matches!( - EqResponseConfiguration::prepare(request_at_rate(&disabled_nan, false, 48_000)), - Err(EqResponseError::Configuration(_)) - )); - - for rate in [44_100, 48_000, 88_200, 96_000] { - assert!(EqResponseConfiguration::prepare(request_at_rate(&source, false, rate)).is_ok()); - } - assert!(matches!( - EqResponseConfiguration::prepare(request_at_rate(&source, false, 176_400)), - Err(EqResponseError::Configuration(_)) - )); -} - #[test] fn deep_cut_plus_gain_composes_before_public_flooring() { let rate = 48_000; diff --git a/crates/protocol/src/btlv.rs b/crates/protocol/src/btlv.rs index 1e15dfba6..c8942c923 100644 --- a/crates/protocol/src/btlv.rs +++ b/crates/protocol/src/btlv.rs @@ -1067,51 +1067,6 @@ mod tests { ); } - #[test] - fn nested_count_mismatch_restores_parent_counter() { - let limits = ProtocolLimits::default(); - let nested = FieldSpec::msg(1, true, false, &crate::schema::enum_choice::SPEC); - let child_count = crate::schema::enum_choice::SPEC - .field_count(&[]) - .expect("schema count"); - - let mut sizing = CountSink::new(limits); - sizing.check_field_count(1).expect("parent count"); - assert_eq!( - sizing.nested_spec(nested, &mut |sink| { - sink.message_header(child_count)?; - sink.field_spec(crate::schema::enum_choice::VALUE, &1.0_f32.to_le_bytes()) - }), - Err(EncodeError::LimitExceeded) - ); - assert_eq!(sizing.fields.actual, 0); - sizing - .nested_spec(nested, &mut |sink| { - sink.message_header(child_count)?; - sink.field_spec(crate::schema::enum_choice::VALUE, &1.0_f32.to_le_bytes())?; - sink.field_spec(crate::schema::enum_choice::LABEL, b"one") - }) - .expect("parent counter restored"); - sizing.finish_message().expect("parent count matches"); - - let mut bytes = [0_u8; 96]; - let mut writer = SliceSink::new(&mut bytes, limits); - writer.check_field_count(1).expect("parent count"); - assert_eq!( - writer.nested_spec(nested, &mut |sink| sink.message_header(child_count)), - Err(EncodeError::LimitExceeded) - ); - assert_eq!(writer.fields.actual, 0); - writer - .nested_spec(nested, &mut |sink| { - sink.message_header(child_count)?; - sink.field_spec(crate::schema::enum_choice::VALUE, &1.0_f32.to_le_bytes())?; - sink.field_spec(crate::schema::enum_choice::LABEL, b"one") - }) - .expect("parent counter restored"); - writer.finish_message().expect("parent count matches"); - } - #[test] fn nested_body_runs_once_per_sink_and_patches_length() { let limits = ProtocolLimits::default(); diff --git a/crates/protocol/tests/MUTATIONS.md b/crates/protocol/tests/MUTATIONS.md index df37d9bb0..30353e2ea 100644 --- a/crates/protocol/tests/MUTATIONS.md +++ b/crates/protocol/tests/MUTATIONS.md @@ -46,9 +46,3 @@ Driver: a scratch script (PR evidence, not committed), one mutation at a time on | M7 | the console decoder reads `pre_insert` from the `post_insert` field | `session_wire.rs` | `console_declaration_and_track_entry_opcodes_round_trip_canonically` and the three above | | M8 | `ConsoleSlotFixed` reported as `session.edit.not_found` | `controller.rs` | `retired_and_console_refused_codes_meet_their_conformance_rows` | | M9 | `SetTrackConsole` writes the first track's entries | `model.rs` | `every_console_edit_round_trips_...`, `a_slot_set_change_that_skips_a_track_refuses_whole` | - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `a_slot_set_change_that_skips_a_track_is_never_acknowledged`: protocol `console_session_edits::a_slot_set_change_that_skips_a_track_refuses_whole` diff --git a/crates/protocol/tests/console_session_edits.rs b/crates/protocol/tests/console_session_edits.rs index ce1705d26..909c9eb2d 100644 --- a/crates/protocol/tests/console_session_edits.rs +++ b/crates/protocol/tests/console_session_edits.rs @@ -14,9 +14,7 @@ //! The base session has two tracks and one `pre_insert` slot, `eq`. Track `a` also carries an //! insert whose ID is `eq`, so an edit routed to the wrong place changes a value these tests read. -use protocol::control_core::{ - BYPASS_CONTROL, ControlAddress, ControlError, Lane, Owner, Section, row_address, -}; +use protocol::control_core::{BYPASS_CONTROL, ControlAddress, ControlError, Lane, Owner, Section}; use protocol::{ DecodeScratch, ExpectedRevision, ProtocolCodec, RequestId, SessionEdit, SessionEditError, SessionRevision, SessionStore, SessionStoreError, SessionTransactionFrame, apply_session_edit, @@ -841,93 +839,6 @@ fn a_track_cannot_change_the_slot_set_through_its_entries() { } } -/// #1218 gates 6 and 7 (D1), as a `SET_CONTROL` of a route's `follows_mute` row (decision 17, -/// #1561 retired `SetRouteFollowsMute`), through the wire: -/// -/// - `true` on route `a-out`, whose destination is the output, is refused at its own edit with -/// `control.inactive` (the row does not apply to an output route); the revision, model and -/// snapshot stay; -/// - the same edit after re-pointing `a-out` into submix `bus` commits, and the committed snapshot -/// is the canonical JSON of the hand-edited model; -/// - `false` then commits back. -/// -/// Red if an output route can follow (a strip's main route would stay silent after a live -/// unmute, VERIFY-2 N1), if the re-pointed route cannot, or if the row writes the wrong route or -/// ignores the value. -#[test] -fn set_route_follows_mute_is_legal_only_on_a_route_into_a_submix() { - let mut start = base(); - start - .submixes - .push(Submix::unity(id("bus"), &start.console)); - let mut store = SessionStore::new(start, caps()).expect("a unity bus compiles"); - let revision = store.revision(); - let snapshot = store.canonical_snapshot().to_owned(); - let model = store.compiled().normalized_model().clone(); - assert_eq!(model.routes[0].id.as_str(), "a-out"); - let follow = |follows_mute| { - SessionEdit::set_control( - row_address( - Owner::Route(id("a-out")), - Section::Own, - "follows_mute", - Lane::Both, - ) - .expect("the follows_mute row"), - f32::from(u8::from(follows_mute)), - None, - ) - }; - - let refused = through_the_wire(&[follow(true)]); - let error = store - .apply_transaction(ExpectedRevision::Exact(revision), &refused) - .expect_err("an output route cannot follow"); - assert_eq!( - error, - SessionStoreError::Edit { - operation_index: 0, - error: SessionEditError::Control(ControlError::Inactive), - } - ); - assert_eq!(store.revision(), revision); - assert_eq!(store.canonical_snapshot(), snapshot); - assert_eq!(store.compiled().normalized_model(), &model); - - let repointed = through_the_wire(&[ - SessionEdit::SetRouteDestination { - route_id: id("a-out"), - destination: session::RouteDestination::SubmixInput { - submix_id: id("bus"), - }, - }, - follow(true), - ]); - let commit = store - .apply_transaction(ExpectedRevision::Exact(revision), &repointed) - .expect("a follow on a route re-pointed into a submix commits"); - assert_eq!(commit.revision.0, revision.0 + 1); - let mut expected = model.clone(); - expected.revision = revision.0 + 1; - expected.routes[0].follows_mute = true; - expected.routes[0].destination = session::RouteDestination::SubmixInput { - submix_id: id("bus"), - }; - assert_eq!( - store.canonical_snapshot(), - canonical_session_json(&expected).expect("canonical") - ); - assert!(!store.compiled().normalized_model().routes[1].follows_mute); - - store - .apply_transaction( - ExpectedRevision::Exact(SessionRevision(revision.0 + 1)), - &through_the_wire(&[follow(false)]), - ) - .expect("a follow switched off commits"); - assert!(!store.compiled().normalized_model().routes[0].follows_mute); -} - /// #1561 gate 2 (D3). `SetTrackConsole` is structural: a transaction that carries one with no /// `SetConsole` before it is refused at that edit with `session.edit.value_op_retired`, and nothing /// commits -- not even an earlier edit of the transaction. Setting the same knob with `SET_CONTROL` diff --git a/crates/protocol/tests/session_edit_builtins_rack.rs b/crates/protocol/tests/session_edit_builtins_rack.rs index c93b568a4..146d4294b 100644 --- a/crates/protocol/tests/session_edit_builtins_rack.rs +++ b/crates/protocol/tests/session_edit_builtins_rack.rs @@ -89,29 +89,6 @@ fn rack_addressed_edits_refuse_the_builtins_token() { } } -/// The same edits against a real rack are applied, so the refusal above is about the token and not -/// about the edits. -#[test] -fn the_same_edits_against_a_real_rack_are_applied() { - let rack = session::Rack { - effects: Vec::new(), - }; - let mut model = session(); - assert_ne!(model.tracks[0].inserts, rack); - assert_eq!( - apply_session_edit( - &mut model, - &SessionEdit::SetTrackRack { - track_id: track_id(), - rack_name: RackName::Inserts, - rack: rack.clone(), - }, - ), - Ok(()), - ); - assert_eq!(model.tracks[0].inserts, rack); -} - /// And the strip is edited through `SET_CONTROL` on its builtin rows, which the new token does not /// touch. #[test] diff --git a/crates/rack/src/lib.rs b/crates/rack/src/lib.rs index d404f7601..d27d66e3d 100644 --- a/crates/rack/src/lib.rs +++ b/crates/rack/src/lib.rs @@ -4276,42 +4276,6 @@ mod tests { } } - #[cfg(target_feature = "avx2")] - struct WrongWidthPlanes { - planes: Planes, - per_lane_writes: usize, - } - #[cfg(target_feature = "avx2")] - impl BankMembers for WrongWidthPlanes { - fn plane(&self, lane: usize) -> (&[f32], &[f32]) { - self.planes.plane(lane) - } - fn plane_mut(&mut self, lane: usize) -> (&mut [f32], &mut [f32]) { - self.per_lane_writes += 1; - self.planes.plane_mut(lane) - } - fn distinct_planes_mut( - &mut self, - _lanes: usize, - frames: usize, - ) -> Option> { - let mut left = self.planes.left.iter_mut().take(4); - let mut right = self.planes.right.iter_mut().take(4); - let pairs: [BankPlanePair<'_>; 4] = core::array::from_fn(|_| { - ( - left.next() - .expect("four malicious left lanes") - .as_mut_slice(), - right - .next() - .expect("four malicious right lanes") - .as_mut_slice(), - ) - }); - BankPlaneViews::from_four(pairs, frames) - } - } - struct ShortClaimPlanes { planes: Planes, per_lane_writes: usize, @@ -5261,63 +5225,6 @@ mod tests { assert_planes_bit_equal(&members.planes, &expected, "direct call sentinel"); } - /// An other-width probe: the provider offers a four-lane view to an eight-lane chain, so it - /// exists where eight-lane banks do (issue #1112). - #[test] - #[cfg(target_feature = "avx2")] - fn wrong_width_provider_is_dropped_before_complete_staged_fallback() { - let mut state = 0x3994_3995_3996_3997; - let source = hostile_planes(8, 11, &mut state); - let expected = Planes { - left: source.left.clone(), - right: source.right.clone(), - }; - let mut malformed = WrongWidthPlanes { - planes: Planes { - left: source - .left - .into_iter() - .chain([vec![f32::from_bits(0x7fc0_3998); 11]]) - .collect(), - right: source - .right - .into_iter() - .chain([vec![f32::from_bits(0x7fc0_3999); 11]]) - .collect(), - }, - per_lane_writes: 0, - }; - let active = vec![true; 8].into_boxed_slice(); - let mut chain = BankChain::new( - AoSoaScratch::new(BankWidth::Eight, 11).expect("scratch"), - active.clone(), - vec![slot(active.to_vec(), Box::new(PassThrough))], - ) - .expect("chain"); - chain - .run(&mut malformed, 11, 0, LiveSnapshot::ALL) - .expect("staged fallback"); - assert_planes_bit_equal( - &Planes { - left: malformed.planes.left[..8].to_vec(), - right: malformed.planes.right[..8].to_vec(), - }, - &expected, - "wrong-width staged fallback", - ); - assert_eq!(malformed.per_lane_writes, 8); - assert!( - malformed.planes.left[8] - .iter() - .all(|word| word.to_bits() == 0x7fc0_3998) - ); - assert!( - malformed.planes.right[8] - .iter() - .all(|word| word.to_bits() == 0x7fc0_3999) - ); - } - #[test] fn inadequate_claimed_capacity_takes_complete_staged_fallback() { let mut state = 0x399a_399b_399c_399d; @@ -5923,116 +5830,6 @@ mod tests { } } - #[test] - fn all_active_folded_masks_use_one_cohort_with_physical_lane_ids() { - let frames = 13_u32; - // A full four-lane bank; a full, a scattered and a one-lane eight-lane bank, where a - // build has eight lanes (issue #1112). - let masks = BankWidth::ALL.iter().flat_map(|&width| { - if width.lanes() == 4 { - vec![(width, vec![true, true, true, true])] - } else { - vec![ - (width, vec![true; 8]), - ( - width, - vec![true, false, true, false, false, true, false, false], - ), - ( - width, - vec![false, false, true, false, false, false, false, false], - ), - ] - } - }); - for (width, active) in masks { - let lanes = width.lanes() as usize; - let build = || PlanesWithFold { - planes: Planes { - left: (0..lanes) - .map(|lane| vec![lane as f32 + 1.0; frames as usize]) - .collect(), - right: (0..lanes) - .map(|lane| vec![-(lane as f32) - 1.0; frames as usize]) - .collect(), - }, - gains: vec![1.0; lanes], - bus_left: vec![0.0; frames as usize], - bus_right: vec![0.0; frames as usize], - taken: Vec::new(), - trace: Vec::new(), - cohorts: Vec::new(), - }; - let chain = || { - BankChain::new( - AoSoaScratch::new(width, frames).expect("scratch"), - active.clone().into_boxed_slice(), - vec![slot(active.clone(), Box::new(ScaleByLane))], - ) - .expect("chain") - }; - let mut members = build(); - let mut default = DefaultFoldProvider(build()); - let mut optimized_chain = chain(); - let mut default_chain = chain(); - optimized_chain - .arm_fold(active.clone().into_boxed_slice()) - .expect("fold"); - default_chain - .arm_fold(active.clone().into_boxed_slice()) - .expect("fold"); - for block in 0..2 { - optimized_chain - .run( - &mut members, - frames, - block * u64::from(frames), - LiveSnapshot::ALL, - ) - .expect("run"); - default_chain - .run( - &mut default, - frames, - block * u64::from(frames), - LiveSnapshot::ALL, - ) - .expect("default run"); - } - let ids: Vec = (0..lanes).filter(|lane| active[*lane]).collect(); - let expected_cohorts = if ids.is_empty() { - Vec::new() - } else { - vec![ids.clone(), ids] - }; - assert_eq!(members.cohorts, expected_cohorts); - assert!(members.trace.iter().all(|(kind, _)| *kind == 'f')); - assert!( - default.0.cohorts.is_empty(), - "trait default delegates lane by lane" - ); - assert_eq!(members.taken, default.0.taken); - assert_eq!(members.bus_left, default.0.bus_left); - assert_eq!(members.bus_right, default.0.bus_right); - assert_eq!(members.planes.left, default.0.planes.left); - assert_eq!(members.planes.right, default.0.planes.right); - for (lane, is_active) in active.iter().copied().enumerate() { - if !is_active { - assert!( - members.planes.left[lane] - .iter() - .all(|x| x.to_bits() == (lane as f32 + 1.0).to_bits()) - ); - assert!( - members.planes.right[lane] - .iter() - .all(|x| x.to_bits() == (-(lane as f32) - 1.0).to_bits()) - ); - } - } - } - } - /// One recorded [`BankMembers::fold_resident`] offer: `(lanes, frames, lane ids, left bits, /// right bits)`. type ResidentOffer = (usize, usize, Vec, Vec, Vec); @@ -6529,39 +6326,6 @@ mod tests { ); } - #[test] - fn arming_an_auxiliary_destination_refuses_an_unrenderable_mask() { - let frames = 32_u32; - // The build's widest bank, its last lane not rendered (#1112). - let lanes = WIDEST.lanes() as usize; - let mut active = vec![true; lanes]; - active[lanes - 1] = false; - let scratch = AoSoaScratch::new(WIDEST, frames).expect("scratch"); - let mut chain = BankChain::new( - scratch, - active.clone().into_boxed_slice(), - vec![slot(active.clone(), Box::new(PassThrough))], - ) - .expect("chain"); - assert_eq!( - chain.arm_aux(vec![true; lanes - 1].into_boxed_slice()), - Err(RackError::Shape), - "a mask that is not the chain's lane count is refused" - ); - assert_eq!( - chain.arm_aux(vec![true; lanes].into_boxed_slice()), - Err(RackError::Shape), - "arming the last lane, which this chain does not render, is refused" - ); - assert!( - chain.aux_lanes().is_empty(), - "a refused arm leaves the chain on the zero-cost path" - ); - chain - .arm_aux(active.into_boxed_slice()) - .expect("arming exactly the rendered lanes is admitted"); - } - #[test] fn gather_scatter_round_trip_is_bit_exact() { let frames = 128_u32; @@ -6691,58 +6455,6 @@ mod tests { ); } - /// T3: a slot that is an identity on every lane is never executed, and the chain still counts - /// exactly one transpose per block. - #[test] - fn identity_everywhere_slot_is_not_executed() { - struct Counting { - slot: usize, - calls: u64, - } - impl BankStage for Counting { - fn process(&mut self, _block: BankBlock<'_>) -> Result<(), RenderError> { - self.calls += 1; - Ok(()) - } - fn qualification_counters(&self) -> [u64; 2] { - let mut counters = [0, 0]; - counters[self.slot] = self.calls; - counters - } - } - let frames = 16_u32; - let mut planes = Planes { - left: (0..4).map(|_| vec![0.0; frames as usize]).collect(), - right: (0..4).map(|_| vec![0.0; frames as usize]).collect(), - }; - let mut chain = BankChain::new( - AoSoaScratch::new(BankWidth::Four, frames).expect("scratch"), - vec![true; 4].into_boxed_slice(), - vec![ - slot(vec![true; 4], Box::new(Counting { slot: 0, calls: 0 })), - slot(vec![false; 4], Box::new(Counting { slot: 1, calls: 0 })), - slot(vec![true; 4], Box::new(Counting { slot: 0, calls: 0 })), - ], - ) - .expect("chain"); - for block in 1..=5_u64 { - chain - .run( - &mut planes, - frames, - block * u64::from(frames), - LiveSnapshot::ALL, - ) - .expect("run"); - assert_eq!(chain.transposes(), block); - } - assert_eq!( - chain.qualification_counters(), - [10, 0], - "both live slots ran once per block; the identity-everywhere slot never ran" - ); - } - /// T4: `BankChain::new` rejects every mask-shape violation, including a slot active on a lane /// the chain never gathers. #[test] diff --git a/crates/rack/tests/MUTATIONS.md b/crates/rack/tests/MUTATIONS.md index 1efefc84a..47af72b89 100644 --- a/crates/rack/tests/MUTATIONS.md +++ b/crates/rack/tests/MUTATIONS.md @@ -23,8 +23,8 @@ cargo test --locked -p rack -p rack-compiler -p graph-compiler |---|---|---|---|---|---| | M1 | `scatter_lane` reads the wrong lane: `*sample = chunk[lane]` becomes `chunk[lane ^ 1]` | `rack/src/lib.rs` | `gather_scatter_round_trip_is_bit_exact` | RED | ``assertion `left == right` failed: left lane=0 frame=0`` | | M2 | `gather_lane` chunks by frames instead of lanes: `chunks_exact_mut(lanes)` becomes `chunks_exact_mut(frames as usize)` | `rack/src/lib.rs` | `stage_sees_frame_major_layout` | RED | ``assertion `left == right` failed: lane=0 frame=1`` | -| M3 | `BankChain::run` drops the identity-slot guard: `if slot.active_lanes.iter().any(..)` becomes `if true` | `rack/src/lib.rs` | `identity_everywhere_slot_is_not_executed` | RED | ``assertion `left == right` failed: both live slots ran once per block; the identity-everywhere slot never ran`` | -| M3b | the transpose counter moves inside the slot loop (master plan §4.5: it is *per chain*, not per slot) | `rack/src/lib.rs` | `identity_everywhere_slot_is_not_executed` | RED | ``assertion `left == right` failed`` (2 live slots ⇒ 10 counted round-trips for 5 blocks) | +| M3 | `BankChain::run` drops the identity-slot guard: `if slot.active_lanes.iter().any(..)` becomes `if true` | `rack/src/lib.rs` | `identity_everywhere_slot_is_not_executed` (deleted by TA5; catcher `prepared_slot_activity_preserves_dispatch_trace_and_errors`) | RED | ``assertion `left == right` failed: both live slots ran once per block; the identity-everywhere slot never ran`` | +| M3b | the transpose counter moves inside the slot loop (master plan §4.5: it is *per chain*, not per slot) | `rack/src/lib.rs` | `identity_everywhere_slot_is_not_executed` (deleted by TA5; catcher console-workload `the_ragged_tail_banks_like_any_other_cohort_and_pays_one_chain_for_it`) | RED | ``assertion `left == right` failed`` (2 live slots ⇒ 10 counted round-trips for 5 blocks) | | M4 | `BankChain::new` stops enforcing "a slot may only be active on an active lane" | `rack/src/lib.rs` | `chain_new_rejects_mask_shape_and_lane_implication` | RED | ``assertion `left == right` failed: a slot may not be active on a lane the chain never gathers`` | | M5 | `AoSoaScratch::new` re-adds a plane: `vec![0.0; length]` becomes `vec![0.0; length * 2]` for the left plane | `rack/src/lib.rs` | `scratch_allocates_exactly_two_planes` | RED | ``assertion `left == right` failed`` | | M6 | `gather_lane` drops the first frame of every block: `.zip(left)` becomes `.zip(&left[1..])` | `rack/src/lib.rs` | `chain_run_is_partition_invariant` | RED | ``assertion `left == right` failed: partition=1 lane=0 frame=0`` | diff --git a/crates/session/tests/control_smoothing.rs b/crates/session/tests/control_smoothing.rs index 1b3b467ae..32e7eb156 100644 --- a/crates/session/tests/control_smoothing.rs +++ b/crates/session/tests/control_smoothing.rs @@ -4,7 +4,7 @@ use serde_json::{Map, Value, json}; use session::{ CONTROL_SMOOTHING_DEFAULT, ControlSmoothing, ControlSmoothingSamples, DiagnosticCode, - DiagnosticSet, SessionModel, canonical_session_json, parse_session_json, + DiagnosticSet, canonical_session_json, parse_session_json, }; const EXAMPLE: &str = include_str!("../../../fixtures/session/v1/canonical.json"); @@ -148,28 +148,6 @@ fn both_kinds_round_trip_through_canonical_json_to_identical_bytes() { ); } -/// A model built rather than parsed is held to the parser's domain by the validator. -#[test] -fn a_built_model_with_a_length_outside_the_domain_is_refused() { - let mut model: SessionModel = parse_session_json(EXAMPLE).expect("fixture"); - for bad in [-1.0, 1000.5, f32::NAN, f32::INFINITY] { - model.control_smoothing = Some(ControlSmoothing { - mute_ms: 10.0, - fader_ms: 20.0, - pan_ms: bad, - }); - let error = canonical_session_json(&model).expect_err("out of domain"); - assert_eq!( - diagnostics(&error), - [( - DiagnosticCode::NumericOutOfSchemaRange, - "$.control_smoothing.pan_ms".to_owned() - )], - "{bad}" - ); - } -} - fn samples_at(rate: u32, control_smoothing: Option) -> ControlSmoothingSamples { let mut model = parse_session_json(EXAMPLE).expect("fixture"); model.sample_rate_hz = rate; diff --git a/crates/soft-clip/src/padding_tests.rs b/crates/soft-clip/src/padding_tests.rs index d58284f37..8c55227c9 100644 --- a/crates/soft-clip/src/padding_tests.rs +++ b/crates/soft-clip/src/padding_tests.rs @@ -690,67 +690,6 @@ fn padded_banks_render_the_fixtures_per_node() { // Gate 3: the clone source does not reach an active lane // --------------------------------------------------------------------------------------------- -/// Gate 3: an active lane's bits are the same whichever member the padded lanes clone. -/// -/// Every render also matches the members' scalar instances and checks each padded lane (gate 1's -/// checks), and the renders of one mask must agree word for word across every clone source, -/// including a member at every parameter's minimum and one at every maximum. Red if a factory reads -/// its members from anywhere but lanes `0..members` -- from the tail of the requests, say, as if -/// padding came first -- so that an active lane runs a clone; or if a whole-bank decision reads a -/// padded lane's parameters. -#[test] -fn active_lanes_do_not_depend_on_the_clone_source() { - for &width in WIDTHS { - let lanes = width.lanes() as usize; - let masks: Vec> = [1, 2, lanes / 2 + 1, lanes - 1] - .into_iter() - .map(|members| prefix_mask(width, members)) - .collect(); - for (index, mask) in masks.iter().enumerate() { - let members = mask.iter().filter(|active| **active).count(); - let mut draw = Draw::new(0x1092_0300 + (lanes * 10 + index) as u64); - // Members that differ as much as the domains allow: one at every minimum and one at - // every maximum, then drawn ones. - let mut values: Vec = (0..members).map(|_| draw.values()).collect(); - values[0] = values_from(SOFT_CLIP_PARAMETERS.map(|p| { - let minimum = p.minimum.expect("bounded"); - (minimum, minimum) - })); - if members > 1 { - values[members - 1] = values_from(SOFT_CLIP_PARAMETERS.map(|p| { - let maximum = p.maximum.expect("bounded"); - (maximum, maximum) - })); - } - let blocks = random_blocks(&mut draw, members, 8); - let link = LINKS[index % LINKS.len()]; - let mut reference: Option>> = None; - for clone_of in 0..members { - let outputs = render( - &Padded { - width, - mask, - members: &values, - clone_of, - rate: 48_000, - link, - }, - &blocks, - &format!("{width:?} mask {mask:?} clone of member {clone_of}"), - ); - match &reference { - None => reference = Some(outputs), - Some(first) => assert_eq!( - &outputs, first, - "{width:?} mask {mask:?}: the active lanes moved when the padding cloned \ - member {clone_of} instead of member 0" - ), - } - } - } - } -} - // --------------------------------------------------------------------------------------------- // Gate 4: D7 attributes active lanes only // --------------------------------------------------------------------------------------------- diff --git a/crates/soft-clip/tests/MUTATIONS.md b/crates/soft-clip/tests/MUTATIONS.md index c57e8f925..9bfb6dbc9 100644 --- a/crates/soft-clip/tests/MUTATIONS.md +++ b/crates/soft-clip/tests/MUTATIONS.md @@ -109,9 +109,3 @@ mutation and the defect are the same edit. Both reset kinds are now inside the m * The wasm leg of the corpus (`tools/wasm-gates`) is exercised by `scripts/run-wasm-gates.sh`; its own mutations live in that crate's `MUTATIONS.md`. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `partition_invariance` (the test binary; its one test, `every_partition_renders_the_one_shot_bits_and_state`): no plausible same-crate KEEP catcher recorded diff --git a/crates/soft-clip/tests/contract.rs b/crates/soft-clip/tests/contract.rs index ee02fd6d6..9b8792e39 100644 --- a/crates/soft-clip/tests/contract.rs +++ b/crates/soft-clip/tests/contract.rs @@ -15,7 +15,7 @@ use effect_contract::{ }; use lane::kernels::halfband::{HALFBAND63_CENTER, HALFBAND63_EVEN}; use soft_clip::{SOFT_CLIP_DESCRIPTOR, SoftClipFactory}; -use support::{PARAMETERS, bank_available, initial_values, prepare, process, request, values_from}; +use support::{PARAMETERS, initial_values, prepare, process, request, values_from}; /// E11 — resources, latency, tail and the tap table against the independent `f64` design. #[test] @@ -220,73 +220,6 @@ fn identity_and_bypass_emit_the_delayed_dry_signal_bit_for_bit() { } } -/// Bank binding validates before it declines, and declines rather than failing where the width is -/// not this artifact's. Run at the build's own width: eight lanes in the 8-lane (AVX2) build, four -/// in a 4-lane (NEON/simd128) build (#1112). -#[test] -fn bank_binding_validates_before_declining_an_unavailable_width() { - let width = BankWidth::for_backend(lane::Backend::current()).expect("a vector build"); - let lanes = width.lanes() as usize; - let values = initial_values(); - let requests = vec![request(&values); lanes]; - // Wrong request count for the width. - assert!(matches!( - SoftClipFactory.bind_homogeneous_bank(PrepareEffectBankRequest { - backend: support::backend(width), - width, - requests: &requests[..lanes - 1], - active_mask: width.full_mask(), - }), - Err(EffectPrepareError { - code: "effect.bank.requests" - }) - )); - // Backend and width disagree: every other vector backend this build has, so none in a 4-lane - // build. - for &other in lane::Backend::VECTOR { - if other == support::backend(width) { - continue; - } - assert!(matches!( - SoftClipFactory.bind_homogeneous_bank(PrepareEffectBankRequest { - backend: other, - width, - requests: &requests, - active_mask: width.full_mask(), - }), - Err(EffectPrepareError { - code: "effect.bank.requests" - }) - )); - } - // A mixed cohort is declined, not rejected. - let other = values_from([(6.0, 6.0), (0.0, 0.0), (1.0, 1.0)]); - let mut mixed = vec![request(&values); lanes]; - mixed[lanes / 2] = request(&other); - mixed[lanes / 2].quantum = 64; - assert!( - SoftClipFactory - .bind_homogeneous_bank(PrepareEffectBankRequest { - backend: support::backend(width), - width, - requests: &mixed, - active_mask: width.full_mask(), - }) - .expect("mixed cohort declines") - .is_none() - ); - // The host's own width binds. - let bound = SoftClipFactory - .bind_homogeneous_bank(PrepareEffectBankRequest { - backend: support::backend(width), - width, - requests: &requests, - active_mask: width.full_mask(), - }) - .expect("bind"); - assert_eq!(bound.is_some(), bank_available(width)); -} - /// Automation validation is unchanged: canonical ordered points only. #[test] fn automation_rejects_everything_but_canonical_ordered_points() { diff --git a/crates/source/src/lib.rs b/crates/source/src/lib.rs index 6346f4fb8..7f7ca1f99 100644 --- a/crates/source/src/lib.rs +++ b/crates/source/src/lib.rs @@ -4284,39 +4284,6 @@ mod tests { } } - #[test] - fn graph_driver_forwards_underrun_and_seek_generation_facts() { - let (producer, consumer, _) = session_ring(config(1, 4, 8)).expect("ring"); - let mut host = producer.into_host_chunk_provider(RATE); - let mut driver = test_driver(consumer, vec![test_mapping(0)]); - - driver.begin_block(0, 4).expect("first block"); - assert_eq!( - driver.observation_validity(), - GraphObservationValidity { - source_underrun: true, - source_generation_changed: false, - } - ); - let samples = [1.0; 4]; - host.try_seek(SourceCommand::Seek { - generation: SourceGeneration(2), - frame: SourceFrame(100), - }) - .expect("seek"); - assert!(driver.prepare_source_seek(0, 2, 100)); - host.submit(chunk(2, 100, &[&samples], 4, false)) - .expect("fresh block"); - driver.begin_block(4, 4).expect("second block"); - assert_eq!( - driver.observation_validity(), - GraphObservationValidity { - source_underrun: false, - source_generation_changed: true, - } - ); - } - /// #1318 gate 3. Red if the graph source driver still folds a held block into the graph-wide /// `source_underrun` flag (a planned wait would mark every spectrum window as starved), or if /// the fix swallows a true underrun on another source in the same block. @@ -5655,44 +5622,6 @@ mod tests { assert!(left.iter().chain(&right).all(|word| word.to_bits() == 0)); } - /// Follow-up MINOR 4. Red if a successor with an installed program reports - /// `NotRequested` (or `Carried`) when its predecessor is not a graph plan: it asked for - /// state and got none, so the swap must count a mismatch. - #[test] - fn a_program_facing_a_plain_predecessor_reports_a_mismatch() { - struct Silent; - impl engine::realtime::PreparedPlanExecutor for Silent { - fn render( - &mut self, - _arena: &mut engine::realtime::BufferArena, - mut output: PlanarBufferMut<'_>, - _time: engine::realtime::RenderTime, - ) -> Result<(), engine::realtime::RenderError> { - for channel in 0..output.channels() { - output.plane_mut(channel)?.fill(0.0); - } - Ok(()) - } - } - let validity = Arc::new(AtomicU8::new(0)); - let mut predecessor = PreparedRenderPlan::prepare_with_executor( - engine::realtime::PrepareRenderPlan { - plan_id: 1, - envelope: envelope(), - scratch: &[], - }, - Box::new(Silent), - ) - .expect("plain plan"); - let mut successor = bind(SourceGraphSource::vacant(2), &validity); - graph::install_carry_program(&mut successor, carry_source_zero(1)).expect("install"); - assert_eq!( - successor.adopt_predecessor_plan(&mut predecessor), - CarryOutcome::PredecessorMismatch - ); - assert_eq!(plan_block(&mut successor), silence()); - } - /// Follow-up MINOR 7. Red if the swap block stops comparing channel counts (a one-channel /// consumer would land under two-channel mappings and fail render) or quantum sizes. #[test] @@ -6660,53 +6589,6 @@ mod tests { assert_eq!(consumer.active_generation(), SourceGeneration(3)); } - #[test] - fn the_producer_refuses_without_changing_anything() { - let (mut producer, mut consumer) = timeline(4); - for (command, error) in [ - (seek(0, 5), SourceSeekError::GenerationZero), - ( - seek(1, 5), - SourceSeekError::GenerationNotStrictlyIncreasing { - active: SourceGeneration(1), - requested: SourceGeneration(1), - }, - ), - ( - SourceCommand::SeekAt { - generation: SourceGeneration(2), - frame: SourceFrame(5), - anchor_sample: QU + 1, - }, - SourceSeekError::AnchorUnaligned, - ), - ( - seek(2, TIMELINE_SAMPLE_LIMIT + 1), - SourceSeekError::FrameOutOfRange, - ), - ] { - assert_eq!(producer.check_seek(command), Err(error)); - assert_eq!(producer.try_seek(command), Err(error)); - assert_eq!(producer.active_generation(), SourceGeneration(1)); - } - producer.try_seek(seek(2, TIMELINE_SAMPLE_LIMIT)).unwrap(); - // The one slot is taken: a second seek is backpressure, checked or pushed, and the - // first one still applies. - assert!(matches!( - producer.check_seek(seek(3, 9)), - Err(SourceSeekError::Backpressure { .. }) - )); - assert!(matches!( - producer.try_seek(seek(3, 9)), - Err(SourceSeekError::Backpressure { .. }) - )); - assert_eq!(producer.active_generation(), SourceGeneration(2)); - consumer.begin_block_at(0); - assert_eq!(consumer.position(), TIMELINE_SAMPLE_LIMIT + QU); - assert_eq!(consumer.active_generation(), SourceGeneration(2)); - assert_eq!(producer.check_seek(seek(3, 9)), Ok(())); - } - #[test] fn the_history_reads_both_sides_of_a_seek_and_extrapolates_below_its_oldest_entry() { let (mut producer, mut consumer) = timeline(4); diff --git a/crates/transient-shaper/tests/MUTATIONS.md b/crates/transient-shaper/tests/MUTATIONS.md index 49ddbc030..4ad5bb788 100644 --- a/crates/transient-shaper/tests/MUTATIONS.md +++ b/crates/transient-shaper/tests/MUTATIONS.md @@ -184,9 +184,3 @@ dropped. Bit-identical for the reason given under row 8. It is a performance regression — it puts three `LinearRamp::next_value` calls per lane per channel back into the steady-state loop, which is audit finding F6 — and is rejected on that ground, not on a numeric one. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `the_scalar_product_is_partition_invariant`: no plausible same-crate KEEP catcher recorded diff --git a/crates/transient-shaper/tests/contract.rs b/crates/transient-shaper/tests/contract.rs index 520fde858..3815f6f58 100644 --- a/crates/transient-shaper/tests/contract.rs +++ b/crates/transient-shaper/tests/contract.rs @@ -351,51 +351,6 @@ fn identity_rules_are_bit_exact_and_the_followers_still_warm() { } } -/// The three link modes, read straight off the envelope state after one frame. -/// -/// From a zeroed envelope the first rising sample gives `e = attack * 0 + (1 - attack) * u`, which -/// is exactly `(1 - attack) * u` in `f32`, so the detector each channel saw is readable from the -/// state word to the last bit. That pins the linking law itself — including `Average`'s frozen -/// `0.5 * |l| + 0.5 * |r|` operation order — instead of a downstream consequence of it. -/// -/// Red mutation: dispatch `LinkMode::Maximum` to `LINK_AVERAGE`. The two half-scaled products -/// remain the frozen Average law; this row does not require alternative parenthesization to differ. -#[test] -fn link_modes_drive_the_detector_as_specified() { - let values = values_of(1.0, 0.0, 1.0); - let one_minus_attack = 1.0_f32 - f32::from_bits(TRANSIENT_SHAPER_COEFFICIENT_BITS[1][0]); - let half = 0.5_f32; - let expected = [ - (LinkMode::DualMono, 1.0_f32, 0.25_f32), - (LinkMode::Maximum, 1.0, 1.0), - ( - LinkMode::Average, - half * 1.0 + half * 0.25, - half * 1.0 + half * 0.25, - ), - ]; - for (link_mode, left_detector, right_detector) in expected { - let mut effect = prepare_with(&values, 48_000, false, link_mode); - let mut left = [-1.0_f32]; - let mut right = [0.25_f32]; - effect.process( - effect_contract::EffectProcessBlock::new(&mut left, &mut right, None, 0, &[], 128) - .expect("link block"), - ); - let state = snapshot(effect.as_ref()); - assert_eq!( - state_f32(&state.0, 0).to_bits(), - (one_minus_attack * left_detector).to_bits(), - "{link_mode:?} left detector" - ); - assert_eq!( - state_f32(&state.1, 0).to_bits(), - (one_minus_attack * right_detector).to_bits(), - "{link_mode:?} right detector" - ); - } -} - /// A restore is atomic and every word is validated. /// /// Red mutation: accept `remaining > RAMP_SAMPLES`, or drop the `valid_envelope` check. diff --git a/crates/true-peak-limiter/src/lib.rs b/crates/true-peak-limiter/src/lib.rs index 3a816898a..846ef0307 100644 --- a/crates/true-peak-limiter/src/lib.rs +++ b/crates/true-peak-limiter/src/lib.rs @@ -6642,10 +6642,10 @@ mod tests { /// A core of `L::WIDTH` identically prepared lanes, driven directly through `process_block`. /// - /// The same construction `a_nonfinite_block_is_zeroed_reset_and_counted` uses, and for the same - /// reason: `process_block` *is* the shipped path — `process` and `process_bank` both end in it - /// — and reaching it directly is what lets the control arm suppress the fast path without - /// having to change the signal or the parameters to do it. + /// The same construction `a_nonfinite_block_is_zeroed_reset_and_counted` (deleted by TA5) + /// used, and for the same reason: `process_block` *is* the shipped path — `process` and + /// `process_bank` both end in it — and reaching it directly is what lets the control arm + /// suppress the fast path without having to change the signal or the parameters to do it. fn silent_core(ceiling: f32, release: f32, lookahead: f32) -> LimiterCore { let values = values_with(ceiling, release, lookahead); let mut preparation = request(&values); @@ -7064,37 +7064,6 @@ mod tests { } } - /// **A `-0.0` input block is not silence, and is not skipped.** - /// - /// Issue #182 S2, the input side of the signed-zero rule. Masking the sign bit in - /// `block_is_positive_zero` makes a `-0.0` block count as silence, and a standing claim then - /// engages on it. Every other test in this family stays green under that mutation. - /// - /// This crate's exposure is its delay line, as the compressor's is. A `-0.0` block the kernel - /// actually renders is written into `main_ring` and emerges `B = 486` samples — a little under - /// four blocks — later, with its sign intact: `select(bypass, delayed, delayed * gain)` gives - /// `-0.0 * 1.0 = -0.0` on the limiting arm and `-0.0` on the bypass arm. A fast path that - /// skipped the block never writes it, so the sample that should have emerged is `+0.0`. - /// - /// The `any(.. == 0x8000_0000)` is the anti-vacuity: it asserts a `-0.0` really did come out - /// the far end, so the comparison had the divergence available to it. - #[test] - fn a_negative_zero_input_block_is_not_treated_as_silence() { - let mut plan = vec![None]; - plan.extend(vec![Some(0.0_f32); 40]); - plan.push(Some(-0.0_f32)); - plan.extend(vec![Some(0.0_f32); 16]); - - // The anti-vacuity at the build's own width (issue #1112). - let arm = compare_silence_arms::("native", &plan, -6.0, 100.0, 0.05); - assert!( - arm.rendered.contains(&0x8000_0000), - "no -0.0 ever reached the output, so the comparison had nothing to catch" - ); - compare_silence_arms::("scalar", &plan, -6.0, 100.0, 0.05); - compare_silence_arms::("W4", &plan, -6.0, 100.0, 0.05); - } - /// **A block carrying automation is rendered, not skipped, and the resident tap keeps up.** /// /// Issue #182 S2 at the contract boundary rather than the kernel one: `process` and @@ -7538,40 +7507,6 @@ mod tests { ); } - /// E10: the D7 boundary check replaces every per-value recovery path. - #[test] - fn a_nonfinite_block_is_zeroed_reset_and_counted() { - let values = values_with(-6.0, 100.0, 5.0); - let mut preparation = request(&values); - preparation.link_mode = LinkMode::DualMono; - let metadata = expected_prepared_metadata(&TRUE_PEAK_LIMITER_DESCRIPTOR, preparation) - .expect("metadata"); - let (left_defaults, right_defaults) = initial_defaults(&values).expect("defaults"); - let mut core = LimiterCore::::new( - metadata, - vec![left_defaults].into_boxed_slice(), - vec![right_defaults].into_boxed_slice(), - ) - .expect("core"); - let mut left = vec![0.5_f32; 128]; - let mut right = vec![0.5_f32; 128]; - core.process_block(&mut left, &mut right, 128); - assert_eq!(core.nonfinite_report().nonfinite_blocks, 0); - - core.left.reduction[0] = f32::NAN; - let mut left = vec![0.5_f32; 128]; - let mut right = vec![0.5_f32; 128]; - core.process_block(&mut left, &mut right, 128); - assert!(left.iter().all(|sample| sample.to_bits() == 0)); - assert!(right.iter().all(|sample| sample.to_bits() == 0)); - assert_eq!(core.nonfinite_report().nonfinite_blocks, 1); - assert_eq!(core.nonfinite_report().nonfinite_lanes, 1); - assert_eq!(core.cursors, Cursors::default()); - assert_eq!(core.left.reduction[0].to_bits(), 0); - assert!(core.left.required_ring.iter().all(|value| *value == 1.0)); - assert_eq!(core.left.box_sum[0], core.left.lane[0].window as f32); - } - /// E11: the current layout round-trips, and every corruption is rejected without mutating the peer. #[test] fn state_round_trips_and_rejects_corruption() { diff --git a/crates/true-peak-limiter/tests/MUTATIONS.md b/crates/true-peak-limiter/tests/MUTATIONS.md index f82d9df10..a7813f483 100644 --- a/crates/true-peak-limiter/tests/MUTATIONS.md +++ b/crates/true-peak-limiter/tests/MUTATIONS.md @@ -27,7 +27,7 @@ cargo test -p true-peak-limiter --lib phase_outputs | 6 | `flush(target.max(released))` → `target.max(released)` | `src/lib.rs` `channel_frame` | `silence_restores_exact_identity_including_signed_zero` | | 7 | van Herk suffix pass guarded by `complete && width < 2`, so it never runs at W4/W8 | `src/lib.rs` `sliding_minimum` | `lane_identity_holds_across_widths` | | 8 | `left.prefix.fill(1.0)` / `right.prefix.fill(1.0)` at block entry (min-filter prefix not carried across blocks) | `src/lib.rs` `limiter_block` | `partition_invariance_holds_over_block_sizes` (deleted by TA4) | -| 9 | `return;` inserted after `limiter_block` so the §4.4 boundary check never runs | `src/lib.rs` `LimiterCore::process_block` | `a_nonfinite_block_is_zeroed_reset_and_counted` | +| 9 | `return;` inserted after `limiter_block` so the §4.4 boundary check never runs | `src/lib.rs` `LimiterCore::process_block` | `a_nonfinite_block_is_zeroed_reset_and_counted` (deleted by TA5; no catcher recorded) | | 10 | the `recomputed == box_sum` check in restore disabled | `src/lib.rs` `read_lane` | `state_round_trips_and_rejects_corruption` | | 11 | `peak = history[6].abs()` → `peak = L::zero()` (sample term dropped from `P`) | `src/lib.rs` `detector_peak` | `fixed_latency_guarded_ceiling_and_bypass_bits_hold` | | 12 | `box_sum.div(window)` → `box_sum.mul(1.0.div(window))` (reciprocal instead of divide) | `src/lib.rs` `channel_frame` | `silence_restores_exact_identity_including_signed_zero` | @@ -146,7 +146,7 @@ Every row below is a **bit** test. The claims here are about *when* a state word | # | mutation | file | test that turned red | |---|---|---|---| | round2-1 | the block-end write-back of `prefix` dropped | `src/lib.rs` `limiter_block_uniform` | `a_mixed_lookahead_cohort_falls_back_bit_identically`, `a_restore_that_desyncs_the_phase_falls_back`, `fixed_latency_guarded_ceiling_and_bypass_bits_hold`, `lane_identity_holds_across_widths`, `partition_invariance_holds_over_block_sizes` (deleted by TA4) | -| round2-2 | the block-end write-back of `phase` dropped, so the cohort restarts each block at the phase it entered the previous one with | `src/lib.rs` `limiter_block_uniform` | `a_de_zipper_window_open_across_a_block_boundary_refuses_the_claim`, `a_mixed_lookahead_cohort_falls_back_bit_identically`, `a_negative_zero_input_block_is_not_treated_as_silence`, `a_restore_that_desyncs_the_phase_falls_back`, `a_restore_withdraws_the_silence_claim`, `a_settled_silent_limiter_renders_exactly_the_never_fast_path` | +| round2-2 | the block-end write-back of `phase` dropped, so the cohort restarts each block at the phase it entered the previous one with | `src/lib.rs` `limiter_block_uniform` | `a_de_zipper_window_open_across_a_block_boundary_refuses_the_claim`, `a_mixed_lookahead_cohort_falls_back_bit_identically`, `a_negative_zero_input_block_is_not_treated_as_silence` (deleted by TA5; no catcher recorded), `a_restore_that_desyncs_the_phase_falls_back`, `a_restore_withdraws_the_silence_claim`, `a_settled_silent_limiter_renders_exactly_the_never_fast_path` | | round2-3 | `.min(ring - left_end)` dropped from the segment run | `src/lib.rs` `segment` | `the_segment_walk_visits_the_slots_a_frame_at_a_time_walk_visits` — **and nothing else** | | round2-4 | `.min(ring - left_expiring)` dropped from the segment run | `src/lib.rs` `segment` | `the_segment_walk_visits_the_slots_a_frame_at_a_time_walk_visits` — **and nothing else** | | round2-5 | `.min(ring - start)` dropped from the segment run | `src/lib.rs` `segment` | six render tests, including `a_settled_silent_limiter_renders_exactly_the_never_fast_path` and `a_restore_that_desyncs_the_phase_falls_back` | @@ -240,9 +240,9 @@ the recursive word, the cursors, the phases and all four ramps — are compared, | # | mutation | file | test that turned red | |---|---|---|---| -| 182-6 | input `block_is_positive_zero` legs dropped from the admission test | `src/lib.rs` `LimiterCore::process_block` | `a_settled_silent_limiter_renders_exactly_the_never_fast_path`, `a_negative_zero_input_block_is_not_treated_as_silence`, `a_stale_detector_history_refuses_the_claim` | +| 182-6 | input `block_is_positive_zero` legs dropped from the admission test | `src/lib.rs` `LimiterCore::process_block` | `a_settled_silent_limiter_renders_exactly_the_never_fast_path`, `a_negative_zero_input_block_is_not_treated_as_silence` (deleted by TA5; no catcher recorded), `a_stale_detector_history_refuses_the_claim` | | 182-7 | `block_is_positive_zero(&self.reduction)` dropped from `is_at_silent_rest` | `src/lib.rs` `ChannelState::is_at_silent_rest` | `a_limiter_still_releasing_through_the_silence_is_never_frozen` | -| 182-8 | `block_is_positive_zero(&self.main_ring)` dropped | `src/lib.rs` `ChannelState::is_at_silent_rest` | `a_settled_silent_limiter_renders_exactly_the_never_fast_path`, `a_negative_zero_input_block_is_not_treated_as_silence` | +| 182-8 | `block_is_positive_zero(&self.main_ring)` dropped | `src/lib.rs` `ChannelState::is_at_silent_rest` | `a_settled_silent_limiter_renders_exactly_the_never_fast_path`, `a_negative_zero_input_block_is_not_treated_as_silence` (deleted by TA5; no catcher recorded) | | 182-9 | `block_is_positive_zero(&self.history)` dropped | `src/lib.rs` `ChannelState::is_at_silent_rest` | `a_stale_detector_history_refuses_the_claim` — **and nothing else** | | 182-10 | output `block_is_positive_zero` legs dropped from the claim | `src/lib.rs` `LimiterCore::process_block` | `a_settled_silent_limiter_renders_exactly_the_never_fast_path` | | 182-11 | `self.cursors.advance(frames, &self.shape)` deleted from the fast path | `src/lib.rs` `LimiterCore::process_block` | `a_settled_silent_limiter_...`, `a_negative_zero_input_...`, `a_stale_detector_history_...` (via the state comparison, not the sample comparison) | @@ -641,9 +641,3 @@ NL green is the case's reference: its pin is the words of the pre-#990 behaviour here; the session test's "equal" check (`ch16`) still owns it at every width. E0 is green at `Simd8` because lanes 0 and 7 unlink in the same block, so the eight-lane bank unlinks through lane 7; the session test's `ch48` row still owns E0 and EL at `Simd8`. - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `partition_invariance_holds_over_block_sizes`: no plausible same-crate KEEP catcher recorded diff --git a/hosts/host-web/MUTATIONS.md b/hosts/host-web/MUTATIONS.md index cd710ca5d..09bc84391 100644 --- a/hosts/host-web/MUTATIONS.md +++ b/hosts/host-web/MUTATIONS.md @@ -565,9 +565,3 @@ qualification of decision 15's heavy gates" (#1605) or the first CI run that app | same (S3), Chromium, Firefox, WebKit | in `#submit` (`sdk/src/core/observation-subscriptions.ts`), drop `if (!rendered)` so the typed refusal is thrown whatever `next` returns | gate 3: the render instance's close ends in `backpressure` (`resolved: false`, log `[ok, bp]`) | | same (S4) | `current.renderedQuanta >= since` in `next` | gate 1: early, and more than one close send in the log | | same (S5) | the browser engine passes no `renderWait` | gates 1 and 3 | - -## TA4 deletions - -The 2026-10 test audit (TA4, batch 1 mutation measurement at `81a3074fc`) deleted the tests named below. Where a KEEP test is named, batch 1 recorded it red on that test's sampled mutants in this crate; the mutation of each row above was not re-run. Where none is named, batch 1 recorded no same-crate catcher that could plausibly see the row's mutation. - -- `default_ring_covers_stall_tolerance`: no plausible same-crate KEEP catcher recorded diff --git a/hosts/host-web/tests/control_parity.rs b/hosts/host-web/tests/control_parity.rs index 53fb7e85e..23ddfe631 100644 --- a/hosts/host-web/tests/control_parity.rs +++ b/hosts/host-web/tests/control_parity.rs @@ -2112,133 +2112,6 @@ fn a_stale_effect_row_edit_is_refused_alike_on_both_hosts() { } } -/// #1623 (root ruling, thick core): a `RESPONSE_GET` frame whose value the Rust encoder refuses -/// -- a NaN or infinite axis endpoint, a NaN override value, a bypass value between 0 and 1 -- is -/// decoded as sent and refused by the core on both hosts, with one result, the same reply bytes -/// and the same typed code (`response.grid`, `response.override.value`, -/// `response.override.bypass`), and changes nothing: the control rows and the document are the -/// bytes they were on each host. -/// -/// Test value: red if either host's codec refuses the value again (the code becomes the generic -/// `protocol.failure`), if one host checks a value the other does not, or if a refusal changes -/// state. -#[test] -fn a_response_request_with_a_bad_value_is_refused_alike_on_both_hosts() { - let request = protocol::ResponseGetRequest { - target: protocol::ResponseTarget::Configuration(protocol::ResponseConfiguration::Effect { - effect: "miso.parametric-eq".to_owned(), - quality: session::EffectQuality::Normal, - link_mode: session::LinkMode::DualMono, - }), - grid: protocol::ResponseGrid::Logarithmic, - points: 64, - minimum_hz: 20.0, - maximum_hz: 20_000.0, - channels: protocol::ParameterChannel::Both, - sections: false, - overrides: vec![ - protocol::ResponseOverride { - control: protocol::RESPONSE_BYPASS_CONTROL, - lane: protocol::ParameterChannel::Both, - value: 1.0, - }, - protocol::ResponseOverride { - control: 4, - lane: protocol::ParameterChannel::Both, - value: 3.25, - }, - ], - configuration_id: None, - sample_rate_hz: None, - quantum_frames: None, - maximum_prepared_bytes: None, - maximum_state_bytes: None, - maximum_scratch_bytes: None, - maximum_automation_spans: None, - maximum_reply_bytes: None, - }; - let model = model_at(48_000); - let mut browser = Rig::new(&model); - let mut c_abi = CAbi::new(&model); - // One frame, sent to both hosts, with a request ID past both legs' counters (the C ABI leg - // pages its control dumps in more frames), which the C ABI leg's counter then takes: each host - // sees ascending IDs, and both see the same frame. - let next_frame = |browser: &mut Rig, c_abi: &mut CAbi| loop { - let frame = browser.encode(CommandPayload::ResponseGet(&request), ExpectedRevision::Any); - let id = u64::from_le_bytes(frame[24..32].try_into().expect("request ID")); - if id > c_abi.request { - c_abi.request = id; - break frame; - } - }; - let frame = next_frame(&mut browser, &mut c_abi); - // The unpatched request is answered alike. - let (b, c) = (browser.send_frame(&frame), c_abi.send_raw(&frame)); - assert_eq!(b, c, "one answer to the unpatched request"); - assert_eq!(b.0, C_RESULT_OK); - let before_b = dump(|payload, expected| browser.command(payload, expected)); - let before_c = dump(|payload, expected| c_abi.send(payload, expected)); - assert_eq!(before_b, before_c); - let patched = |frame: Vec, from: f32, to: f32| { - let from = from.to_le_bytes(); - let at: Vec = frame - .windows(4) - .enumerate() - .filter(|(_, window)| *window == from) - .map(|(at, _)| at) - .collect(); - assert_eq!(at.len(), 1, "the value is in the frame exactly once"); - let mut bytes = frame; - bytes[at[0]..at[0] + 4].copy_from_slice(&to.to_le_bytes()); - bytes - }; - for (name, from, to, code) in [ - ("a NaN minimum", 20.0, f32::NAN, "response.grid"), - ( - "an infinite maximum", - 20_000.0, - f32::INFINITY, - "response.grid", - ), - ( - "a NaN override value", - 3.25, - f32::NAN, - "response.override.value", - ), - ("a bypass of one half", 1.0, 0.5, "response.override.bypass"), - ] { - let bytes = patched(next_frame(&mut browser, &mut c_abi), from, to); - let (b, c) = (browser.send_frame(&bytes), c_abi.send_raw(&bytes)); - assert_eq!(b, c, "{name}: one answer on both hosts"); - assert_eq!(b.0, C_RESULT_OK, "{name}: a refusal is a non-OK frame"); - let mut fields = [0_u16; 1024]; - let DecodedTypedResponseFrame::NonOk { header, payload } = ProtocolCodec::default() - .decode_typed_response(&b.1, &mut DecodeScratch::new(&mut fields)) - .expect("a typed response") - else { - panic!("{name}: expected a refusal"); - }; - assert_eq!(header.status, protocol::StatusCode::InvalidField, "{name}"); - let codes: Vec<_> = payload - .diagnostics - .iter() - .map(|d| d.code.as_str()) - .collect(); - assert_eq!(codes, [code], "{name}"); - assert_eq!( - dump(|payload, expected| browser.command(payload, expected)), - before_b, - "{name}: the browser host is unchanged" - ); - assert_eq!( - dump(|payload, expected| c_abi.send(payload, expected)), - before_c, - "{name}: the C ABI is unchanged" - ); - } -} - /// Block the bypass of `a_live_bypass_crossfades_alike_on_both_hosts` is submitted before. const BYPASS_BLOCK: u64 = 6; @@ -3176,25 +3049,8 @@ fn a_moved_target_defers_its_jump_alike_on_both_hosts() { } } -/// #1711 U1 fold 1 (MAJOR-1) across hosts: on a fader ride flat at -3 dB, a hand move with its -/// own 4,000 samples heard 3 blocks, then a table-only rebuild to -5 dB up to 2,000, a linear -8 -/// to -14 dB over 2,000 to 8,000, then -14 dB. The moved target defers the cell's jump to the -/// move's first free sample (4,512), and the table's step at 2,000, inside the move's ramp, -/// replaces the ramp the deferral waits for. Both hosts give one verdict and reply per edit, the -/// same bits in every block and the same watermark (`EXACT`, no transition fallback), and every -/// block equals the pair of rigs prepared with -3 dB before 2,000 (the same table after it), -/// given the same move and, at the same block, a table-only rebuild that moves nothing (a split -/// at 950,000), at the four rates. Both rebuilds keep the hand move's stored offset. -/// -/// Test value: red if a discontinuity jump on a restartable cell leaves the pending deferral in -/// place (its grid hold freezes the lane on the step's target until 4,512), on either host. -#[test] -fn a_table_step_inside_a_deferred_moves_ramp_lands_alike_on_both_hosts() { - table_step_inside_a_deferred_move(model_at); -} - /// #1655 U3 fold 1 (MAJOR-1) across hosts: the composed twin of -/// [`a_table_step_inside_a_deferred_moves_ramp_lands_alike_on_both_hosts`]. `t1` is also in VCA +/// `a_table_step_inside_a_deferred_moves_ramp_lands_alike_on_both_hosts` (deleted by TA5). `t1` is also in VCA /// `v`, whose `offset_db` rides linearly from 0 to -6 dB over 48,000 samples in every plan, so /// `t1`'s fader channels are composed lanes over its own ride and the VCA's. The adoption holds /// and defers every cursor; the own table's step at 2,000 replaces the move's ramp on the whole @@ -3223,8 +3079,8 @@ fn a_table_step_inside_a_deferred_moves_ramp_releases_a_composed_lane_alike_on_b }); } -/// The body of [`a_table_step_inside_a_deferred_moves_ramp_lands_alike_on_both_hosts`] over the -/// session `model_of(rate)`. +/// The table step inside a deferred move's ramp (#1711 U1 fold 1), over the session +/// `model_of(rate)`. fn table_step_inside_a_deferred_move(model_of: fn(u32) -> SessionModel) { let segment = |shape, start, end, from, to| session::AutomationSegment { shape, diff --git a/tools/bench-support/src/json.rs b/tools/bench-support/src/json.rs index 56ccedb67..54f68dca7 100644 --- a/tools/bench-support/src/json.rs +++ b/tools/bench-support/src/json.rs @@ -84,12 +84,6 @@ mod tests { ); } - #[test] - fn serializes_empty_and_empty_element_arrays() { - assert_eq!(json_string_array(&[]), "[]"); - assert_eq!(json_string_array(&[String::new()]), "[\"\"]"); - } - #[test] fn serializes_ordered_duplicate_elements() { let values = ["first", "first", "second"] diff --git a/tools/console-workload/tests/automation.rs b/tools/console-workload/tests/automation.rs index e3704142a..df911198f 100644 --- a/tools/console-workload/tests/automation.rs +++ b/tools/console-workload/tests/automation.rs @@ -180,9 +180,8 @@ mod mixing { use console_workload::SessionRuntime; use console_workload::mixing_automation::{ - self, Arm, CONTROLS, Effect, Lowering, MixingArm, MixingAutomation, ResolveError, + self, Arm, CONTROLS, Lowering, MixingAutomation, ResolveError, }; - use effect_contract::ParameterChannel; use lane::Backend; /// Every control resolves by `(track_id, effect contract id)` to its own channel, and names @@ -312,84 +311,4 @@ mod mixing { let restated = preflight.collapse(Arm::Restated, None); assert!(restated[0] <= quiet[0]); } - - /// The EQ is pushed as the SDK pushes it: a Left edit then a Right edit, as two - /// `push_parameter` calls. Both landing before a block reads them keep the collapse, because - /// the target cells hold the latest word per channel and the block sees two equal words - /// (VERIFY-AUTOMATION F2, issue #1345). A block that runs between the two edits reads one - /// channel changed and retires the three EQ cohorts, and they stay retired for the whole - /// preroll: the lane's words differ from then on, so no block of it runs collapsed. - #[test] - fn the_eq_lowering_keeps_the_collapse_when_a_pair_lands_in_one_block() { - let backend = Backend::current(); - let eq_both = MixingArm::prepare(Arm::Restated, Some(Effect::Eq), backend); - let quiet = MixingArm::prepare(Arm::Quiet, None, backend); - assert_eq!( - eq_both.runtime.bank_collapse_counters(), - quiet.runtime.bank_collapse_counters(), - "a Both EQ restatement keeps every cohort collapsed" - ); - let [kept, cohorts] = quiet.runtime.bank_collapse_counters(); - let mut together = SessionRuntime::build_with_dispatch( - mixing_automation::WORKLOAD, - mixing_automation::CONFIG, - backend, - ); - let mut apart = SessionRuntime::build_with_dispatch( - mixing_automation::WORKLOAD, - mixing_automation::CONFIG, - backend, - ); - let automation = MixingAutomation::resolve(&together).expect("controls"); - let eq_controls: Vec<_> = automation - .controls() - .iter() - .filter(|control| control.control.effect == Effect::Eq) - .collect(); - for control in &eq_controls { - for side in [ParameterChannel::Left, ParameterChannel::Right] { - assert!(together.push_parameter( - control.channel, - control.control.parameter_index, - side, - control.base - )); - } - } - for block in 0..mixing_automation::PREROLL_BLOCKS { - together.render(block).expect("render"); - } - let [together_kept, _] = together.bank_collapse_counters(); - assert_eq!( - together_kept, kept, - "a Left and a Right edit before one block keep all {cohorts} cohorts collapsed" - ); - for control in &eq_controls { - assert!(apart.push_parameter( - control.channel, - control.control.parameter_index, - ParameterChannel::Left, - control.base - )); - } - apart.render(0).expect("render"); - for control in &eq_controls { - assert!(apart.push_parameter( - control.channel, - control.control.parameter_index, - ParameterChannel::Right, - control.base - )); - } - for block in 1..mixing_automation::PREROLL_BLOCKS { - apart.render(block).expect("render"); - } - let [apart_kept, _] = apart.bank_collapse_counters(); - assert_eq!( - apart_kept, - kept - 3 * mixing_automation::PREROLL_BLOCKS, - "a block between the edits retires the three EQ cohorts of the {cohorts} for the whole \ - preroll" - ); - } } diff --git a/tools/console-workload/tests/paired_spans.rs b/tools/console-workload/tests/paired_spans.rs index 707710ed2..eaf603a3a 100644 --- a/tools/console-workload/tests/paired_spans.rs +++ b/tools/console-workload/tests/paired_spans.rs @@ -1410,11 +1410,6 @@ fn the_limiter_bank_renders_the_dual_bits_in_every_scenario() { run_all(&[Fx::Limiter]); } -#[test] -fn the_chained_strip_renders_the_dual_bits_in_every_scenario() { - run_all(&[Fx::Eq, Fx::Compressor, Fx::Limiter]); -} - /// Every order of a mixed drain on the chained strip: one-channel, `Both` and paired writes in /// one block, across the EQ's target cells and the compressor's and the limiter's parameter /// cells. diff --git a/tools/realtime-policy/tests/policy/calls.rs b/tools/realtime-policy/tests/policy/calls.rs index 14355d49f..003d6fb63 100644 --- a/tools/realtime-policy/tests/policy/calls.rs +++ b/tools/realtime-policy/tests/policy/calls.rs @@ -253,46 +253,6 @@ fn an_iterator_that_pops_is_refused() { refuses("calls-iterator-count", &with_count, &[ITERATOR]); } -#[test] -fn every_iterator_trait_and_every_rename_of_one_is_refused() { - for (name, header) in [ - ("double-ended", "impl DoubleEndedIterator for Lane"), - ("into", "impl IntoIterator for Lane"), - ("path", "impl core::iter::Iterator for Lane"), - ("raw", "impl r#Iterator for Lane"), - ] { - let text = marked(&format!( - "{header} {{\n fn next_back(&mut self) -> Option {{\n self.control.try_pop().ok()\n }}\n}}\n" - )); - refuses(&format!("calls-trait-{name}"), &text, &[ITERATOR]); - } - // A `use` renames the trait: the impl names the new spelling, in another file. - let tree = super::common::Tree::base("calls-trait-renamed"); - tree.apply(&[ - Edit::Create { - path: "crates/pops/src/lib.rs", - text: "mod alias;\nmod model;\n", - }, - Edit::Create { - path: "crates/pops/src/alias.rs", - text: "use core::iter::Iterator as Walk;\n", - }, - Edit::Create { - path: "crates/pops/src/model.rs", - text: &marked( - "impl Walk for Lane {\n fn next(&mut self) -> Option {\n self.control.try_pop().ok()\n }\n}\n", - ), - }, - ]); - let report = tree.check(); - assert_eq!( - report.classes(), - [ITERATOR].into_iter().collect(), - "{:#?}", - report.findings - ); -} - #[test] fn an_iterator_that_does_not_pop_and_a_pop_in_another_trait_are_accepted() { let quiet = "impl Iterator for Lane {\n type Item = Record;\n fn next(&mut self) -> Option {\n self.items.pop()\n }\n}\n"; diff --git a/tools/realtime-policy/tests/policy/drain/forms.rs b/tools/realtime-policy/tests/policy/drain/forms.rs index 5476730d5..d0f01068f 100644 --- a/tools/realtime-policy/tests/policy/drain/forms.rs +++ b/tools/realtime-policy/tests/policy/drain/forms.rs @@ -2,12 +2,10 @@ //! region (D1), the scope that resolves a count (D2), the syntax it visits (D4) and what counts as //! a pop (D5). -use realtime_policy::Class; - use super::super::common::{ BASE_FILES, BASE_REGIONS, BEGIN, END, Edit, expect_failure, expect_valid, }; -use super::{ANCHOR, BUILTINS_COMPILER, DRAIN, accepts, each_row, refuses}; +use super::{DRAIN, accepts, each_row, refuses}; const BUFFER: &str = "crates/engine/src/realtime/buffer.rs"; @@ -237,22 +235,6 @@ fn a_pop_below_a_node_outside_the_allow_list_is_refused() { each_row(rows, |name, text| refuses(name, &text)); } -/// D4: `Expr::Async` is not on the list. The `async` keyword is forbidden too (A2), so both -/// classes report. -#[test] -fn a_counted_drain_in_an_async_block_is_refused_twice() { - let text = "fn drain(control: &mut Consumer) {\n let _ = async {\n let available = control.available_at_entry();\n for _ in 0..available {\n let Ok(record) = control.try_pop() else {\n break;\n };\n apply(record);\n }\n };\n}"; - expect_failure( - "drain-in-async-block", - &[Edit::ReplaceLine { - path: BUILTINS_COMPILER, - old: ANCHOR, - new: text, - }], - &[Class::ForbiddenBody, DRAIN], - ); -} - /// D5: a raw-identifier method name is the same method. #[test] fn a_raw_identifier_pop_is_a_pop() { @@ -262,21 +244,6 @@ fn a_raw_identifier_pop_is_a_pop() { ); } -/// D3: a loop outside a nested `fn` counts as around a pop inside it. -#[test] -fn a_pop_in_a_nested_function_is_judged_by_the_loops_outside_it() { - // The loop also calls the nested function, which pops: the call rule (#1444) refuses that too. - expect_failure( - "pop-in-a-nested-function-in-an-unbounded-loop", - &[Edit::ReplaceLine { - path: super::BUILTINS_COMPILER, - old: super::ANCHOR, - new: "fn drain(control: &mut Consumer) {\n loop {\n fn helper(control: &mut Consumer) {\n let _ = control.try_pop();\n }\n helper(control);\n break;\n }\n}", - }], - &[DRAIN, Class::PoppingCall], - ); -} - /// D1: every node the rule reads lies in the pop's region. The same drain passes when its count /// binding is inside the region. #[test] diff --git a/tools/realtime-policy/tests/policy/drain/twins.rs b/tools/realtime-policy/tests/policy/drain/twins.rs index 06281e6af..622fd4205 100644 --- a/tools/realtime-policy/tests/policy/drain/twins.rs +++ b/tools/realtime-policy/tests/policy/drain/twins.rs @@ -13,15 +13,6 @@ fn a_single_pop_in_a_method_chain_passes() { ); } -/// `acquire_current_block`: two counted phases with a re-observe between them. -#[test] -fn the_two_phase_acquire_passes() { - accepts( - "twin-two-phase-acquire", - "impl Consumer {\n fn acquire(&mut self, clock: Clock) {\n if self.current.is_some() {\n return;\n }\n let available = self\n .data_consumer\n .available_at_entry()\n .min(self.transfer_block_count);\n let mut popped = 0_usize;\n let mut unobserved = None;\n for _ in 0..available {\n let Ok(block) = self.data_consumer.try_pop() else {\n break;\n };\n popped += 1;\n if self.is_unobserved(block.generation) {\n unobserved = Some(block);\n break;\n }\n if self.settle(block) {\n return;\n }\n }\n let Some(block) = unobserved else {\n return;\n };\n self.observe(clock);\n if self.settle(block) {\n return;\n }\n let unpopped = available.saturating_sub(popped);\n let rest = self.data_consumer.available_at_entry().min(unpopped);\n for _ in 0..rest {\n let Ok(block) = self.data_consumer.try_pop() else {\n break;\n };\n if self.settle(block) {\n return;\n }\n }\n }\n}", - ); -} - /// The spectrum capture's drains: a named cap, a `break` on an empty queue, and a read that matches /// the pop and returns after the loop. #[test] @@ -31,13 +22,3 @@ fn the_spectrum_drains_pass() { "impl Capture {\n fn cancel(&mut self) {\n let available = self.consumer.available_at_entry().min(RESULT_SLOTS);\n for _ in 0..available {\n if self.consumer.try_pop().is_err() {\n break;\n }\n }\n self.reset();\n }\n\n fn read_record(&mut self) -> Result {\n match self.state.load() {\n COMPLETE => match self.consumer.try_pop() {\n Ok(record) => Ok(record),\n Err(_) => Err(ReadError::Pending),\n },\n INVALID => {\n let _ = self.consumer.try_pop();\n Err(ReadError::Invalid)\n }\n _ => Err(ReadError::Invalid),\n }\n }\n\n fn read_continuous(&mut self) -> Result {\n let available = self.consumer.available_at_entry().min(RESULT_SLOTS);\n for _ in 0..available {\n match self.consumer.try_pop() {\n Ok(record) if self.stale(&record) => {}\n Ok(record) => {\n return Ok(record);\n }\n Err(_) => return Err(ReadError::Pending),\n }\n }\n Err(ReadError::Warming)\n }\n}", ); } - -/// The collection's `cancel_except`: a drain loop over the captures that names `capture` only in -/// its count and its pop, then a reset loop of the same header with a pop-free call. -#[test] -fn the_collection_cancel_except_passes() { - accepts( - "twin-cancel-except", - "impl Collection {\n fn cancel_except(&mut self, keep: Option) {\n for (index, capture) in self.captures.iter_mut().enumerate() {\n if keep == Some(index) {\n continue;\n }\n let available = capture.consumer.available_at_entry().min(RESULT_SLOTS);\n for _ in 0..available {\n if capture.consumer.try_pop().is_err() {\n break;\n }\n }\n }\n for (index, capture) in self.captures.iter_mut().enumerate() {\n if keep == Some(index) {\n continue;\n }\n capture.reset();\n }\n }\n}", - ); -} diff --git a/tools/realtime-policy/tests/policy/markers.rs b/tools/realtime-policy/tests/policy/markers.rs index d4445f599..3339545e4 100644 --- a/tools/realtime-policy/tests/policy/markers.rs +++ b/tools/realtime-policy/tests/policy/markers.rs @@ -19,19 +19,6 @@ fn rewrite<'a>(path: &'a str, text: &'a str) -> [Edit<'a>; 2] { [Edit::Delete { path }, Edit::Create { path, text }] } -#[test] -fn a_marker_written_in_a_string_literal_is_malformed() { - // One line: the marker word inside a literal. - let one_line = format!("const S: &str = \"// {BEGIN}\";\n"); - expect_failure("marker-in-string", &append(&one_line), &[MALFORMED]); - // Across lines: the middle line is a valid-looking marker line, and only the literal that - // spans it says otherwise. - let spanning = format!("const S: &str = \"\n// {BEGIN}\n\";\n"); - expect_failure("marker-line-in-string", &append(&spanning), &[MALFORMED]); - let raw = format!("const S: &str = r#\"\n// {END}\n\"#;\n"); - expect_failure("marker-line-in-raw-string", &append(&raw), &[MALFORMED]); -} - #[test] fn a_marker_written_in_a_doc_comment_is_malformed() { let line_doc = format!("/// {BEGIN}\nfn documented() {{}}\n"); @@ -189,16 +176,6 @@ fn unmatched_markers_name_the_file_and_drop_it_from_the_floors() { assert_eq!(unmatched.path.as_deref(), Some("hosts/host-web/src/lib.rs")); } -#[test] -fn the_file_floor_fires_when_a_marked_file_loses_its_markers() { - // Removing every marker line of one file drops the file and its regions; its code stays, - // including the file's unmarked `try_pop` drains. - let tree = Tree::base("marked-file-count-floor"); - strip_marker_lines(&tree, "crates/builtins/src/lib.rs"); - // The file's drains are pops outside every region now (#1443 D2). - super::common::assert_classes(&tree, &[Class::UnmarkedTryPop, FILE_FLOOR, REGION_FLOOR]); -} - #[test] fn the_floors_fire_when_no_file_is_marked() { let tree = Tree::base("no-marked-files"); diff --git a/tools/realtime-policy/tests/policy/source_reads.rs b/tools/realtime-policy/tests/policy/source_reads.rs index 316525e27..d3bb48e95 100644 --- a/tools/realtime-policy/tests/policy/source_reads.rs +++ b/tools/realtime-policy/tests/policy/source_reads.rs @@ -162,29 +162,6 @@ fn a_path_that_is_not_a_string_literal_is_a_finding() { } } -/// rustc reads `r#path` as `path` and `r#include` as `include`. -#[test] -fn raw_identifiers_do_not_hide_a_path_or_an_include() { - expect_failure( - "reads-raw-path", - &[create(READS, "#[r#path = \"shadow.txt\"]\nmod m;\n")], - &[PATH], - ); - expect_failure( - "reads-raw-include", - &[ - create(READS, "const X: u8 = r#include!(\"hidden.in\");\n"), - create("crates/lane/src/hidden.in", LOOPING_TRAIT), - ], - &[INCLUDE], - ); - expect_failure( - "reads-raw-include-import", - &[create(READS, "use std::r#include as inc;\n")], - &[INCLUDE_IMPORT], - ); -} - #[test] fn an_include_of_source_is_a_finding() { expect_failure( diff --git a/tools/realtime-policy/tests/policy/unmarked.rs b/tools/realtime-policy/tests/policy/unmarked.rs index 77c32d509..4270eadb8 100644 --- a/tools/realtime-policy/tests/policy/unmarked.rs +++ b/tools/realtime-policy/tests/policy/unmarked.rs @@ -200,16 +200,6 @@ fn every_declaration_must_be_test_code() { const QUEUES: &str = "struct Queues;\nimpl Queues {\n fn dequeue(&mut self, c: &mut Consumer) {\n while let Ok(r) = c.try_pop() {\n apply(r);\n }\n }\n}\n"; -#[test] -fn an_allowlisted_function_admits_its_pops() { - entries( - "allowed", - &[create(LIB, QUEUES)], - vec![entry(LIB, "Queues::dequeue", 1)], - &[], - ); -} - #[test] fn an_entry_admits_one_function_only() { let text = format!( diff --git a/tools/realtime-policy/tests/policy/web_host.rs b/tools/realtime-policy/tests/policy/web_host.rs index 12742693a..d36a2aa51 100644 --- a/tools/realtime-policy/tests/policy/web_host.rs +++ b/tools/realtime-policy/tests/policy/web_host.rs @@ -209,41 +209,6 @@ fn a_path_on_a_guarded_module_or_an_inline_module_is_refused() { ); } -/// Rule (d): a glob `use` among the top-level items of `ffi.rs` or `render_lock.rs`, plain, -/// public or grouped. A glob in a child module is not refused. -#[test] -fn a_top_level_glob_use_is_refused_and_a_child_module_glob_is_not() { - let globs = [ - "use crate::fake::*;", - "pub use crate::fake::*;", - "use crate::{fake::*, other};", - "use crate::fake::{self, *};", - ]; - for (index, glob) in globs.iter().enumerate() { - for path in [FFI, RENDER_LOCK] { - let report = expect_failure( - &format!("web-glob-{index}-{}", path.len()), - &[append(path, &format!("{glob}\n"))], - &[Class::GlobInWrapModule], - ); - assert_eq!(report.findings.len(), 1, "{glob} in {path}"); - assert_eq!(report.findings[0].path.as_deref(), Some(path)); - } - } - // `use super::*;` in a child module that holds no listed export (the shape of the five test - // modules of the real tree) cannot change how an export or the import resolves. - expect_valid( - "web-glob-child-module", - &[ - append( - FFI, - "#[cfg(test)]\nmod child_tests {\n use super::*;\n}\npub(crate) mod live_tests {\n pub use super::*;\n}\n", - ), - append(RENDER_LOCK, "mod more {\n use super::*;\n}\n"), - ], - ); -} - /// A listed export must be a top-level item of `ffi.rs`: moved into a child module (where a glob /// is not refused) it is missing, not accepted. #[test] diff --git a/tools/realtime-policy/tests/policy/whole_plan.rs b/tools/realtime-policy/tests/policy/whole_plan.rs index 9ff0c02ef..28fb32e2b 100644 --- a/tools/realtime-policy/tests/policy/whole_plan.rs +++ b/tools/realtime-policy/tests/policy/whole_plan.rs @@ -107,13 +107,6 @@ fn a_missing_file_or_a_render_entry_only_in_tests_is_a_finding() { ); } -/// The test module no longer ends the scan: items after it are production code. -#[test] -fn a_whole_plan_borrow_after_the_test_module_is_a_finding() { - let after = format!("fn after_tests(plan: *mut Plan) {{ let _ = {UNSAFE} {{ &*plan }}; }}\n"); - expect_failure("whole-plan-after-tests", &[append(&after)], &[WHOLE_PLAN]); -} - /// Only a module named `tests` under exactly `#[cfg(test)]` is test code. #[test] fn only_a_cfg_test_module_named_tests_is_skipped() {