Skip to content

Viewer M2: readable at your width (first view, one-row header, claim-first panes, bottom sheet, calm canvas) - #16

Merged
realmyang merged 12 commits into
mainfrom
viewer-m2-readable
Oct 2, 2026
Merged

realmyang merged 12 commits into
mainfrom
viewer-m2-readable

Conversation

@realmyang

Copy link
Copy Markdown
Owner

Milestone M2 of the approved UI/UX direction: make diagrams readable at the width you actually use, beside the code. No pilot records here, so any merge method is fine. No WorkflowDocument contract change and no new settings.

What a reader sees

  • A readable first view. The diagram opens on phase 1 at about 90% zoom, or whole when it fits at 62% or more.

    Diagram 1440 px before → after 900 px 541 px
    vit-cc 48%, 5.8 px titles → 90%, 11.7 px 40% → 90% 17% → 90%
    yolov5-cc2 47% → 84% 39% → 90% 23% → 90%

    Zoomed-out cards show only their title, sized to stay readable without overflowing.

  • One header row. The brand row, toolbar, stage chips and authored header are now a single 36 px row at every width. It holds:

    • the title and the revision;
    • search, severity toggles and "N not observed";
    • a ⋯ menu;
    • Refine….

    The diagram now gets about 93% of the panel height, up from 56–77%. The scope picker and the stage chips are removed.

  • Claim first. The rail's tabs are About · Findings · Selection · Outline.

    • About shows only what the model wrote: the question, its summary split at its own "Data:/Model:" heads, coverage, limitations (once), configuration, cited files with freshness, and provenance. A new revision opens on About.
    • Selection starts with the phase and kind, then the title and the full explanation. Next come findings with "What to change", numbered quotes with freshness, and "comes from / feeds" sentences.
  • Bottom sheet at narrow widths. When a docked rail would leave the canvas under 900 px, a bottom sheet replaces the old hidden drawer. It shows two columns (claim | evidence) from 620 px up and one column below that, and the selected card stays visible above it.

  • A calmer diagram:

    • phases are coloured by order, and no phase colour is near the warning or error hues;
    • only inferred or unresolved claims are marked (dashed or dotted border plus a tag, not colour alone), and connection dashes now mean certainty;
    • connection and border contrast is at least 3:1 in Dark, Light and HC;
    • findings carry F1…Fn labels;
    • every count names its unit;
    • per-phase counts keep the PR Viewer fixes from the Stage 1 review: finding counts, connection hover, direct-only node hover #14 rule;
    • flow animations settle after two passes and respect VS Code's reduce-motion.
  • Editor groups and keys:

    • jumps reuse the existing source group instead of opening a third one;
    • b toggles the rail and t focuses its tabs;
    • the viewer answers no Ctrl/Cmd chord except find, so it no longer fights VS Code's Cmd+B and Cmd+K;
    • macOS labels show ⌘.
  • Behaviour you may notice: hovering a card no longer dims the rest; the cards it connects to get a ring. Focus mode (F) still dims everything else.

