Files
vscode-cowriting-plugin-con…/specs/coauthoring-native-surfaces.md
T
BenStullsBets 61755cafd7 spec(0062): baseline source follows the file's home — git HEAD where tracked, snapshot otherwise (D13)
Answers 'what about docs not in a git repo' (~/Downloads, untitled): a
BaselineRouter mirroring the SidecarRouter. Git-tracked file -> baseline =
HEAD blob (read via Git extension API, auto-resets on commit, storage-free);
no commit to anchor to -> snapshot (set on entry, re-pinnable, global
storage/in-memory). Manual pin works in both (precedes HEAD until next
commit); new in-repo file flips snapshot->HEAD on first commit. Updated
INV-7, data model, baseline router, PUC-1/7, decisions, deps; new open Q8
(pin-ahead-of-HEAD precedence in git files).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:18:18 -07:00

60 KiB
Raw Blame History

status
status
draft

Solution Design: Coediting Markdown with a Machine — a Native VS Code Experience

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.

Change log

Date Version Change By
2026-06-27 v0.1.0 Initial draft — brainstorming session 0062 Ben Stull + Claude

1. Business Context

The business lens — solution-agnostic throughout. No mechanism is proposed until §2.

1.1 Executive Summary

A growing share of real writing — specs, docs, RFCs, design notes, prose — happens in markdown, and writers increasingly want a machine to help author it. But coediting a markdown document with a machine is awkward today. When the machine edits the file it hands back a rewrite, not a reviewable change: the writer is left staring at a wall of new text with no natural answer to "what did you actually change?" The writer can't easily keep some of the machine's edits and drop others; after a few rounds nobody can tell which words are the human's and which the machine's; and there's no clean rendered view of the work-in-progress with the changes made legible. In practice "writing with a machine" collapses into copy-paste between a chat window and the file — throwing away the diff, granular control, and provenance. This design delivers human↔machine markdown coediting inside the editor, through the surfaces a writer already uses to review changes, so coediting feels like a native capability of the editor rather than a chat window bolted onto the side. The value: writers can let a machine help with real documents while staying in control of what lands and confident about what changed.

1.2 Background

Markdown is the lingua franca of technical and semi-technical writing — it is where specifications, documentation, RFCs, and a great deal of prose are actually drafted and revised. At the same time, capable machine coauthors have arrived, and writers want to use them on these documents, not just on code.

But the modalities available for "writing with a machine" were built for other shapes of work, and they serve document coediting poorly:

  • Chat copy-paste. Paste the document (or a passage) into a conversation, get a rewrite back, paste it into the file. The diff is gone, authorship is gone, granular accept/reject is gone, and the file and the conversation drift apart.
  • Whole-file rewrite. The machine overwrites the file. The writer must diff it by hand to see what happened and has only all-or-nothing control.
  • Inline code completions. Built for short, accept-as-you-type code suggestions in the editor — not for reviewing a machine's substantive revisions to a prose document, where the writer wants to see, weigh, and selectively keep changes.

None of these lets the writer do the thing that matters for a document: review the machine's proposed revision the way they'd review any change — as a diff they can read, accept or reject piece by piece, attribute, and preview rendered.

Crucially, the editor already has best-in-class machinery for exactly this — diff viewing, source-control review, multi-change accept/reject, threaded comments, and a rendered Markdown preview — but none of it is wired up for coediting with a machine. The opportunity is to deliver machine coediting through those surfaces.

1.3 Business Actors / Roles

Role Responsible for (in the business)
Writer (human) Authors and owns a markdown document; decides what changes land in it.
Machine coauthor A capable machine writing assistant that the writer asks to help revise the document; it proposes changes on the writer's behalf and never lands them unilaterally.

1.4 Problem Statement

A writer who wants a machine to help revise a markdown document has no good way to do it while staying in control. They cannot see exactly what the machine changed, cannot keep some changes and reject others, cannot tell who wrote which words, and cannot read a clean rendered result — at least not without leaving their editor and diffing, cherry-picking, and reconciling by hand. The machine's revision arrives as an opaque rewrite rather than a reviewable proposal, so the writer must choose between blind trust and tedious manual reconciliation.

1.5 Pain Points

