[BUGFIX] Reject conditioned/gated configs in the A2 fast-path detector#301
Merged
sdatkinson merged 1 commit intoJun 25, 2026
Merged
Conversation
is_a2_shape() validated the layer array exhaustively but never inspected the
top-level "condition_dsp" key. The generic WaveNet, given a non-null
condition_dsp, builds a nested model and routes the conditioning signal through
it before the layer stack (model.cpp); the A2 fast path has no such stage and
feeds the raw input as the condition. Because the condition DSP carries its own
weights, the parent WaveNet weight stream is byte-identical with or without it,
so the loader's weight-count check cannot catch the mismatch. The dispatcher
(model.cpp: create_config) consults is_a2_shape before it would ever read
condition_dsp, so an A2-shaped config that also carries a condition_dsp was
silently routed to the fast path and produced different audio than the generic
WaveNet it is meant to replace -- with no error.
This contradicts the A2 fast-path's stated invariant ("checks every knob
against the A2 signature ... never silently routes a non-A2 model to the fast
path"), and conditioning a WaveNet with a nested model is a real feature.
Reject any config with a non-null top-level condition_dsp. Also reject the
legacy boolean `gated: true` (pre-gating_mode schema), which maps to GATED
layers the fast path doesn't implement -- previously caught only indirectly by a
downstream weight-count throw; now rejected by the detector so the boundary is
enforced in one place.
Adds test_detector_rejects_condition_dsp and test_detector_rejects_legacy_gated,
mirroring the existing detector-rejection tests. Verified both fail without the
guards (the detector accepts the config) and pass with them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The A2 fast-path detector
is_a2_shapevalidated the layer array exhaustivelybut never inspected the top-level
condition_dspkey. The genericWaveNet, given a non-nullcondition_dsp, builds a nested model and routes theconditioning signal through it before the layer stack (
model.cpp:841,_process_condition). The A2 fast path has no such stage — it feeds the rawinput as the conditioning signal (
a2_fast.cpp,cond[f] = x).Because the condition DSP carries its own weights (
WaveNet::set_weights_skips them,
model.cpp:626), the parent weight stream is byte-identical with orwithout it, so the loader's weight-count check cannot catch the mismatch. The
dispatcher (
model.cpp:1233,create_config) consultsis_a2_shapebeforeit would ever read
condition_dsp, so an A2-shaped config that also carries acondition_dspwas silently routed to the fast path and produced differentaudio than the generic WaveNet — with no error.
This contradicts the A2 fast-path's own stated invariant (PR #251: "checks
every knob against the A2 signature … never silently routes a non-A2 model to
the fast path"), and conditioning a WaveNet with a nested model is a real
feature (#188 — "investigated during A2 development to have a conditioning
WaveNet compute the features that condition the main WaveNet").
Fix
is_a2_shaperejects any config with a non-null top-levelcondition_dsp.gated: true(pre-gating_modeschema),which maps to GATED layers the fast path doesn't implement. Previously this was
caught only indirectly by a downstream weight-count throw; now the detector
enforces the boundary in one place.
Both fall back to the generic WaveNet, which handles these configs correctly.
Tests
Adds
test_detector_rejects_condition_dspandtest_detector_rejects_legacy_gated,mirroring the existing
test_detector_rejects_*cases. Verified both failwithout the guards (the detector wrongly accepts the config — confirmed
end-to-end with a probe showing
is_a2_shapereturningtrueon a conditionedA2 config) and pass with them. Full
run_testssuite passes.