Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88ba6ffd69 | |||
| c10f70bdc8 |
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
status: draft
|
status: graduated
|
||||||
---
|
---
|
||||||
# Solution Design: Coediting Markdown with a Machine — a Native VS Code Experience
|
# Solution Design: Coediting Markdown with a Machine — a Native VS Code Experience
|
||||||
|
|
||||||
@@ -7,8 +7,8 @@ status: draft
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **Author(s)** | Ben Stull (with Claude) |
|
| **Author(s)** | Ben Stull (with Claude) |
|
||||||
| **Reviewers / approvers** | Ben Stull |
|
| **Reviewers / approvers** | Ben Stull |
|
||||||
| **Status** | `draft` |
|
| **Status** | `graduated` |
|
||||||
| **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. |
|
| **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**
|
**Change log**
|
||||||
@@ -17,6 +17,7 @@ status: draft
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 2026-06-27 | v0.1.0 | Initial draft — brainstorming session 0062 | Ben Stull + Claude |
|
| 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.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.
|
document always resolves a baseline; non-coedited documents resolve none.
|
||||||
- **QuickDiffProvider** — `provideOriginalResource(docUri) → cowriting-baseline:` URI
|
- **QuickDiffProvider** — `provideOriginalResource(docUri) → cowriting-baseline:` URI
|
||||||
(drives gutter bars). Registered on the "Cowriting" `SourceControl`.
|
(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:
|
- **Machine-edit seam** — the single boundary where machine text enters the model:
|
||||||
`proposeAgentEdit(docUri, range, newText, provenance)` → produces **pending**
|
`proposeAgentEdit(docUri, range, newText, provenance)` → produces **pending**
|
||||||
`proposals[]` entries; nothing settles until Keep (INV-5). Block/word granularity via
|
`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
|
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).
|
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).
|
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
|
### 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
|
1. **Static mockups (done).** Validate visual design + state coverage. *(Already
|
||||||
surfaced and closed the empty-state, comments-from-preview, and discoverability
|
surfaced and closed the empty-state, comments-from-preview, and discoverability
|
||||||
gaps.)*
|
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
|
disposable VS Code extension (`vscode-cowriting-prototype`; the machine
|
||||||
**stubbed** with canned edits) proving the API-dependent assumptions on the
|
**stubbed** with canned edits) proving the API-dependent assumptions on the
|
||||||
real surfaces. Companion: `coauthoring-feasibility-spike.md`. **Findings so
|
real surfaces. Companion: `coauthoring-feasibility-spike.md`. **Findings:**
|
||||||
far (2026-07-01):**
|
|
||||||
- **E1 (editable proposals + Keep/Undo) — PASS with pivot.** VS Code does
|
- **E1 (editable proposals + Keep/Undo) — PASS with pivot.** VS Code does
|
||||||
**not** render extension CodeLens inside a diff editor, ruling out the
|
**not** render extension CodeLens inside a diff editor, ruling out the
|
||||||
multi-diff review surface; per-hunk CodeLens works in a normal editor, and
|
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).
|
with a working toggle (D3 confirmed).
|
||||||
- **E5 (discoverability) — PASS.** Title-bar + status-bar entry points read as
|
- **E5 (discoverability) — PASS.** Title-bar + status-bar entry points read as
|
||||||
obvious with no Source Control pane (INV-13 confirmed).
|
obvious with no Source Control pane (INV-13 confirmed).
|
||||||
- **E2 (baseline router: QuickDiff against git `HEAD` *and* snapshot, clean on
|
- **E2 (baseline router) — PASS.** QuickDiff gutter bars + the native diff
|
||||||
commit / Mark-Reviewed — INV-7) and E4 (comment → reply → offer → proposal —
|
render in both modes, driven end to end: git **`HEAD`** (tracked file — the
|
||||||
PUC-8) remain — now the riskiest unvalidated assumptions and the next
|
baseline advanced automatically on commit) and **snapshot** (a file in no
|
||||||
concrete work.**
|
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
|
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 →
|
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
|
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 |
|
| 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) |
|
| 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 (E4 unvalidated) | M / M | E4 spikes it with latency notes; D10's off-switch ("Stop editing with Claude") bounds the blast radius |
|
| 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 |
|
| 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 |
|
| 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) |
|
| 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) |
|
||||||
|
|||||||
Reference in New Issue
Block a user