Skip to content

Viewer M3: review walk, phase overview and Reveal in Diagram - #17

Merged
realmyang merged 16 commits into
mainfrom
viewer-m3-verify
Oct 3, 2026
Merged

realmyang merged 16 commits into
mainfrom
viewer-m3-verify

Conversation

@realmyang

Copy link
Copy Markdown
Owner

Viewer milestone M3 ("verify"), roadmap steps 11–14 of the UX direction approved on 2026-10-01. You can now check a diagram against the code one claim at a time, see all phases at once, and get from a cited line in the editor back to the diagram. Nothing in the WorkflowDocument contract changes, there are no new settings, and the geometry golden is unchanged.

What ships

  • Review walk (step 11).
    • Press r, click Review in the header, or choose ⋯ → Review the claims.
    • The walk goes through every step, connection and finding exactly once, in the order the diagram draws them. Counts: vit-cc 79 = 31 + 41 + 7; yolov5-cc2 176 = 59 + 113 + 4.
    • Filters: Not observed (the default; its count matches the header's), Findings, Changed files (only when a cited file changed) and All claims.
    • Keys:
      • j/k or ↓/↑ step;
      • [/] step through a claim's quotes;
      • u/Shift+U walk the Not observed claims;
      • n/p walk findings;
      • Enter reopens;
      • Escape ends the walk.
    • Each step selects and reveals the claim, and highlights the cited lines in the editor beside it while keyboard focus stays on the diagram.
    • A bar at the foot of the diagram shows your place, with Previous and Next buttons. Its hint reads "In the editor beside: file · lines, highlighted. Focus stays here." At 541 px it shrinks to "3/16".
    • A screen-reader live region announces each step. The walk remembers your place separately for each revision. It records no marks.
    • The stale-files notice gains Review affected claims.
  • Editor side of the walk (step 12).
    • Opens are numbered, sent after a ~150 ms pause, and the editor side drops any request a newer one has overtaken. Ten fast j presses produce one open.
    • A changed, missing or moved file is never opened. The walk shows the reason, with no pop-up notification.
    • The highlight, and any selection MLView made, is cleared when the walk ends or is blocked.
    • The check behind each jump is cached, so a large notebook is no longer re-hashed on every jump. Profile: docs/PERFORMANCE.md.
    • An Escape the viewer handles no longer also reaches VS Code.
  • Phase overview and phase index (step 13).
    • Shift+0 opens one block per phase: its step titles with inferred/unresolved marks and finding labels, "N connections" to the next phase, brackets for links that skip ahead or go back, and "… N more steps" counts that add up.
    • Click a block, or press Enter on it, to move to that phase at readable zoom. Escape returns to where you were.
    • A labelled phase index replaces the minimap and never covers the selected card. Below 1000 px it collapses to a small button.
  • Reveal in Diagram (step 14).
    • Right-click a cited line → MLView: Reveal in Diagram. One claim is revealed directly; when several cite the line, a picker asks which.
    • On an uncited line it says so and offers the nearest cited claims.
    • This is the extension's second contributed command. It has no default keybinding and appears only for files the open diagram cites that are unchanged (resourcePath in mlview.citedFiles). packaging.test.js, activation.test.js and scripts/vsix_check.py change deliberately to name it. There is no hover popup or CodeLens in your editors.
  • Fixes along the way:
    • The Selection pane starts each claim at its top. Before, it kept the previous scroll offset; this bug predates M3.
    • Arrow keys from a connection or finding now move to the right neighbour. Before, they jumped to the first card of phase 1.
    • Hover cards hide while the keyboard moves the diagram.
    • The overview header stays visible while the overview scrolls.
    • The walk bar fits on two rows at 320 px.

The notebook focus loss carried over from M2

In the first M3 live check, the first key pressed after a notebook opened beside the diagram moved keyboard focus out of the diagram, every time it was tried. During the walk that stopped the walk at each switch between the notebook and .py.

Investigation shows the cause is how the check drove VS Code, not MLView:

  • When it happens: only in a window that has never been active since it started (launched while the screen was locked), with keys sent through Chrome's DevTools protocol.
  • Trace: a Chromium trace shows the notebook's output-webview process moving focus to the workbench right after DevTools gives the page focus. No workbench script calls focus() or blur().
  • Windows started while VS Code was the active app: focus was kept in 19 of 19 attempts, in 2 more with another app in front, and through a 79-claim walk.

MLView is unchanged for this, and no focus-recovery code was added.

Please check at your machine (Cmd = Ctrl on Windows/Linux):

  1. Open a notebook from the diagram with Enter, then press Escape. Does the diagram keep the keyboard?
  2. With a notebook just opened from the diagram, switch to another app with Cmd+Tab and back, then press a key. Does the diagram still have the keyboard?

Choices I made (say if you want them changed)

  • Findings that cite no step come last in the walk, in document order.
  • The walk bar sits at the foot of the diagram rather than under the header. Under the header it would have added a fifth Tab stop and broken the M2 four-stop rule.
  • The walk keeps opening files in preview tabs. Reopening a notebook costs about 0.5 s; ordinary tabs would leave one tab open per cited file.
  • At 541 px, a walk step keeps the claim's title in the Selection pane and shows the quote only when both fit, because the editor beside already highlights the quoted lines. [/] bring the quote into view.

How it was checked

All local, on macOS, Node 26:

  • sh scripts/e2e.sh --skip-npm-install: E2E OK, 15 exercised gates (pytest 917 passed, webview 342, extension 350)
  • npm run check && npm test: webview 342/342 pass, vscode-extension 350/350 pass.
  • python tools/verify.py --all: VERIFY OK. python scripts/check_docs.py: OK.
  • Each fix's regression test was run with the fix switched off and failed.
  • Geometry golden: byte-identical at every commit.

Process:

  • Three independent reviews (behaviour, integrity, accessibility/UX) produced 16 findings, all fixed.
  • A second round fixed the live-check defects. An independent verifier then found 4 gaps (docs wording, two missing tests), all closed.
  • Two live checks ran in an isolated VS Code 1.139 Extension Development Host (throwaway profile, driven over the DevTools protocol, never your VS Code profile), on the public vit-cc artifact at about 1382, 900 and 541 px. Verified:
    • the walk beside the notebook, including the burst of fast steps and blocked steps for a changed file;
    • the stale-file flow and restore;
    • the overview and phase index;
    • Reveal in Diagram, including the picker;
    • a regression sweep.

What has not been checked

  • Not checked by a person, with a screen reader, on Windows or Linux, or as a usability check.
  • The live checks ran with the window never active, so focus behaviour in an active window rests on the focus investigation above. It is what you are asked to confirm.
  • yolov5-cc2 was checked only in jsdom and headless Chrome, not live.
  • The pilot keeps the frozen candidate VSIX; nothing was installed into your VS Code.

🤖 Generated with Claude Code

realmyang and others added 16 commits October 2, 2026 20:10
…page

openLocation takes seq, requestId, walk and highlight. The host drops an
open whose seq is not above the last one the page sent, or that a later
open overtook, and answers a request id with an actionResult: done,
blocked (reason and a short message), cancelled or failed. A changed,
missing or otherwise stale file is never opened; a blocked walk open
raises no notification, while Enter, double-click and Open links keep
theirs. A new walk end message clears the cited-range highlight and its
overview-ruler mark, as disposing the panel does. The check behind a jump
is cached per revision and freshness, keyed by the cited file's stat, so
a walk through one notebook hashes it once instead of on every jump.

Escape: VS Code's webview host forwards every keydown to the workbench,
even one the page handled, so a viewer Escape also ran workbench Escape
commands (it hid a visible notification, measured live). The bootstrap
now stops a handled Escape at the document after the mount, the search
box marks its Escape handled, and an Escape with nothing left to dismiss
is left unconsumed so VS Code can use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ebook load

A new CHANGELOG section for viewer M3, a STATUS paragraph, the protocol
notes in webview/README.md, Escape and the jump cache in the extension
README and LLM_WORKFLOW.md, and a dated PERFORMANCE section with the
notebook-jump profiles (single runs in an isolated VS Code 1.139 EDH).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
r (or the header's Review button, or Review the claims in the ... menu)
walks the displayed revision in the diagram's drawn order: each step, its
outgoing connections, then the findings whose first cited step it is.
Findings that cite no step come last, in document order (the roadmap is
silent on them). Every claim is visited once: 79 in vit-cc, 176 in
yolov5-cc2.

- Filters with counts: Not observed (default, the header's count),
  Findings, Changed files (only while the host reports changed or missing
  cited files) and All.
- Keys: j/k and Down/Up step while walking, [ and ] change quote, Enter
  opens again, u/Shift+U go through the claims not observed, n/p follow the
  walk's order; r or Escape ends it (a rung of the Escape cascade before the
  bottom sheet). No Ctrl/Cmd keys; outside the walk nothing changes.
- Each step selects and reveals the claim, shows it in Selection, and after
  150 ms asks the host to open its quote beside the panel (walk, seq,
  requestId; focus kept). Only the latest answer is shown; a blocked one
  puts its reason in the walk bar and under the quote, with no
  notification. A claim with nothing to open sends walk clear.
- The walk bar sits at the foot of the diagram column, above the bottom
  sheet, so the canvas stays within four Tab stops; below 620 px it is
  "3/16", the filters and Exit.
- The place is kept per revision in ViewState.walk; nothing is a verdict.
  The stale notice offers "Review affected claims".
- Host: walk clear clears the highlight; a blocked walk open clears the
  previous claim's highlight.

Tests: test/walk.test.mjs (synthetic vit-cc and yolov5-cc2 shapes),
authoredWalkHandshake (real host with the built bundle), host tests, and
deliberate updates to the header tests for the new row button, menu item
and shortcut rows. Golden unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG (the M3 section), STATUS, README, LLM_WORKFLOW, the webview and
extension READMEs: what the walk visits and in which order, the filters,
the keys, the walk bar, the place per revision, Review affected claims,
the host's walk clear, and what was checked (local tests, plus a short live
run on vit-cc in an isolated Extension Development Host).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shift+0 (or Phase overview in the ... menu) draws every phase as a block
over the canvas, outside the world layer: number, label, step count with
the inferred and unresolved ones, findings touching the phase (PR #14
rule), then the step titles in the Outline's reading order with basis
marks (a drawn dotted ring for inferred, ? for unresolved) and F labels the
severity toggles keep. Arrows join neighbouring phases with "N
connections"; skipped or backward links (adjacent backward ones included)
are brackets on the right, packed into shared slots. A block that does not
fit ends with "... N more steps", so listed + counted = steps per block and
in all, and inside + arrows + brackets = connections. The geometry is pure
(render/phaseoverview.ts): two title columns from 600 px blocks, one
below 620 px, trimmed from the longest block, never below two titles and
the count, scrolling past that.

Arrows, Home and End move between blocks (roving tab stop, screen-reader
names and descriptions); Enter, Space or a click animates to that phase at
reading size (phasePlan, about 240 ms, instant under reduced motion) with
the focus on the canvas, and the next arrow starts at the phase's first
step. Escape, Shift+0 or Back returns to the viewport and focus the reader
had; any other canvas key closes the overview first and then acts.

The labelled phase index replaces the minimap: rows with number, label,
severity counts and step count, phases in view marked, a row going to its
phase; below 1000 px (or a canvas under 350 px tall) a "k/N label" pill
that opens the rows above itself. It sits inside the canvas, above the
bottom sheet, and the viewport treats it as covering the canvas: reveal,
centring, framing a finding's anchor and the visibility test pan the
least distance off it. The ... menu's map item is now Phase index; saved
minimapCollapsed opens the index folded.

Shift+0 no longer folds every group; Fit the whole diagram stays in the
menu. The geometry golden is unchanged. Tests: phase-overview.test.mjs
(geometry at the canvases of 1440x900, 900x800 and 541x798 on synthetic
vit-cc and yolov5-cc2 shapes, counts, link classes, keys, Escape focus,
animation and reduced motion, names, the index never covering the focused
card along arrows, Outline, search, host reveal, findings and the walk),
plus deliberate updates to tests that held the minimap and the old Shift+0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG (the M3 section), STATUS, README, LLM_WORKFLOW, the extension
README and the webview README: Shift+0 and its keys, the counts that sum,
the phase index replacing the overview map (its pill below 1000 px, the
rule that it never covers the card you are on, the ... menu item), Shift+0
no longer folding every group, the 14 stylesheet files and 21 icons, the
new screenshot states, and what was checked (jsdom tests and headless
Chrome screenshots only, not VS Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A second contributed command, MLView: Reveal in Diagram, in the editor
context menu and the Command Palette, gated by a new mlview.citedFile
context key and with no default keybinding. packaging.test and
activation.test change deliberately to name it (the owner-approved
widening of the manifest); scripts/vsix_check.py allows it too.

- Host: each panel builds a citation index from its validated document
  (file -> cited ranges -> steps, connections and findings, counter-
  evidence included), rebuilt on every revalidation. The key is on only
  while a panel is open and the active editor's file is cited, not
  stale, and still has at least one quote at its cited lines (an unsaved
  edit that moves them turns it off, throttled to 150 ms). The editor
  listeners and the key go with the last panel.
- The command finds the claims whose cited lines include the cursor's
  line or overlap the selection: one is revealed at once, several are
  listed in a QuickPick (kind, title, F label, phase, basis, lines), and
  a place no claim cites offers the nearest claims in the file. With
  several diagrams citing the file the reader chooses the diagram first.
  A stale file, unsaved edits that moved the lines, a notebook opened as
  text and the parent-folder case are said plainly. Notebook cell
  editors are supported (cell index as the artifact records it).
- The host posts reveal {kind, id} and calls panel.reveal(undefined,
  false): the one explicit focus move. A page VS Code discarded while
  hidden gets the frame after its next ready, within 5 s.
- Webview: the reveal frame reaches the kept revealNode and revealIssue
  handlers plus a new revealEdge. The claim is selected, its collapsed
  groups open, the Selection tab shows it (a hidden side panel or a
  collapsed sheet opens), and it is brought into view above the sheet and
  clear of the phase index; a connection frames both ends (zooming out,
  not below the frame floor, when the index pushed one out). The shortcut
  sheet, the Refine popover (text kept) and the phase overview close; the
  keyboard lands on the card or connection. Measured live: VS Code's
  focus hand-over left the page on <body>, so for 1.5 s a window focus
  that finds nothing focused puts the keyboard back on the claim.
- The shortcut sheet says how to come back from the code.

Tests: reveal-host.test.js (index, nearest, pick text, the key for
cited, stale, unsaved and closed files, revisions, QuickPicks, several
panels, replay after ready, revision changing mid-pick, notebook cells,
disposal), reveal.test.mjs (frames for the three kinds, malformed and
unknown ids, collapsed groups, focus hold, overlays closing, the walk,
the hidden side panel, and every step and connection on screen at
1440x900, 900x800 and 541x798 on the vit-cc and yolov5-cc2 shapes), and
authoredRevealHandshake over the real host and built bundle. Mutation-
checked. Golden unchanged; no contract change, no new setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG (the M3 section's intro and a "Reveal in Diagram (step 14)"
subsection with what was checked, locally and in an isolated VS Code 1.139
Extension Development Host on macOS), docs/STATUS.md, README.md,
docs/LLM_WORKFLOW.md (the feature and one live-validation checklist item),
vscode-extension/README.md and webview/README.md (the reveal frame,
revealClaim, frameEdge, the focus hold and the replay after ready). The
shortcut sheet's note was updated with the code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Escape, the walk bar

Fixes from an independent review of M3 steps 11-14, each with a test that
fails on the code before it:
- Reveal in Diagram: the `when` clause reads `resourcePath in
  mlview.citedFiles`, a list of the open diagrams' cited, unchanged files,
  instead of a key worked out from the active editor, which was still off
  on a right-click that came straight from the diagram (F1).
- The walk: an explicit filter resumes only its own place (F2); a claim
  that leaves Changed files is replaced by the next one, shown and
  announced (F3); a stale quote never reads "Enter shows" (F4); a late
  answer for a claim the walk left is dropped (A11Y-M3-4); after Alt+Enter
  the bar says the focus moved (A11Y-M3-3).
- Escape over the phase overview goes through the cascade, legend first (F5).
- Review and the menu item focus the diagram (A11Y-M3-1); Previous and
  Next in the walk bar (A11Y-M3-2); the narrow place is screen-reader text
  (A11Y-M3-6); "All claims", one "not opened", a short overview key below
  620 px (A11Y-M3-8); F labels read once, row tooltips and the Review name
  (A11Y-M3-7); the phase index grows to 360 px (A11Y-M3-5).
- The reveal sweep takes every connection (I2).

The geometry golden is unchanged. No contract change, no new setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CHANGELOG (viewer M3 section): a review-fixes block with what was found,
  what changed and how it was checked (jsdom and mock vscode tests run
  against the code before and after, screenshots, and a live context-menu,
  walk-bar and Alt+Enter check in an isolated Extension Development Host).
- Records corrected: a quote with unsaved edits is not opened only when the
  edits no longer contain the cited lines (I1); the reveal check's claim
  matches what it pins (I2); the watcher-load figure says the run created
  and then deleted the files and that its output was not kept (I3).
- STATUS, README, LLM_WORKFLOW and both package READMEs follow the new
  `when` clause, the walk bar's Previous and Next, "All claims", the
  overview key and Escape order, and the wider phase index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cards, the overview header, arrows from a connection

Webview defects from the M3 live check (vit-cc, VS Code 1.139), each
reproduced first in jsdom or headless Chrome:

- W1: a new claim starts the Selection tab at its top (the scroller kept
  the offset of the claim before). The walk then brings the quote's file
  line and walk line into view the least distance, keeping the title when
  both fit; [ and ] use the same rule. Set at once; when the step also opens
  the bottom panel (a 0.01 ms transition under reduced motion), the reveal
  runs again once the pane has its height.
- W2: when the host's stale list changes for the file of a quote it did not
  open, the walk bar and the quote are said again ("Enter shows ..." or the
  new reason); nothing is opened by itself. Blocks for other reasons stay.
- W3: keyboard moves (arrows, e, n/p, zoom, fit, z, Enter on an overview
  block) and walk steps hide the hover card and hold it back until the
  pointer really moves or is pressed.
- W4: the phase overview's header (Back, counts, key) sticks while the
  overview scrolls; a block brought into view sits below it; Home scrolls to
  the top. A header taller than half the overlay scrolls as before.
- W5: from a connection the arrows select the end that lies that way; from
  a finding, as from its first cited step (else its first connection); from
  a folded step, as from its group. They went to the diagram's first card.
- The narrow walk bar is two rows at 320 px (it was four).

webview/test/m3-live.test.mjs adds 14 jsdom tests, all failing on the build
before these fixes; the [ / ] walk test now checks the scroll position.
No contract change, no new setting or keybinding, geometry golden unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The M3 changelog section gets the live-check fixes for the viewer (W1 to W5
and the walk bar at 320 px) with what was checked and what was not, and two
earlier statements that the fixes change (the arrows in the walk, the narrow
bar's rows). docs/STATUS.md and the extension README say what ships.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the review walk ended, moved to a claim it opens nothing for, or did
not open a quote, the host cleared the highlight but the editor kept the
earlier claim's lines selected (inactive-selection colour). The host now
remembers the editor and selection its last jump set; on a walk end, a walk
clear or a blocked walk open, if that editor is still visible and its
selection is exactly the one the jump set, it collapses to the start of the
cited range. A selection the reader changed, an editor no longer shown and
a blocked Enter or Open link are left alone.

walk-host.test.js adds four mock vscode tests (end and clear, the reader's
selection and a hidden editor, a blocked walk open, a notebook cell
editor); the three that collapse fail with the collapse switched off, the
other fails without the equality check. The mock gains an opt-in for
showTextDocument's editor joining visibleTextEditors. The walk message's
comment in webview/src/types.ts says so (no change to the built viewer).

Live (isolated VS Code 1.139 on vit-cc, over DevTools): after r, k,
Escape the notebook cell's lines stayed selected on the build before and
are no longer selected now. No contract change, no new setting or
keybinding, geometry golden unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s selection

The M3 live check's main defect, the diagram losing the keyboard on the
first key after a notebook that was not open had opened, comes from how
that check drove VS Code: it happens only while VS Code is not the active
application and keys arrive over the DevTools protocol (the check ran with
the display asleep). Reproduced in a window started while the screen was
locked (4 of 5 Escapes, 2 of 2 arrow keys and q, a 79-claim walk stopped
at claim 50); not seen in a window of the active application (19 Escapes,
a 79-claim walk). A Chromium trace shows the browser giving the page focus
for the DevTools key, the notebook output webview's process reporting that
the workbench frame took focus, and the browser moving it there; no
workbench script focus() or blur() call and no change on the diagram's
frame. Emulating a focused page in that webview's process prevented it 3
of 3 times. MLView is unchanged for it and adds no recovery; the walk keeps
preview tabs. Not checked by a person, nor after switching applications.

CHANGELOG (M3 section), docs/STATUS.md, the extension README and the
workflow guide also describe the walk releasing its selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and unsaved blocks; wording

- A walk step to another claim keeps the claim's title in the Selection tab
  and shows the quote only when both fit; [ and ] still bring the quote.
- Tests: Home in a short phase overview (header whole only when the first
  block fits), a host block for unsaved edits that stays when its file leaves
  the stale list, and the walk keys from the page body (as after Cmd+1).
- Docs: the notebook focus loss was seen only in a window never active since
  it started; Cmd+1 returns the keyboard to the panel's page body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e test

On the Windows runner the host reads a cited file at its native realpath, the
long form of a temp folder os.tmpdir() spells in 8.3 short form (RUNNER~1), so
comparing path strings counted 0 reads. Test-only change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@realmyang
realmyang merged commit 0138c9e into main Oct 3, 2026
@realmyang
realmyang deleted the viewer-m3-verify branch October 30, 2026 18:42
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