Checks

  • sh scripts/e2e.sh --skip-npm-install: E2E OK: 15 exercised gates (pytest 915 passed; webview 241/241; extension 307/307). Node v26.4.0, Python 3.13.15.

  • The geometry golden changed once, deliberately, in da11cfa (the basis chip row came off the cards). Every other commit leaves it byte-identical.

  • Three independent reviews (behaviour, integrity, accessibility and visual design, with before/after screenshots at 1440/900/541 in Dark, Light and HC) found 29 issues: 28 were fixed with regression tests, and 1 was deferred (below).

  • Live checks in an isolated VS Code 1.139 Extension Development Host (throwaway profile, driven over the DevTools protocol; not the owner's VS Code), at 1430, 900 and 541 px beside a notebook:

    • first paint, the header, About, the rail and the sheet;
    • click, Enter and Esc;
    • stale marks, themes and phase colours.

    The first run found 7 problems: a selection hidden after a resize, a third editor group, a phase/amber clash, a stale menu checkmark, macOS key conflicts, a wrapping finding id, and lost state on reopen. All are fixed, and an independent re-check passed all 8 items.

These are behaviour checks, not usability or semantic accuracy. Windows and Linux key behaviour comes from VS Code's bundled keybinding table and was not tried live. Pilot-01 reviews keep the frozen candidate VSIX.

Known and deferred:

  • When a whole diagram fits at 62% or more it opens whole, so a wide panel can show slightly smaller text (72% for one diagram at 1440 px). The threshold was left as approved.
  • After Enter opens a notebook that was not open, the next Escape can move keyboard focus to the workbench. This is older than M2 and is carried to M3.
  • In Light Modern, "muted" text uses VS Code's description colour, which equals the foreground there.
  • Fixed on the way: Space on a selected group toggled it twice (older than M2).

Bundle: mlview.js 289 → 298 KB, mlview.css 62 → 72 KB.

🤖 Generated with Claude Code

realmyang and others added 12 commits October 2, 2026 10:57
… the golden

The one deliberate geometry-golden re-record of M2.

Cause: normalizeWorkflow gave every card attrs={basis}, so every expanded
authored card reserved and drew a 26 px `basis=<basis>` chip row, and every
edge label ended in " · <basis>". Both are gone: MLNode.attrs and
MLEdge.authoredLabel are removed, MLEdge.label is the authored label, and
the card's second line is the authored detail (else the kind), never the
basis. The chip row is now reserved only for a collapsed group's count, so
collapsed groups keep their size and only their labels move. Shorter cards
also change how ranks wrap (MAX_RANK_H is three 72 px cards).

Canvas (world) size, measured in jsdom on the built bundle, before -> after:
- samples/configured_training.mlview.json: 956 x 1734.5 -> 712 x 1592 px
- synthetic 120-step screenshot document:  2086 x 3018 -> 1354 x 3514 px
- renderer-regression fixture, expanded:    954 x 3112 -> 710 x 3464 px
  (cards 98 -> 72 px, 0 overlaps, hidden labels 22 -> 3)
- renderer-regression fixture, collapsed:   482 x 1736 -> 482 x 1736 px
- public shakedown artifacts (not committed): vit-cc 2088 x 2620.5 ->
  2132 x 2480.5 px, yolov5-cc2 2140 x 5503.4 -> 2184 x 5016.5 px

Golden digests: expanded 3710cd67… -> 6f29f6b8…, collapsed dc5ac0b5… ->
bfb42d2c…. The connection's accessible name now says "inferred, not
observed" or "unresolved" for exceptions (route basis from plan.ts), since
the label no longer carries the basis. The SVG export draws the same card.

Checks: webview npm run check && npm test (155 pass); vscode-extension
npm run check && npm test (302 pass); python tools/verify.py --all;
python scripts/check_docs.py. Local checks only, not live VS Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rked, contrast, units, settling flow)

No layout change: the geometry golden is byte-identical (re-recorded only in
da11cfa). No contract change, no new setting.

- Phase colour by document ORDER. GraphIndex.phaseIndexOf() is a phase's
  position among the declared phases; render/phase.ts stamps
  data-phase-index and data-phase-tone (index mod 8) on lanes, cards, groups,
  connections, trunks, minimap dots and phase chips, and node.css binds
  --mlv-stage from the tone. Every authored phase is coloured (before, only
  the eight analyzer stage ids were). Calm: a 3 px lane rule and the card's
  left edge; the icon tile, lane wash and group frame are neutral. High
  contrast uses the contrast border for every tone. data-stage stays.
- Exceptions only. Observed cards and connections carry no basis mark.
  Inferred: dashed border or line plus an "inferred" tag. Unresolved: dotted
  border or line, faint hatch, "? unresolved" tag. The card border is a
  ::after overlay (no layout space); tags and dashes divide by --mlv-z (the
  zoom, rounded to the nearest of 13 buckets) so they keep their size on
  screen. The Outline, hover card and accessible names follow the same rule.
- Edge dashes encode certainty, not kind; one arrowhead marker. The kind stays
  in the hover card, the Inspector and the accessible name, and the legend
  lists the kinds in use with counts. The kind classes stay for the flow layer.
