feat: wire the fusion rung into the board seam (ADR 0064 P3)#64
Merged
Conversation
coder.solve()'s ladder always supported fusion (rung 4: a richer generator,
oracle-selected) but the board seam (P2) never wired it -- solve() was called
with no fusion_generate at all, so no board dispatch could ever reach it,
regardless of how many rungs failed.
Fusion can't tool-call (a plain chat completion, e.g. protolabs/fusion -- not
an ACP session), so its candidate generation is a different shape from the
ACP rungs: _fusion_prompt hands it the task + the CURRENT content of the
feature's declared files_to_modify (read from the base repo -- fusion has no
tool access to look these up itself) and asks for the complete, final content
of every file it creates or changes. _parse_fusion_files extracts {path:
content} from the reply; generate_fusion writes those files into a fresh
worktree (same throwaway-per-candidate discipline as the ACP rungs, same
promote/reap bookkeeping) and hands the path to the SAME verify() -- real
acceptance tests, no separate judge. Guards against a completion naming an
absolute path or a ../ climb escaping the worktree.
New config: coder_solve_fusion_delegate (an openai-type delegate name,
resolved by _drive the same way coder/reviewer already are), coder_solve_fusion_k.
Blank delegate (default) -> solve() gets fusion_generate=None, identical to
before this rung existed -- honest degrade, unchanged.
Tests: file-format parsing, prompt construction (existing-file content,
missing-file note, feedback), generate_fusion (writes correctly, rejects path
traversal, handles an empty/unparseable reply without crashing), dispatch()
end-to-end reaching fusion after cheaper rungs fail, and the no-delegate
honest-degrade path. 255 passed (was 244; +11 new, +9 existing _fake_solve
signatures updated for the new fusion_generate/fusion_k kwargs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
👀 Quinn is reviewing — verdict (PASS / WARN / FAIL) + findings to follow. |
There was a problem hiding this comment.
QA Audit — PR #64 | feat: wire the fusion rung into the board seam (ADR 0064 P3)
VERDICT: WARN (CI queued — non-blocking comment; formal PASS/FAIL will follow once test is terminal)
CI Status
test: queued
Diff Review
coder_seam.py: Adds fusion rung (P3) to the solve ladder —_fusion_prompt(),_parse_fusion_files(), newgenerate_fusion(in truncated portion),_new_candidate_worktree()extracted for reuse. New__init__params (fusion_delegate,files_to_modify,_fusion_dispatchseam) are cleanly defaulted for honest degrade.README.md: Documents the two new config keys and the fusion rung in the ladder description. Clear opt-in semantics.
Observations
- Gap — truncated diff: Only 200/698 lines visible. The
generate_fusionmethod, path-traversal guards (promised in the PR description: "Guards against a completion naming an absolute path or a../climb"), dispatch wiring, and 11 new tests are all in the unseen portion. Cannot verify these from the diff alone. - Gap — clawpatch unavailable: HTTP 502 on checkout — structural cross-file review skipped. The diff is large enough (698 lines, multiple files) that a structural pass would have caught any cross-file contract mismatches.
- LOW:
_FUSION_FILE_REuses.*?between backtick fences — file content containing triple backticks (e.g. a Markdown file) would cause misparse. This is documented as acceptable: misparse → empty candidate → failsverify(), same as any other empty candidate. No silent corruption path. - LOW:
_fusion_prompt()reads files from the base repo viaPath(repo) / rel— this is correct for P3's design constraint (fusion can't tool-call, needs to be handed file contents), and the_FUSION_READ_MAX_CHARS = 20_000cap prevents unbounded prompt growth.
— Quinn, QA Engineer
|
Submitted COMMENT review on #64. |
4 tasks
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.
What
coder.solve()'s ladder always supported fusion (rung 4: a richer generator, oracle-selected) but the board seam (P2, #61) never wired it —solve()was called with nofusion_generateat all, so no board dispatch could ever reach rung 4, no matter how many cheaper rungs failed. This is ADR 0064's explicit P3.The design constraint: fusion can't tool-call
Per the ADR, fusion (e.g.
protolabs/fusion) is a strong generator but a plain chat completion — unlike theacpcoder (a real edit/verify session in the worktree), it can't read files or run anything. So its candidate generation is a genuinely different shape from the ACP rungs:_fusion_prompthands it the task + the current content of the feature's declaredfiles_to_modify(read from the base repo — fusion has no tool access to look these up itself), and asks for the complete, final content of every file it creates or changes (wholesale replacement, not a diff — an LLM reliably reproduces a full file; a hand-rolled patch with drifted context lines is agit applyfailure mode this avoids)._parse_fusion_filesextracts{path: content}from the reply.generate_fusionwrites those files into a fresh worktree (same throwaway-per-candidate discipline as the ACP rungs, samecandidatesbookkeeping) and hands the path to the sameverify()— real acceptance tests, no separate judge.../climb escaping the worktree (a model completion is untrusted input).Config
Resolved in
_drivethe same waycoder/revieweralready are (_resolve_delegate(name, "openai")). Blank/unresolved ⇒solve()getsfusion_generate=None— identical to today's behavior, honest degrade unchanged.Tests
255 passed (was 244; +11 new — file-format parsing, prompt construction,
generate_fusion's write/traversal-guard/empty-reply behavior,dispatch()reaching fusion end-to-end after simulated cheaper-rung failures, and the no-delegate honest-degrade path; +9 existing_fake_solvefixtures updated for the newfusion_generate/fusion_kkwargssolve()now always receives).Gate:
ruff check . && ruff format --check . && pytest -q— all green.Version bumped 0.27.0 → 0.28.0 (new capability).
🤖 Generated with Claude Code