Repository navigation
fix(claude): read the composer live right before writing a prompt - #1390
Closed
Juliusolsson05 wants to merge 2 commits into
Closed
Juliusolsson05 wants to merge 2 commits into
Juliusolsson05 wants to merge 2 commits into
Conversation
…1294) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude delivery trusted a cached composer reading. It is recomputed only on the package's throttled screen event (which can stall behind pendingWrites), and it counts only plain cells as typed. So a stale 'empty', a one-character draft under the inverse cursor, or an [Image #1] chip let the agent's prompt be typed into a human's draft and submitted with it. Immediately before the first prompt byte (text and image paths), deliverClaudePrompt now reads the composer from the live buffer (readComposer: text and attributes at the same instant) with the fail-closed classifier the rollback uses (#1309), renamed classifyClaudeComposerLive. A draft refuses before-write, retry-safe, with nothing written. A dim suggestion placeholder is still delivered. Fail-first: frames painted through the real claude-code-headless HeadlessTerminal with genuine SGR; on main all three drafts are overwritten. The #1309 rollback tests now state an empty composer before our first byte. Fixes #1294 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Stale check (W1). Idle since 09:04 UTC because the reviewer queue was full. The PR still merges cleanly with main and CI is green at |
Owner
Author
|
Status (W1): held for a manager decision on file overlap. Reviews a and b are both FIX-BEFORE-MERGE, with one shared P1:
|
Owner
Author
|
Closed by B6 (manager, owner proxy) during the owner's PR freeze: its remaining fixes need a package PR and overlap W2's #1358 area, which can't be done under the PR freeze. Nothing is deleted. The branch stays on origin and the PR can be reopened. The linked issue stays open with this PR's findings as its starting point. |
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.
Fixes #1294.
Plan:
docs/plans/2026-09-27-claude-live-composer-gate.md(first commit).Problem
Claude delivery decided whether it may type from a CACHED composer reading,
ClaudeSession.derivePromptGateState→headless.getComposerState(). That reading goes wrong in two ways:screenevent, which can stall behindpendingWrites(HeadlessTerminal.ts, "KNOWN ISSUE"). A staleemptythen outlives a human who started typing.[Image #1]-only draft (the whole chip is inverted) both readempty.Either way the agent's prompt is typed into the human's draft and submitted with it.
Change
deliverClaudePromptreads the composer from the LIVE buffer:ClaudeSession.readComposer(), text and cell attributes at the same instant.classifyClaudeComposerLivebecause it now has both callers. Only a dim-only placeholder reads empty.drafted→before-write,retry-after-resolve, nothing written.unpainted→before-write,retry-same-session, nothing written.Tests
promptDelivery.liveComposerGate.test.tspaints frames through claude-code-headless's realHeadlessTerminalwith genuine SGR (dim 2, inverse 7), the method of the package's own composer tests. The cached gate says ready in every case.[Image #1]-only draft.draftedthat attributes were added to fix.promptDelivery.rollbackPlaceholder.test.ts(#1309) now states its pre-write composer as empty. Before, its "before" frame showed our typed prompt already sitting in the composer, which the new guard correctly refuses to type over. Its screen is unchanged, so absorption still sees no transition.Verification
npx tsc -bclean.src/providers/claude,src/mainandsrc/shared: 323 of 324 files pass, 3,048 tests.src/main/workflows/control.system.test.ts, times out in 5 s in these local worktrees WITHOUT this change too: an origin/main-based worktree fails the same way. It is not touched here; CI is the gate.Residual
Native voice interim text is painted dim, the same as a placeholder, so the live read also calls it empty. There is no recorded frame of it and no attribute separates it from a suggestion, so it is stated rather than guessed at.
🤖 Generated with Claude Code