- Contrast (WCAG 1.4.11), computed from the harness theme table
  (webview/tools/screenshots/themes.js, VS Code 1.139) in
  test/calm-canvas.test.mjs. --mlv-edge and --mlv-node-edge are the theme's
  text mixed into its background (54%/46% dark, 64%/58% light):
    connections, Dark Modern: 1.86-3.59:1 by kind (old token at per-kind
      opacity) -> 3.97:1 canvas, 3.69:1 lane, 3.93:1 card
    connections, Light Modern: 1.94-4.59:1 -> 3.87:1 canvas, 3.71:1 lane,
      3.64:1 card
    connections, Dark High Contrast: 10.55:1 (contrast border, unchanged)
    card borders: 1.27 -> 3.26:1 (Dark Modern), 1.26 -> 3.31:1 (Light Modern)
  Phase tones, basis borders and severity-tinted basis borders are >= 3:1 on
  cards and lanes in all three themes.
- Exceptions mode (toolbar toggle "N not observed (3 steps, ...)") fades
  observed cards and connections through fill and stroke only; card text
  stays >= 4.5:1 (tested). Hidden when every claim is observed. It sits after
  the severity chips; under 1000 px the bracket folds into the tooltip and
  under 700 px the toolbar's duplicate step/connection counts give way to the
  status bar.
- Counts: Issue.short is F1..Fn in document order; badges print up to two
  labels then "+N", edge markers name them; tooltips, the Findings list and
  the Inspector show the real id beside the label, and the refine selection
  keeps the real id. Every count names its unit (steps, connections,
  findings, coverage limitations). Lane and Outline phase counts read
  "N findings touch this phase" and keep the PR #14 rule (a finding in two
  phases counts in both; not a partition).
- Motion: motion.ts reads body.vscode-reduce-motion as well as the media query
  and watches the body class; base.css and flow.css honour the class. A hover
  or focus-mode flow runs two passes (finite --mlv-flow-iter per cable, SMIL
  repeatCount=2) and settle() leaves the static marks on animationend;
  Shift+A replays it (keymap and shortcut sheet).
- The SVG export draws the same tags, dashes, lane rule and phase tones.
- Screenshot harness: focus-settled, exceptions and legend states; severity
  chips found by data-severity (their title changed); index.json records the
  flow state, canvas box and bar heights.

Measured with the harness (headless Chrome, simulated host; public shakedown
artifacts, not committed): vit focus mode had 9 lit and 9 moving cables at
0.9 s and 9 lit, 0 moving, data-flow-settled after 7 s. Canvas box, dark
theme, a914f66 -> this commit: 541x798 482 -> 480 px tall (status bar +1 px),
900x800 556 -> 556 px, 1440x900 701 -> 697 px (toolbar 65 -> 68 px: Flow
wraps to the second row). First-paint zoom unchanged except the step 7 card
height (vit 41% -> 40% at 900 px). Bundle 287,766 -> 298,358 bytes, CSS
61,769 -> 66,309 bytes.

Tests: test/calm-canvas.test.mjs (13 new: contrast against the theme table,
faded-text contrast, dash-by-basis rules, marks only on exceptions, phase
tone by order past 8 phases, export parity, F-label mapping and renumbering,
refine keeps the real id, units, toggle, --mlv-z buckets, settle + Shift+A,
pulse repeatCount, reduce-motion class at mount and on change). Updated
expectations, keeping each test's intent: hover (rows now "F1 · f-edge ..."),
finding-counts (lane wording; PR #14 sums 3 > header 2), authored-ui (badge
names F labels), viewer-layout (dotted overlay instead of the dashed icon
tile; legend kinds and one arrowhead instead of per-kind rows),
workflow (Outline marks exceptions only).

