fix(go): fall back to the harness when the .ai() gates are unavailable - #67
Merged
Merged
Conversation
intake_phase and coverage_gate ask the AI seam for a response_format
schema. The Go port propagated every failure out of both, so a node whose
harness is not OpenRouter-backed failed the entire review with "AI not
configured for this agent" (BuildAgent only attaches AIConfig when
OPENROUTER_API_KEY is set), and a provider that rejects structured output
sank it the same way.
Mirror harnesses.py, which wraps both calls: an unusable AI seam leaves the
intake gate unconfident so control falls through to the harness classifier
already sitting below it, and coverage_gate retries the same prompt through
the harness, returning {} when the result fails to parse.
Verified end to end with PR_AF_PROVIDER=claude-code and no OpenRouter key:
the full pipeline completes instead of failing at the first phase.
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.
Problem
intake_phaseandcoverage_gatein the Go port ask the AI seam for aresponse_formatschema and propagate every failure out of the reasoner. Two real configurations hit this:A node whose harness is not OpenRouter-backed.
node.BuildAgentattachesAIConfigonly whenOPENROUTER_API_KEYis set (go/internal/node/node.go), so running with, say,PR_AF_PROVIDER=claude-codeand no OpenRouter key fails the entire review at the first phase:A provider that rejects structured output — the case fix: fall back to harness when .ai() structured output is unsupported #60 fixed on the Python side.
The Python implementation already handles both:
harnesses.pywraps each.ai()call intry/exceptand falls through to the harness (commit 3c8eca9). The Go port does not, so the two implementations diverge on a failure path that takes down the whole pipeline.Change
Restores parity with
harnesses.py, nothing else:intake.go— an unusable AI seam leaves the gate unconfident, so control falls through to the harness classifier already sitting below it (Python'sexcept -> gate_result = None).coverage.go— retries the same coverage prompt through the harness, returning{}when the harness result fails to parse (Python'sgate.parsed.model_dump() if gate.parsed else {}).Behaviour is unchanged whenever the AI seam works: the fallbacks only run on the path that previously raised.
Tests
Two new cases in
reasoners_test.go:TestIntakePhaseAIUnavailableFallsBackToHarness— table over a nil AI seam and a seam that rejects structured output; both must invoke the harness exactly once and return the full intake key set.TestCoverageGateAIUnavailableFallsBackToHarness— asserts the harness receives the same coverage prompt, plus the parse-failure path returning{}.go build ./... && go vet ./... && go test ./...all pass;gofmtclean.Verification
Ran the full pipeline against a local repo/branch review with
PR_AF_PROVIDER=claude-code,PR_AF_MODEL=sonnetand noOPENROUTER_API_KEY:intake_phase;HTTP 200in 611s, 22 agent invocations, all phases completed (intake→anatomy→meta_*→review_dimension→evidence_verifier→compound_finder→ synthesis), 7 findings on a diff with 3 planted defects.Note, out of scope for this PR
Under
claude-codethe budget accounting stays at zero (total_cost_usd: 0, all per-phase entries0), because the cost the CLI reports is not the OpenRouter spend PR-AF meters. The USD ceiling is therefore inert for that provider and only the wall-clock cap applies. Worth a separate issue; this PR deliberately does not touch it.