diff --git a/specs/coauthoring-native-surfaces.md b/specs/coauthoring-native-surfaces.md index 0ba89d9..47509f1 100644 --- a/specs/coauthoring-native-surfaces.md +++ b/specs/coauthoring-native-surfaces.md @@ -8,7 +8,7 @@ status: draft | **Author(s)** | Ben Stull (with Claude) | | **Reviewers / approvers** | Ben Stull | | **Status** | `draft` | -| **Version** | v0.2.0 | +| **Version** | v0.2.1 | | **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** @@ -17,6 +17,7 @@ status: draft | --- | --- | --- | --- | | 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 | +| 2026-07-01 | v0.2.1 | Rung-2 spike **complete** (session 0064): **E2 PASS**, **E4 PASS-with-fallback** — comment-loop API seams folded into §6.4 (commenting-range refresh on gate change, input focus via `workbench.action.addComment`, `commentThread` menu when-key, offer affordances) and baseline-router notes (nested-repo discovery); §7.1 rung 2 closed | Ben Stull + Claude | --- @@ -642,6 +643,12 @@ state (INV-7), not durable coauthoring metadata. document always resolves a baseline; non-coedited documents resolve none. - **QuickDiffProvider** — `provideOriginalResource(docUri) → cowriting-baseline:` URI (drives gutter bars). Registered on the "Cowriting" `SourceControl`. + **Spike-verified (E2, 2026-07-01):** gutter bars and the native diff render in both + baseline modes, including for a file in **no repository at all**; + `Repository.show('HEAD', path)` and `state.onDidChange` behave as assumed (the + change event is coarse — key the re-read off `state.HEAD.commit`); a **nested** + repo may need explicit `openRepository()` discovery before `getRepository()` + resolves. - **Machine-edit seam** — the single boundary where machine text enters the model: `proposeAgentEdit(docUri, range, newText, provenance)` → produces **pending** `proposals[]` entries; nothing settles until Keep (INV-5). Block/word granularity via @@ -690,6 +697,18 @@ state (INV-7), not durable coauthoring metadata. but cannot host the thread; the Comments API renders only in the gutter + Comments panel), or on the **whole document** (anchored at line 0, full-document context). All threads are native — the preview never hosts comment UI (INV-3). + **Spike-verified API seams (E4, 2026-07-01):** (1) the editor **caches commenting + ranges per document** — when the CoeditingRegistry gate flips for an already-open + document, the controller must **re-assign `commentingRangeProvider`** (its setter is + the API's only ranges-changed signal), or the `+` gutter and Add Comment stay stale + ("cursor must be within a commenting range"); (2) there is **no API to focus a + thread's input** — "Ask Claude" focuses the comment box by invoking the built-in + **`workbench.action.addComment`** (cursor moved to the top first for a + whole-document ask), not by `createCommentThread` + `Expanded`; (3) the + thread-contextValue menu `when` key is **`commentThread`** (not + `commentThreadContextValue`); the "make this edit" offer is carried as contributed + thread actions (`comments/commentThread/title` + `…/context`), optionally + reinforced by an in-body command link (requires `isTrusted.enabledCommands`). ### 6.5 Per–Product-Use-Case design @@ -964,11 +983,10 @@ 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 (partially done — 3 of 5 experiments).** A +2. **Throwaway feasibility spike (complete — 5 of 5 experiments, 2026-07-01).** 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):** + real surfaces. Companion: `coauthoring-feasibility-spike.md`. **Findings:** - **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 @@ -980,10 +998,19 @@ The vehicle is the **shipped extension, evolved in place** (D17/§6.10): 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.** + - **E2 (baseline router) — PASS.** QuickDiff gutter bars + the native diff + render in both modes, driven end to end: git **`HEAD`** (tracked file — the + baseline advanced automatically on commit) and **snapshot** (a file in no + repo at all — "Mark Changes as Reviewed" re-pinned and the diff went clean). + INV-7/D13/D14 confirmed; API notes folded into §6.4. + - **E4 (comment → reply → offer → proposal) — PASS with fallback.** The full + loop works on the real Comments API (thread → turn with progress/cancel → + in-thread machine reply → offer → pending in-buffer proposal). Three API + seams required workarounds, folded into §6.4: commenting-range refresh on + gate change, input focus only via `workbench.action.addComment`, and the + `commentThread` menu when-key. *(The preview-selection → source-thread half + of E4/D15 was not spiked — confirm at the preview-surface build.)* + - **The spike is complete; delivery moves to rung 3 (vertical slice) / rung 4.** 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 @@ -1006,8 +1033,8 @@ host E2E green (§6.8). Marketplace packaging/release is out of scope here. | Risk | Likelihood / impact | Mitigation | | --- | --- | --- | -| 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 | +| Baseline router assumptions fail on real git repos | retired | **E2 PASSed (2026-07-01)** — both baseline modes verified on the real API; snapshot mode remains the always-works fallback (INV-7) | +| Comment-response loop feels laggy or noisy with the **real** SDK (E4 spiked with a ~2s stub) | M / M | E4 PASSed on feel with the stub; real-turn latency lands at the rung-3 vertical slice; 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 buffer (D18), not the preview; the preview is read/annotate only (a deliberate split) |