Checks: webview npm run check && npm test (168 pass); vscode-extension npm run
check && npm test (302 pass); python tools/verify.py --all; python
scripts/check_docs.py. Local checks only, not live VS Code, not a screen
reader, not a usability check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG (the viewer M2 section), docs/STATUS.md, README.md,
docs/LLM_WORKFLOW.md, vscode-extension/README.md and webview/README.md now
say what the canvas shows: marks only on inferred and unresolved claims, line
style as certainty rather than kind, phase colour by document order, the
"not observed" toggle, F1..Fn finding labels with the real id kept in the
Inspector and Refine prompts, units on every count ("findings touch this
phase" for phase counts), flows that stop after two passes (Shift+A replays)
and VS Code's Reduce Motion setting. webview/README documents the internals
and the new screenshot harness states and facts. The contrast figures are
computed from theme colours, not measured on screen.

Checks: python scripts/check_docs.py; python tools/verify.py --all; webview
npm run check && npm test (168 pass); vscode-extension npm run check &&
npm test (302 pass). Local checks only, not live VS Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No layout change: the geometry golden is byte-identical (the viewport is not
part of it). No contract change, no new setting.

First view (render/canvas.ts readablePlan, pure, next to fitPlan):
- The whole document, centred, when its fit is LOD_FULL_ZOOM (0.62) or more.
- Otherwise phase 1, anchored top-left including the left routing channel:
  fitted when that zoom is PHASE_FIT_MIN_ZOOM (0.75) or more, capped at
  READABLE_ZOOM (0.9); else at 0.9. A document narrower or shorter than the
  canvas at that zoom is centred on that axis. A projection fits whole.
- A viewport saved for the same revision still wins (App.setWorkflow).
- Key 0 re-runs the plan from any zoom (the HOSTS-UX-FITZOOM "whole below
  50 %" rule is gone). The toolbar's "Fit to view" is now "Fit the whole
  diagram" (fitWhole, groups as they are); Shift+0 Overview is unchanged.
  The ... menu item comes with the header step. fitPlan is now only the
  whole-document fit; its tall branch, TALL_SCREENS and MIN_FIT_ZOOM are gone.

First-paint zoom and card-title size on screen, measured with the screenshot
harness (headless Chrome, simulated host, dark theme; public shakedown
artifacts, not committed), 3991f3c -> this commit, at 1440x900 / 900x800 /
541x798:
  vit-cc      48 / 40 / 17 % (5.8 / 4.8 / 2.1 px) -> 90 / 90 / 90 % (11.7 px)
  yolov5-cc2  47 / 39 / 23 % (5.7 / 4.7 / 2.7 px) -> 84 / 90 / 90 % (11.0-11.7)
  dino-copilot 59 / 50 / 35 % (7.1 / 6.0 / 4.2 px) -> 86 / 90 / 90 % (11.2-11.7)
  sample      71 / 56 / 50 % (9.3 / 6.7 / 6.0 px) -> 90 / 90 / 90 % (11.7 px)
  synthetic   50 / 50 / 36 % (6.0 / 6.0 / 4.4 px) -> 80 / 90 / 90 % (10.4-11.7)
At 541x798 the canvas is 541x450-480 under today's header, so 1-6 whole cards
are in view.

Compact level (below 0.62). Prototyped first, as specified, on the real core
with the harness: titles at 11 px / --mlv-z with the existing clamps. vit at
900x800: from 43 % down every visible title overflowed its card's box (12 of
12) and was cut through a line, and the shown lines held 32 % of the title
characters at 43 %, 8-11 % at 21-25 %. So the counter-scale is capped by the
card's own box: .mlv-node__main is a size container and the title is
min(var(--mlv-compact-title) / var(--mlv-z), 100cqh / (lines x 1.15)) with
--mlv-compact-title 11.2px, clamped to 2 lines (3 when data-lines="3"); the
icon tile, detail, file:line and chips are hidden. The bucket rounding keeps
the counter-scale at 10-12.5 px; the cap keeps whole lines inside the
reserved box. No per-card style write, no relayout. Measured (vit, yolov5,
dino, sample, synthetic at 900x800, '-' from 90 %): 10.1-12.2 px from 52 % to
36 %, 8.6-8.9 px at 30 %, 5.0-5.2 px at 17 % (before: 6.3, 4.3, 3.6 and
2.1 px), 0 titles overflowing or cut through a line at any step. Full detail
between 62 and 77 % is unchanged (8.1-10 px). At this level the inferred /
unresolved tag hangs from the card's bottom edge: straddling it, it covered
the title's last line.

Cost (Chrome Performance metrics, script + style + layout, headless,
900x800; descriptive, not a budget), plan-only build -> this commit: wheel
zoom event 0.2 ms median; a bucket crossing 2.7-4.9 -> 2.8-6.4 ms (vit,
yolov5), 6.0-6.7 -> 6.1-8.7 ms (synthetic 120), 38-49 -> 40-60 ms (synthetic
1,000; one 73 ms outlier in four runs); hover 3-4 ms (public artifacts),
26-32 ms (1,000 steps), unchanged. Bundle 298,358 -> 299,037 bytes, CSS
66,309 -> 67,471 bytes.

Tests: test/readable-view.test.mjs (12 new): readablePlan cases compiled from
source with esbuild (whole fit, phase 1 at 0.9 with the channel, phase 1 fit
at 0.75-0.9, the bounds, no lane), first paint = plan, key 0 from 20 % and
200 %, Fit the whole diagram, a restored viewport for the same revision wins,
the shortcut sheet, the compact rules (screen and print read apart), the
compact size recomputed at every compact zoom from the stylesheet's numbers
and cardHeight (10 px or more down to 0.35 / 0.29 / 0.34 for 1 / 2 / 3-line
titles, 0.43 without evidence; never more lines than the box holds), and
--mlv-z buckets without relayout. viewer-layout.test: the refit test keeps
its intent at sizes where the readable plan changes zoom; the "Fit after
widening" test becomes key 0 + Fit the whole diagram; the compact clamp
assertion moved to the new file. Screenshot harness: compact and whole
states and a titles fact.

Docs: CHANGELOG (viewer M2 section), docs/STATUS.md, README.md,
docs/LLM_WORKFLOW.md, vscode-extension/README.md, webview/README.md; the
shortcut sheet (KEYMAP) names 0 "Readable view".

Checks: webview npm run check && npm test (180 pass); vscode-extension npm
run check && npm test (302 pass); python tools/verify.py --all; python
scripts/check_docs.py. Local checks only, not live VS Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The brand row, the 21-control toolbar, the phase chip row and the authored
header become one row of about 36 px: title (ellipsis, whole on hover), a
host · revision chip whose dot turns amber only for stale evidence, search,
the severity toggles counted once, "N not observed" (toggles the exception
emphasis), a ... menu (legend, flow, overview map, side rail, fit whole,
zoom to selection, Export SVG/PNG, Copy SVG, shortcuts) and Refine…, which
names its target by label. The row keeps fewer controls as the panel
narrows (full >= 1200, wide >= 1000, mid >= 620, narrow below); at 541 px
only title, severity, not observed, ... and Refine… stay. The request and
coverage details open over the diagram from the chip or the status bar.

The scope picker, breadcrumb, Inspector scope button, phase chips and the
s, Shift+S, [ and ] keys are removed with their state, CSS and tests; an
older saved ViewState (scope, filters.stages, legacy keys) still loads and
is not written back. The status bar (about 22 px) reads "N steps · M
connections", "Coverage: <status> · K limitations", freshness (muted when
nothing is stale, a warning only for changed or missing files) and the
zoom. Ctrl/Cmd+F focuses search; search rows put the title first under a
count with units; a finding Inspector shows its title once. Chrome icons
are 19 inline SVG paths (no icon font).

