Skip to content

THI-443: review walkthrough — two-column stops, legible diagrams, reviewed marks, type and color - #49

Merged
tdody merged 49 commits into
mainfrom
thibaultdody/thi-443-review-walkthrough-full-width-layout-legible-diagrams
Nov 4, 2026
Merged

tdody merged 49 commits into
mainfrom
thibaultdody/thi-443-review-walkthrough-full-width-layout-legible-diagrams

Conversation

@tdody

@tdody tdody commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes THI-443. Rebuilds the review walkthrough view (static/src/review/Walkthrough.jsx).

Before this change:

  • Narrow text: stop text was a centered 72–80ch column about a third of the card's width.
  • Unreadable diagrams: they were squeezed to that column, at 30% scale with ~5px labels.
  • Code changes buried: behind a toggle, under a wall of "not in this diff" paths.
  • No progress tracking: nothing recorded which stops you'd read.

The design is in docs/superpowers/specs/2026-10-29-walkthrough-two-column-design.md and the plan in docs/superpowers/plans/2026-10-29-walkthrough-two-column.md. CLAUDE.md's reviews row now points at that spec.

Page

  • A fixed header (title, PR link, staleness badge, "N / M reviewed") over one scrolling body.
  • A numbered contents list beside the problem statement. The problem statement now renders its markdown.
  • Stop cards edged in their kind's color. Each has a title row, a full-width diagram row, then the prose beside a code-changes column.
    • The grid is minmax(min(52ch, 440px), 72ch) minmax(540px, 1fr), switching to one column below 1050px (a container query on the scroller).
    • The prose gives up width before the code column drops under ~70 monospace characters.
  • Code column: a file list with change counts, all hidden refs (not in this diff / generated / unchanged at the cited lines / no text changes) in one summary line, then the hunks.
    • The column is sticky beside the prose and scrolls on its own.
    • A file row or a prose cite chip scrolls the column (never the page) to that file and flashes it.
    • Files over 300 lines start collapsed behind "show N lines".
    • Hunks are memoized, so a reviewed toggle doesn't re-highlight them.
  • Comments: the always-open boxes become a "comment" link, with a ⌘↩/Ctrl+↩ hint. Drafts survive a stop folding. A folded stop shows "2 comments · 1 open".

Diagrams

  • Parser: parseWalkthrough lifts top-level mermaid fences into stop.diagrams. Nested ones stay inline.
  • Size: in the diagram row a diagram fills the card up to its natural width, never below 75% of it, and scrolls sideways inside its own box when wider than the card.
  • Full-size view: ⤢, or a click on the diagram, opens it at natural size in a lightbox.
    • It's mounted at the app root in overlays/Overlays.jsx; inside #split-view the header would paint over it.
    • It re-renders the source with a fresh id; a copied SVG's duplicate ids broke its arrowheads.
    • Focus goes to the scroller, Tab is kept inside, and Esc, backdrop or ✕ closes it and returns focus.
  • App-wide theme: mermaid's base theme in periscope's tokens (split/mermaidTheme.js, with the DOM side in split/mermaidRender.js). It waits for the UI font and follows Settings → Fonts.
    • Pie, git, mindmap and timeline get explicit category palettes. The base theme would have collapsed them to one grey.
    • This restyles diagrams in file previews too.

Reviewed marks

  • stopSig is an FNV-1a hash of the stop's source, with trailing whitespace trimmed, keyed by title in ~/.claude/reviews/<repo>/<slug>/reviewed.json. A mark lapses when a re-prepare rewrites the stop.
  • POST /api/reviews/reviewed returns 400 for a bad stop or sig, and 404 with no walkthrough or when the review is cleared mid-request.
  • Writes take a thread lock plus an fcntl.flock on the review dir, because dev and prod both write ~/.claude/reviews, and they're atomic (temp file + os.replace).
  • clear_review now takes the same flock, so a mark can't leave a stray reviewed.json-only dir behind as an orphan queue row.
  • The client updates optimistically through a per-title queue, reverts on failure, and a refetch can't undo a mark that landed meanwhile.
  • A reviewed stop folds to its title row; its title unfolds it without unmarking.

Type and color: scoped to .walkthrough, so file previews and the Reviews queue don't change, apart from the diagram theme.

  • Five sizes (12/13/15/18/22px).
  • All text is at least 4.5:1, measured in the browser. That covered --fg-3 coming in from shared styles (hunk heads, list markers, closed PR links, syntax comments) and links in comments.
  • Kind tokens in :root.
  • Focus rings on every control.

Process

The spec and plan went through an adversarial review before any code. Each task then had a spec-compliance review and a code-quality review, several with multiple rounds, and the branch had a final whole-branch review.

Review findings fixed along the way:

  • compat's memo would have installed global vnode hooks;
  • a refetch race;
  • lost drafts;
  • the lightbox under the header;
  • grey pie charts;
  • the cross-process write race.