# Pain Who feels it Cost / frequency today
PP-1 The machine's revision arrives as a rewrite, not a reviewable change — "what did you change?" has no easy answer Writer (human) Every machine revision; manual diffing each time
PP-2 Accepting the machine's help is all-or-nothing — no way to keep some edits and reject others in place Writer (human) Every revision with mixed-quality changes
PP-3 Authorship blurs — after a few rounds nobody can tell which words are the human's and which the machine's Writer (human) Cumulative; erodes trust and review confidence
PP-4 No clean rendered view of the in-progress document with the changes made legible Writer (human) Every time the writer wants to judge the result as prose
PP-5 The machine works opaquely — ask, wait, a blob appears; no sense of progress or ability to stop it Writer (human) Every machine turn

1.6 Targeted Business Outcomes

# Outcome Success metric Baseline → Target Guardrail (must not regress) How / when measured
BO-1 Writers adopt machine coauthoring for real documents because it's reviewable and in-editor A writer completes a full revise → review → keep/reject → read loop without leaving the editor or copy-pasting chat copy-paste / blind rewrite → in-editor reviewable coediting The writer always stays in control of what lands Dogfooding walkthrough
BO-2 Coediting feels like a built-in editor capability, not a separate tool The diff, accept/reject, and preview use surfaces the writer already knows bespoke/foreign UI → native surfaces Full capability (see-change, selective accept, authorship, preview, progress) preserved Dogfooding walkthrough

1.7 Scope (business)

  • In scope: enabling a writer to coedit a markdown document with a machine while 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.
  • 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.

1.8 Assumptions · Constraints · Dependencies

  • 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 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 git-tracked baselines — §6.4). Files outside a repo degrade to the snapshot baseline, so git is not strictly required.

1.9 Business Use Cases

BUC-1 — As a writer, I can see exactly what the machine changed in my document since a point I chose, so that I can judge it instead of trusting blindly.

Scenario: BUC-1 — see what changed
  Given I marked my document as "good" at some earlier moment
  And the machine has since revised it
  When I ask to see what changed
  Then the changes are shown to me as a clear before/after I can read
  • BUC-1 acceptance criteria: the writer sees an accurate before/after of the document against the chosen point.

BUC-2 — As a writer, I can keep or reject the machine's proposed changes one at a time, so that I stay in control of what lands.

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
  • 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-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.

Scenario: BUC-3 — authorship and rendered result
  Given my document has mixed human/machine authorship and recent changes
  When I open its rendered view with annotations on
  Then I see the document rendered, with changes and authorship visibly marked
  And I can turn annotations off to read it clean
  • BUC-3 acceptance criteria: the rendered document shows changes and authorship when annotations are on, renders clean when off.

BUC-4 — As a writer, I can follow the machine's progress while it works and stop it, so that it is never an opaque black box.

Scenario: BUC-4 — visible, stoppable machine work
  Given I asked the machine to revise my document
  When it is working
  Then I can see live progress
  And I can cancel before it finishes

BUC-5 — As a writer, I can leave a remark on a passage of a document I'm coediting and have the machine respond and offer to make the change, so that a comment can become an edit without me leaving the document.

Scenario: BUC-5 — a comment summons a response and an offer to edit
  Given I have invited the machine to coedit this document
  When I leave a comment on a passage
  Then the machine replies to my comment
  And it offers to make the change I described
  And if I accept, its edit arrives as a proposed change I review like any other
  • BUC-5 acceptance criteria: on an invited document a comment elicits a machine reply and an offer; accepting produces a reviewable proposed change (it never edits directly); on a non-invited document nothing is summoned.

BUC-3a (unhappy) — As a writer, when a comment, an attributed span, or a proposed change can no longer be confidently placed after edits, I am shown it as displaced rather than silently moved to the wrong place.


2. Solution Proposal

Build software: a VS Code extension that lets a writer coedit a markdown document with a machine coauthor, delivering the whole loop through the editor's own native review surfaces.

The enabling idea: model the coauthored document as a tiny source control. The point the writer last marked "good" (the baseline checkpoint, set on entering coediting and re-pinnable) is the source-control original; the live document is the working tree; the machine's proposed edits are pending changes. Once the relationship is framed as source control, the editor's own machinery supplies the experience the writer needs — and it is machinery they 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)
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

Coediting is something a document opts into. A writer turns a document into a coedited document with one command — "Coedit this Document with Claude" — and only then do the surfaces above attach to it: the SourceControl/QuickDiff entry, the auto-responding comments, the annotation toggle, and the machine-edit entry points. The extension registers its providers once but scopes every surface to the active coediting set (INV-10), so it never hijacks Comments, Source Control, or the preview for the writer's other markdown files. This gate is what makes the auto-responding-comments behavior safe: a comment only summons the machine on a document the writer has explicitly invited it into.

