12 Commits

Author SHA1 Message Date
BenStullsBets 9f0d896ea9 spec(0062): staged delivery (§7.1) + companion feasibility spike plan
§7.1 now records the 4 de-risking rungs (mockups → throwaway feasibility
spike → vertical slice → full build), riskiest-API-assumption-first, so any
forced design change lands on throwaway code. Adds coauthoring-feasibility-
spike.md: 5 experiments (E1 editable proposals+Keep/Undo, E2 baseline router,
E3 preview authorship, E4 comment loop, E5 discoverability) with PASS/FAIL
criteria; closes open Q2/Q4/Q7 before any plan is written.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 08:07:00 -07:00
BenStullsBets 7d842a840e spec(0062): no flow requires the Source Control pane — title bar + status bar are primary (D16/INV-13)
Non-git writers (~/Downloads, untitled) won't know to open Source Control.
So: editor title-bar actions (Review Changes / Ask Claude / Toggle
Annotations / Mark Changes as Reviewed) + '✦ Coediting · N changes'
status-bar item (click -> review) + auto-open review on proposals are the
primary entry points; SCM viewlet + gutter become optional git-user extras.
Resolves Q3. Updated INV-13, §5 UX, PUC-1/2, decisions; also removed the
stale open Q8 (resolved by D14).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:47:51 -07:00
BenStullsBets 92df8c551f spec(0062): comment from the preview (native thread on source) + whole-document comment (D15)
Verified the Comments API can't render in the markdown preview (webview).
So: preview *initiates* a comment (selection -> source range via markdown-it
token source map) and shows a deep-linking marker, but the thread renders
natively in the gutter/Comments panel; no bespoke in-webview comment UI
(keeps INV-3). Whole-document comment anchors at line 0 -> full-document
context for the machine. Updated PUC-4/8, UX, ThreadController contract,
decisions; D15.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:40:35 -07:00
BenStullsBets 1d27b74a2b spec(0062): rename pin command to 'Mark Changes as Reviewed'
Replaces the jargon 'Pin Review Baseline to Now' (snapshot-mode reset) with
the user-intent label 'Mark Changes as Reviewed', which fits the review
framing of the product. Label-only; semantics unchanged (snapshot-mode only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:23:02 -07:00
BenStullsBets 22393f0d63 spec(0062): pin only in snapshot mode (resolve Q8/D14); pre-session changes attributed to writer (INV-8)
- D14: 'Pin Review Baseline to Now' exists only in snapshot mode (no committed
  HEAD); git-tracked files have no manual pin -> commit is the reset; pin
  command when-gated on cowriting.baselineMode==snapshot. Removed open Q8.
- INV-8: changes already present at coediting start (uncommitted vs HEAD,
  incl. edits made outside this experience) are attributed to the writer
  (human) -- session can't know their origin; surfaces prior work as human.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:21:03 -07:00
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
BenStullsBets 4ccba9ea93 spec(0062): baseline = clean checkpoint set on entry; only empty state is an empty doc (D13)
Entering coediting sets the baseline to current content automatically;
'Pin Review Baseline to Now' resets it ('everything so far is settled; show
changes from here'). A coedited doc always has a baseline -> removed the
'no/missing baseline' empty state entirely; the only empty state is a
genuinely empty document. Updated INV-7, PUC-1/7, baseline provider, preview
(marks since checkpoint), failure modes, flags, glossary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:13:22 -07:00
BenStullsBets 1e54abdd8d spec(0062): resolve Q5 — Option 1 (preview authorship) + editable proposals (INV-12)
Authorship lives in the annotated preview (D11); native diff stays
author-blind. Crucially, the review's proposed side is WRITABLE (INV-12,
D12): the writer tweaks the machine's suggestion before Keep ('close, but a
few human edits'), the live doc is untouched until Keep (INV-5), and on Keep
machine words vs writer tweaks are attributed separately by diffing
final<->machine-original<->baseline. This keeps authorship clean AT CREATION,
so post-hoc in-editor authorship (opts 2/3) is unnecessary and deferred. New
open Q7: per-change Keep/Undo semantics after free cross-hunk editing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:09:58 -07:00
BenStullsBets 81b6891805 spec(0062): resolve Q6 — every comment summons the machine while coediting; 'Stop editing with Claude' context-menu off switch (D10)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:03:37 -07:00
BenStullsBets aaf5fb46eb spec(0062): opt-in coediting mode + comment auto-response; native diff is author-blind (verified)
- INV-10: coediting is opt-in per document ('Coedit this Document with
  Claude'); every surface (SCM/QuickDiff, comments, preview annotations,
  edit entry points) gates on the active coediting set so other markdown
  files are never hijacked. Adds PUC-7 (enter/leave), CoeditingRegistry.
- BUC-5/PUC-8/D8: on a coedited doc a comment fires a turn that replies
  in-thread and offers an edit -> pending proposal (never edits directly).
- INV-11/D9: verified against the VS Code API that the native diff editor
  cannot recolor changes per-author (diffEditor.* tokens are global;
  inlineEdit./chat tokens are accept-state not author; diff-pane decorations
  composite + are unreliable). Authorship lives in the preview (optionally a
  decoration track-changes editor). New open Qs: Q5 (authorship surface),
  Q6 (comment trigger).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 06:55:55 -07:00
BenStullsBets f6a86d6354 spec(0062): reframe around the human problem — coediting markdown with a machine
Reframe §1 away from a redesign-of-the-old-plugin narrative and root it in
the real-world problem: coediting a markdown document with a machine is hard
today (rewrite-not-a-diff, all-or-nothing, blurred authorship, no clean
rendered view, opaque machine work). Solution and technical substance stand on
their own; proven patterns reused on merit, not as old-plugin lineage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 05:57:37 -07:00
BenStullsBets 74df46d078 spec(0062): native-first coauthoring — VS Code-idiomatic redesign (design-only north star)
Solution Design for a brand-new plugin that re-homes the inner-loop
coauthoring experience onto native VS Code surfaces: QuickDiffProvider +
native diff editor (any diff), multi-diff editor Keep/Undo (propose/accept),
built-in Markdown preview markdown-it extension (rendered preview), Comments
API (threads). Carries forward pinned baseline (F6), authorship attribution
(F3), cross-rung sidecar (F5), live progress (#60), on-behalf-of identity, and
the pure-core/thin-controller discipline. Design-only: no repo/migration
commitment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 05:43:22 -07:00
2 changed files with 1180 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
---
status: draft
---
# Feasibility Spike Plan — Coediting Markdown with a Machine (native surfaces)
| | |
| --- | --- |
| **Companion to** | `coauthoring-native-surfaces.md` (Solution Design) — §7.1 rung 2 |
| **Type** | Throwaway discovery **prototype** (handbook §5.3) — code is disposable |
| **Goal** | Prove the API-dependent design assumptions on the **real** VS Code surfaces, cheaply, **before** the full build — so post-ship iteration is polish, not design |
| **Non-goal** | Production code, real Claude/SDK wiring (except E4), persistence durability, polish, breadth |
| **Status** | `draft` |
---
## Why this exists
Static mockups validated the *look* and *state coverage*; they prove **nothing**
about whether VS Code's native surfaces actually behave as the spec assumes. Twice
already, an unexamined assumption would have forced a redesign (the diff can't
recolor per author; the Comments API can't render in the preview). The remaining
high-risk assumptions can only be settled by **building on the real API**. This spike
does exactly that and nothing more: each experiment returns a **PASS / PASS-with-
fallback / FAIL**, and any FAIL becomes a spec delta folded back into
`coauthoring-native-surfaces.md` before a plan is written.
## Shape & guardrails
- **One throwaway VS Code extension** (`vscode-cowriting-prototype`), run in the
Extension Development Host. **Delete it when the spike ends** — none of this code
graduates.
- **The machine is stubbed** for E1E3, E5 (a function returning canned `before/after`
edits) so we test *VS Code feasibility and feel*, not the SDK. E4 may use a minimal
real call only if cheap.
- **Time-box: ~23 focused days.** If an experiment can't be made to PASS or
PASS-with-fallback inside its slice, that is itself the finding — record it and move
on.
- **No persistence/durability work**, no anchoring ladder, no cross-rung format — those
are not API-risk; defer to the build.
## Experiments (riskiest first)
### E1 — Editable proposed side + Keep/Undo *(highest risk)*
- **Assumption (INV-12, Q2, Q7):** the machine's proposal can be reviewed in a
multi-diff / diff editor whose **proposed side is writable**, the writer can tweak it
before keeping, and **per-change Keep/Undo** works.
- **Build:** open a diff between a read-only baseline (`cowriting-baseline:` virtual
doc) and a **writable** proposal doc (untitled/in-memory) seeded with a canned edit;
attach Keep/Reject actions (try the multi-diff overlay; fall back to per-hunk
**CodeLens**). Edit the proposal side; on Keep, apply to the "live" doc and attribute
machine-vs-tweak by diffing final ↔ canned ↔ baseline.
- **PASS:** proposed side is editable; Keep applies the *tweaked* text; attribution
splits correctly; live doc untouched until Keep.
- **Decides:** Q2 (stable ceiling vs CodeLens fallback), Q7 (Keep/Undo after free
cross-hunk edits). **If FAIL:** the accept/reject surface design changes — know now.
### E2 — Baseline router (git HEAD + snapshot)
- **Assumption (INV-7):** a `QuickDiffProvider` against a `cowriting-baseline:` doc
shows gutter bars + "Open Changes"; the original resolves from **git `HEAD`** when
tracked and from a **snapshot** otherwise; the diff goes **clean on commit /
Mark-Reviewed**.
- **Build:** register the provider; for a repo file read `HEAD` via the Git extension
API and recompute on `repository.state.onDidChange`; for a `~/Downloads` / untitled
file use a stored/in-memory snapshot. Commit (git) and "Mark Changes as Reviewed"
(snapshot) → confirm the diff clears.
- **PASS:** both modes render the expected diff; both resets clear it; works for an
untitled doc.
### E3 — Preview authorship via markdown-it
- **Assumption (PUC-3, D11):** a contributed `markdown.markdownItPlugins` /
`extendMarkdownIt` plugin injects per-span **authorship colors + deletions** into the
**built-in** Markdown preview, toggled by a setting/command, with no custom webview.
- **Build:** contribute the plugin; feed canned attributions/changes; render
green/blue + strikethrough; toggle `cowriting.annotations` on/off.
- **PASS:** marks render inside the native preview; toggle works; deletions show;
scroll-sync intact. **If FAIL:** authorship-surface design changes.
### E4 — Comment → reply → offer → proposal loop
- **Assumption (PUC-8, D10):** a Comments-API thread on a coedited doc can fire a turn,
post a **machine reply `Comment`**, and convert an accepted **offer** into a pending
proposal (E1's surface). Also: a **preview selection → native thread on source** via
the markdown-it token `.map` (D15).
- **Build:** create a thread on selection (and from a preview selection mapped to
source); on add, run a stubbed-or-minimal turn; post a reply comment with an
"Make this edit" action that opens an E1 proposal.
- **PASS:** reply appears in-thread; offer→proposal works; preview-initiated thread
lands on the correct source range. *(Feel/latency notes captured.)*
### E5 — Discoverability (title bar + status bar)
- **Assumption (INV-13):** the editor **title-bar** actions (`editor/title` menus) and
a **`StatusBarItem`** (`✦ Coediting · N changes`, click → review) are visible and
obvious without the Source Control pane; everything gates on `cowriting.isCoediting`.
- **Build:** contribute the menus + status-bar item gated on the context key; enter/exit
coediting flips them.
- **PASS:** a first-time (non-git) user can find "review changes" without opening Source
Control. *(Cheapest experiment — fold into the others.)*
## Output
A short **findings report** (PASS / PASS-with-fallback / FAIL per experiment, with the
feel notes for E1/E4) and, for any non-PASS, a concrete **spec delta** applied to
`coauthoring-native-surfaces.md` — explicitly resolving open questions **Q2, Q4, Q7**.
Then the code is deleted and delivery moves to rung 3 (vertical slice).
## Mapping to the design
| Experiment | Validates | Closes |
| --- | --- | --- |
| E1 | INV-12 · editable proposals + Keep/Undo | Q2, Q7 |
| E2 | INV-7 · baseline router (HEAD + snapshot) | — |
| E3 | PUC-3 / D11 · preview authorship | — |
| E4 | PUC-8 / D10 / D15 · comment loop + preview-initiated thread | — |
| E5 | INV-13 · title-bar / status-bar discovery | — |
| (any FAIL needing a non-native surface) | INV-3 escape hatch | Q4 |
File diff suppressed because it is too large Load Diff