Proposal block shows a diff against the original #58

Open
opened 2026-06-15 17:21:34 +00:00 by benstull · 0 comments
Owner

Proposal block shows a diff against the original

Summary

As a coauthor, I can see Claude's pending change-recommendation block (the one
I accept or decline) rendered as a diff against the original text, so that I
can see exactly what is changing rather than eyeballing two full blocks.

Problem / pain

The pending proposal block today renders the original and the proposed text as
two separate full blocks<del> the whole "before" followed by <ins> the
whole "after" (trackChangesModel.ts:715-716) — with no word-level diff
between them
. On anything but a wholesale rewrite this is noisy and hard to
read: a one-word fix shows the entire paragraph struck through and the entire
paragraph re-inserted, and the reviewer has to visually diff the two themselves
to find what actually changed before deciding to accept or decline. The rest of
the track-changes review rendering already shows proper inline diffs
(wordMergedMarkdown() / diffWords(), trackChangesModel.ts:431-438), so the
proposal block reads as inconsistent and lower-fidelity than the surrounding
review.

Who feels it

The human coauthor reviewing a pending Claude proposal — every accept/decline
decision goes through this block.

Desired outcome / value

The reviewer can see, at a glance, precisely what Claude changed in a
proposal — the specific words removed and added in context — so accept/decline is
a fast, confident decision instead of a manual two-block comparison. The proposal
block matches the fidelity of the rest of the review surface.

Acceptance — "done right"

  • The pending proposal block renders a word-level diff of original →
    proposed: removed words struck inline, inserted words highlighted, unchanged
    words shown once as context (not duplicated across two full blocks).
  • The presentation is consistent with the existing track-changes "changed
    block" rendering (same struck/inserted styling, ideally the same
    wordMergedMarkdown path).
  • Accept / decline behavior is unchanged — only the display of the proposal
    changes.
  • Reads sensibly across cases: a small in-block edit (a few words), a wholesale
    block replacement, and an insertion (no original) all render coherently.

Scope / non-goals

In scope: how the pending proposal block is rendered in the review preview —
showing a word-level diff against the original instead of two full <del>/<ins>
blocks.