Why this approach over the alternatives. Doing nothing leaves writers in the copy-paste-from-chat world (§1.2), which structurally cannot offer a diff, selective accept, or authorship. Building a bespoke coediting UI (custom panels, hand-rolled diff rendering, overlay decorations) can imitate these surfaces but won't inherit the platform's behavior — theming, scroll-sync, accessibility, the keyboard model, navigation, cooperation with other extensions — so it pays the cost 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).

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).

Solution scope. In: the architecture, surface mapping, data model, contracts, and per-use-case design for native, in-editor human↔machine markdown coediting, including baseline pinning, authorship attribution, durable git-native persistence, live machine progress, region threads, and on-behalf-of identity. Out: product packaging/release, multi-file orchestration, non-markdown formats. Non-goal: mutating the writer's document without explicit acceptance.


3. Product Personas

Product persona In the plugin Maps to business role(s)
PP-1 Writer Pins a baseline, asks the machine to revise the document (or a selection), reviews proposed changes in the diff, reads the annotated preview, opens region threads, watches/stops the machine. Writer (human)
PP-2 Machine coauthor Runs a turn locally, streams progress, and emits proposed edits (never lands them); authored spans carry its provenance. Machine coauthor

4. Product Use Cases

Scenario: PUC-1 — see the diff against the baseline checkpoint (realizes BUC-1)
  Given I am coediting a document (its baseline is the last commit if it's in git, else a snapshot taken on entry)
  When I (or the machine) change the document
  Then the source-control gutter shows change bars for what changed since the checkpoint
  And "Open Changes" opens the native diff editor (baseline ⟷ live), inline or side-by-side at my choice
  And committing the file (when it's in a git repo) advances the baseline to the new commit (the diff goes clean)
  And running "Pin Review Baseline to Now" resets the checkpoint to the current content (works anywhere, incl. ~/Downloads and untitled)
Scenario: PUC-2 — keep/reject the machine's proposed changes (realizes BUC-2)
  Given I ask the machine to revise the document (or a selection)
  When the turn completes
  Then the proposed changes open in a multi-diff review (baseline ⟷ proposed)
  And the proposed side is editable, so I can tweak the machine's wording before keeping it
  And each change offers Keep / Undo (Accept / Reject)
  And toolbar actions offer Keep all / Reject all
  And my document is unchanged until I keep a change
  And on keep, the machine's words are attributed to the machine and my tweaks to me
Scenario: PUC-3 — read the annotated rendered preview (realizes BUC-3)
  Given my document has changes and mixed authorship
  When I open the built-in Markdown preview with annotations enabled
  Then insert/delete marks and authorship colors render inside the native preview
  And toggling annotations off renders the document clean
Scenario: PUC-4 — region thread (realizes BUC-3a)
  Given I select a passage and add a coauthoring thread
  When I edit around it or reopen the document
  Then the thread re-anchors; if it cannot be confidently placed it is shown displaced, never silently moved
Scenario: PUC-5 — live machine progress (realizes BUC-4)
  Given I started a machine turn
  When the machine is working
  Then a notification shows the live activity line and token count
  And an OutputChannel streams the full text
  And I can cancel the turn
Scenario: PUC-6 — reopen / external change (realizes BUC-3a)
  Given I reopen the workspace or an external change lands (a git pull)
  When the document loads
  Then baseline, proposed changes, attributions, and threads re-resolve against current text
  And anything that cannot be confidently placed is shown displaced
Scenario: PUC-7 — enter (and leave) coediting mode (realizes INV-10)
  Given an ordinary markdown document
  When I run "Coedit this Document with Claude" (command, editor title, or context menu)
  Then this document gains the Cowriting source-control entry, the annotation toggle, and machine-edit/comment-response behavior
  And the baseline is established — the last commit if the file is in git, otherwise a snapshot of the current content
  And my other markdown documents are unaffected
  And running "Stop editing with Claude" (context menu) removes those surfaces (the saved sidecar is kept for next time)
Scenario: PUC-8 — comment summons a machine reply + offer to edit (realizes BUC-5)
  Given I am coediting this document
  When I add a comment on a passage (native Comments gutter)
  Then a machine turn runs (with live progress, PUC-5) and replies in the thread
  And it offers to make the change; accepting opens its edit as a pending proposed change (PUC-2)
  And on a document I am not coediting, adding a comment summons nothing

5. UX Layout

The experience is delivered through native VS Code surfaces; there is no bespoke panel to wireframe. Described in text (source of truth):

  • Entering coediting. A "Coedit this Document with Claude" command (command palette, editor title menu, and editor/explorer context menu, markdown-gated) turns the active document into a coedited document; a "Stop editing with Claude" command — in the same command palette and the editor/explorer context menu — reverses it. A subtle status-bar item ("✦ Coediting") indicates when the active document is in coediting mode. Until a document is entered, none of the surfaces below attach to it (INV-10). Entering also sets the baseline to the document's current content — a clean checkpoint to measure future changes against (INV-7).
  • Source Control gutter & viewlet. A dedicated source-control entry, "Cowriting," coexists with Git. Its quick-diff provider draws the familiar change bars in the editor gutter against the pinned baseline; its resource group lists the document's pending coauthoring changes; "Open Changes" uses the native diff editor.
  • 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.
  • 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 and offers an edit (BUC-5 / PUC-8); the offer, when accepted, becomes a pending proposed change reviewed in the multi-diff.
  • Notification + OutputChannel. Live machine progress, with a Cancel action.

5.1 Design tooling decision

  • Decision: Code directly.
  • Rationale: the experience is delivered through native VS Code chrome, so there is no net-new bespoke visual surface to explore. Scoring the six-question rubric: Q1 1 (no net-new surface — native editor chrome), Q2 1 (UI specified at wireframe-level prose against known platform surfaces), Q3 1 (no multi-page visual language), Q4 1 (the editor is the design system here), Q5 1 (solo build), Q6 1 (logic-dominant — wiring cores to platform APIs). Total 6 → Skip Design. The only "designed" pixels are the preview annotation stylesheet (a small CSS theme using the editor's theme variables), which does not warrant Design.
  • Design: N/A — no bespoke UI surface (native VS Code surfaces only).

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 coauthoring displaced state surfaced in the thread / proposed-change listing.

6. Technical Design

6.1 Invariants

  • INV-1 — never silently moved: an anchored artifact (thread, attributed span, proposed change) that cannot be confidently re-resolved becomes displaced (visible, flagged), never relocated to a wrong span.
  • INV-2 — git-native and serverless: durable coauthoring data is diffable, human-resolvable JSON committed alongside the document; no server, no external store. (The baseline is the exception — a throwaway local artifact kept outside the repo, INV-7.)
  • INV-3 — native-first: the diff, accept/reject, and rendered-preview surfaces are delivered by native VS Code APIs, not bespoke webviews or decoration overlays. New custom rendering requires an explicit, recorded justification (§6.7) that no native surface fits.
  • INV-4 — forward-compatible & portable: the persisted artifact carries a schemaVersion; anchors, provenance, attributions, proposals, and 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-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 without touching the logic.
  • INV-7 — baseline is the last settled version; its source follows the file's home: the baseline is the diff original — the last "settled" version. Where the file is tracked in a git repo, the baseline is the file at HEAD (the last commit) and resets automatically when a commit is made — the diff is the file's uncommitted work, git-native and storage-free. Where there is no commit to anchor to (outside any repo, untracked/ignored, brand-new, or untitled), the baseline is a snapshot defaulted to the current content on entry and reset by "Pin Review Baseline to Now," stored in extension global storage keyed by URI hash (in-memory for untitled). A manual pin is available in both homes as a finer checkpoint (in a git file it sits ahead of HEAD until the next commit supersedes it); a new in-repo file flips from snapshot to HEAD-tracking on its first commit. A coedited document therefore always has a baseline — there is no "missing baseline" state; the only empty state is a genuinely empty document. The baseline is disposable review state, never committed by us.
  • INV-8 — provenance carries on-behalf-of identity: every authored span / message records provenance (the human's git identity, or the machine acting onBehalfOf a human), reused across attributions, proposed changes, and threads.
  • INV-9 — machine turns are observable and cancellable: a turn streams progress and honors an AbortSignal; the progress reducer is pure.
  • INV-10 — coediting is opt-in per document: every coauthoring surface (the "Cowriting" SourceControl + QuickDiff, auto-responding comments, preview annotations, the machine-edit entry points) activates only for a document the writer has explicitly entered into coediting mode ("Coedit this Document with Claude"). The extension registers its providers globally but gates every surface on membership in the active coediting set, so it never hijacks Comments/SCM/preview for documents the writer did not opt in. Exiting coediting (or closing the workspace) removes the document from the set; the durable sidecar 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.
  • INV-12 — proposed changes are editable before they are kept: the review surface presents the machine's proposal on a writable side, so the writer can tweak it in place before keeping it (the common "close, but a few human edits" case). The live document stays untouched until Keep (INV-5 still holds); on Keep, the words the machine proposed are attributed to the machine and the writer's tweaks to the writer — so authorship is correct at the moment the change is made, never reconstructed afterward. Editing happens at review time; once kept, the text is just text (no lingering "trapped proposal" state to untangle).

6.2 High-level architecture

Pure, vscode-free cores + thin controllers that wire those cores to native surfaces.

flowchart LR
  subgraph Cores["Pure cores (vscode-free, unit-tested)"]
    AT[Attribution tracker<br/>char-precise spans]
    AN[Anchorer<br/>fingerprint + offsets + displaced]
    MG[mergeArtifacts<br/>union-by-id, unknown-field-safe]
    DF[Diff/hunk engine<br/>word- & block-level]
    TP[turnProgress<br/>reducer]
    RA[renderAnnotations<br/>markdown-it transform]
  end
  subgraph Ctrls["Thin controllers (vscode-aware)"]
    SC[SourceControl + QuickDiffProvider]
    BP[Baseline provider<br/>TextDocumentContentProvider]
    PR[Review controller<br/>multi-diff Keep/Undo]
    PV[Preview extension<br/>extendMarkdownIt]
    TC[ThreadController<br/>Comments API]
    LP[liveProgress relay]
    ST[Sidecar router + store]
  end
  subgraph Native["Native VS Code surfaces"]
    GUT[Gutter dirty-diff + SCM viewlet]
    DIFF[Native diff editor]
    MDIFF[Multi-diff review + Keep/Undo]
    MDPREV[Built-in Markdown preview]
    COMM[Comments gutter/peek]
    NOTE[Notification + OutputChannel]
  end
  SDK[[Machine-coauthor runtime<br/>dynamic import]]

  AN --> SC --> GUT
  BP --> DIFF
  DF --> PR --> MDIFF
  AT --> RA --> PV --> MDPREV
  AN --> TC --> COMM
  TP --> LP --> NOTE
  SDK --> PR
  Cores --- ST
  Ctrls --- ST
  • SourceControl + QuickDiffProvider — owns the "Cowriting" source control and the gutter dirty-diff; must never write to the document.
  • 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.
  • 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 document is in a workspace, a global-storage sidecar keyed by URI hash otherwise.

6.3 Data model & ownership

Entity Owned by Key fields System of record
Coauthoring sidecar the extension (sole writer) schemaVersion, document.path, anchors{}, provenance, attributions[], proposals[], threads[], unknown-field passthrough git-committed .threads/<path>.json (in-workspace) or global-storage sidecar (out-of-workspace)
Baseline (checkpoint) the extension git-tracked → resolved from HEAD (no storage); else → snapshot {text, reason, time} keyed by URI hash git object store (HEAD) or out-of-repo global storage (snapshot); never committed by us (INV-7)
Provenance the extension kind (human/machine), id, email, onBehalfOf, agent{runtime,model,sessionId} embedded in sidecar (INV-8)

The sidecar envelope is forward-compatible and portable (INV-4): additive, unknown-field-preserving, so it round-trips to an outer review forge unchanged. The baseline is deliberately not in this envelope: it is local, disposable review state (INV-7), not durable coauthoring metadata.

// .threads/docs/spec.md.json — the coauthoring envelope (INV-4)
{
  "schemaVersion": 1,
  "document": { "path": "docs/spec.md" },
  "anchors":      { "a1": { "fingerprint": { "text": "…", "before": "…", "after": "…", "lineHint": 42 } } },
  "attributions": [ { "anchorId": "a1", "provenance": <Provenance>, "span": { "start": 0, "end": 12 } } ],
  "proposals":    [ { "id": "p1", "anchorId": "a1", "status": "pending",   // pending|accepted|rejected (INV-5)
                      "granularity": "block",        // word|block — the decision unit
                      "provenance": <Provenance>, "before": "…", "after": "…" } ],
  "threads":      [ { "id": "t1", "anchorId": "a1", "status": "open", "messages": [  ] } ]
  // unknown top-level fields preserved verbatim (INV-4)
}

6.4 Interfaces & contracts

  • Baseline router + provider — a TextDocumentContentProvider for cowriting-baseline: whose provideTextDocumentContent(uri) resolves the original by the file's home (INV-7): git-tracked → the HEAD blob (read via the built-in Git extension API; auto-advances on commit, watched via repository.state.onDidChange); otherwise → a stored snapshot (BaselineStore.snapshot(docUri, text, reason) / get(docUri)), set on enterCoediting (reason entered) and on "Pin Review Baseline to Now" (reason pinned). A pin in a git-tracked file records a snapshot that takes precedence over HEAD until the next commit supersedes it (baseline = most-recent settle). This mirrors the in-repo/out-of-repo SidecarRouter (§6.2). A coedited document always resolves a baseline; non-coedited documents resolve none.
  • QuickDiffProviderprovideOriginalResource(docUri) → cowriting-baseline: URI (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 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 controlleropenReview(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).
  • Preview extensionextendMarkdownIt(md) → md.use(cowritingPlugin); the plugin invokes the pure renderAnnotations(tokens, attributions, proposals, options) transform, gated by the cowriting.annotations setting/command.
  • Turn runnerrunEditTurn(prompt, { onProgress, signal, env }) → AgentResult; pure turnProgress reducer; liveProgress relay to a notification
    • OutputChannel; Cancel → abort(). The machine runtime is loaded via runtime dynamic import() (it is ESM and must not be bundled), and spawned with IDE auto-connect disabled so it never triggers an OS automation-permission prompt.
  • CoeditingRegistry (the activation gate, INV-10) — enter(docUri) / exit(docUri) / isCoediting(docUri) → boolean / onDidChange. Holds the active coediting set (persisted across reloads). Every controller above checks 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 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 machine Comment carrying onBehalfOf provenance (INV-8).

6.5 PerProduct-Use-Case design

PUC-1 — see the diff against the baseline checkpoint

sequenceDiagram
  actor U as Writer
  participant C as SCM/QuickDiff ctrl
  participant B as Baseline provider
  participant V as Native diff editor
  U->>C: Pin baseline
  C->>B: BaselineStore.pin(docUri, text)
  U->>U: edits document (or the machine proposes)
  C-->>U: gutter dirty-diff bars (provideOriginalResource)
  U->>V: Open Changes
  V->>B: read cowriting-baseline:docUri
  V-->>U: native diff (baseline ⟷ live)
  • Implementation: the QuickDiffProvider points at the cowriting-baseline: URI; the platform renders gutter bars and powers "Open Changes" / vscode.diff. No custom diff rendering. Honors INV-3, INV-7.

PUC-2 — keep/reject the machine's proposed changes

sequenceDiagram
  actor U as Writer
  participant R as Review ctrl
  participant S as Machine runtime
  participant M as Multi-diff editor
  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
  • 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.

PUC-3 — annotated rendered preview

sequenceDiagram
  actor U as Writer
  participant P as Built-in MD preview
  participant E as Preview extension (extendMarkdownIt)
  participant T as renderAnnotations (pure)
  U->>P: Open Preview (annotations on)
  P->>E: render document tokens
  E->>T: transform(tokens, attributions, proposals)
  T-->>E: tokens w/ authorship + change marks
  E-->>P: annotated HTML (preview stylesheet)
  P-->>U: native preview, annotated
  • Implementation: a contributed markdown-it plugin runs the pure renderAnnotations transform and a small preview stylesheet using the editor's theme variables. Toggle via cowriting.annotations. No webview. Authorship coloring + insert/delete marks are shown for changes since the baseline checkpoint; a freshly entered or freshly pinned, zero-diff document renders clean.

PUC-4 / PUC-6 — threads & re-anchoring

  • Implementation: ThreadController + Anchorer, gated on isCoediting(docUri) (INV-10). On load / external change (FileSystemWatcher), every anchor re-resolves (exact-unique → context-disambiguated → displaced, INV-1). Proposed changes and attributions ride the same anchors primitive, so they re-anchor and displace by the same ladder.

PUC-7 — enter / leave coediting

  • Implementation: cowriting.enterCoediting(docUri) adds the URI to the CoeditingRegistry's active set and persists it; cowriting.exitCoediting removes it (the sidecar is kept). The registry fires onDidChange; controllers (QuickDiff, comment-response, annotations, edit commands) attach/detach and the cowriting.isCoediting context key flips so menu when clauses show/hide. Commands are markdown-gated. No surface exists for a document until it is entered.

PUC-8 — comment summons a machine reply + offer

sequenceDiagram
  actor U as Writer
  participant T as ThreadController
  participant G as CoeditingRegistry
  participant S as Machine runtime
  participant R as Review ctrl
  U->>T: add comment on a passage
  T->>G: isCoediting(docUri)?
  G-->>T: yes
  T->>S: runEditTurn(comment + context, {onProgress, signal})
  S-->>T: reply text (+ optional edit)
  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)
  • Implementation: gated on isCoediting (INV-10) — inert otherwise. The turn runs with live progress (PUC-5). The reply is a machine Comment; an accepted offer never edits the document directly, only proposes (INV-5). While the document is in coediting mode, every new comment fires a turn (D10) — the opt-in mode is the control, so there is no per-comment gate; "Stop editing with Claude" is the off switch.

PUC-5 — live machine progress

  • Implementation: pure turnProgress reducer; runEditTurn onProgress/AbortSignal; liveProgress relay to a notification activity-line + token count + an OutputChannel; Cancel → abort(). The machine runtime is spawned with IDE auto-connect disabled so it never triggers an OS automation prompt.

6.6 Non-functional requirements & cross-cutting concerns

  • Security & privacy: serverless; no secret bytes in sidecars or transcripts. The machine runs locally; provenance records identity, not credentials. The runtime is spawned with IDE auto-connect disabled (no spurious OS automation-permission prompt).
  • Performance & scale: anchor resolution is O(document) text search per anchor on load/change — fine for human-scale documents; skip non-text/oversized files. Native diff/preview rendering is the platform's, not ours.
  • Availability & resilience: no service; the worst case is a displaced anchor (handled, INV-1); a baseline always exists once coediting is entered (INV-7), so there is no missing-baseline path.
  • 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. This is a primary reason for the native-first choice.

6.7 Key decisions & alternatives considered

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)
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
Coediting activation opt-in per document via "Coedit this Document with Claude"; every surface gated on the active coediting set (INV-10) always-on for all markdown; opt-in per workspace/folder Per-document opt-in is the only grain that avoids hijacking Comments/SCM/preview for the writer's other files while keeping single-file precision
Authorship in the diff the native diff is author-blind (what changed); authorship is shown in the preview, optionally a decoration track-changes editor (INV-11) recolor machine changes inside the native diff editor Not possible: diffEditor.* colors are global theme tokens with no per-author scoping; inlineEdit.*/chat tokens differentiate accept-state not author; decorations over the diff pane composite over green/red and are unreliable (vanish on tab-switch). Verified against the VS Code API (§13-Q5)
Comment → machine response on a coedited doc, a comment fires a turn that replies + offers an edit → pending proposal comment is inert (human-only threads) Turns the familiar review-comment gesture into a coediting action without a new surface; the opt-in gate (INV-10) keeps it from firing on other docs
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)

6.8 Testing strategy

  • Unit (vitest, vscode-free): the pure cores — attribution spans, anchoring (fingerprint/resolve/displaced/offset shift), mergeArtifacts (union-by-id, unknown-field preservation), the diff engine (wordEditHunks / diffToBlockHunks), the turnProgress reducer, and the renderAnnotations markdown-it transform (token-in → annotated-token-out).
  • Integration / E2E (@vscode/test-electron): drive the controllers in the Extension Development Host — pin baseline → assert QuickDiff original; ask-to-edit → assert pending proposals + multi-diff opened; Keep/Undo → assert document mutation only on Keep + authorship recorded; 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 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).
  • 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 thread→reanchor→displaced; PUC-5 progress→cancel.

6.9 Failure modes, rollback & flags

  • Displaced anchor (INV-1) → shown displaced at last-known lineHint, never moved → auto-re-anchors if the text reappears → no alert (local).
  • Empty document (genuinely no content) → the only true empty state → a gentle "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.
  • 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.

  • 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).

