diff --git a/specs/coauthoring-inline-editor-diff.md b/specs/coauthoring-inline-editor-diff.md index bb3f90e..d45300c 100644 --- a/specs/coauthoring-inline-editor-diff.md +++ b/specs/coauthoring-inline-editor-diff.md @@ -8,13 +8,14 @@ status: graduated | **Author(s)** | Ben Stull (with Claude) | | **Reviewers / approvers** | Ben Stull | | **Status** | `graduated` | -| **Version** | v0.1.0 | +| **Version** | v0.1.1 | | **Source artifacts** | Feature `benstull/vscode-cowriting-plugin#64` (Inline editable proposed-change diff in the Markdown editor + Accept/Reject controls in both surfaces, `type/feature`, `priority/P2`) · Brainstorming session `vscode-cowriting-plugin-0058` (2026-06-26) · Builds on (all shipped): F4 `#12` (propose/accept seam, INV-9/10/11/13), F6 `#17` (baseline / machine-landing), F7 `#21` (rendered preview, pure render engine INV-22), F10 `#29` (interactive review preview — the **clean-editor** decision INV-32; ✓/✗ accept-reject), F11 `#43` (preview toolbar, `data-src` block→source mapping INV-36), document-edit-flow `#42/#47/#46` (block proposals INV-39/40, accept-all INV-42) · Parent specs (graduated): `coauthoring-propose-accept.md`, `coauthoring-diff-view.md`, `coauthoring-rendered-preview.md`, `coauthoring-interactive-review.md`, `coauthoring-document-edit-flow.md` · Lineage: `ben.stull/rfc-app#48` | **Change log** | Date | Version | Change | By | | --- | --- | --- | --- | +| 2026-06-26 | v0.1.1 | Implementation refinement (planning-and-executing session 0059): made the **re-anchor** explicit. Optimistic apply (§3.2) must store the pre-apply text on a new `Proposal.original` field **and** re-fingerprint the proposal's anchor to the *applied* text — F4's `fp.text` is the *original* target, which leaves the buffer once the replacement lands, so `resolve()` would orphan every applied proposal otherwise. `finalizeInPlace`/`revertInPlace`/decorate all key off the re-anchored fp; revert restores `original`. Reload-safety (INV-51/54): a proposal already carrying `original` is never re-captured (the in-memory applied-set is empty after a window reload), so the revert target survives save+reload. Shipped #64 (PR, session 0059). | | 2026-06-26 | v0.1.0 | Initial draft — brainstorming session 0058. Four forks locked with the operator: **(1) editor model** = *optimistic apply + decorations* — on propose, the editor buffer becomes the would-be-accepted text (insertions real & editable & tinted; deletions shown as struck-red non-editable hints); accept = finalize-in-place, reject = revert. **(2) timing** = *on proposal* (turn complete), not a live token-stream into the editor (that stays in #60's notification/OutputChannel). **(3) editor affordance** = CodeLens `Accept ▾ / Reject ▾` above each block, `▾` → QuickPick (this / all); the webview keeps HTML buttons with the same dropdown. **(4) controls parity** = Accept / Reject / Accept-all / Reject-all reachable from **both** the editor and the webview. Two sub-decisions confirmed: a **dedicated `EditorProposalController`** owns optimistic-apply + decorations + CodeLens (keeps `ProposalController` the pure F4 state/seam owner); **saving while pending persists** the proposed (accepted-result) text. Reverses INV-32 and INV-10; supersedes the ✓/✗ glyph controls. | Ben Stull + Claude | --- @@ -318,12 +319,19 @@ all four to the controller methods of §3.3 (INV-35 preserved). ### 3.8 Invariants -- **INV-48 — Optimistic apply.** On propose, the proposed text is written into the - live editor buffer (the buffer becomes the would-be-accepted result); this write - does **not** advance the F6 baseline and does **not** fire the F4 machine-landing - seam. **Reverses INV-10** (propose no longer leaves the document untouched) and - **INV-32** (the editor is no longer kept unconditionally clean — it shows pending - proposals). +- **INV-48 — Optimistic apply (with re-anchor).** On propose, the proposed text is + written into the live editor buffer (the buffer becomes the would-be-accepted + result); this write does **not** advance the F6 baseline and does **not** fire the + F4 machine-landing seam. Because F4's `fp.text` is the *original* target — which + leaves the buffer once the replacement lands — optimistic apply **stores the + pre-apply text on `Proposal.original` and re-fingerprints the anchor to the applied + text**, so `resolve()` keeps finding the proposal in the mutated buffer; finalize / + revert / decorate all key off the re-anchored fp, and revert restores `original`. + `original` is captured **exactly once** (first apply): a proposal that survives a + save+reload already carries it, so a fresh session never re-captures it from the + already-applied buffer (reload-safety, INV-51/54). **Reverses INV-10** (propose no + longer leaves the document untouched) and **INV-32** (the editor is no longer kept + unconditionally clean — it shows pending proposals). - **INV-49 — Single diff source.** Editor decorations and webview HTML both derive from one pure, deterministic per-proposal diff (extends `diffToBlockHunks` / `wordEditHunks`, INV-22/39/40). The same proposal yields the same diff in both