Non-goals:

  • The accept/decline mechanics, anchoring, or proposal granularity (#47).
  • Inline-at-anchor proposal placement (#31) — that's where the block sits, this
    is what it shows.
  • Live human edits inside a pending block (a separate concern).
  • Changing the diff for non-proposal (authorship/track-changes) rendering, which
    already does this.

Assumptions · constraints · dependencies

  • The ProposalView already carries both replaced (original) and replacement
    (proposed) text (proposalController.ts:81-95), so the diff can be computed
    from existing data — no new state needed.
  • A word-diff helper already exists and is used by the changed-block rendering
    (wordMergedMarkdown(), trackChangesModel.ts:431-438); the natural
    implementation is to route proposalBlockHtml() through it. (Solution hint, not
    a mandate.)
  • Webview stays sealed (INV-21) — this is pure rendering, no new surface.
  • Related (not blocking): #31 (inline placement), #47 (block granularity).

Source / signal

Self-originated — capture session vscode-cowriting-plugin-0052
(2026-06-15). Dev observation: "the claude change recommendation block (which
user will accept or decline) should show the diff with the original." Current
behavior (two full <del>/<ins> blocks, no word diff) confirmed by reading
trackChangesModel.ts proposalBlockHtml().

Priority (WSJF)

Provisional: Value 6 · Time-criticality 3 · Opportunity-enablement 2 ÷ Size 2 =
~5.5. priority/P2 — directly improves the core accept/decline decision the
whole propose/accept loop hinges on, and is small (reuses the existing word-diff
path).

Decomposition

Single increment (Story). Tasks:

  • Route proposalBlockHtml() through the word-level diff
    (wordMergedMarkdown or equivalent) using replacedreplacement.
  • Handle the insertion case (no original) and wholesale-replacement case.
  • Verify consistency with the changed-block rendering styling.
  • Unit coverage for the proposal-block diff output; manual smoke in the
    preview.
<!-- Set the type/* label: type/story --> # Proposal block shows a diff against the original ## Summary As a **coauthor**, I can see Claude's pending change-recommendation block (the one I accept or decline) rendered as a **diff against the original text**, so that I can see exactly what is changing rather than eyeballing two full blocks. ## Problem / pain The pending proposal block today renders the original and the proposed text as **two separate full blocks** — `<del>` the whole "before" followed by `<ins>` the whole "after" (`trackChangesModel.ts:715-716`) — with **no word-level diff between them**. On anything but a wholesale rewrite this is noisy and hard to read: a one-word fix shows the entire paragraph struck through and the entire paragraph re-inserted, and the reviewer has to visually diff the two themselves to find what actually changed before deciding to accept or decline. The rest of the track-changes review rendering already shows proper inline diffs (`wordMergedMarkdown()` / `diffWords()`, `trackChangesModel.ts:431-438`), so the proposal block reads as inconsistent and lower-fidelity than the surrounding review. ## Who feels it The **human coauthor** reviewing a pending Claude proposal — every accept/decline decision goes through this block. ## Desired outcome / value The reviewer can see, at a glance, **precisely what Claude changed** in a proposal — the specific words removed and added in context — so accept/decline is a fast, confident decision instead of a manual two-block comparison. The proposal block matches the fidelity of the rest of the review surface. ## Acceptance — "done right" - The pending proposal block renders a **word-level diff** of original → proposed: removed words struck inline, inserted words highlighted, unchanged words shown once as context (not duplicated across two full blocks). - The presentation is **consistent** with the existing track-changes "changed block" rendering (same struck/inserted styling, ideally the same `wordMergedMarkdown` path). - Accept / decline behavior is unchanged — only the *display* of the proposal changes. - Reads sensibly across cases: a small in-block edit (a few words), a wholesale block replacement, and an insertion (no original) all render coherently. ## Scope / non-goals **In scope:** how the pending proposal block is *rendered* in the review preview — showing a word-level diff against the original instead of two full `<del>`/`<ins>` blocks. **Non-goals:** - The accept/decline mechanics, anchoring, or proposal granularity (#47). - Inline-at-anchor proposal *placement* (#31) — that's where the block sits, this is what it shows. - Live human edits inside a pending block (a separate concern). - Changing the diff for non-proposal (authorship/track-changes) rendering, which already does this. ## Assumptions · constraints · dependencies - The `ProposalView` already carries both `replaced` (original) and `replacement` (proposed) text (`proposalController.ts:81-95`), so the diff can be computed from existing data — no new state needed. - A word-diff helper already exists and is used by the changed-block rendering (`wordMergedMarkdown()`, `trackChangesModel.ts:431-438`); the natural implementation is to route `proposalBlockHtml()` through it. (Solution hint, not a mandate.) - Webview stays sealed (INV-21) — this is pure rendering, no new surface. - Related (not blocking): #31 (inline placement), #47 (block granularity). ## Source / signal Self-originated — capture session **vscode-cowriting-plugin-0052** (2026-06-15). Dev observation: "the claude change recommendation block (which user will accept or decline) should show the diff with the original." Current behavior (two full `<del>`/`<ins>` blocks, no word diff) confirmed by reading `trackChangesModel.ts` `proposalBlockHtml()`. ## Priority (WSJF) Provisional: Value 6 · Time-criticality 3 · Opportunity-enablement 2 ÷ Size 2 = ~5.5. `priority/P2` — directly improves the core accept/decline decision the whole propose/accept loop hinges on, and is small (reuses the existing word-diff path). ## Decomposition Single increment (Story). Tasks: - [ ] Route `proposalBlockHtml()` through the word-level diff (`wordMergedMarkdown` or equivalent) using `replaced` → `replacement`. - [ ] Handle the insertion case (no original) and wholesale-replacement case. - [ ] Verify consistency with the changed-block rendering styling. - [ ] Unit coverage for the proposal-block diff output; manual smoke in the preview.
benstull added the type/storypriority/P2 labels 2026-06-15 17:21:34 +00:00
Sign in to join this conversation.