7. Delivery Plan

7.1 Approach / strategy

This is a design-only north star: it produces no implementation plan and ships no code. When the operator decides to act on it, the build order follows the surface mapping — stand up the pure cores, then the diff surface (smallest, highest-confidence native win), then the preview extension, then the multi-diff accept/reject (largest API-boundary risk — do it last, with the CodeLens fallback ready). Each delivered increment is one SPEC → one plan → one execution once decomposed.

7.2 Rollout / launch plan

A VS Code extension has no §9 webapp deploy pipeline (localhost/PPE/prod) — it is not a webapp. "Done" for a delivered increment = acceptance met (§1.9) + unit and host E2E green (§6.8). Marketplace packaging/release is out of scope here.

7.3 Risks & mitigations

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)
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

8. Success Metrics & Measurement

8.1 Business success metrics

Outcome Measured by (source) Baseline captured how Owner Review cadence
BO-1 (adoption for real docs) Dogfooding: complete revise→review→keep/reject→preview without leaving the editor or copy-pasting The copy-paste-from-chat flow as the before Ben At first build
BO-2 (feels built-in) The diff, accept/reject, and preview use surfaces the writer already knows Bespoke-UI alternatives as the before Ben At first build

8.2 Product success metrics

# 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-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

A local VS Code extension — no telemetry service, no server monitoring. The user-facing turn log is the OutputChannel (PUC-5). Deliberately omitted: events pipeline, dashboards, alerts, SLOs (nothing is operated as a service). N/A — TEL/SLO/ALR rows are not applicable to a serverless local extension.