Harness chrome above and below the canvas: 203 -> 58 px at 1440x900,
201-244 -> 58 px at 900x800, 299-348 -> 58 px at 541x798. Geometry golden
byte-identical. New test/header-m2.test.mjs; affected tests ported.
Local jsdom tests and headless-Chrome screenshots only, not live VS Code.

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

The rail's tabs are About · Findings (n) · Selection · Outline. A new
revision opens on About; afterwards the reader's tab is kept, saved with
the view and restored for the same revision only. A selection switches to
Selection unless the reader is in Findings or the Outline with the rail on
screen.

About (ui/about.ts) holds authored fields only: the question (clamped,
Show all), the coverage summary split at its own run-in heads when it has
three, coverage in plain words with the limitations listed once, scope,
run configuration with k=v tokens in monospace, the cited files with their
freshness, and provenance with "Model-authored; MLView checks citations,
not the interpretation." It replaces the details panel over the diagram.

The Selection pane (ui/selection.ts) reads claim first for a step, a
connection and a finding: eyebrow, title, a basis note for exceptions
only, detail, findings with What to change, numbered quotes with line
numbers, a muted freshness word and Open, Comes from / Feeds sentences,
Challenge and Refine, one limitations link. Selecting a finding frames
every cited step.

Where a docked rail would leave the canvas under 900 px the rail is a
bottom sheet under the canvas (32 px tab strip, about 47 % open, drag
handle, chevron, Escape), never a drawer over it; opening it does not
refit and keeps the selection in view. Two columns from 620 px. The
shortcut sheet and the Refine popover trap Tab and restore focus; VS
Code's screen-reader class announces the claim and stops motion.

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

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

