Let the writer draft their brief from the document - #598
Open
kcarnold wants to merge 5 commits into
Open
Conversation
Groundwork for letting the assistant offer wording for the brief's fields. A candidate is not part of the brief until the writer accepts it, and the types say so: BriefProposal is deliberately separate from DocBrief, so there is no way to serialize one into the document by accident. The state is session-only for the same reason — something the writer has not agreed to should not follow the file to whoever opens it next. It lives in the context rather than in the section component so a candidate survives collapsing the section or moving between pages, which is why the brief itself is in a context too. acceptProposal routes through setField, so an accepted candidate is saved, logged, and cleared by exactly the same code as text the writer typed — there is no second way for a field to change. setField also clears the field's candidate outright: a field the writer has answered themselves has a spent candidate, whether they accepted it or ignored it and wrote their own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGZQEsAGYQsV7anwsPS6xk
The brief is usually blank or thin, and that is structural rather than lazy: a writer who can crisply state their audience and their success conditions has already done the hardest part of the work, so the writers who most need the brief are the ones least able to fill it in cold. Their draft, meanwhile, is full of evidence about all three fields — they have been making decisions about audience and purpose in every paragraph without writing them down. The Constraints guidance generalizes a prompt that worked by hand in Chat: a checklist of clear, succinct criteria the writer could judge as met or unmet, no more than a dozen. The venue-specific parts of that prompt are deliberately not restated — they belong to the document and to whatever the writer has already put in the brief, both of which are in the request. The instructions push hard on staying inside the document and omitting a field rather than guessing at it. The failure mode is worse than a wrong outline: a plausible invented audience reads as insight, gets accepted without much scrutiny, and then silently frames every request on every page. A blank field is visibly blank; a wrong one is not. The parser is defensive for the same reason parseDocBrief is — it runs on whatever came back, and a malformed response should cost an error notice rather than crash a page the writer just opened. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGZQEsAGYQsV7anwsPS6xk
brief_proposal_resolved is the one that matters: it records accepted vs dismissed per field. Candidates that are almost always accepted unedited would mean the tool is writing the brief rather than co-creating it, which is the failure this whole feature has to be measured against. The candidate text rides in `result` so the consent gate treats it as AI output. An empty `fields` array is the "nothing to propose" outcome, not a failure — those are distinguished by the presence of _error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGZQEsAGYQsV7anwsPS6xk
Reads the current draft and offers candidate wording for each field. The candidates render below their field rather than in it, dashed and tinted, so a candidate is never mistakable for something already in the brief — including when the field is empty, and including when the field is already filled and the candidate is only a sharper version of it. That is interface-concepts.md's rule for AI-authored prose: draft material to be edited, visibly provisional, inert until the writer touches it. The document is pulled at request time rather than tracked. Reading it is an Apps Script round-trip on the Google Docs surface, and the page already holds its own copy for its own requests, so a second useDocContext here would double every read. "Nothing to suggest yet" and "nothing to read yet" are visible outcomes with their own notices — a run that quietly changes nothing reads as a broken button. The first one's wording points at the finding: a draft that does not settle who it is for is telling the writer something worth knowing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGZQEsAGYQsV7anwsPS6xk
Records the reasoning the code cannot carry: why this is not a fourteenth Revise button (every other feature there answers "what is in my document?", this one answers "what would make it done?"), why the checklist is not a fourth brief field (interface-concepts.md reserves that vocabulary for the Charter's Rubric, and a field named "Success criteria" would squat on the name while providing none of the mechanic), and what is still open — chat proposing brief updates, and whether the checklist deserves to be its own gradeable artifact. The CLAUDE.md note states the invariant rather than the feature, so the next person editing this code knows which property they would be breaking: putting a candidate into a field, or into the saved JSON, is how this turns into a tool that writes the writer's brief for them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGZQEsAGYQsV7anwsPS6xk
kcarnold
force-pushed
the
claude/paper-acceptance-checklist-preset-rmjjda
branch
from
July 31, 2026 21:38
db56271 to
a4de7af
Compare
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.
Where this started
A prompt that worked well by hand on the Chat page:
The obvious home was a fourteenth button on the Revise grid. That's the wrong shape twice over: every other Revise feature answers what is in my document?, while this answers what would make this document done? — a statement about the goal, not an observation about the text. And Revise results are read and discarded, whereas acceptance criteria are something you want next week, having shaped what the tool says to you in between.
So it goes to the brief instead. But the brief has its own problem, which is what this PR is really about: it's three fields the writer states from scratch, and in practice it's usually blank or thin. That's structural rather than lazy — a writer who can crisply state their audience and success conditions has already done the hardest part. Meanwhile their draft is full of evidence about all three fields; they've been deciding about audience and purpose in every paragraph without writing it down.
What this adds
A "Draft from my document" action in
BriefSection. It reads the current draft and offers candidate wording per field, rendered as provisional cards beside the fields.Constraints is asked for as a checklist — clear, succinct criteria the writer could judge as met or unmet, no more than a dozen. That's the generalization of the original prompt. "Paper" and "registered report" aren't restated anywhere; they come from the document and the existing brief, both of which are in the request, which is what makes it a preset rather than a one-off.
The rule that shapes the code
docs/design/interface-concepts.mdrequires AI-authored prose to be "framed as draft material to be edited, rendered in a visibly provisional style, and inert until the writer touches it." Concretely:DocBrief, never serialized. Nothing the writer hasn't agreed to should follow the file to whoever opens it next.acceptProposal→setField, so an accepted candidate is saved, logged, and cleared by exactly the same code as typed text.Grounding is strict, and the prompt asks for a field to be omitted rather than guessed at. The failure mode is worse than a bad outline: a plausible invented audience reads as insight, gets accepted without scrutiny, and then silently frames every request on every page. A blank field is visibly blank; a wrong one isn't. "Nothing to suggest yet" and "nothing to read yet" are visible outcomes with their own notices.
Changes
frontend/src/api/briefProposal.tsfrontend/src/contexts/docBriefContext.tsxproposals,setProposals,acceptProposal,dismissProposal.frontend/src/components/briefSection/frontend/src/api/logging.tsbrief_proposal_requested/_received/_resolved/_error;LOG_SCHEMA_VERSION→ 5.docs/design/co-created-brief.mdfrontend/CLAUDE.md_resolvedrecords accepted vs dismissed per field. That's the measurement the feature exists for: candidates almost always accepted unedited would mean the tool is writing the brief rather than co-creating it.Testing
npm test— 241 pass (29 files), including 13 new: parser edge cases (fenced JSON, preambles, non-string values, truncated output) and section behaviour (a candidate stays out of its field, accept/dismiss reach the context, an empty document doesn't generate).npm run lint— 0 errors (3 pre-existing warnings, unrelated files).npm run format:check— my files clean; 5 pre-existing failures in files I didn't touch.mainin this environment — the sandbox ships Chromium build 1194 and the snapshots were made with 1223. I verified my diff doesn't move any snapshot:chat-startis byte-identical betweenmainand this branch, and no snapshot renders the Revise page or an expanded brief. Worth flagging separately:chat-two-turnsproduced three different images across three runs of identical code, so it looks inherently flaky.Not in scope
The Revise feature grid is untouched — it's now #597, which also notes that all 13 features carry an
icon:field that's never rendered, and thatisOverallsilently splits them into whole-document and part-by-part sweeps with no UI signal.Open questions (in the design doc)
setProposalsis on the shared context — but deciding when to propose without turning every message into an interruption isn't answered yet.interface-concepts.mdreserves that vocabulary for the Charter's Rubric, and a field named "Success criteria" would squat on the name while providing none of the mechanic.Generated by Claude Code