10. Operations

10.1 Operational plan

N/A — a local VS Code extension has no day-to-day operator; the "operator" is the developer running it. No on-call, no service runbooks. Routine maintenance is dependency patching (§10.3).

10.2 Support & incident response

Pre-v1; issues are filed on the project tracker and triaged in a session. One line: a bug reaches us as a tracker issue.

10.3 Maintenance & lifecycle

  • Dependency patching: the machine-coauthor runtime and dev deps via the normal tracker flow.
  • Backup / restore: N/A — sidecars are git-committed; the baseline is disposable.
  • Capacity & cost: local; the only cost is the machine's token usage, surfaced live (PUC-5).
  • Deprecation / sunset: this design is superseded only by a later architecture spec.

11. Documentation plan

  • Where docs live: spec + dev docs → framework repo; this Solution Design → content repo specs/; no public-facing site in scope.
# Document Audience Location New / updated
DOC-1 This Solution Design dev/operator content repo specs/coauthoring-native-surfaces.md new
DOC-2 README "how coediting maps to native editor surfaces" dev/user framework repo README new (at delivery)

12. Traceability matrix

Pain Business UC Product UC Tests Measured by
PP-1 BUC-1 PUC-1 host E2E: pin→QuickDiff→native diff PM-1 / BO-1
PP-2 BUC-2 PUC-2 host E2E: propose→review→keep/undo→keep-all PM-2 / BO-1
PP-3, PP-4 BUC-3 PUC-3 unit (renderAnnotations) + host E2E: annotate toggle PM-3 / BO-1
PP-5 BUC-4 PUC-5 host E2E: progress→cancel BO-1
(displacement) BUC-3a PUC-4/6 unit (anchorer) + host E2E: reanchor→displaced PM-1
PP-1 (comment→edit) BUC-5 PUC-8 host E2E: comment→reply→offer→pending proposal BO-1
(no hijack) PUC-7 host E2E: enter/exit gates every surface; non-coedited doc inert BO-2