Test plan

  • npm test: 1390 passed. New tests:
    • the parser's diagram lift;
    • stopSig / isReviewed, including a pinned hash vector;
    • evidenceFor grouping;
    • markQueue and appliesRefetch;
    • the theme mapping;
    • lightbox focus and backdrop;
    • render tests of WalkthroughView: header states, contents, cards, folding, cite wiring, large-file collapse and comment placement.
  • uv run pytest -q: 2035 passed. New tests: read_reviewed / set_reviewed (corrupt input, flock, atomic write, never creating the dir) and the route (round-trip, 400s, 404s, mid-request clear, surrogate stops).
  • bin/check: passes (3 pre-existing biome warnings in files this PR doesn't touch).
  • static/dist rebuilt and fresh.
  • Dev server (:17375), on a real 13-stop walkthrough and a 5-stop one, at 1600, 1420 and 1000px:
    • the layout and the breakpoint (two columns at a 1110px pane: 462px prose, 540px code; one column at 1030px);
    • no sideways page scroll;
    • diagram size (labels from 7.6px up to 10.5–14px);
    • the lightbox (above the header, Esc/backdrop/✕, focus return);
    • file and cite jumps (the page doesn't move);
    • a reviewed mark surviving a reload, unfolding without unmarking, and unmarking removing the file;
    • contrast spot-checks (all ≥ 4.5:1);
    • pie and gitGraph in distinct colors.

Follow-ups

  • THI-446: most cited files report "not in this diff" (server ref matching or diff base).
  • THI-447: a refetch still re-highlights every hunk (memoize on content).

🤖 Generated with Claude Code

tdody and others added 30 commits October 29, 2026 15:41
…-width row, code column beside the text, reviewed.json marks, collapsed comment box, scoped type and color (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t to browser check (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t, zoom via real buttons, flock'd reviewed.json that never recreates a cleared dir, refetch/draft/sig fixes, contrast gaps, formatted tests, trailers (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…into stop.diagrams, keeps stop.source and the problem's markdown (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d and withMark for per-stop reviewed marks (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…h hunks) and hidden (missing, generated, unchanged); hiddenSummary and evidenceIndex (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…verlaps, pinned sig, tighter tests, helpers grouped by page vs queue (review of THI-443 tasks 1–3)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…iew of tasks 1–3) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…an task (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… text fg-0, lines fg-2, Hanken Grotesk 14px), oklch tokens converted to hex on a 1×1 canvas (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…a click target plus a full-size button; one lightbox at the app root (focus on its scroller, Tab cycles, Esc/backdrop/✕ close, focus returns) (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…egory colors, not primaryColor's hue rotation; drop undefined tokens instead of nulling mermaid's keys (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…maidRender.js; Mermaid.jsx re-renders from source for the lightbox (fresh ids), ignores clicks on links inside the diagram, and disables the full-size button until it's drawn (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… a diagram's source for its full-size view, ignore a drag that ends on the backdrop, pure nextFocus, and skip refocus for a detached opener (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…/ re-rendering from source, labelled ⤢ buttons, lightbox under toasts (review of tasks 4–5) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…et_reviewed (thread lock + flock on the review dir for dev/prod, atomic, removes the file when empty, never creates the dir) (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…stop/sig, 404 without a walkthrough or when cleared mid-request); the walkthrough GET carries reviewed (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…htbox needs mousedown+mouseup+click all on the backdrop to close, and caps the font-load wait at 1.5s; test Mermaid's own ⤢ open via options.vnode (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…contents list, stop cards with a diagram row and prose beside the code column, reviewed marks that fold a stop, collapsed comment box (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…f tasks 6–7) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…racing a mark), RecursionError on hand-mangled JSON reads as empty, non-ASCII marks write literally, the walkthrough route's is_file check moves off the event loop (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…1:1 under the light label); chain the lightbox test's options.vnode hook instead of clobbering it (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…000px container fallback, sticky code column, kind-colored cards and tokens, five-step type scale, ≥4.5:1 text, lightbox (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ts at the THI-443 spec, the skill says diagrams render above the text, CLAUDE.md names the spec

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mponentUpdate, not compat's memo, whose global hooks rewrite onChange), evidence and prose memoized per stop, a file block past 300 lines waits behind 'show N lines' and a row or cite click opens it (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n, cancel or send (not when a draft remounts it open), cancel discards the draft, one always-present status note, the link is named for its stop (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…le row ('2 comments · 1 open'), since folding hides the owning pane's replies; tests route comments to their stop and unknown titles to 'unattached comments' (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ne at a time and, when its newest click settles, shows the last server-confirmed mark (seeded from an applied refetch); errors show detail only when it's a string, not FastAPI's 422 list (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…abindex -1), stop and comment headings demote below the stop's h3, each code column is named for its stop and each reviewed toggle described by the stop title, the contents check is role=img 'reviewed', inert cite chips are aria-disabled (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lways-present role=status line), code columns blame the worktree only when the badge does, no empty problem block, 'no stops in this walkthrough', and reveal asks the column's overflow so a static column scrolls the page; tests pin the header PR link (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tdody and others added 18 commits October 29, 2026 15:41
…nt reworded (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…iles over 300 lines start collapsed (review of task 8) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…efetch can't move the open state to another file; stop title ids are stop-<id>__title, which no stop id can equal; cancel is held while a comment sends (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rflow-wrap on unbreakable content, stop head wraps instead of overflowing, one focus-visible ring for the view, card-fill overrides for shared chips/code/table/tok-comment, lightbox and sticky-column polish (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…, .wt-empty-stops, always-present .wt-error/.wt-comment-note hide when empty, a focus-visible ring on the keyboard-focusable stop card, demoted headings brightened to fg-0 (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he a11y tree while empty, legible comment headings, disabled-cancel state, full-contrast table stripes and prose tok-comment/tok-meta, wider breakpoint floor for an 80-char code column, solid lightbox panel, diagram scroll moves to the svg host (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…o wide flowcharts' labels stay legible; the svg host scrolls sideways to it instead of shrinking the drawing (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ars (switch at 1050px); diagrams keep ≥75% of natural width and scroll in their box; the full-size view has a solid panel (browser check) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… mono UI face can't push it past the 1050px switch, diagram sideways-scroll scoping covers a mermaid fence nested in prose, syntax-comment color also covers the problem statement's code (outside any card, on --bg-term), corrected character-count and contrast comments (THI-443)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sh it past the 1050px switch; the code column holds ~70 chars at its floor; the 75% diagram floor holds for wide diagrams (final CSS review) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rmaidRender.js owns init and token conversion, mermaidTheme({color, font}), the sticky column's +32px cap (final review) (THI-443)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ed.json's tmp on any write failure

A lone surrogate round-trips through JSON (ensure_ascii=False) into write_text,
which raises UnicodeEncodeError, not OSError; _check_stop now 400s it before
any file is touched, and the cleanup catches BaseException so a non-OSError
failure still can't leave reviewed.json.tmp behind. Also covers _set_reviewed's
is_file() guard (a dir holding only comments.md) with a dedicated 404 test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ss, keep the lightbox from scrolling the page shut

appliesRefetch(marks, settledAtStart) pulls the untested refetch guard out of
Walkthrough.jsx into a pure, tested helper next to markQueue. closeLightbox
refocuses `from` with preventScroll, since it can be a stop section whose own
scrollIntoView-on-focus would snap the page back to it. wt-stop-body has no
CSS and no test asserting it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ntents list, fold the mermaid-zoom button's position, regroup the radius/kind tokens

.walkthrough .md-doc :is(.md-icode, .md-link) joins the overflow-wrap:
anywhere group, so a long autolinked URL or identifier can't scroll the page
sideways. .wt-intro > .wt-toc gets grid-column: 2 so a contents list with no
problem paragraph lands beside where it belongs, reset to auto under the
1050px single-column switch. The global .md-mermaid-zoom now carries top:
0; right: 0 directly — the walkthrough is the only place it's ever drawn, so
the .walkthrough override styled it twice for nothing. The --kind-* block
moves after --r-lg so it no longer splits the radius tokens.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…43's D6 from the queue spec's, rename vague describe labels

mermaidTheme.js's token conversion moved to mermaidRender.js's tokenHex; the
comment still named Mermaid.jsx. periscope/reviews.py and routes/reviews.py
had a couple of bare "(D6)"s that meant THI-443's D6 (reviewed marks) while
others in the same files already said so and still others correctly mean
the 2026-10-26 spec's D6 (the queue) — now spelled out everywhere THI-443's
is meant. Three vitest describe blocks were tagged "(THI-443 review)", which
names no decision; renamed to what they test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tdody
tdody requested a review from tomplex October 29, 2026 21:06
@tdody

tdody commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

@tomplex, could you review this one? It's a big visual change to the review walkthrough, so I'd suggest trying it locally before reading the diff. The bundle is committed, so there's no build step:

git fetch origin
git worktree add .claude/worktrees/thi-443 origin/thibaultdody/thi-443-review-walkthrough-full-width-layout-legible-diagrams
cd .claude/worktrees/thi-443
PERISCOPE_PORT=17375 PERISCOPE_DEV=1 uv run server.py

Then open http://127.0.0.1:17375/, click ◉ reviews, and open any review that has a walkthrough, ideally one with mermaid diagrams.

Worth trying:

  • a wide and a narrow window, to see two columns vs. one (it switches at about a 1050px pane);
  • ⤢, or a click on a diagram, for the full-size view; Esc closes it;
  • a file row or a path:line chip in the text, which should scroll only the code column;
  • reviewed on a stop, then reload; it stays folded. The dev server shares ~/.claude/reviews with prod, so this writes the real reviewed.json. Unmark it afterwards; unmarking deletes the file;
  • any .md with a pie chart or gitGraph in a file preview: the diagram theme is app-wide now.

When you're done, git worktree remove .claude/worktrees/thi-443.

The spec is in docs/superpowers/specs/2026-10-29-walkthrough-two-column-design.md, if you want the reasoning behind any of it.

…ources

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tdody
tdody merged commit 46834fb into main Nov 4, 2026
2 checks passed
@tdody
tdody deleted the thibaultdody/thi-443-review-walkthrough-full-width-layout-legible-diagrams branch November 4, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant