Skip to content

fix(pipeline): tolerate a flaky synthesizer instead of 502ing the fusion (#32) - #33

Merged
stubbi merged 1 commit into
mainfrom
fix/synthesis-retry-and-degrade
Jun 20, 2026
Merged

stubbi merged 1 commit into
mainfrom
fix/synthesis-retry-and-degrade

Conversation

@stubbi

@stubbi stubbi commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #32. In a live benchmark a slow, flaky synthesizer (26-89s, returning bodies chorus could not decode) 502'd the entire fusion for every task, even though the panel had produced usable answers. The panel tolerates a flaky member via min_quorum and the judge already degrades gracefully; the synthesizer was the one stage with no tolerance.

Change

  • run_synthesis retries once on any synthesizer failure. A single transient slow or undecodable response gets one more chance before the error is surfaced (issue option a).
  • If the retry also fails, the pipeline degrades to the strongest panel answer (the longest non-empty response) returned under the fusion/<profile> alias, rather than erroring (issue option b). It only returns Error::Synthesis when no panel answer is available to fall back to.
  • A new chorus_synthesis_degraded_total counter (labelled by profile) makes the degradation observable rather than silent.

This follows operating principle 4 (boring failure behavior): partial failure degrades predictably, it does not crash a request. It mirrors the existing judge degradation path. Option (c) from the issue (more lenient decoding of specific upstream response shapes) is a separate, backend-client-level change and is not needed for the fusion to stay up.

Tests (same commit)

  • run_synthesis_retries_once_on_transient_error: a backend that fails the first call and succeeds the second returns the synthesized answer after exactly two calls.
  • run_synthesis_surfaces_synthesis_error_after_retry_exhausted: an always-failing synthesizer yields Error::Synthesis.
  • degrades_to_panel_answer_when_synthesis_fails: a never-decoding synthesizer yields a panel answer under the fusion alias, with panel and judge usage still accounted (no synthesizer usage on the degraded answer).

Verification

cargo test --workspace (45 core + 6 server integration), cargo clippy --workspace --all-targets -- -D warnings, and cargo fmt --all -- --check all pass locally. No public quality or cost numbers changed, so no benchmark run is required.

…ion (#32)

The synthesizer is a single call with no quorum, so a slow or flaky synthesizer
that returned an undecodable body (observed in a live benchmark: a 26-89s model
returning bodies chorus could not decode) failed the entire fusion for every
task, even though the panel had produced usable answers. The panel tolerates a
flaky member via min_quorum and the judge already degrades gracefully; the
synthesizer was the one stage with no tolerance.

run_synthesis now retries once on any synthesizer failure (a transient slow or
undecodable response gets one more chance). If the retry also fails, the
pipeline degrades to the strongest panel answer (longest non-empty response)
under the fusion alias rather than erroring, and increments a new
chorus_synthesis_degraded_total counter so the degradation is observable. It
only surfaces Error::Synthesis when no panel answer is available to fall back
to. This follows the "boring failure behavior" operating principle: partial
failure degrades predictably, it does not crash a request.

Adds tests for the synthesizer retry (recovers after one transient failure;
surfaces the error after the retry is exhausted) and for the pipeline
degradation (a never-decoding synthesizer yields a panel answer with panel and
judge usage still accounted, not a 502).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jannes Stubbemann <jannes.stubbemann@gmail.com>
@stubbi
stubbi merged commit 685d726 into main Jun 20, 2026
3 checks passed
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.

Synthesizer decode failure 502s the whole fusion (no retry/tolerance)

1 participant