Update pointer — mark what changed on reload - #13
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
reload now captures a pre-change baseline, diffs it against the newly rendered lines via changedLines, and composes the display with composeMarked so changed bullets/lines get the ▸ pointer. A brief line-level background flash (lineFlash/lineFlashOffMsg) highlights what changed on both the fsnotify and tick-fallback reload paths, and recompose() lets the flash toggle without re-reading the file. newModel gains a noFlash param (--no-flash support lands in the CLI flag in a later task); main.go's single call site is updated to pass false so the package keeps compiling.
…e pointer) recompose() could resurrect stale rendered content over the "waiting for file" placeholder or render-error view if the file was deleted (or began erroring) while a line-flash timer was pending. Guard recompose() against fileMissing/loadErr, and reset renderedLines/changed/lineFlash on both failure exits of reload so a later flash-off is a no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Reviewed the whole branch against the hard requirements. The core is sound — the watcher is untouched, scroll preservation holds on every What checks out
a. The bullet swap drops the foreground for the rest of the line
Fix: don't emit a bare reset. Build the marker next to b.
|
…, reject unknown flags (update pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks — addressed the four actionable findings (commit 3b1ba9e): a + b. Marker color — Fixed together. The c. LCS memory — Bounded via common prefix/suffix trim in d. Blank-line bar — Flash background now guarded on e. Unknown flags — Full suite green (55), |
|
Reviewed the whole branch. This is solid work — the hard guarantees all survive, and diffing with an LCS over rendered lines (rather than index-wise) is the right call. Confirmed non-regressions
Worth fixing: the LCS table is unbounded in file size
That is
(arithmetic, not a measurement — but the shape is the point). And since the model re-diffs on every render, a terminal drag-resize replays this per Two-line guard that degrades to "mark nothing" instead of to a stall: const maxDiffCells = 4 << 20 // ~32 MB table; past this, skip the markers
if len(om)*len(nm) > maxDiffCells {
return changed // empty
}
Minor a. A transient read failure silently swallows the next update's markers. The error path in b. Double compose per file event. c. The marker pins the item text to d. Unrelated deletion in e. The flag-parsing rewrite is an improvement (unknown flags now error instead of being taken as a path), though it is scope the PR body does not mention. Not blocking, your call
The two acknowledged minors (resize double-renders the baseline; overlapping sub-500ms flashes clear early) both read as genuinely cosmetic to me — I agree with deferring them. Fix the LCS bound and this is good to merge. |
…te pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the blocker + the doc regression (commit db5f9c8): LCS bound — (d) mouse-capture comment — restored on the Deferring the remaining minors as genuinely cosmetic/self-healing, per your read: transient-read baseline loss (self-heals on next change), double-compose per event, and the marker's 56 tests green, vet + gofmt clean. |
|
Reviewed the whole branch. This is solid work — the hard guarantees survive:
A few real things: a. The marker never lands on a wrapped continuation line
Fix: when a changed line isn't a bullet line, walk backwards through b. Pure deletions mark nothing
c.
|
…egrade (update pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed the blocker + two more (commit dc8e734): a. Wrapped-item edits now mark the item — c. LCS cap — lowered d. Baseline degrade — added a comment marking the baseline-render-fails → no-markers path as deliberate. Deferring the rest as you flagged them (minors): deletion-marks-nothing is intended and the wrapped-item fix covers the practical move case; double-compose-per-event is cosmetic; the arg-order edges are trivial/nonsensical invocations. 58 tests green, vet + gofmt clean. |
|
Review — solid; a few things worth fixing, nothing blocking. Verified locally: The hard guarantees hold
The LCS itself is correct: greedy match-on-equal is optimal, the prefix/suffix trim is right, and the forward backtrack marks only insertions into Worth fixing a. Nothing asserts the composed output stays within the pane. b. The diff cap silently switches the feature off at ~512 lines. c. Nits d. e. When only a wrapped continuation line changed, the owning bullet gets the f. g. Of these, (b) is the only one I would want addressed before merge; the rest are follow-ups. |
…aseline, width test, README (update pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the blocker and folded in the rest to converge (commit bd6b8cd): b (blocking). Diff cap — table is now a. Width guard — added c. O(n) owning-bullet — replaced the per-changed-line backward walk with a single d. hasBaseline — added an explicit e. Marker line flashes — folded the resolved owning-bullet indices into the flash set, so the line carrying the f. Documented Still deferring the double-compose-per-event and arg-order edges as you flagged (cosmetic/trivial). Full suite green, vet + gofmt clean. |
Review — solid, ship itI read Hard requirements — verified
The Notesa. In b. Resize re-renders the baseline through glamour and re-runs the full LCS on every Re-diffing on resize is the right call — it is what makes the markers survive a rewrap. But a drag-resize fires one message per column, and each one costs two Cheap guard: if c. Not a real path today (all callers pass consts), but the README tells users to edit those consts and rebuild, and a typo silently yields d. Deletion-only edits give no line-level signal. e. Nit: the flash tint stops 2 columns shy of the pane edge (padded to None of these block. (a) is the only one I would fix before merging. |
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed the one pre-merge item + the cheap defensive one (commit 03b6032): a. c. Deferring the rest as you flagged (non-blocking follow-ups): the resize baseline-render skip when 61 tests green, |
ReviewThe shape of this is good: the LCS-over-rendered-output approach is the right call (an insert marks only itself), the diff is derived state recomputed from One real bug, plus some smaller notes. Important — a forced re-render before the first content change marks the whole document
Now the user resizes the pane, or presses
Fix — seed the baseline to the current content on the first successful render, right after m.raw = raw
// First successful render: the baseline is the content itself, so a forced
// re-render (resize, r) before any change diffs against itself and marks nothing.
if !m.hasBaseline {
m.prevBaseline = raw
}This also does the right thing after an error/missing-file recovery, where Test gap that let this through: no test sends a second Minora. Flash tint stops 2 columns short of the pane edge. b. c. Multiple positional args silently last-wins. d. Non-bullet changes leave no persistent trace. A changed heading, table row, or code line gets the 500 ms flash and nothing after; under The documented-and-accepted items ( Fix the baseline seeding and this is good to merge. |
…nothing (update pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed the baseline-seeding regression (commit a6de483):
Added two regression tests that failed before the fix and pass after: render→resize→assert no Deferring the minors you accepted as non-blocking (tint stops 2 cols shy, the 63 tests green, vet + gofmt clean. |
Review — solid, with one behavioral bug worth fixingI verified the hard requirements hold:
The one real bug: overlapping flashes cancel each other
The PR notes this as a cosmetic minor, but this is the primary use case, not an edge: an agent writing flashGen int // bump per flash; a stale lineFlashOffMsg is ignoredcarry it through Minor
Not flagging, but noting
The two swallowed errors ( Ship it after the flash-generation fix. |
…s flash (update pointer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed the flash-cancellation bug (commit a032a2c): Added a Remaining items all previously accepted as non-blocking follow-ups (double-compose per change, baseline re-render on resize, the diff.go:92 comment wording, trailing-pad-on-selection during the flash window). Happy to take the comment-wording nit now if you'd like. Full suite green, vet + gofmt clean. |
Review — solid, ship it with a few small notesI read The hard requirements hold. Checked each one specifically:
The LCS design is the right call. Diffing the rendered output ANSI-stripped is what makes insertions mark only themselves and makes markers survive a rewrap, and the prefix/suffix trim plus the Notesa. Task-list items may silently lose the b. A resize racing a pending change swallows the flash. c. Baseline re-render is avoidable on the common path. d. e. Flash tint stops two columns short. f. None of these block. Test coverage is genuinely good — the insertion-no-cascade, restyle-ignored, file-deleted-mid-flash, empty-file-baseline, and stale-generation cases are exactly the ones I would have gone looking for. |
What
When the watched file changes, the viewer now points at what moved instead of leaving you to hunt for it.
▸marker (bullets): a changed bullet line has glamour's•swapped for a bright▸(same width, no shift). Persists until the next change.▸. No strobe. Disable with--no-flash(the▸still works).How
diff.go— a line-level LCS over the rendered output (ANSI-stripped for comparison), so an inserted line marks only itself instead of cascading onto everything below it.prevBaselineand re-diffsrender(prevBaseline)vsrender(raw)at the current width on every render, so markers survive a rewrap.applyLineBgre-applies the bg after every\x1b[0mreset so the tint spans the whole line without losing content colors; the bullet swap runs first so its reset is re-tinted too.Scope / safety
renderMarkdown/watcher.go.style.go.Tests
52+ passing. Covers: LCS (identical / modified / insertion-no-cascade / deletion / restyle-ignored), bullet swap + non-bullet-no-marker, flash bg present/absent, marker persistence after flash-off,
--no-flash, initial-load-unmarked, and the file-deleted-mid-flash edge (below).Review
Built subagent-driven (4 tasks, reviewed each). Final whole-branch review (opus) found one Important bug —
recompose()could resurrect stale content over the "waiting for file"/error view if the file was deleted mid-flash — fixed (guardrecompose()+ reset cached state onreload's failure paths) with a regression test. Two Minors documented as out-of-scope: resize double-renders the baseline; overlapping <500ms flashes clear early (cosmetic).Spec:
docs/superpowers/specs/2026-07-31-update-pointer-design.mdPlan:
docs/superpowers/plans/2026-07-31-update-pointer.md🤖 Generated with Claude Code