Skip to content

fix(drafts): the held-draft notice names the message and says why in a sentence - #656

Open
antra-tess wants to merge 1 commit into
mainfrom
fix/draft-notice-wording
Open

antra-tess wants to merge 1 commit into
mainfrom
fix/draft-notice-wording

Conversation

@antra-tess

Copy link
Copy Markdown
Collaborator

The held-draft notice a resident gets when its plain speech is held back now says which message it means, and why, in a full sentence.

Before

[drafts] scout: not sent — a plain-speech segment held as draft d-k3m9q2x — an explicit send in the same round holds plain speech back. drafts(action: "resend", …) delivers it unchanged; drafts(action: "dismiss", …) sets it aside.

After

[drafts] scout: your plain-speech message starting "Sure, I'll take a look at the deploy logs and get …" was not sent and is instead held as draft d-k3m9q2x because there was an explicit send in the same round as the plain speech. drafts(action: "resend", …) delivers it unchanged; drafts(action: "dismiss", …) sets it aside.

When several are held:

[drafts] scout: your 2 plain-speech messages were not sent and are instead held as drafts d-a7b2c4d (starting "First thought here") and d-e5f6g7h (starting "And a second, longer message that will be cut off …") because their routing prefix bounced. …

Changes

  • Each held draft is named with its opening words (draftPreview, cut at 50 characters).
  • The reason is a "because" clause from a new DRAFT_REASON_BECAUSE, with plural forms for no-destination and bounced. DRAFT_REASON_TEXT is unchanged, so the drafts tool's listing keeps its wording.
  • "Was not sent" is still left out when a held draft carries words that may already have been posted. That notice reads "is held as draft …".
  • This reverses the "notices quote no draft words" rule from b2a21ec, for this notice only. The catch-up notice and the turn-end receipt still quote none.

Tests: prose-drafts now checks the new sentence for one held draft, and for a free draft next to an unconfirmed copy (no "not sent"). prose-drafts, explicit-prose-routing and present-while-acting pass (267/267). A changelog fragment is included.

🤖 Generated with Claude Code

…a sentence

Before: "[drafts] scout: not sent — a plain-speech segment held as draft
d-… — an explicit send in the same round holds plain speech back."

After: "[drafts] scout: your plain-speech message starting "…" was not
sent and is instead held as draft d-… because there was an explicit send
in the same round as the plain speech."

- Each held draft is named with its opening words (draftPreview, 50
  chars), so a resident can tell which of its messages the notice means;
  several drafts read "drafts d-a (starting "…") and d-b (starting "…")".
- The reason is a "because" clause (DRAFT_REASON_BECAUSE), plural-aware
  for no-destination and bounced. DRAFT_REASON_TEXT stays as is for the
  drafts tool's listing.
- "Not sent" is still left out when a draft carries words that may
  already have been posted ("is held as draft …").
- This reverses b2a21ec's "notices quote no draft words" for this one
  notice; the catch-up notice and receipts still quote none.

Tests: prose-drafts asserts the new sentence for one draft, and for a free
plus an unconfirmed copy (no "not sent").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

Automated review

Recommendation: needs a maintainer's decision. The change belongs, but part of it needs a maintainer's call.

Reviewed commit 35c2713 with claude-opus-5-5, by reading the code. It did not run the code or look at the checks.

Does this change belong in the project?

It fits, with concerns. Rewording an existing drafts notice is in scope and stays where that code already lives. It does reverse the recorded rule that notices quote none of a draft's words, though, so a maintainer should decide that on purpose.

4 reasons with sources
  • The change rewrites the wording of a notice the framework already sends, and keeps it in the same method and test file. Only draftsHeldNotice changes, plus a new DRAFT_REASON_BECAUSE table placed next to the existing DRAFT_REASON_TEXT. It reuses the existing draftPreview helper and adds no dependency, service or public interface. (src/framework.ts (draftsHeldNotice); test/prose-drafts.test.ts)
  • It reverses a documented behavior: the changelog records that held-draft notices quote none of a draft's words. The shipped entry says "Notices name drafts and say how to resend or dismiss them, and quote none of their words; the drafts tool's read shows the words, and its list a preview of each." The PR now puts a 50-character preview into the held-draft notice, and it drops a test assertion that checked for this. The catch-up notice and its tests (prose-drafts.test.ts ~892-940) still follow the old rule, so different notices now behave differently, and a maintainer should accept that on purpose. (CHANGELOG.md (drafts entry, lines 1050-1053))
  • Quoting words in a notice that co-residents share doesn't seem to expose anything new under the project's stated model. The project says that residents sharing one message slot already share the assistant turn the words came from, so a preview in that shared notice reveals nothing they couldn't already see. (CHANGELOG.md (lines 1054-1057))
  • The PR follows the contribution conventions: a changelog fragment, updated tests and a numeric test count. It adds changelog.d/draft-notice-wording.changed.md, updates the assertions in prose-drafts and reports 267/267 passing. As the code review noted, the fragment doesn't mention that the earlier no-quoting rule is reversed for this notice. (CONTRIBUTING.md (What a PR should contain; Changelog))

Findings

No findings of medium or high severity.

1 more finding, less severe
  • Low severity, documentation, changelog.d/draft-notice-wording.changed.md:1-5. The changelog fragment does not say this notice now quotes draft words, reversing a documented rule. CHANGELOG.md (around line 1051) tells users that draft notices 'name drafts and say how to resend or dismiss them, and quote none of their words'. This change makes the held-draft notice quote each draft's opening words. The fragment does not say that this rule changed, or that the catch-up notice and the receipt still quote none. Readers of the released changelog would still believe notices never contain draft text. The fragment should state the reversal explicitly, as the PR description does.

@nissa-seru

Copy link
Copy Markdown
Contributor

@antra-tess We reviewed 35c2713d and opened #668 into this branch. It keeps the full-sentence reason and makes two changes, each explained there.

  1. Drafts are named without their words. Each held draft is named by its length, and several by their order ("in the order you wrote them"). The rule this reverses came from b2a21ec, after your ablation in 54b8b53. The user-role notice that passed there named a length and quoted nothing: Your text (N chars) was not delivered — …. A notice that quotes the model's own just-written words back to it in the user role is a shape that ablation didn't test. Quoting exposes nothing new: in a run with this PR's test harness, a co-resident's request already carried the held words once, as the resident's own message, and with the quote it carried them twice. @antra-tess, what do the opening words give the resident that the length and order don't?
  2. The explicit-send clause. A send holds back plain speech in its own round and the turn's later rounds (turnSilenced). So "in the same round as the plain speech" isn't true of drafts from a later round, such as rounds 2 and 3 of the three-segment test in prose-drafts. The clause now reads "because you made an explicit send in this round or an earlier one this turn". It names the cause only, since new input clears the silence and a context-budget restart starts without it.

Two small notes on this PR's text:

  • The description's plural example "because their routing prefix bounced" can't occur today. Both bounced holds pass notice: 'later', so they never reach this notice.
  • The commit message says DRAFT_REASON_TEXT keeps the drafts listing's wording. DRAFT_REASON_TEXT is the read action's. The listing reads DRAFT_REASON_SHORT, which neither PR changes.

Written by Nigel-2405.

— Lottie-2661

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.

2 participants