CHANGELOG (viewer M2 section), docs/STATUS.md, README.md,
docs/LLM_WORKFLOW.md, webview/README.md and vscode-extension/README.md
describe the four tabs, About, the claim-first Selection pane, finding
framing, the bottom sheet below 1260 px, the focus traps and the
screen-reader announcement, with the harness measurements at 1440, 900
and 541 px. Local tests and headless-Chrome screenshots of a simulated
host only; nothing here was tried in live VS Code or with a screen reader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es, canvas

Fixes the independent review of viewer M2 (findings in the commit body ids).

Header and keyboard:
- M2R-1, A11Y-1, A11Y-3: RovingGroup skips controls with no client rects
  (CSS display:none) while its container is rendered, takes non-items out
  of the Tab order and keeps the stop where the user left it; search result
  options carry tabindex=-1.
- M2R-2, A11Y-8: Chrome.fitRow measures the row after each change and folds
  the revision chip, then "not observed" (into the ... menu), then the
  title, and only while search is open at mid/narrow the severity toggles
  (data-fit 0-4).
- M2-INT-2, A11Y-5: "findings" after the severity toggles; "N claims not
  observed" below full, the breakdown at full.
- A11Y-12: an off toggle is struck through and dashed, not faded.
- A11Y-2: .mlv-root .mlv-btn--primary takes --mlv-on-accent; HC border.
- M2R-9: Ctrl/Cmd+F and +K stay inside the shortcut sheet and the composer.
- M2R-11: beside the code a stale warning keeps its width.

Selection and rail:
- M2-INT-1: the M1 rule is back: canvas, search, pane links and host reveal
  show Selection; only a selection from the list on screen (fromList)
  keeps Findings or Outline.
- M2R-3: a search hit for a step shows its claim (opens the sheet).
- M2R-5: a claim read in the docked rail stays open into the sheet.
- M2R-6: a group's pane lists subtree findings, its steps and the
  connections across its edge.
- M2R-7, A11Y-4: no basis mark for observed findings in the rail.
- M2R-8: a finding frames cited steps and connection ends when they fit
  at 0.45, else the steps.
- M2R-10: sheet handle aria-valuemax follows the canvas floor; a drag that
  collapses keeps the earlier height.
- A11Y-10: steps/connections in announcements; n/p lead with the F label.

Canvas (cardmetrics and layout unchanged; geometry golden byte-identical):
- M2R-4: "· N findings touch this phase" after the lane's numbers (DOM, SVG).
- A11Y-6: cards with a detail draw two detail lines instead of file:line.
- A11Y-9: a hover dims nothing; focus mode still fades and disables.
- A11Y-11: numbered lane heading in text colour at 13 px on a plate;
  Outline numbers phases and puts the count on its own line.