13. Open Questions & Decisions log

Open

# 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)
Q3 One "Cowriting" SourceControl vs. QuickDiff-only (no full SCM viewlet entry) — how much SCM presence is wanted Ben PUC-1 build
Q4 Does any need genuinely require a webview the native surfaces can't serve (INV-3 escape hatch)? Ben Per-surface build
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
Q8 In a git-tracked file, may a manual pin checkpoint ahead of HEAD (finer than commits), or is committing the only reset for git files? (Spec currently: pin allowed everywhere, superseded by the next commit.) Ben PUC-1 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
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
D6 Design tooling Code directly (rubric 6); no bespoke UI surface 2026-06-27
D7 Coediting is opt-in per document A document enters coediting via "Coedit this Document with Claude"; every surface gates on the active coediting set (INV-10), so other markdown files are never hijacked 2026-06-27
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
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 + re-pinnable (global storage / in-memory). A manual pin works in both; a coedited doc always has a baseline; the only empty state is a genuinely empty document (INV-7) 2026-06-27

14. Glossary & References

  • Baseline (checkpoint) — the last settled version, used as the diff original. Its source follows the file's home: git HEAD for tracked files (resets on commit), else a snapshot set on entry and reset by "Pin Review Baseline to Now." 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).
  • 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.
  • Provenance — the author envelope (the human's git identity, or the machine acting on-behalf-of a human) reused across attributions, proposed changes, and threads (INV-8).
  • Displaced — an anchor that could not be confidently re-resolved; shown, never silently moved (INV-1).
  • Decision unit vs attribution unit — a block (paragraph/header/list-item/fence) is what the writer keeps or rejects; the word diff inside it is what carries authorship.
  • 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 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).