From 36bc4e3d00d5ab112664068561c87dd24bf9df3e Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Thu, 11 Jun 2026 06:58:02 -0700 Subject: [PATCH] add spec ./specs/coauthoring-diff-view.md (status: graduated) --- specs/coauthoring-diff-view.md | 483 +++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 specs/coauthoring-diff-view.md diff --git a/specs/coauthoring-diff-view.md b/specs/coauthoring-diff-view.md new file mode 100644 index 0000000..82b18e9 --- /dev/null +++ b/specs/coauthoring-diff-view.md @@ -0,0 +1,483 @@ +--- +status: graduated +--- +# Solution Design: Diff-View Toggle (F6) + +| | | +| --- | --- | +| **Author(s)** | Ben Stull (with Claude) | +| **Reviewers / approvers** | Ben Stull | +| **Status** | `draft` | +| **Version** | v0.1.0 | +| **Source artifacts** | Feature `benstull/vscode-cowriting-plugin#17` (F6) · Epic `#1` (closed — F6 is the first post-epic UX feature) · Parent specs: `vscode-cowriting-plugin-content/specs/coauthoring-inner-loop.md`, `specs/coauthoring-attribution.md`, `specs/coauthoring-propose-accept.md`, `specs/coauthoring-cross-rung-format.md` + `specs/coauthoring-sidecar-contract.md` (all graduated) · F5 shipped: `#14` (PR #15, session 0015) · Lineage: `ben.stull/rfc-app#48` | + +**Change log** + +| Date | Version | Change | By | +| --- | --- | --- | --- | +| 2026-06-11 | v0.1.0 | Initial draft — brainstorming session 0017 | Ben Stull + Claude | + +--- + +## 1. Business Context + +### 1.1 Executive Summary + +F6 gives the human coauthor the review surface the machine already has. F4 +made every machine change reviewable-before-landing (proposal diffs); F3 +paints who owns the current text; but the operator's **own** contribution is +visible only as final text. F6 adds a one-gesture **diff-view toggle**: flip +the editor into a diff of the document against a **coauthoring baseline** — +and back — so "what did I actually change?" is answered in one keystroke +instead of git archaeology. The load-bearing design move is the baseline +itself: it **advances automatically at every machine landing** (every +successful `applyAgentEdit` seam application — the only way machine text ever +enters the document, INV-9/INV-10), so everything the diff shows is +operator-authored *by construction*. A single **pin** gesture gives the +operator an arbitrary epoch when they want one. The baseline lives in +extension workspace storage — never in the repo — so the sidecar, the +cross-rung contract (INV-14..17), and `SCHEMA_VERSION` are untouched. + +### 1.2 Background + +The inner-loop triad shipped across F2–F4 (threads · attribution · +propose/accept) and F5 made its sidecar a cross-rung contract. Review parity +is now asymmetric in the human's favor toward the *machine's* changes: +machine edits arrive as anchored diffs (F4) and land tinted (F3), while the +operator's own work between machine landings has no diff perspective at all. +Git's diff is against HEAD — the wrong baseline mid-session, where the +meaningful "before" is a coauthoring moment (a machine landing, a chosen +instant), not the last commit. Issue #17 parked the design forks — +**baseline choice** (the load-bearing one), snapshot home, whose-changes, +and the relationship to git's own features — for this session; all are +resolved here (§6.7, §9). + +### 1.3 Business Actors / Roles + +- **Coauthor (human)** — the writer/engineer (PP-1); F6's sole user: the + diff view exists to make their own contribution self-reviewable. +- **Coauthor (machine)** — Claude via `@cline/sdk`; not a user of F6, but + its landings define the default baseline epoch. + +### 1.4 Problem Statement + +While coauthoring, the operator cannot see their own changes as a diff. The +editor shows ownership of current text (F3) and machine intent before it +lands (F4), but the human's contribution since the last meaningful +coauthoring moment is only visible as final prose. The only diff available +— git's — is anchored to the wrong moment (HEAD). + +### 1.5 Pain Points + +- "What did I actually change?" requires git archaeology or memory. +- Self-review during coauthoring is expensive exactly where machine-review + is cheap — an inverted trust asymmetry. +- No way to mark "I'm about to do a risky pass — let me review it as a diff + afterwards" (no operator-chosen baseline moment). + +### 1.6 Targeted Business Outcomes + +One gesture flips the active document into a diff of the operator's own +changes against a coauthoring-meaningful baseline; the same gesture flips +back; nothing about the document, sidecar, or editor state is disturbed. +Self-review during coauthoring becomes as cheap as accepting a proposal. + +### 1.7 Scope (business) + +**In scope:** the baseline lifecycle (initialize at first track, advance at +machine landings, pin on demand); persistence of the baseline across window +reloads (extension workspace storage); the toggle command + keybinding; a +native `vscode.diff` view (readonly baseline left, the **live document** +right — editing continues inside the diff view); test-facing surface; host +E2E + unit coverage; manual smoke. + +**Out of scope (deferred, not forgotten):** baseline **splicing** (keeping +pre-accept operator edits visible across a baseline advance — §6.7, §9); +multiple named/selectable baselines; any cross-rung sharing of baselines; +diffing against arbitrary git refs; changed-line gutter indicators in the +normal (non-diff) editor view. + +**Non-goals (firm, from #17):** replacing git history; a general-purpose +diff tool; changing how proposals render (F4 owns machine diffs). + +### 1.8 Assumptions · Constraints · Dependencies + +- **Anchor:** Feature #17. Builds on the shipped inner loop (F2 `#4` · F3 + `#6` · F4 `#12` · F5 `#14`); Epic #1 is closed. +- The whole design leans on two shipped invariants: **INV-9** (the seam + `applyAgentEdit` is the single machine-edit ingress) and **INV-10** + (proposals never mutate the document) — together: *between machine + landings, every buffer change is operator-authored.* +- F3 attribution is **state, not history** (cannot reconstruct before-text) + — confirmed: F6 needs a snapshot, and takes one; it does not consume + attribution records at all. +- Nothing persisted touches `.threads/`: the cross-rung contract + (INV-14..17) and `SCHEMA_VERSION = 1` are untouched by construction + (INV-19). +- No new credential surface (INV-8 untouched); no LLM anywhere in F6 or its + tests. + +### 1.9 Business Use Cases + +- **BUC-1 (self-review)** Mid-session, the operator flips into the diff + view and sees exactly what *they* changed since Claude last landed text — + then flips back and keeps writing. +- **BUC-2 (deliberate pass)** Before a risky rewrite pass, the operator + pins the baseline; afterwards they review their whole pass as one diff. + +--- + +## 2. Solution Proposal + +Keep one **baseline snapshot** per tracked document: the full document text +captured at an epoch. The epoch is initialized when the document is first +tracked, **advances automatically on every successful seam application** +(`applyAgentEdit` — the moment machine text lands), and can be **pinned to +now** by the operator. Because the seam is the only machine ingress +(INV-9/10), the diff `baseline → current buffer` shows operator-authored +changes by construction (INV-18) — no attribution filtering needed. A +`cowriting.toggleDiffView` command (with default keybinding) opens a native +`vscode.diff` editor: left side a readonly virtual document +(`cowriting-baseline:` scheme) serving the baseline text, right side **the +live document itself** — so the operator keeps editing inside the diff +view, and toggling back simply closes the diff tab. Baselines persist in +**extension workspace storage** via a vscode-free `BaselineStore` (the +`CoauthorStore` pattern), surviving window reloads without ever entering +the repo (INV-19). The machine-landing signal is one additive event on the +seam owner: `AttributionController.onDidApplyAgentEdit`. + +--- + +## 3. Product Personas + +- **PP-1 Inner-loop coauthor** — the human writer/engineer (as F2–F5); the + only persona F6 serves. + +## 4. Product Use Cases + +- **PUC-1 (toggle)** In a tracked document, run the toggle (command or + keybinding) → a diff view opens: baseline left, live document right. Run + it again → the diff closes and the normal editor is back. The document + text, sidecar, threads, attributions, and proposals are untouched either + way. +- **PUC-2 (epoch follows the machine)** Accept a pending proposal → the + baseline advances past it: the accepted text does **not** appear as a + change in the diff; the operator's subsequent edits do. +- **PUC-3 (pin)** Run "pin diff baseline" → the diff goes empty (baseline = + now); everything the operator changes from here shows against the pin. +- **PUC-4 (survive reload)** Reload the window mid-session → the baseline + (and therefore the diff) is the same as before the reload. +- **PUC-5 (graceful edges)** An untracked document refuses the toggle with + a warning; a missing/ancient baseline is visible in the diff title + (epoch + when) and one pin gesture recovers; external file changes (e.g. + a git pull) show up as changes — pin recovers there too. + +## 5. UX Layout + +No bespoke UI surface — native VS Code primitives only (the F2–F5 +Claude-Code-rubric precedent). The diff view **is** VS Code's diff editor: +readonly baseline on the left, the live, editable document on the right; +all existing decorations and comment threads keep working on the right side +because it is the same `TextDocument`. The diff tab title carries the epoch +story: ` — my changes since ` where epoch reads `opened +