spec(0063): v0.2.0 — in-buffer pending review (D18, resolves Q2/Q7), evolve-in-place packaging (D17, resolves Q1), comments-first ask (D19), D11→shipped reality (D21), rung-2 spike findings recorded
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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 (F1–F12), 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).*
|
||||
|
||||
Reference in New Issue
Block a user