fix(paste): a half-arrived long send is no longer send evidence - #113
Merged
Conversation
`pasteCarriesSend` accepted the token + literal tail shape whenever the tokens
claimed no more lines than we sent and every literal fragment occurred in order.
A truncated tail satisfies both — `Σ M ≤ S` is deliberately loose, and a
truncated tail is still a prefix-ordered substring — so a send whose later chunks
never landed looked exactly like a complete one and the guard pressed Enter on it.
When the draft ENDS in literal text, that trailing text must now be the END of
what we sent, not merely somewhere inside it. That is the one question the screen
can answer: per-fragment newline accounting is unrecoverable, because the box
wraps and `extractInputDraft` space-joins the rows. A draft that ends ON a token
keeps the old rule — the end of the message is invisible there, and rejecting a
shape we cannot read would turn working sends into permanent stalls.
Re-probed live 2026-08-17 (collie-demo, pane `w6:p1`, 200-col PTY); both halves
of the split shape are now in the corpus as
`claude--draft-paste-split-{partial,tail}.txt` and pinned by the conformance and
chrome suites.
Fixes #110
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 #110.
Reproduced live in the
collie-demosandbox before changing anything: a six-line send whose final chunk never arrived rendered as[Pasted text #3 +5 lines] TAIL-ONE… TAIL-TWO…, andpasteCarriesSendaccepted it — the guard would have fired Enter on half a message. Both screens (partial and complete) are committed as byte-faithful corpus fixtures; the complete one is the positive control that keeps the fix from regressing into stalls.The rule (rule 5): when the draft ends in literal text, that trailing text must be a suffix of the whitespace-stripped sent text. In the split shape the token comes first and the tail after, so the last thing on the row is the last thing that arrived — if it isn't the end of our message, bytes are still missing. The issue's alternative (newline accounting) turned out to be structurally dead, not just awkward: the box wraps and
extractInputDraftspace-joins rows, so the tail's newlines never exist anywhere in the pipeline.Residual hole, deliberate and documented at the rule: a draft that ends on a token keeps the old
≤rule — the message end is inside the token where nothing is visible, that shape was never observed under truncation, and rejecting a screen we can't read would convert working sends into permanent stalls (the worse failure per ADR 0010's budget). Pinned by a test as deliberately loose.No version bump — release deferred; PATCH axis, wants a loud CHANGELOG line when 0.31.0 is cut.
Tests: web 2307 pass / 0 fail (every pre-existing fixture still accepts), root 617 pass, tsc clean both packages.
🤖 Generated with Claude Code