Skip to content

[BUGFIX] Reject conditioned/gated configs in the A2 fast-path detector#301

Merged
sdatkinson merged 1 commit into
sdatkinson:mainfrom
rhaist:rhabugfix/a2-detector-condition-dsp
Jun 25, 2026
Merged

[BUGFIX] Reject conditioned/gated configs in the A2 fast-path detector#301
sdatkinson merged 1 commit into
sdatkinson:mainfrom
rhaist:rhabugfix/a2-detector-condition-dsp

Conversation

@rhaist

@rhaist rhaist commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

The A2 fast-path detector 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:841,
_process_condition). The A2 fast path has no such stage — it feeds the raw
input
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 or
without it, so the loader's weight-count check cannot catch the mismatch. The
dispatcher (model.cpp:1233, 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
— 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_shape rejects any config with a non-null top-level condition_dsp.
  • Also rejects the legacy boolean gated: true (pre-gating_mode schema),
    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_dsp and test_detector_rejects_legacy_gated,
mirroring the existing test_detector_rejects_* cases. Verified both fail
without the guards
(the detector wrongly accepts the config — confirmed
end-to-end with a probe showing is_a2_shape returning true on a conditioned
A2 config) and pass with them. Full run_tests suite passes.

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.

@sdatkinson sdatkinson left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@sdatkinson sdatkinson changed the title Reject conditioned/gated configs in the A2 fast-path detector [BUGFIX] Reject conditioned/gated configs in the A2 fast-path detector Jun 25, 2026
@sdatkinson sdatkinson merged commit 7b4c3de into sdatkinson:main Jun 25, 2026
4 checks passed
@rhaist rhaist deleted the rhabugfix/a2-detector-condition-dsp branch June 26, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants