1 Commits

2 changed files with 261 additions and 161 deletions
+18 -1
View File
@@ -9,10 +9,27 @@ status: draft
| **Type** | Throwaway discovery **prototype** (handbook §5.3) — code is disposable |
| **Goal** | Prove the API-dependent design assumptions on the **real** VS Code surfaces, cheaply, **before** the full build — so post-ship iteration is polish, not design |
| **Non-goal** | Production code, real Claude/SDK wiring (except E4), persistence durability, polish, breadth |
| **Status** | `draft` |
| **Status** | `draft`**in progress: E1/E3/E5 done, E2/E4 remain** |
---
## Status (2026-07-01, session 0063)
Three of the five experiments are built and passed in `vscode-cowriting-prototype`:
- **E1 — PASS with pivot.** VS Code does **not** render extension CodeLens inside
a diff editor; per-hunk CodeLens works in a normal editor, and tweak-then-Keep
attributes machine words vs. writer edits correctly. Folded back into the
Solution Design as **D18** (the review surface is the live buffer itself,
in-buffer pending changes — see `coauthoring-native-surfaces.md` v0.2.0).
- **E3 — PASS.** The `markdown-it` contribution renders author-colored marks +
deletions in the built-in preview, theme-aware, with a working toggle.
- **E5 — PASS.** Title-bar + status-bar entry points read as obvious without the
Source Control pane.
- **E2 (baseline router: QuickDiff vs git `HEAD` + snapshot) and E4 (comment →
reply → offer → proposal) are not built yet** — now the riskiest unvalidated
assumptions and the spike's remaining work.
## Why this exists
Static mockups validated the *look* and *state coverage*; they prove **nothing**
+243 -160
View File
@@ -8,14 +8,15 @@ status: draft
| **Author(s)** | Ben Stull (with Claude) |
| **Reviewers / approvers** | Ben Stull |
| **Status** | `draft` |
| **Version** | v0.1.0 |
| **Source artifacts** | North-star architecture spec (design-only) for human↔machine markdown coediting. Reference: VS Code's native review surfaces (SCM/QuickDiff, diff editor, multi-diff editor, Markdown preview, Comments). Supersedes: none. |
| **Version** | v0.2.0 |
| **Source artifacts** | North-star architecture spec for human↔machine markdown coediting. Reference: VS Code's native review surfaces (SCM/QuickDiff, diff editor, Markdown preview, Comments). Inputs: the shipped plugin (F1F12), the rung-2 feasibility spike (`vscode-cowriting-prototype`), `coauthoring-feasibility-spike.md`. Supersedes: none. |
**Change log**
| Date | Version | Change | By |
| --- | --- | --- | --- |
| 2026-06-27 | v0.1.0 | Initial draft — brainstorming session 0062 | Ben Stull + Claude |
| 2026-07-01 | v0.2.0 | Session 0063 recommendation folded in: review surface is **in-buffer pending changes + per-hunk CodeLens** (supersedes the multi-diff Keep/Undo surface — D18, resolves Q2/Q7, amends INV-5/INV-12); **Q1 resolved — evolve the shipped extension in place** (D17); **comments-first ask surface** (D19); D11 updated to shipped reality (D21); rung-2 spike findings (E1/E3/E5) recorded | Ben Stull + Claude |
---
@@ -110,9 +111,9 @@ between blind trust and tedious manual reconciliation.
staying in control — seeing what changed, accepting/rejecting changes
individually, knowing authorship, reading the rendered result, and following the
machine's progress — entirely within their editor.
- **Out of scope:** committing a specific product packaging or release; multi-file /
whole-project machine orchestration; a server or cloud backend. This is a
**design-only north star** (see §2): packaging and delivery decisions are deferred.
- **Out of scope:** marketplace release; multi-file / whole-project machine
orchestration; a server or cloud backend. (v0.1.0 also deferred the packaging
decision; v0.2.0 resolves it — the shipped extension evolves in place, D17/§13-Q1.)
- **Non-goals:** replacing the writer's judgment (the machine proposes; the human
disposes); non-markdown document formats in v1; a real-time multi-human
collaboration server.
@@ -122,8 +123,9 @@ between blind trust and tedious manual reconciliation.
- **Assumptions:** the writer works in an editor with native diff, source-control,
multi-change review, Comments, and Markdown-preview surfaces (VS Code is the
target); a capable machine coauthor is available to run locally.
- **Constraints:** serverless and git-native (no external store); the writer's
document is never mutated without their explicit acceptance; no secret bytes in
- **Constraints:** serverless and git-native (no external store); nothing the
machine proposes ever *lands* without the writer's explicit acceptance — a
pending suggestion is always revertible in one gesture; no secret bytes in
any persisted artifact.
- **Dependencies:** a local machine-coauthor runtime; the editor's stable extension
APIs for the surfaces above; the built-in **Git extension API** (to read `HEAD` for
@@ -154,13 +156,15 @@ Scenario: BUC-2 — keep or reject, change by change
Given the machine has proposed changes to my document
When I review them
Then I can keep or discard each change individually, or all at once
And nothing the machine proposed alters my document until I keep it
And nothing the machine proposed lands in my document until I keep it
discarding a change restores my text exactly as it was
```
- **BUC-2 acceptance criteria:** no proposed change alters the document until the
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-2 acceptance criteria:** no proposed change *settles* until the writer
keeps it, and rejecting one restores the prior text exactly; 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.**
@@ -227,7 +231,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 — 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) |
| Keep/reject — and **tweak** — changes (BUC-2) | **Pending changes in the live editor** — proposed edits land decorated-but-unsettled in the buffer, with per-hunk **✓ Keep / ✗ Reject** CodeLens (D18) | The paradigm the platform's own AI edit sessions use: review the change *in the document*, tweak it by just typing (INV-12), revert it with one gesture (INV-5) |
| 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 |
@@ -252,12 +256,16 @@ of building review machinery without getting the polish, and asks the writer to
learn a foreign surface. **Delivering through the editor's native surfaces** gets
that behavior for free, makes coediting feel built-in, and shrinks what must be
built and maintained to a thin layer of wiring over proven cores. The cost is
accepting the platform's affordances where they differ from a bespoke one, plus a
small stable-API boundary on per-change Keep/Undo (§6.10, §13-Q2).
accepting the platform's affordances where they differ from a bespoke one. (The
v0.1.0 stable-API worry on per-change Keep/Undo resolved the other way: the spike
showed CodeLens does not render in a diff editor at all, which — together with the
shipped F12 experience — moved the review surface into the live buffer, D18.)
**Decision posture:** this is a **design-only north star**. It commits to the
architecture and the native-surface mapping; it does **not** commit to a product
packaging or a delivery sequence — those are taken later (§7.1, §13-Q1).
**Decision posture:** this is a **north star with a committed delivery vehicle**.
It commits to the architecture and the native-surface mapping, and (as of v0.2.0,
D17) to the packaging: **the shipped extension evolves in place onto these
surfaces** — its pure cores are retained, its bespoke webview surfaces sunset
(§6.10, §7.1).
**Solution scope.** *In:* the architecture, surface mapping, data model, contracts,
and per-use-case design for native, in-editor human↔machine markdown coediting,
@@ -292,12 +300,16 @@ Scenario: PUC-1 — see the diff against the baseline checkpoint (realizes BUC-1
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
Then each proposed change appears in my editor as a pending, decorated change
(proposed words marked by author color, replaced words struck) visible in
place but not settled
And each change carries Keep / Reject actions (CodeLens above the change)
And Keep all / Reject all are available (CodeLens menu, title bar, status bar)
And I can tweak the proposed wording by simply typing in the pending text
And rejecting a change restores my text exactly as it was
And on keep, the machine's words are attributed to the machine and my tweaks to me
And "Review Changes" opens the native diff (baseline live) to sweep everything
at once
```
```gherkin
@@ -374,8 +386,11 @@ panel to wireframe. Described in text (source of truth):
the document is coedited, title-bar buttons (**Review Changes**, **Ask Claude**,
**Toggle Annotations**, and in snapshot mode **Mark Changes as Reviewed**) and the
`✦ Coediting · N changes` status-bar item are the everyday entry points — visible
without going anywhere. The review also **auto-opens** on new proposals, and the
live-progress notification carries a *Review* action.
without going anywhere. **Ask Claude** opens a comment thread (on the selection if
there is one, else on the whole document) — the comment box *is* the ask input
(D19). New proposals land as pending changes **in the buffer in front of the
writer** (no navigation at all), and the live-progress notification carries a
*Review* action.
- **Source Control gutter & viewlet (optional, for git users).** A dedicated
source-control entry, *"Cowriting,"* coexists with Git: its quick-diff provider
draws the familiar change bars in the editor gutter against the baseline checkpoint,
@@ -384,16 +399,26 @@ panel to wireframe. Described in text (source of truth):
— never the required path (INV-13).
- **Native diff editor.** The writer's normal diff (`baseline ⟷ live`), with the
platform's inline/side-by-side toggle, navigation, and accessibility.
- **Multi-diff review editor.** When the machine proposes edits, a multi-diff editor
opens showing `baseline ⟷ proposed`, each change carrying **Keep/Undo**; a
toolbar carries **Keep all / Reject all**. This is the accept/reject surface.
- **Pending changes in the editor (the accept/reject surface, D18).** When the
machine proposes edits, each change lands **in the live buffer** as a pending,
decorated change — proposed words marked in the machine's author color, replaced
words shown struck — with per-hunk **✓ Keep / ✗ Reject** CodeLens (and a
Keep-all/Reject-all menu). The writer tweaks a pending change by **typing in it**;
Reject restores the prior text exactly. This is the same review-in-the-document
paradigm the platform's own AI edit sessions use, so it reads as native even
though the decorations are the extension's. (The v0.1.0 multi-diff Keep/Undo
surface is superseded — the spike showed CodeLens cannot render in a diff editor,
§7.1/D18.)
- **Built-in Markdown preview.** The writer's normal "Open Preview to the Side";
with annotations on, authorship colors and change marks appear *inside* it. A
command/setting toggles annotations.
- **Comments gutter.** Region threads via the native Comments API (create on
selection, reply, resolve). On a coedited document, the machine replies in-thread
- **Comments gutter — the primary ask surface (D19).** Region threads via the
native Comments API (create on selection, reply, resolve). The comment box is the
one native multi-line input the editor offers, so it is **how the writer asks for
anything**: an imperative ask ("tighten this paragraph") and a discussion remark
are the same gesture. On a coedited document, the machine replies in-thread
and offers an edit (BUC-5 / PUC-8); the offer, when accepted, becomes a pending
proposed change reviewed in the multi-diff. A comment can be **started from the
proposed change reviewed in the buffer (PUC-2). A comment can be **started from the
rendered preview** (select text there → "Comment on this"): the selection is mapped
back to the source range and a **native** thread is created — the preview shows a
💬 marker that deep-links to it, but the thread itself renders in the gutter /
@@ -419,7 +444,7 @@ panel to wireframe. Described in text (source of truth):
### 5.2 Screen: native surfaces (serves PUC-1…PUC-6)
Covered in the §5 text above. No custom screen; states map to platform states (diff
editor empty/identical, multi-diff empty, preview loading/error) plus the
editor empty/identical, no pending changes, preview loading/error) plus the
coauthoring **displaced** state surfaced in the thread / proposed-change listing.
## 6. Technical Design
@@ -442,9 +467,15 @@ coauthoring **displaced** state surfaced in the thread / proposed-change listing
`threads` share one envelope; **unknown fields are preserved** on read/merge, so
the artifact round-trips to an outer review forge (e.g. Gitea/GitHub) without
loss.
- **INV-5 — proposed changes are pending until kept:** a machine-proposed edit does
**not** mutate the document until the writer keeps it (Keep in the multi-diff, or
Accept). The machine proposes; the human disposes.
- **INV-5 — proposed changes are pending until kept:** a machine-proposed edit
never **settles** until the writer keeps it. It appears in the live buffer as a
visibly pending, decorated change (D18) — but it is fully revertible: **Reject
restores the prior text exactly**, the model retains each proposal's original,
and nothing is attributed as landed machine work until Keep. The machine
proposes; the human disposes. *(Amended in v0.2.0: v0.1.0 kept the buffer
byte-untouched until Keep; the guarantee is now "nothing lands irrevocably,"
which is what the writer actually needs — and what makes tweak-by-typing
possible, INV-12.)*
- **INV-6 — pure cores stay vscode-free:** attribution, anchoring, merge, diffing,
and the progress reducer are pure modules with no `vscode` import, unit-tested in
isolation; controllers are the only `vscode`-aware layer, so surfaces can change
@@ -486,24 +517,28 @@ coauthoring **displaced** state surfaced in the thread / proposed-change listing
remains, so re-entering restores state.
- **INV-11 — the native diff is author-blind:** the native diff editor shows *what*
changed against the baseline, not *who* changed it (the diff API has no per-author
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.
color scoping — §6.7). Authorship (human vs. machine) is shown on surfaces the
extension renders: the annotated preview and the in-editor author-colored
track-changes decorations (D21), never by recoloring the native diff.
- **INV-13 — no surface requires the Source Control pane:** the primary,
always-visible entry points for a coedited document are the **editor title-bar
actions** and a **status-bar item** (both gated on `cowriting.isCoediting`), and the
review **auto-opens** on new machine proposals. The SCM viewlet entry and the gutter
actions** and a **status-bar item** (both gated on `cowriting.isCoediting`), and
new machine proposals land **in the buffer in front of the writer** (D18) — the
review requires no navigation at all. The SCM viewlet entry and the gutter
dirty-diff are additional native affordances, not the required path — a writer
unfamiliar with git / Source Control never has to find them to coedit, review, or
settle a checkpoint.
- **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).
- **INV-12 — proposed changes are editable before they are kept:** a pending
change sits in the live buffer, so the writer tweaks it by **typing directly in
it** (the common "close, but a few human edits" case) — no separate proposal
document, no mode. Nothing settles until Keep (INV-5); on Keep, the words the
machine proposed are attributed to the machine and the writer's tweaks to the
writer — by diffing *final ↔ the machine's original proposal ↔ baseline* — so
authorship is correct **at the moment the change is made**, never reconstructed
afterward. Once kept, the text is just text (no lingering "trapped proposal"
state to untangle). A pending change re-anchors around the writer's edits; one
displaced by heavy rewriting collapses to a whole-proposal Keep/Reject (D20,
INV-1 discipline).
### 6.2 High-level architecture
@@ -523,7 +558,7 @@ flowchart LR
subgraph Ctrls["Thin controllers (vscode-aware)"]
SC[SourceControl + QuickDiffProvider]
BP[Baseline provider<br/>TextDocumentContentProvider]
PR[Review controller<br/>multi-diff Keep/Undo]
PR[Pending-change controller<br/>in-buffer decorations + CodeLens]
PV[Preview extension<br/>extendMarkdownIt]
TC[ThreadController<br/>Comments API]
LP[liveProgress relay]
@@ -532,7 +567,7 @@ flowchart LR
subgraph Native["Native VS Code surfaces"]
GUT[Gutter dirty-diff + SCM viewlet]
DIFF[Native diff editor]
MDIFF[Multi-diff review + Keep/Undo]
MDIFF[Live editor buffer<br/>pending changes + CodeLens]
MDPREV[Built-in Markdown preview]
COMM[Comments gutter/peek]
NOTE[Notification + OutputChannel]
@@ -555,9 +590,10 @@ flowchart LR
- **Baseline provider** — a `TextDocumentContentProvider` for the
`cowriting-baseline:` scheme; serves the pinned baseline text for any document URI
from the out-of-repo baseline store (INV-7).
- **Review controller** — turns the machine's emitted edits into pending proposed
changes, opens the multi-diff review, and applies Keep/Undo by delegating to the
proposed-change model; honors INV-5.
- **Pending-change controller** — turns the machine's emitted edits into pending
proposed changes, lands them in the live buffer as decorated pending text
(retaining each proposal's original for exact revert), and renders per-hunk
Keep/Reject CodeLens; Keep settles + attributes, Reject restores; honors INV-5.
- **Preview extension** — contributes `markdown-it` so the pure `renderAnnotations`
transform runs inside the built-in preview; owns no webview.
- **Sidecar router + store** — persistence: a repo-committed sidecar when the
@@ -608,21 +644,23 @@ state (INV-7), not durable coauthoring metadata.
(drives gutter bars). Registered on the "Cowriting" `SourceControl`.
- **Machine-edit seam** — the single boundary where machine text enters the model:
`proposeAgentEdit(docUri, range, newText, provenance)` → produces **pending**
`proposals[]` entries (never mutates the doc — INV-5). Block/word granularity via
`proposals[]` entries; nothing settles until Keep (INV-5). Block/word granularity via
the pure diff engine (`diffToBlockHunks` / `wordEditHunks`): a block (paragraph,
header, list item, fenced code) is the *decision* unit a writer keeps or rejects;
the word diff inside it is the *attribution* unit, so keeping a block attributes
only the words that actually changed.
- **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). 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).
- **Pending-change controller** — on new proposals, lands each **optimistically in
the live buffer** as decorated pending text (the model retains the proposal's
`original` for exact revert) and renders per-hunk **✓ Keep / ✗ Reject** CodeLens
(D18). `keep(proposalId)` = Accept: settles the change and attributes it —
machine-proposed words to the machine, any writer tweaks (typed directly into the
pending text, INV-12) to the writer, by comparing *final ↔ the machine's original
proposal ↔ baseline*. `reject(proposalId)` restores the retained original
exactly. `keepAll()` / `rejectAll()` apply descending, skip + report any
displaced change. Pending changes re-anchor around writer edits; a displaced one
collapses to whole-proposal Keep/Reject (D20). `openReview(docUri)` opens the
**native diff editor** (`baseline ⟷ live`) as the sweep-everything reference
view — read-only, author-blind (INV-11); decisions stay in the buffer.
- **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.
@@ -637,8 +675,12 @@ state (INV-7), not durable coauthoring metadata.
`isCoediting(docUri)` before attaching a surface: the QuickDiffProvider returns no
original for non-coedited docs, the comment-response controller ignores them, and
the annotation/edit commands are disabled (`when` clause `cowriting.isCoediting`).
- **ThreadController + comment-response**create/reply/resolve via the Comments
API. On a coedited document only, a new comment fires `runEditTurn` to **reply in
- **ThreadController + comment-response — the primary ask surface (D19)** —
create/reply/resolve via the Comments API. The comment box is the editor's one
native multi-line input, so **asking is commenting**: the title-bar **Ask
Claude** action just creates a thread (on the selection, else whole-document) and
focuses its input; no bespoke input surface exists. On a coedited document only,
a new comment fires `runEditTurn` to **reply in
the thread** and, when the remark implies a change, **offer an edit**; an accepted
offer routes through the machine-edit seam to a **pending** proposed change
(INV-5) — the comment never edits the document directly. The reply is posted as a
@@ -677,34 +719,37 @@ sequenceDiagram
```mermaid
sequenceDiagram
actor U as Writer
participant R as Review ctrl
participant R as Pending-change ctrl
participant S as Machine runtime
participant M as Multi-diff editor
participant E as Live editor buffer
U->>R: Ask the machine to revise
R->>S: runEditTurn(prompt, {onProgress, signal, env})
S-->>R: proposed text
R->>R: proposeAgentEdit → pending proposals[] (INV-5)
R->>M: openReview (baseline ⟷ proposed)
U->>M: Keep / Undo per change · Keep all / Reject all
M->>R: keep(p)/undo(p)
R-->>U: document updated only on Keep; authorship recorded
R->>E: land pending changes (decorated, original retained)
U->>E: tweak by typing · Keep / ✗ Reject per change (CodeLens)
E->>R: keep(p)/reject(p) · keepAll()/rejectAll()
R-->>U: Keep settles + attributes · Reject restores the original exactly
```
- **Implementation:** the machine never edits the document; it emits **pending**
proposed changes (INV-5). The multi-diff editor is the review surface; Keep =
Accept (apply + attribute changed words), Undo = Reject. Keep-all/reject-all apply
descending and skip + report any displaced change. **Stable-API boundary:** the
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.
- **Implementation:** the machine emits **pending** proposed changes; each lands in
the live buffer as a decorated pending change with its original retained, and
nothing settles until Keep (INV-5). Per-hunk **CodeLens** carries ✓ Keep /
✗ Reject (with a Keep-all/Reject-all menu); keep-all/reject-all apply descending
and skip + report any displaced change. The **native diff editor**
(`baseline ⟷ live`) is the sweep-everything reference view; the buffer is where
decisions happen. **Why in-buffer (D18):** the rung-2 spike verified VS Code does
**not** render extension CodeLens inside a diff editor, ruling out the v0.1.0
multi-diff Keep/Undo surface; the shipped F12 experience proved the in-buffer
model end-to-end, and it matches the platform's own AI edit-session paradigm.
- **Editable before keep (INV-12):** the pending change sits in the live buffer, so
the writer tweaks it by typing directly in it ("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*, so authorship is
correct at creation — the preview and the in-editor track-changes then show clean
green/blue with no post-hoc untangling. Pending changes **re-anchor** around
writer edits; one displaced by heavy rewriting collapses to a whole-proposal
Keep/Reject (D20, resolving the old Q7).
#### Always-visible entry points (no Source Control navigation) — INV-13
@@ -713,8 +758,9 @@ sequenceDiagram
it exists). When `cowriting.isCoediting` is set, the actions surface where the
writer already is: **editor title-bar buttons** (Review Changes, Ask Claude, Toggle
Annotations, and in snapshot mode Mark Changes as Reviewed) and a **status-bar
item** (`✦ Coediting · N changes`, click → Review Changes). The multi-diff review
**auto-opens** on new proposals, and the live-progress notification carries a
item** (`✦ Coediting · N changes`, click → Review Changes). New proposals land
**in the buffer in front of the writer** (D18 — the review comes to them), and
the live-progress notification carries a
*Review* action. The SCM viewlet entry and the gutter dirty-diff remain as native
extras for git-literate users, never the required path.
@@ -774,7 +820,7 @@ sequenceDiagram
T-->>U: machine reply posted in thread (onBehalfOf provenance)
U->>T: accept the offered edit
T->>R: proposeAgentEdit → pending proposal (INV-5)
R-->>U: review in multi-diff (PUC-2)
R-->>U: pending change lands in the buffer (PUC-2)
```
- **Implementation:** gated on `isCoediting` (INV-10) — inert otherwise. The turn
@@ -809,7 +855,7 @@ sequenceDiagram
- **Observability:** the OutputChannel stream (PUC-5) is the user-facing turn log;
no telemetry service (a local extension — §9).
- **Accessibility:** inherited from the native surfaces — the diff editor,
multi-diff, Markdown preview, and Comments all carry the editor's accessibility.
CodeLens, Markdown preview, and Comments all carry the editor's accessibility.
This is a primary *reason* for the native-first choice.
### 6.7 Key decisions & alternatives considered
@@ -817,20 +863,21 @@ sequenceDiagram
| Decision | Chosen | Alternatives considered | Why chosen |
| --- | --- | --- | --- |
| Diff surface | `QuickDiffProvider` + native diff editor against a `cowriting-baseline:` virtual doc | bespoke webview diff; decoration-only inline diff | Native gutter + diff editor for free: theming, inline/side toggle, a11y, navigation; zero custom rendering (INV-3) |
| Accept/reject surface | **Multi-diff editor with Keep/Undo**, backed by the proposed-change model | source-control stage/unstage; in-editor CodeLens Keep/Reject; bespoke webview ✓/✗ | Closest to a modern "review the machine's edits" feel; reviews all changes in one native surface. Stable fallback: per-hunk CodeLens (§6.10) |
| Accept/reject surface (v0.2.0, D18 — supersedes the v0.1.0 multi-diff choice) | **Pending changes in the live buffer** with per-hunk **✓ Keep / ✗ Reject CodeLens**, backed by the proposed-change model; native diff editor as the read-only sweep view | multi-diff editor with Keep/Undo (v0.1.0 choice — **ruled out**: the spike verified CodeLens does not render in a diff editor, and inline overlays lean on evolving APIs); a separate writable proposal document (spike E1 pivot — works, but puts an artifact between the writer and their document); source-control stage/unstage; bespoke webview ✓/✗ | The platform's own AI edit-session paradigm: review the change in the document, tweak by typing, revert in one gesture. Shipped and proven end-to-end (F12); all-stable APIs (decorations + CodeLens) |
| Rendered preview | **Extend the built-in Markdown preview** (`markdown-it` contribution) | bespoke sealed webview; both surfaces | Native scroll-sync, theming, refresh, and cooperation with the writer's other Markdown extensions; no webview to own (INV-3) |
| Baseline source | follows the file's home (INV-7): **git `HEAD`** where tracked (resets on commit, storage-free), a **snapshot** (set on entry, re-pinnable; global storage / in-memory) where there is no commit to anchor to — outside any repo, untracked, or untitled | always a stored snapshot; always defer to git (breaks outside a repo) | Git-tracked files get the native "uncommitted work, reset on commit" diff for free; `~/Downloads` / untitled still work via the snapshot fallback. Mirrors the in-repo/out-of-repo `SidecarRouter` |
| 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 |
| Authorship surface (v0.2.0, D21 — updates D11 to shipped reality) | the annotated preview **and** the in-editor author-colored track-changes decorations (both shipped); native diff stays author-blind (INV-11) | preview-only (v0.1.0 D11 — overtaken: the in-editor decorations shipped 2026-06-27 and earn their keep); Option 3 (owned author-colored track-changes diff replacing native diff) | Both surfaces ride the same pure render/attribution cores; the writer gets authorship where they read (preview) and where they write (editor). Opt 3 still out |
| Editing proposals | pending changes are **tweaked by typing directly in the buffer**; pre-Keep tweaks are absorbed and attributed (machine vs. writer) at Keep (INV-12) | a separate writable proposal document (v0.1.0); machine proposal read-only (tweak only after accepting) | Most revisions are "close, but a few human edits"; editing in place, at review time, keeps authorship clean at creation with no extra artifact and no messy post-acceptance untangling |
| Ask surface (v0.2.0, D19) | **comments-first** — the native comment thread input is the ask input; title-bar "Ask Claude" creates/focuses a thread (selection or whole-document) | the shipped bespoke split-pane input webview (sunset — one custom surface eliminated); single-line `InputBox` (too small for real asks) | The Comments API is the editor's one native multi-line input; ask-for-an-edit and remark-on-a-passage collapse into a single familiar gesture, and the machine's answer lands in the same thread (D8/D10) |
| 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 |
| Change discovery (resolves Q3) | primary entry = **editor title bar + status-bar item + auto-open review**; the SCM viewlet + gutter are optional extras (INV-13) | rely on the Source Control pane / gutter as the entry point | Writers working outside git won't find (or know) the Source Control pane; always-visible title-bar / status-bar actions need no git familiarity |
| Change discovery (resolves Q3) | primary entry = **editor title bar + status-bar item**, and proposals land **in the buffer in front of the writer** (D18); the SCM viewlet + gutter are optional extras (INV-13) | rely on the Source Control pane / gutter as the entry point | Writers working outside git won't find (or know) the Source Control pane; always-visible title-bar / status-bar actions need no git familiarity |
| 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 |
| Comments & the preview | comments are **native** (source gutter + Comments panel); the preview can *initiate* a comment (selection → source range via the `markdown-it` source map) and show a deep-linking 💬 marker, but cannot **host** the thread (it's a webview — verified) | render a bespoke comment widget inside the preview webview | Keeps comments on the native surface (no INV-3 exception, keeps the Comments panel + gutter); the writer can still comment on what they're reading and add whole-document comments (top-anchored) |
| Scope | design-only north star (no packaging/migration commitment) | commit a packaging + delivery sequence now | Keeps the architecture decision separate from the delivery decision (§2, §7.1) |
| Scope & packaging (v0.2.0, D17 — resolves Q1) | north star **with a committed vehicle**: the shipped extension **evolves in place** onto these surfaces (pure cores retained, webview surfaces sunset) | greenfield extension importing the cores as a library (re-derives wiring + E2E harness the shipped repo already has); stay design-only (stalls — §7.3) | ~60% of the shipped code (21 pure modules, ~3.5k LOC) *is* this design's cores already; evolve-in-place keeps tests, history, and continuous shipping |
### 6.8 Testing strategy
@@ -841,15 +888,18 @@ sequenceDiagram
markdown-it transform (token-in → annotated-token-out).
- **Integration / E2E (`@vscode/test-electron`):** drive the controllers in the
Extension Development Host — mark-reviewed → assert checkpoint reset; ask-to-edit
→ assert pending proposals + multi-diff opened; Keep/Undo → assert document
mutation only on Keep + authorship recorded; toggle annotations → assert preview
→ assert pending proposals landed decorated in the buffer with originals
retained; Keep/Reject → assert Keep settles + attributes and Reject restores the
original text exactly; toggle annotations → assert preview
HTML marks; thread create → re-anchor → displaced. Where the harness cannot drive
a native surface's chrome directly (multi-diff Keep/Undo, Comments UI, preview
a native surface's chrome directly (CodeLens clicks, Comments UI, preview
DOM), assert controller/provider state and pure-transform output instead. **No
Playwright** — these are native surfaces, not a webview. E2E are first-class plan
tasks (handbook §4 / §6.8).
tasks (handbook §4 / §6.8). The shipped repo's 19 E2E suites carry forward under
evolve-in-place (D17).
- **Named E2E scenarios this design must pass:** PUC-1 pin→diff; PUC-2
propose→review→keep/undo→keep-all; PUC-3 annotate-toggle; PUC-4/6
propose→tweak→keep/reject→keep-all (incl. reject-restores-exactly); PUC-3
annotate-toggle; PUC-4/6
thread→reanchor→displaced; PUC-5 progress→cancel.
### 6.9 Failure modes, rollback & flags
@@ -860,63 +910,91 @@ sequenceDiagram
"start writing, or ask Claude to draft something" affordance; not an error. A
coedited document always has a baseline (set on entry, INV-7), so there is **no
"missing baseline" state** to handle.
- **Multi-diff Keep/Undo API unavailable/changed** → fall back to per-hunk CodeLens
Keep/Reject in the diff editor (§6.10); the proposed-change *model* is unchanged.
- **Save while changes are pending** → the buffer (and on save, the disk file)
contains visibly-pending machine text; safe because every pending proposal's
original is retained in the sidecar and Reject restores it exactly after reload
(INV-5, re-anchored on load per INV-1/PUC-6).
- **Feature flags / settings:** `cowriting.annotations` (preview annotations on/off),
`cowriting.liveProgress.revealOutput`. The whole capability is additive — off by
absence of coediting mode for the document (INV-10).
### 6.10 Migration & compatibility
**Greenfield — nothing to migrate.** This is a from-scratch design for in-editor
human↔machine markdown coediting; it does not replace an existing data format or
contract that must be carried.
**Evolve in place (D17, resolves Q1).** The v0.1.0 draft called this greenfield;
that undersold the shipped extension: **~60% of its code — 21 pure, vscode-free
modules (~3.5k LOC) — already implements this design's cores** (attribution span
algebra, fingerprint anchoring, the sidecar envelope + router + merge, the
block/word diff engine, the render/annotation transform, the turn-progress
reducer, the machine turn runner). The delivery vehicle is therefore the shipped
extension itself, migrated **surface by surface**:
- **Data migration:** none. The sidecar envelope is additive and
unknown-field-preserving (INV-4) from v1, so future versions extend it without a
break. The baseline (out-of-repo, disposable) needs no migration ever.
- **Backwards compatibility:** N/A at v1 (nothing precedes it); the envelope's
forward-compatibility rule (INV-4) protects future consumers.
- **Cutover:** N/A (design-only; no packaging committed — §7.1).
- **Stable-API boundary (recorded risk):** the native diff editor, SCM/QuickDiff,
multi-diff editor, Markdown-preview `markdown-it` contribution, Comments, and
decorations are **stable**. The per-change inline **Keep/Undo** overlay that some
AI tools render uses **evolving** editor APIs; the design's stable contract is
therefore "multi-diff review + per-hunk Keep/Reject CodeLens," with the inline
overlay as a progressive enhancement where the API allows (§13-Q2).
- **Retained as-is (the cores):** the 21 pure modules and their unit suites; the
sidecar contract (INV-4) and stores; the `@cline/sdk` turn runner + live
progress; the in-buffer pending-change experience (F12) and the in-editor
author-colored track-changes decorations — both already match this design (D18,
D21).
- **Rewired (thin controllers):** baseline moves behind the router (git `HEAD` +
snapshot, INV-7 — today it is snapshot-only); a QuickDiffProvider +
`cowriting-baseline:` content provider replace nothing (net-new native surface);
the CoeditingRegistry opt-in gate (INV-10) replaces the current always-on-for-
markdown behavior; ThreadController gains the comment-response loop (D8/D10).
- **Sunset (the bespoke webview stack, ~800 LOC):** the sealed review-panel
webview (`trackChangesPreview` + its client) is replaced by the extended
built-in Markdown preview (D3); the split-pane ask-input webview is replaced by
comments-first asking (D19). Each sunset lands only after its native replacement
is green.
- **Data migration:** none needed — the sidecar envelope carries forward
(additive, unknown-field-preserving, INV-4). The baseline (out-of-repo,
disposable) needs no migration ever.
- **Stable-API boundary:** every surface this design now stands on — diff editor,
SCM/QuickDiff, Markdown-preview `markdown-it` contribution, Comments,
decorations, CodeLens — is **stable API**. The one evolving-API worry from
v0.1.0 (per-change overlays in a multi-diff review) is gone with the in-buffer
decision (D18).
## 7. Delivery Plan
### 7.1 Approach / strategy
This is a **design-only north star** — it ships no code. Delivery proceeds in **four
de-risking rungs, riskiest-API-assumption first**, so any forced design change is
discovered on throwaway code rather than after the full build (the explicit goal:
post-ship iteration is *polish*, not *design*):
Delivery proceeds in **four de-risking rungs, riskiest-API-assumption first**, so
any forced design change is discovered on throwaway code rather than after the
full build (the explicit goal: post-ship iteration is *polish*, not *design*).
The vehicle is the **shipped extension, evolved in place** (D17/§6.10):
1. **Static mockups (done).** Validate visual design + state coverage. *(Already
surfaced and closed the empty-state, comments-from-preview, and discoverability
gaps.)*
2. **Throwaway feasibility spike (next).** A disposable VS Code extension (a §5.3
*prototype*; the machine **stubbed** with canned edits) whose only job is to prove
the API-dependent assumptions on the real surfaces and return a **go/no-go per
assumption — closing the build-time open questions (Q2, Q4, Q7) before any plan is
written.** Riskiest first: (a) the multi-diff proposed side is **editable** with
working **Keep/Undo** (INV-12); (b) the **baseline router** renders QuickDiff
against a snapshot *and* git `HEAD`, going clean on commit / Mark-Reviewed (INV-7);
(c) the **`markdown-it`** plugin injects authorship + deletions in the built-in
preview with a toggle (PUC-3); (d) the **comment → reply → offer → proposal** loop
(PUC-8); (e) the **title-bar + status-bar** discoverability reads as obvious
(INV-13). Companion: `coauthoring-feasibility-spike.md`. Output: a findings report
+ any spec deltas folded back here.
3. **Vertical slice.** One real end-to-end flow (enter → Ask Claude via the **real
`@cline/sdk`** → real proposal → review → keep) on a real document, minimal
breadth — proving the loop works for real once the surfaces are validated.
4. **Full build.** The implementation plan decomposed from this (spike-revised) spec,
built surface-by-surface in the validated order: **pure cores → diff surface**
(highest-confidence native win) **→ preview extension → multi-diff accept/reject**
(largest API-boundary risk, last, with the CodeLens fallback ready). One SPEC →
one plan → one execution per increment.
2. **Throwaway feasibility spike (partially done — 3 of 5 experiments).** A
disposable VS Code extension (`vscode-cowriting-prototype`; the machine
**stubbed** with canned edits) proving the API-dependent assumptions on the
real surfaces. Companion: `coauthoring-feasibility-spike.md`. **Findings so
far (2026-07-01):**
- **E1 (editable proposals + Keep/Undo) — PASS with pivot.** VS Code does
**not** render extension CodeLens inside a diff editor, ruling out the
multi-diff review surface; per-hunk CodeLens works in a normal editor, and
tweak-then-Keep attributes machine words vs. writer edits correctly. Folded
back as **D18** (with the shipped F12 experience): the review surface is the
live buffer itself.
- **E3 (preview authorship) — PASS.** The `markdown-it` contribution injects
author-colored marks + deletions into the built-in preview, theme-aware,
with a working toggle (D3 confirmed).
- **E5 (discoverability) — PASS.** Title-bar + status-bar entry points read as
obvious with no Source Control pane (INV-13 confirmed).
- **E2 (baseline router: QuickDiff against git `HEAD` *and* snapshot, clean on
commit / Mark-Reviewed — INV-7) and E4 (comment → reply → offer → proposal —
PUC-8) remain — now the riskiest unvalidated assumptions and the next
concrete work.**
3. **Vertical slice.** One real end-to-end flow (enter → ask via a comment thread
with the **real `@cline/sdk`** → real pending change in the buffer → tweak →
keep) on a real document, minimal breadth — proving the loop works for real
once E2/E4 are validated.
4. **Full build (the evolve-in-place migration, §6.10).** The implementation plan
decomposed from this (spike-revised) spec, migrated surface-by-surface in the
validated order: **baseline router + QuickDiff/diff surface** (E2) **→
coediting opt-in gate → preview extension replaces the review-panel webview →
comments-first ask + comment-response loop replaces the input webview** (E4) —
each bespoke surface sunsetting only after its native replacement is green.
One SPEC → one plan → one execution per increment.
### 7.2 Rollout / launch plan
@@ -928,11 +1006,13 @@ host E2E green (§6.8). Marketplace packaging/release is out of scope here.
| Risk | Likelihood / impact | Mitigation |
| --- | --- | --- |
| Per-change Keep/Undo overlay relies on evolving editor APIs | M / M | Stable contract = multi-diff + per-hunk CodeLens Keep/Reject; overlay is progressive enhancement (§6.10) |
| Baseline router assumptions fail on real git repos (E2 unvalidated) | M / M | E2 is the next spike experiment; snapshot mode (shipped today) is the always-works fallback (INV-7) |
| Comment-response loop feels laggy or noisy (E4 unvalidated) | M / M | E4 spikes it with latency notes; D10's off-switch ("Stop editing with Claude") bounds the blast radius |
| Save-while-pending leaves machine text on disk before a decision | M / L | Pending state + originals persist in the sidecar; Reject restores exactly after reload (§6.9); status-bar count keeps pending changes visible |
| Two source controls (Git + Cowriting) confuse the SCM viewlet | L / M | Multiple SCM providers coexist by design; name it clearly; QuickDiff alone (no full SCM) is the minimal fallback |
| Built-in preview can't host interactive ✓/✗ inside the preview | M / L | Accept/reject lives in the multi-diff surface, not the preview; the preview is read/annotate only (a deliberate split) |
| Native surfaces are harder to E2E than a queryable webview | M / L | Assert controller/provider state + pure-transform output |
| Design-only spec stalls (never delivered) | M / L | §13-Q1 names the delivery decision and owner; the architecture stands regardless |
| Built-in preview can't host interactive ✓/✗ inside the preview | M / L | Accept/reject lives in the buffer (D18), not the preview; the preview is read/annotate only (a deliberate split) |
| Native surfaces are harder to E2E than a queryable webview | M / L | Assert controller/provider state + pure-transform output; the shipped E2E harness carries forward (D17) |
| Evolve-in-place migration destabilizes a working product mid-flight | M / M | Surface-by-surface order (§7.1 rung 4): each bespoke surface sunsets only after its native replacement is green; the pure cores never move |
## 8. Success Metrics & Measurement
@@ -948,7 +1028,7 @@ host E2E green (§6.8). Marketplace packaging/release is out of scope here.
| # | Metric (scores PUC-n) | Target | Fed by | Review cadence |
| --- | --- | --- | --- | --- |
| PM-1 | PUC-1 diff opens in the native diff editor with an accurate baseline⟷live | works for any file incl. untitled | host E2E | per build |
| PM-2 | PUC-2 no document mutation until Keep; each change independently keep/undo-able | 100% (INV-5) | host E2E | per build |
| PM-2 | PUC-2 no proposed change settles until Keep; Reject restores the original exactly; each change independently keep/reject-able | 100% (INV-5) | host E2E | per build |
| PM-3 | PUC-3 annotations render in the built-in preview and toggle clean | on/off both correct | unit + host E2E | per build |
## 9. Telemetry, Observability & Monitoring
@@ -1009,17 +1089,14 @@ a bug reaches us as a tracker issue.
| # | Question | Owner | Blocks |
| --- | --- | --- | --- |
| Q1 | Product packaging & delivery sequence — the decision to act on this north star | Ben | Any implementation plan |
| 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) |
| Q4 | Does any need genuinely require a webview the native surfaces can't serve (INV-3 escape hatch)? | Ben | Per-surface build |
| 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 |
| Q4 | Does any need genuinely require a webview the native surfaces can't serve (INV-3 escape hatch)? — narrowed at v0.2.0: the two shipped webviews both have native replacements (D3, D19); the one candidate left is mermaid rendering in the preview, expected to ride `markdown.previewScripts` (the `markdown-mermaid` pattern), to be confirmed at the preview-surface build | Ben | Per-surface build |
**Resolved**
| # | Decision | Resolution | Date |
| --- | --- | --- | --- |
| D1 | Scope / altitude | Design-only north star — architecture + surface mapping, no packaging/migration commitment | 2026-06-27 |
| D2 | Accept/reject primary surface | Multi-diff editor with Keep/Undo (CodeLens stable fallback) | 2026-06-27 |
| D1 | Scope / altitude | Design-only north star — architecture + surface mapping, no packaging/migration commitment. *(Amended by D17: the packaging commitment is now taken.)* | 2026-06-27 |
| D2 | Accept/reject primary surface | Multi-diff editor with Keep/Undo (CodeLens stable fallback). *(Superseded by D18: the spike showed CodeLens cannot render in a diff editor.)* | 2026-06-27 |
| D3 | Rendered preview surface | Extend the built-in Markdown preview via a `markdown-it` contribution (no webview) | 2026-06-27 |
| D4 | Diff surface | `QuickDiffProvider` + native diff editor against a `cowriting-baseline:` virtual doc | 2026-06-27 |
| D5 | Core capabilities | Pinned baseline, char-precise authorship attribution, durable git-native sidecar, live cancellable progress, region threads, on-behalf-of identity, pure-core/thin-controller discipline | 2026-06-27 |
@@ -1028,12 +1105,17 @@ 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 |
| 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. *(Updated by D21: opt 2 shipped and is retained.)* | 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). *(Amended by D18/D20: the writable surface is the live buffer itself.)* | 2026-06-27 |
| D13 | Baseline semantics & source | Baseline = the last settled version. Its **source follows the file's home**: git `HEAD` where tracked (auto-resets on commit, storage-free), else a snapshot set on entry (global storage / in-memory). A coedited doc always has a baseline; the only empty state is a genuinely empty document (INV-7) | 2026-06-27 |
| D14 | Pin is the non-git fallback only (resolves Q8) | "Mark Changes as Reviewed" exists **only in snapshot mode** (no committed `HEAD`); git-tracked files have no manual pin — the writer **commits** and the baseline follows `HEAD`. The pin command is `when`-gated on `cowriting.baselineMode == snapshot` | 2026-06-27 |
| D15 | Comments & the preview | Native comment threads can't render in the preview (it's a webview — verified). The preview *initiates* a comment (selection → source range via the `markdown-it` source map) and shows deep-linking 💬 markers; a whole-document comment anchors at the top. Threads stay native (gutter + Comments panel); no bespoke in-webview comment UI | 2026-06-27 |
| D16 | Change discovery (resolves Q3) | No flow requires the Source Control pane (INV-13). Primary entry = editor title-bar actions + `✦ Coediting · N changes` status-bar item + auto-open review; SCM viewlet + gutter kept as optional git-user extras | 2026-06-27 |
| D16 | Change discovery (resolves Q3) | No flow requires the Source Control pane (INV-13). Primary entry = editor title-bar actions + `✦ Coediting · N changes` status-bar item + auto-open review; SCM viewlet + gutter kept as optional git-user extras. *(v0.2.0: "auto-open review" becomes "proposals land in the buffer in front of the writer," D18.)* | 2026-06-27 |
| D17 | Packaging & delivery vehicle (resolves Q1) | **Evolve the shipped extension in place** onto the native surfaces: the 21 pure core modules (~3.5k LOC, ~60%) are retained as-is, thin controllers are rewired, and the two bespoke webviews sunset only after their native replacements are green (§6.10). Greenfield rejected (re-derives wiring + E2E harness); staying design-only rejected (stalls) | 2026-07-01 |
| D18 | Accept/reject surface (resolves Q2; supersedes D2) | **Pending changes live in the buffer** — proposals land optimistically as decorated pending text (originals retained), decided by per-hunk ✓ Keep / ✗ Reject CodeLens, tweaked by typing. Grounds: the spike verified CodeLens does **not** render in a diff editor (killing the multi-diff surface); the shipped F12 proved the in-buffer model end-to-end; it matches the platform's own AI edit-session paradigm and uses only stable APIs. INV-5 reworded from "buffer untouched" to "nothing settles until Keep; Reject restores exactly" | 2026-07-01 |
| D19 | Ask surface | **Comments-first**: the native comment thread input is the ask input for both imperative asks and remarks; the title-bar "Ask Claude" creates/focuses a thread (selection, else whole-document); the shipped split-pane input webview sunsets. One custom surface eliminated; ask and discuss collapse into one native gesture (D8/D10) | 2026-07-01 |
| D20 | Tweaks × per-hunk decisions (resolves Q7; amends D12) | Free editing happens in the live buffer; each pending change **re-anchors** around writer edits so per-hunk Keep/Reject survives ordinary tweaking; a change displaced by heavy rewriting collapses to a whole-proposal Keep/Reject (skip + report in keep-all/reject-all) — the INV-1 discipline applied to proposals | 2026-07-01 |
| D21 | Authorship surfaces (updates D11) | The annotated preview **and** the in-editor author-colored track-changes decorations are both authorship surfaces (the latter shipped 2026-06-27, after D11 deferred it); both ride the same pure cores; the native diff stays author-blind (INV-11). Option 3 (owned track-changes diff) remains out | 2026-07-01 |
## 14. Glossary & References
@@ -1043,8 +1125,9 @@ a bug reaches us as a tracker issue.
Disposable; never committed by us (INV-7).
- **QuickDiffProvider** — the VS Code API that supplies gutter dirty-diff bars from a
virtual *original* document.
- **Multi-diff editor** — VS Code's native multi-change review surface; here the
accept/reject surface (Keep/Undo).
- **Pending change** — a machine-proposed edit landed optimistically in the live
buffer as decorated, unsettled text (original retained); decided by per-hunk
✓ Keep / ✗ Reject CodeLens, tweaked by typing (D18). The accept/reject surface.
- **Coauthoring sidecar** — the forward-compatible, unknown-field-preserving artifact
that persists anchors, authorship, proposed changes, and threads, and round-trips
to an outer review forge.
@@ -1059,8 +1142,8 @@ a bug reaches us as a tracker issue.
- **Pure core / thin controller** — the vscode-free, unit-tested logic vs. the
vscode-aware wiring split (INV-6).
- **References:** VS Code APIs — SCM/`QuickDiffProvider`, diff editor (`vscode.diff`),
multi-diff editor, Markdown preview `markdown-it` contribution, Comments,
`TextDocumentContentProvider`, decorations. *Prior art (patterns proven in earlier
Markdown preview `markdown-it` contribution, Comments,
`TextDocumentContentProvider`, decorations, CodeLens. *Prior art (patterns proven in earlier
coauthoring work, reused here on their own merits): baseline pinning, char-precise
attribution, the portable coauthoring sidecar, live turn progress, and editable
proposals (tweak-before-keep with mixed human/machine authorship).*