spec(0062): resolve Q5 — Option 1 (preview authorship) + editable proposals (INV-12)

Authorship lives in the annotated preview (D11); native diff stays
author-blind. Crucially, the review's proposed side is WRITABLE (INV-12,
D12): the writer tweaks the machine's suggestion before Keep ('close, but a
few human edits'), the live doc is untouched until Keep (INV-5), and on Keep
machine words vs writer tweaks are attributed separately by diffing
final<->machine-original<->baseline. This keeps authorship clean AT CREATION,
so post-hoc in-editor authorship (opts 2/3) is unnecessary and deferred. New
open Q7: per-change Keep/Undo semantics after free cross-hunk editing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-28 07:09:58 -07:00
parent 81b6891805
commit 1e54abdd8d
+36 -6
View File
@@ -156,8 +156,9 @@ Scenario: BUC-2 — keep or reject, change by change
```
- **BUC-2 acceptance criteria:** no proposed change alters the document until the
writer keeps it; each change is independently keepable/discardable; keep-all and
reject-all exist.
writer keeps it; each change is independently keepable/discardable; the writer can
**edit a proposed change before keeping it**, and those edits are attributed to the
writer; keep-all and reject-all exist.
**BUC-3 — As a writer, I can tell who wrote which parts of my document and read a
clean rendered version, so that I can judge the result as finished prose.**
@@ -223,7 +224,7 @@ already know:
| What the writer needs | Native surface that delivers it | What it gives them, for free |
| --- | --- | --- |
| See what changed (BUC-1) | Source-control gutter change bars + the **native diff editor** against a virtual *baseline* document | The exact diff experience they use for everything else: inline/side-by-side, navigation, accessibility |
| Keep/reject changes (BUC-2) | The **multi-diff review editor** with per-change **Keep/Undo** | One native surface to sweep all of the machine's changes, accepting or discarding each |
| Keep/reject — and **tweak** changes (BUC-2) | The **multi-diff review editor** with per-change **Keep/Undo** and a **writable proposed side** | One native surface to sweep all of the machine's changes — editing the proposal in place before keeping or discarding each (INV-12) |
| Authorship + rendered result (BUC-3) | The **built-in Markdown preview**, extended via a `markdown-it` plugin to inject authorship + change marks | Native rendering, scroll-sync, theming, and cooperation with the writer's other Markdown extensions |
| Discuss a passage — and have the machine respond (BUC-5) | The **Comments API** — threaded comments where, on a coedited document, the machine replies in-thread and offers an edit | The familiar review-comment experience, in the gutter, that can turn a remark into a proposed change |
| Follow + stop the machine (BUC-4) | A progress **notification** + a shared **OutputChannel**, with Cancel | Live, stoppable, legible machine work |
@@ -286,9 +287,11 @@ Scenario: PUC-2 — keep/reject the machine's proposed changes (realizes BUC-2)
Given I ask the machine to revise the document (or a selection)
When the turn completes
Then the proposed changes open in a multi-diff review (baseline proposed)
And the proposed side is editable, so I can tweak the machine's wording before keeping it
And each change offers Keep / Undo (Accept / Reject)
And toolbar actions offer Keep all / Reject all
And my document is unchanged until I keep a change
And on keep, the machine's words are attributed to the machine and my tweaks to me
```
```gherkin
@@ -441,6 +444,14 @@ coauthoring **displaced** state surfaced in the thread / proposed-change listing
color scoping — §6.7). Authorship (human vs. machine) is shown on a surface the
extension renders: the annotated preview (and optionally a decoration-based
track-changes editor), never by recoloring the native diff.
- **INV-12 — proposed changes are editable before they are kept:** the review
surface presents the machine's proposal on a **writable** side, so the writer can
tweak it in place before keeping it (the common "close, but a few human edits"
case). The live document stays untouched until Keep (INV-5 still holds); on Keep,
the words the machine proposed are attributed to the machine and the writer's
tweaks to the writer — so authorship is correct **at the moment the change is
made**, never reconstructed afterward. Editing happens at review time; once kept,
the text is just text (no lingering "trapped proposal" state to untangle).
### 6.2 High-level architecture
@@ -545,7 +556,13 @@ state (INV-7), not durable coauthoring metadata.
- **Review controller** — `openReview(docUri)` opens the multi-diff
(`baseline ⟷ proposed`); `keep(proposalId)` = Accept (applies the edit, attributes
changed words); `undo(proposalId)` = Reject (drops it); `keepAll()` / `undoAll()`
= Keep/Reject all (apply descending, skip + report any displaced change).
= Keep/Reject all (apply descending, skip + report any displaced change). The
**proposed side is a writable scratch document** (untitled / in-memory) seeded with
the machine's text (INV-12); the left side (baseline) is read-only. `keep` diffs
the **final** (possibly writer-tweaked) proposal against the baseline, applies it
to the live document, and attributes machine-proposed words to the machine and
writer tweaks to the writer by comparing *final ↔ the machine's original proposal*.
The live document is untouched until `keep` (INV-5).
- **Preview extension** — `extendMarkdownIt(md) → md.use(cowritingPlugin)`; the
plugin invokes the pure `renderAnnotations(tokens, attributions, proposals,
options)` transform, gated by the `cowriting.annotations` setting/command.
@@ -615,6 +632,14 @@ sequenceDiagram
multi-diff editor is stable; per-change inline **Keep/Undo overlays** as some AI
tools render them lean on evolving editor APIs — the **stable fallback** is
per-hunk **CodeLens** Keep/Reject within the diff (§6.10, §13-Q2).
- **Editable before keep (INV-12):** the proposal renders on the **writable** side of
the review, so the writer can tweak the machine's wording ("close, but a few human
edits") before keeping. `keep` attributes the machine's words and the writer's
tweaks separately by diffing *final ↔ machine-original ↔ baseline*. Because editing
happens on the proposal (a scratch doc), not the live document, INV-5 holds and
authorship is correct at creation — the preview (Option 1, the authorship surface)
then shows clean green/blue with no post-hoc untangling. *Open detail (§13-Q7):*
how per-change Keep/Undo behaves once the writer has freely edited across hunks.
#### PUC-3 — annotated rendered preview
@@ -717,6 +742,8 @@ sequenceDiagram
| Persistence envelope | one forward-compatible, unknown-field-preserving sidecar (INV-4) | a bespoke per-feature format; preview-only ephemeral state | Round-trips to an outer review forge; survives reload; one shared `anchors`/`provenance` primitive |
| Core/controller split | pure vscode-free cores + thin controllers | UI-coupled logic | Unit-testable cores, swappable surfaces; the surface can change without touching the logic (INV-6) |
| Decision vs attribution unit | block = decision unit (keep/reject); word = attribution unit | per-word proposals (too granular to decide on); per-file (all-or-nothing) | The writer decides at a readable grain (a paragraph) while authorship stays word-precise |
| Authorship surface | **Option 1** — the annotated preview is the authorship view (green/blue track-changes incl. deletions); native diff stays author-blind | Option 2 (in-editor decorations); Option 3 (owned author-colored track-changes diff that replaces native diff) | Preview shows author-colored changes for near-zero maintenance; editable proposals (INV-12) keep authorship clean *at creation*, so in-editor / post-hoc authorship rendering is unnecessary. Opts 2/3 deferred |
| Editing proposals | the proposed side of the review is **writable**; pre-Keep tweaks are absorbed and attributed (machine vs. writer) at Keep (INV-12) | machine proposal read-only (tweak only after accepting) | Most revisions are "close, but a few human edits"; editing at review time keeps authorship clean at creation and avoids messy post-acceptance untangling |
| Coediting activation | opt-in per document via "Coedit this Document with Claude"; every surface gated on the active coediting set (INV-10) | always-on for all markdown; opt-in per workspace/folder | Per-document opt-in is the only grain that avoids hijacking Comments/SCM/preview for the writer's other files while keeping single-file precision |
| Authorship in the diff | the native diff is **author-blind** (what changed); authorship is shown in the preview, optionally a decoration track-changes editor (INV-11) | recolor machine changes inside the native diff editor | **Not possible:** `diffEditor.*` colors are global theme tokens with no per-author scoping; `inlineEdit.*`/chat tokens differentiate accept-state not author; decorations over the diff pane composite over green/red and are unreliable (vanish on tab-switch). Verified against the VS Code API (§13-Q5) |
| Comment → machine response | on a coedited doc, a comment fires a turn that replies + offers an edit → pending proposal | comment is inert (human-only threads) | Turns the familiar review-comment gesture into a coediting action without a new surface; the opt-in gate (INV-10) keeps it from firing on other docs |
@@ -880,7 +907,7 @@ a bug reaches us as a tracker issue.
| Q2 | Per-change Keep/Undo: how far can the stable API go before falling back to per-hunk CodeLens? | Ben | PUC-2 build (last surface) |
| Q3 | One "Cowriting" SourceControl vs. QuickDiff-only (no full SCM viewlet entry) — how much SCM presence is wanted | Ben | PUC-1 build |
| Q4 | Does any need genuinely require a webview the native surfaces can't serve (INV-3 escape hatch)? | Ben | Per-surface build |
| Q5 | Authorship (human vs. machine) cannot live in the native diff (INV-11, verified). Which surface carries it — the annotated preview only, a preview **plus** in-editor authorship decorations, or an **owned author-colored track-changes view** that replaces the native diff for review? | Ben | PUC-3 build / authorship-surface scope |
| Q7 | Once the writer freely edits the proposal across hunks (INV-12), how do per-change Keep/Undo behave — do per-hunk actions survive arbitrary edits, or does free editing collapse the change set to a single Keep/Reject-all? | Ben | PUC-2 build |
**Resolved**
@@ -896,6 +923,8 @@ a bug reaches us as a tracker issue.
| D8 | Comments can summon the machine | On a coedited doc, a comment fires a turn that replies in-thread + offers an edit → pending proposal (BUC-5, INV-5); inert on non-coedited docs | 2026-06-27 |
| D9 | Native diff is author-blind | Verified the diff editor has no per-author color API; authorship lives in the preview (and optionally a decoration track-changes editor), not the native diff (INV-11) | 2026-06-27 |
| D10 | Comment trigger | While a document is in coediting mode, **every** new comment summons the machine (no per-comment gate); coediting mode is the control, "Stop editing with Claude" the off switch | 2026-06-27 |
| D11 | Authorship surface (Q5) | Option 1 — the annotated preview is the authorship view; native diff stays author-blind; in-editor decorations (opt 2) and an owned track-changes diff (opt 3) are out of scope | 2026-06-27 |
| D12 | Editable proposals | The review's proposed side is writable; the writer tweaks before Keep; machine words vs. writer tweaks are attributed at Keep (INV-12); live doc untouched until Keep (INV-5) | 2026-06-27 |
## 14. Glossary & References
@@ -922,4 +951,5 @@ a bug reaches us as a tracker issue.
multi-diff editor, Markdown preview `markdown-it` contribution, Comments,
`TextDocumentContentProvider`, decorations. *Prior art (patterns proven in earlier
coauthoring work, reused here on their own merits): baseline pinning, char-precise
attribution, the portable coauthoring sidecar, and live turn progress.*
attribution, the portable coauthoring sidecar, live turn progress, and editable
proposals (tweak-before-keep with mixed human/machine authorship).*