Cleanup:
- M2-INT-5: the benchmarks drop scope timings and export via the ... menu.
- M2-INT-6: removed hidesNode/isFilteredOut/.is-filtered, streamEligible,
  --mlv-fg-boundary and fgBoundary, base64ToBytes/MIME, viewportRect and
  the 'view' export region (exportFile.scope is 'all').

Tests: webview/test/m2-review.test.mjs (20 tests) plus updated existing
tests; each new assertion was run against the pre-fix build and failed.
test/helpers.mjs adds cascadeWinner for specificity-dependent CSS.

Checks run: webview npm run check && npm test (229 pass);
vscode-extension npm run check && npm test (302 pass);
python tools/verify.py --all; python scripts/check_docs.py;
python -m pytest tools scripts -q (483 pass); both benchmarks ran
(node --expose-gc tools/benchmark-workflow.mjs 100, benchmark.html in
headless Chrome). Header, Tab order and status bar probed in headless
Chrome on a simulated host. Local checks only: not live VS Code, not a
screen reader, not a usability or semantic check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CHANGELOG: a "Review fixes" list in the viewer M2 section; earlier step
  bullets now describe what ships (the header toggle instead of the
  toolbar, Fit the whole diagram in the ... menu, About instead of details
  over the diagram, the restored tab rule, "not tried with a screen
  reader"), and the compactness claim names the documents that grew taller
  (M2-INT-4).
- docs/STATUS.md: "severity filters and focus mode" instead of scope
  filters (M2-INT-3), and a review-fixes paragraph.
- docs/PERFORMANCE.md: the benchmarks no longer time scope or reset; the
  dated scope columns are historical (M2-INT-5).
- README.md, docs/LLM_WORKFLOW.md, vscode-extension/README.md: the tab rule,
  the header fold, the group pane, lane headings, card face and hover.
- webview/README.md: roving items, Chrome.fitRow and data-fit, data-folded
  menu items, fromList, frameIssue, the sheet cap, the group pane, the
  canvas changes, the removed dead code and cascadeWinner.

Checks run: python scripts/check_docs.py (OK); python tools/verify.py --all
(OK). Documentation only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds, restore

Seven problems a live check in an isolated VS Code 1.139 Extension Development
Host on macOS found, each with a regression test that fails on the build
before the fix:

1. A resize or rail change that hides a selection which was in view pans the
   least distance that shows it again, at the same zoom, without refitting
   (ViewportController.revealRect); a selection already out of view stays.
2. A jump opens the source in an existing editor group other than the
   panel's own: the group showing the file, the previous jump's, the last
   one used, then the nearest; Beside only for a diagram alone. Notebook
   cell editors report no column, which sent M1's rule to Beside.
3. Phase tones 2 and 3 move off the warning amber and the error red; no tone
   is within 30 degrees of HSL or OKLCH hue of editorWarning, the stale mark
   or editorError in the harness themes.
4. The overview map item is disabled and unchecked, with the reason, while
   the map is not drawn; the 900 px rule moved from a media query to
   CanvasView.setPanelWidth so both agree.
5. The viewer answers no Ctrl/Cmd chord but the find key, since VS Code acts
   on them too: b toggles the rail, t focuses the rail tabs, Ctrl/Cmd+K is
   gone, and keyLabel prints keys per platform.
6. A finding's id under "Findings on this step" is a muted monospace line
   under the title instead of a narrow column that broke letter by letter.
7. ViewState.sheetOpen records an open sheet, and a remount of the same
   revision restores the selection and the sheet with the tab.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG M2 gains a live-check fixes block and its superseded bullets
(search keys, Ctrl+1 to Ctrl+4, the real id, phase tones, the testing scope)
now say what ships; STATUS, LLM_WORKFLOW, the extension README and the
webview README describe the editor-group rule, the single-key shortcuts,
the overview map's reason, the id line and the restored selection and sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The card's keydown handler toggled the group and the canvas's Space
(collapse the selected group) toggled it back, so nothing happened. The
card now stops the event, as it already did for Enter. Found by the M2
live re-check; older than M2. A test pins it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@realmyang
realmyang merged commit 35fef41 into main Oct 2, 2026
@realmyang
realmyang deleted the viewer-m2-readable 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