Reject on an optimistically-applied proposal now restores the retained original even after interior tweaks: appliedSpans tracked-range fallback (pure shiftTracked, boundary-straddle distrust, close-clears, rebuild-only resync), honest hard failure with a Discard action, INV-16 read-only guards, rejectAll {reverted,skipped} reporting on all batch surfaces, CodeLens reachability at the tracked span. 312 unit + 94/5 host E2E.
Closes#70.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings author-colored track changes inline into the main editor (reverses
INV-32): four per-author decoration types, decorateCommitted decorating all
committed changes-since-baseline by author (human green / Claude blue + struck
hints), standalone deletions neutral, proposals recolored Claude, overlap
stacking. Subagent-driven execution of Tasks 6-9; opus whole-branch review +
fix. typecheck + 265 unit + build + E2E green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Delete dead `authorBadge` function (no callers; grep-verified)
- Merge adjacent duplicate imports from trackChangesModel in test file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Final-review follow-up: the live preview colors added blocks via colorByAuthor(kind="ins")
emitting cw-ins-*; the cw-by-*/cw-mixed rules (only authorBadge, which has no callers)
were styled-but-never-emitted. Cosmetic only; build + 260 unit green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Defect: an ADDED block was colored via `render(wordDiffByAuthor("", raw, ...))`, which
wrapped the whole raw markdown in an inline `<ins>` BEFORE markdown-it parsed it — so
`## X` rendered as literal text, not `<h2>`. Same structural bug for list, blockquote,
and thematic-break blocks.
Fix (three-part, pure / vscode-free):
1. `blockContentStart(raw)`: new helper returning the offset past block-level markers
(ATX headings `## `, unordered/ordered list markers, blockquotes). Open sentinels must
not precede these markers or markdown-it cannot recognise the block construct.
2. `injectSentinels`: clamp the open-sentinel lower-bound to `blockContentStart(raw)`,
so for `## New Section` the sentinel lands AFTER `## ` (at position 3) instead of at
position 0, letting the heading parse correctly.
3. `sentinelsToSpans` / `colorByAuthor`: add optional `kind: "by" | "ins" = "by"`
parameter so the sentinel path can emit `cw-ins-{author}` for added blocks while all
existing `colorByAuthor`/`cw-by-*` call-sites are unchanged.
4. `renderReview` ADDED block path: `render(wordDiffByAuthor("", raw, ...))` →
`colorByAuthor(raw, blk.start, landedSpans, render, "ins")`. The CHANGED non-atomic
prose path (`wordDiffByAuthor(before, after, ...)`) is untouched — it correctly keeps
the block markers at column 0 of the unchanged prefix.
5. `renderReviewOp`: removed the now-vestigial `colored` parameter (was always `render`
after the added-block path moved to `changedHtml`); unchanged blocks now call
`render(op.block.raw)` directly.
Regression test added: "renderReview: an added heading block renders as a heading AND
is author-colored as an insertion" — RED on old code, GREEN after fix. All 259 tests
pass; typecheck clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>