Skip to content

🤖 fix: match a send's text in the draft merge only as a whole block - #5577

Merged
ThomasK33 merged 3 commits into
mainfrom
fix/5567-draft-whole-block
Oct 3, 2026
Merged

ThomasK33 merged 3 commits into
mainfrom
fix/5567-draft-whole-block

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Summary

The backend draft merge now matches a send's text only as a whole block: a blank line or the text's edge on both sides. Before, removeDraftBlock also matched the send's text at the end or start of a longer line, so a window's own sentence could lose its last word. Fixes #5567.

Background

removeDraftBlock (src/common/utils/composerDraftText.ts) took its end checks from removeSentText, which accepts any whitespace boundary. removeDraftBlock("I said yes", "yes") returned "I said". Two callers use it:

  • mergeWrite in draftService.ts takes stale copies of pending or accepted sends out of a window's write, and checks whether a returned send is still in the text.
  • DraftStore.observeSends (hasDraftBlock) marks a send inUnsavedText when the window's unsaved text holds it.

Example from the issue: window B has unsaved "I said yes" when window A sends "yes". The send is accepted, and B's next write stored "I said".

Implementation

removeDraftBlock scans every occurrence of the block and keeps only whole-block matches. The order stays as before: the end first, then the start, then the middle. removeSentText (the composer's own send) is unchanged. The text after a removed block loses only its leading line breaks, so an indented block after it (code) keeps its indentation, and the text before it loses only its trailing line breaks, so the line before keeps its trailing spaces (a Markdown hard break). The first version of this PR stripped both in the middle case (found by the independent readiness check and the normal review).

One existing test changed its expectation. "unsaved text that still holds a not-accepted send's text does not get it twice" used unsaved "hello world" for the returned send "hello" and expected the send to count as present. Under whole-block matching, "hello world" is the user's own line, so the returned send comes back beside it ("hello\n\nhello world"): a visible duplicate instead of a silent loss. The test now covers both cases: the send typed again as its own block (not added twice), and a line that only starts with it (comes back).

formal/composer-drafts/ComposerSendText.tla: comment only. Its items are whole blocks, so Found was already block equality. The comment now says the code matches that since this change.

Validation

Pre-fix failures (new tests on origin/main's composerDraftText.ts, 45 pass / 4 fail):

(fail) removeDraftBlock > leaves a word at the end or start of a longer line as it is
(fail) DraftService pending sends > ... > a pending send's text at the end of a longer line of a write stays (#5567)
       Expected: "I said yes"  Received: "I said"
(fail) DraftStore idempotent sends > a sentence ending with an accepted send's text in another window's unsaved text stays
       Expected: "I said hello"  Received: "I said"
(fail) DraftStore idempotent sends > a not-accepted send comes back beside unsaved text that only starts with its text
       Expected: "hello\n\nhello world"  Received: "hello world"

After the fix: composerDraftText, draftService, draftService.pendingSends, DraftStore and DraftStore.sendIds tests pass (118 pass, 0 fail). The DraftStore tests run two real DraftStore windows against a real DraftService.

formal/composer-drafts/check.sh: running on this head; the result will be added here before merge.

Deferred

Two normal-review findings on 7037a70e83 are tracked in #5586 (backlog): indentation on the block's own line counts as a boundary, and the per-occurrence scan cost on pathological near-limit drafts.

Risks

Low. Only the backend merge's text matching changes. A send's text inside a longer line is now kept instead of cut. In the "returned send beside a line that starts with it" case the user sees the send's text twice instead of losing it.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $2.57

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T20:50:52.971610Z 7037a70 New commits
🔒 Security Review ✅ Completed 2026-10-03T20:50:48.886350Z 7037a70 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 839109e964

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/common/utils/composerDraftText.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7037a70e83

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/common/utils/composerDraftText.ts
Comment thread src/common/utils/composerDraftText.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

Readiness record (head 7037a70e83).

Assessments: 8 in total, under a budget exception the issue coordinator granted (ceiling 8, one further push only).

# Assessment Head Findings Disposition
1 normal review 1aafc18 0
2 security review 1aafc18 0
3 independent readiness check 1aafc18 1 (indentation of the next block stripped) fixed in 839109e
4 normal review 839109e 1 P2 (trailing spaces of the previous line stripped) fixed in 7037a70
5 security review 839109e 0
6 normal review 7037a70 2 P2 deferred to #5586 (backlog)
7 security review 7037a70 0
8 final independent check 7037a70 ready with tracked follow-ups; 1 new P2 (quadratic trailing-whitespace regex) deferred to #5586

Exception: findings went 0, 1, 1, so the standard +2 extension did not apply. The coordinator authorized slots 6–8 because the slot-4 P2 was a regression this PR introduced. Rule for the last round: a P1 introduced by the last push stops the merge; anything else goes to a backlog issue with no further push. No P1 was found.

Formal: local full formal/composer-drafts/check.sh exit 0, every result matches EXPECT (the .tla is comment-only and unchanged since the first commit). Tests: 118 pass, 0 fail. make static-check passed on 7037a70e83.

Merge condition: required CI green on 7037a70e83, all threads resolved.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $5.67

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 6453306 Oct 3, 2026
60 of 62 checks passed
@ThomasK33
ThomasK33 deleted the fix/5567-draft-whole-block branch October 3, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Draft merge: match a send's text only as a whole block

1 participant