fix(adapters): render the stdin prompt per attempt in claude/codex/cursor/gemini-local (BLO-22497) - #1362
Merged
Merged
Conversation
…rsor/gemini-local (BLO-22497) PR #1103 fixed the once-computed-prompt defect in opencode-local only. The identical defect was live in four sibling adapters: each built the stdin prompt once at outer scope, keyed on the original sessionId, and runAttempt() captured it. When the session-unavailable fallback calls runAttempt(null) — a genuinely new session — it reused the resume-only prompt, so the recovered attempt could lack the task context it was told to continue. Port the reviewed pattern from #1103: extract the render into buildAttemptPrompt(effectiveSessionId) and call it from inside runAttempt(resumeSessionId) with that attempt's own id. - claude-local: covers BOTH runAttempt(null) sites — the session-unavailable/ poisoned retry and the ccrotate rotation retry. - codex-local: shouldUseResumeDeltaPrompt also drives promptInstructionsPrefix and the command notes, so those move per-attempt too; a fresh-session retry re-injects instructions and must not inherit the resumed-session "skipped reinjection" note. Drops the outer instructionsChars, whose value was always overwritten before its only read. - gemini-local: passes the prompt via argv, so buildArgs now takes the attempt's prompt rather than capturing the outer one. - cursor-cloud is deliberately unchanged: it has no runAttempt indirection. The isPaperclipRecoveryWakePayload term stays session-id-independent, so recovery-shaped wakes still suppress the task prompt — cold-start parity is the invariant, not "always include the task prompt". Co-Authored-By: Claude <noreply@anthropic.com>
Author
1 similar comment
Author
Author
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Author
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 96b5a8b
Looks good. The prompt is now rendered from the session ID actually used by each attempt, and the regression coverage exercises both resumed and recovered attempts across all four adapters. I found no high-confidence correctness, safety, error-handling, or type-design issues in the changed code.
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- Recovery tests assert the actual second-attempt prompt, including Gemini’s argv-based prompt path.
- Claude coverage includes both independent fresh-session fallback sites.
- The Codex command-note change keeps operational metadata aligned with the per-attempt prompt semantics.
Recommended Action
- No Critical or Important code changes are required from this review.
13 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.
Thinking Path
Linked Issues or Issue Description
opencode-localoriginal whose pattern this copies. PR #1078 was its earlier, closed attempt.22497/22301/buildAttemptPrompt/session-recoveryon all PR states: no duplicate or overlapping PR. fix(opencode-local): give the session-recovery retry a fresh-session prompt (BLO-22301) #1103 and fix(opencode-local): give the session-recovery retry a fresh-session prompt (BLO-22301) #1078 are the predecessors above; no other open PR touches these four adapters.What Changed
claude-local— extractedbuildAttemptPrompt(effectiveSessionId), called from insiderunAttempt. Covers bothrunAttempt(null)sites: the session-unavailable/poisoned retry and the ccrotate rotation retry.codex-local— same extraction, plusshouldUseResumeDeltaPromptalso drivespromptInstructionsPrefixand thecommandNotesIIFE, so those become per-attempt (buildCommandNotes(shouldUseResumeDeltaPrompt)). Without that, a fresh-session retry re-injects the instructions while still logging the resumed-session "skipped stdin instruction reinjection" note — logged metadata contradicting the actual prompt. Also removes the outerinstructionsChars, whose value was unconditionally overwritten before its only read.cursor-local— same extraction, no other coupling.gemini-local— same extraction, plusbuildArgsalso captured the outer prompt (gemini passes it as argv,--prompt <value>, not stdin), so it now takesbuildArgs(resumeSessionId, attemptPrompt).cursor-cloud— deliberately unchanged; it has norunAttemptindirection. Verified 0 files touched in the diff.execute.session-recovery.test.tsregression suites (13 tests) mirroring theopencode-localoriginal.isPaperclipRecoveryWakePayload(...)intentionally stays session-id-independent: cold-start parity is the invariant, not "always include the task prompt". Each adapter has a test pinning that.Verification
Per-adapter suites driving
execute()through a simulated session-unavailable first attempt (mockedrunChildProcess) and asserting on the second attempt's stdin — argv for gemini:session-unavailable fallback renders a fresh-session prompt on the recovered attempt…+ccrotate rotation fallback also renders a fresh-session prompt on its retry (the second runAttempt(null) site)renders a fresh-session prompt … while leaving the original resume attempt's prompt unchangedEach file also carries a cold-start guard (initial-attempt prompt unchanged) and a recovery-wake parity case.
Mutation-tested — every test was demonstrated to fail against the unported code, as BLO-22497's verifying signal requires. I re-introduced the defect (
buildAttemptPrompt(resumeSessionId)→buildAttemptPrompt(sessionId)) per adapter and re-ran:All failing on
expected '## Paperclip Resume Delta…' to contain 'BOOTSTRAP-MARKER-BLO-22497'. In every case the single surviving pass is the cold-start guard — correct, because a cold start hassessionId === nullso the defect cannot manifest there. Files restored and re-verified green.general-workspaces-bis confirmed to cover these projects fromscripts/run-vitest-stable.mjs:79-80(every non-server project except@paperclipai/ui/paperclipai).Full adapter suites (the four ported +
opencode-local), this branch vs. stashed-clean master:1 failed | 385 passed | 1 skipped (387)1 failed | 372 passed | 1 skipped (374)The one failure is identical on both sides —
codex-local/src/server/execute.auth-precedence.test.ts > logs and emits a run event when sandbox login is shadowed by host auth— pre-existing and unrelated, reproduced on clean master in isolation and in the parallel run. The +13 delta is exactly the new tests.tsc --noEmitclean on all four adapters.Risks
resumeSessionId === sessionId, so the rendered prompt is byte-identical to today's for both the resumed-session and cold-start cases — each adapter has a cold-start guard test asserting exactly that.renderTemplateis cheap, so this is negligible;promptMetricsis returned data consumed by the already-per-attemptonMeta, so no side effect is double-counted.codex-localcarries the only behavioral change beyond the prompt: its command notes now reflect the attempt rather than the run. That is a correctness fix (the notes previously contradicted the prompt on a recovered attempt) but it does alter logged metadata, so log-scraping on that string would see the corrected value.cursor-clouduntouched.Model Used
claude-opus-5[1m]), 1M context, extended thinking, with tool use and code execution — run as the Paperclip CTO agent on theclaude_k8sadapter.Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue templatebuildAttemptPromptexplain why the render must be per-attempt🤖 Generated with Claude Code