diff --git a/sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md b/sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md index 652914e..8f50676 100644 --- a/sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md +++ b/sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md @@ -16,8 +16,93 @@ ``` +## Plan + +**SLICE-2 — #47 (review, P1)** of the document-edit flow +(`specs/coauthoring-document-edit-flow.md` §7.2). Anchor: Feature #47 +(`type/feature`); covered by the graduated combined Solution Design → §4.3 R3. + +Document rewrites propose **one F4 proposal per changed block** (the unit a human +reviews), but each accept reconciles attribution at **word** granularity (the unit +F3 records). INV-39 supersedes INV-37 for document edits; INV-40 word-precise +intra-block attribution; INV-41 block-insertion anchoring. Selection edits +unchanged. + +Tasks: +1. `model.ts` — add optional `granularity?: "block" | "single"` to `Proposal` + (additive, back-compat: absent ⇒ `"single"`). INV-39/§6.3. +2. `proposalModel.ts` — `addProposal` opts gains `granularity`, threaded onto the + proposal (omitted when absent). +3. `trackChangesModel.ts` — new pure `diffToBlockHunks(currentText, + rewrittenText): EditHunk[]`: split both sides into the existing block units + (`splitBlocksWithRanges` for source ranges + `splitBlocks` keys), diff blocks + (reuse `diffArrays` keying like `diffBlocks`), emit ONE `EditHunk` per + changed/added/removed block — changed → `[block.start,end)`→rewrite; fences + atomic (whole-fence hunk); inserted → anchored to adjacent boundary (INV-41, + reuse the `anchorInsertion` idea); unchanged → none. Same `EditHunk` shape as + `diffToHunks` (which is RETAINED as the intra-block sub-diff engine). +4. `trackChangesPreview.ts` — `runEditAndPropose` **document branch** uses + `diffToBlockHunks` and tags each minted proposal `granularity:"block"`. +5. `proposalController.ts` — `accept`: when `granularity === "block"`, re-resolve + the block text, `diffToHunks(blockText, replacement)` → per-run word sub-diff, + apply **one `applyAgentEdit` per changed run, descending offset** so only the + runs Claude changed land Claude-attributed; unchanged spans keep prior author + (INV-40). Non-block keeps the single `applyAgentEdit`. +6. Tests: unit (`diffToBlockHunks` + INV-40 controller) + host E2E (#47 cases in + §6.8); update the existing f11 document-path E2E (now per-block, supersedes + INV-37 word-level expectation); `docs/MANUAL-SMOKE-F12.md` §2. + +**Design note (seam constraint):** `pendingEdits.matchEvent` resolves ONE +registration per change event, so INV-40's per-run attribution is implemented as +**sequential** `applyAgentEdit` calls (descending offset), not a single +multi-replace `WorkspaceEdit`. The spec's "one undo-grouped edit" wording is thus +approximated as N undo steps per block accept — see Deferred decisions. + +No new persisted artifact; no deploy pipeline (VS Code extension). + +## Results + +**SLICE-2 (#47, review, P1) shipped to `main`** — PR +[#50](https://git.benstull.org/benstull/vscode-cowriting-plugin/pulls/50) +(merged), issue #47 closed. + +- `trackChangesModel.ts` — new pure `diffToBlockHunks` (block-key alignment via + `diffArrays`/`diffBlocks` keying; isolated changed block → block-aligned hunk → + rewritten raw; fences atomic INV-23; insert/delete → exact gap-span hunk; + zero-width gap-span anchored INV-41). Split `diffToHunks` into raw + `wordEditHunks` + anchoring wrapper (fixes a latent overlap bug under batch apply). +- `trackChangesPreview.ts` — document branch uses `diffToBlockHunks`, tags + `granularity:"block"`. +- `model.ts`/`proposalModel.ts` — additive optional `Proposal.granularity`. +- `proposalController.ts` — `acceptBlock`: intra-block word sub-diff + (`wordEditHunks`) → one `applyAgentEdit` per changed run, descending offset + (INV-40 word-precise attribution; unchanged spans keep prior author). +- Tests: `diffToBlockHunks` unit (reconstruction/fence/add-remove); `f12Review` + host E2E (M→M, unchanged→none, fence atomic, INV-40, INV-41); updated f11 + document-path E2E to per-block; `MANUAL-SMOKE-F12.md` §2. + +Verification: `tsc --noEmit` clean; **214 unit** green; **69/5 host E2E** green +(main suite 65 → 69 net with the new F12 review tests). + +**Next:** SLICE-3 — #46 (accept-all, INV-42): `acceptAllProposals` (controller, +descending-order, orphan-skip + report) + `cowriting.acceptAllProposals` command ++ preview toolbar **Accept all** button (`{type:"acceptAll"}` intent, shown ≥2 +pending). + ## Deferred decisions _Autonomous-mode low-confidence calls the driver made and would have liked operator input on. Appended as the session runs; surfaced at finalize. Empty if none._ + +- **INV-40 undo granularity** (driver call). Spec §6.2/§6.7 say accepting a block + proposal should be "one undo-grouped WorkspaceEdit." But the F3 seam's + `pendingEdits.matchEvent` matches exactly ONE registration per change event, so a + single `WorkspaceEdit` with N independent run-replaces can't carry per-run + attribution (the multi-hunk event fails to match any single registration → falls + through to human). Implemented INV-40 as **sequential per-run `applyAgentEdit` + calls, descending offset** — correct word-precise attribution, reuses the seam + with zero attribution-core risk, but a block accept is N undo steps rather than + one. Single-undo-step would require extending `matchEvent`/`onDidChange` to + consume multiple registrations per event (riskier F3 change) — left as a possible + follow-up.