← Qnative (provisional) · c2

review-tour.md

Review stop: the Tour stretch

2026-11-11. Design c131 Phase 2, "Stretch: the Tour guide". The lab's tour layer (design c125 v5 · Panel, with c123's tour type) runs natively over the Inventory section: the engine, one new tour ("What's on this machine"), Info View, and the qpoint-guide MCP driving the window through an endpoint inside the app. Measured against the lab on design :3000 at 1120 × 720 (spec-tour.md). 22 captures in the atlas, thread p2-tour.

How to try it

The tour starts from the guide (or a story); there is no launcher on the pages yet.

  • Run the app: QPOINT_DATA=synthetic cargo run -p app. It logs guide: MCP on http://127.0.0.1:7891/mcp.
  • Connect a harness: claude mcp add --transport http qpoint-guide-native http://127.0.0.1:7891/mcp, then ask it for the tour, or where anything is.
  • Check the map and the tours against the running app: scripts/guide-check.py. It opens all 16 pages and checks every region the map names; then it walks all 9 tour steps and checks each step's targets. 117 of 117 pass.
  • Turn the endpoint off: QPOINT_GUIDE=off. QPOINT_GUIDE_PORT moves it.

What the DOM did, and what stands in

The lab leans onNatively
data-qp-id found by selector, measured every frame.qp_id("models.band") on any element (.key(..) for a row, .text(..) for what it says). A wrapper that adds no layout node: it hands the child's layout to the parent and records the child's box in prepaint into a per-window registry. Bands key their cards, and tables key their rows, by name (models.row, harness.session.row).
A rAF loop re-measuring targetsThe overlay is the window's last deferred draw. Its prepaint commits the frame's boxes, so the dim and the ring paint from this frame with no lag. Callouts are built in render from the last frame. The overlay asks for one more frame only when a box it placed against has moved, so a still tour costs nothing idle.
Ring: a bordered div with a box-shadowTwo quads: 2 px at radius 10, and a 6 px band at 0.3 for the glow.
Dim: an SVG with rounded holesOne even-odd path with a 10 px rounded hole per focus box.
Fade: walk the DOM, set opacity on siblingsThe same path in the page's own background at 0.72. Over that background this is exactly what opacity 0.28 looks like, and the page isn't restyled.
Floating UI + the obstacle scoreplace(): the preferred side, then top, bottom, right and left, -start aligned, shifted to stay 12 px inside the safe area. Each side is scored by its area outside the safe area plus its overlap with obstacles. The callout's size comes from the text system, so there is no frame of lag.
scrollIntoView, the eased glideEach region remembers the scroller it was drawn inside. The glide is the web's: band 80, min(1600, 700 + 0.6·d) ms, ease-in-out quint, and it gives way when the person scrolls.
<html> padding for SplitThe dock is a 420 px column in the window's row; the page narrows beside it.
The rail's data-qp-keyThe kit's sidebar item can't be wrapped, so a zero-size probe in its suffix records the item's row against the sidebar column.
innerText for read-page and pointEach region supplies its own text. A region without any reads as the text of the regions drawn inside it, and a named table reads as its rows.
The dev server's MCP route + an SSE relay to the tabA loopback HTTP server in the app on its own thread: Streamable HTTP with JSON responses, sessions, and Origin checked. It hands each call to the main thread over a channel. Same 16 tool names, same arguments, same instructions (fleet words translated). No tool presses anything.

The pieces

  • Tours as data (crates/app/tours/*.json).
    • c123's Tour type, mirrored in serde: stops, steps, ring, callouts, spots, and blocks (lede, ask, numbers, list, expect, yours, note, route).
    • A step's numbers and texts name facts ({models.top.share}), worked out from the same repositories and period the pages read. A route can name a fact too: the harness step opens the busiest harness's own page.
  • The native tour, "What's on this machine".
    • 7 stops and 9 steps over the Inventory: the overview, Providers, Harnesses, one harness (with three spots), Models, MCP servers, Tools, Skills, Workspaces.
    • Next and Back move through it; a stop marker goes to that stop's first step.
    • The person's own click onto the next step's page advances it (follow the page).
  • The panel, v5 at the spec's numbers.
    • Split (420) or Float (400, radius 14, on the side the web's rule picks).
    • The header: "Tour : name ▾" with the tour menu, minimize, ✕.
    • The stop bar and "n of N", then the label, title and description, the "So, today" line, the spots, and the "on another page" box.
    • Back outlined; Next filled, labelled the web's way.
    • Minimized to the 48 px circle. The lab's placeholder route mark is drawn as paths: the kit's bundled icons have none, and bundling all of Lucide would grow the binary.
  • The unscripted guide.
    • find-in-app searches a native app map (16 pages, 108 regions, 13 concepts for one machine) with the web's scoring, ported as is.
    • The map's rows come from the data: each provider, harness, model, server, skill, tool and workspace on this machine, each opening its own page. The web's are a fixture.
    • open-page rings the way in the sidebar for 1.6 s, then opens the page (1.8 s in all; the web measured 1.75 s).
    • point and highlight ring any region; read-page lists what's on screen.
  • Info View, native first. "Info" in the footer opens a pane that says what the region under the pointer is: the same map entries, the live rows, and a quiet ring on the region. The web hasn't built it (c125 objective 1).

Decided rather than copied (the spec's oddities)

  • A step's callout keeps off the sidebar: the web's safe area lets it sit over the rail.
  • The guide's pointer gets a safe area, and its own region as its one obstacle. The web gives it none.
  • Dark Dim darkens: black at 0.55. The lab's #73858F tint lightens a dark page.
  • Stops are looked up by number, not index.
  • A picked spot keeps its border's width.
  • The first route the window shows isn't a move by the person.

The budget

Release builds, c1's recipe (strobe for 60 s after a 5 s settle, QPOINT_DATA=synthetic), today, the review-stop-3 build (cdf3bf0) interleaved with this one:

Review stop 3The Tour stretch
Binary23.2 MB24.2 MB (+1.05 MB: the guide, the tour, the map and the tour as JSON; tiny_http was already in the tree for the fixture plane)
Private memory, window idle on the overview (the second interleaved pair)62.9 MB63.0 MB
CPU, idle0.006 % of a core0.007 %
Wakes per second1.21.1
A tour open on Providers (Dim, a callout), idle—91 MB, 0.004 %, 0.9 wakes a second
  • A tour costs nothing at idle. The overlay asks for a frame only when a box it placed against has moved. The guide's thread sleeps in accept.
  • The readings drift across a session. The review-stop-3 build read 76 MB earlier today and 62 MB yesterday. One reading of the tour build caught someone using the window: 127 MB, the level the app reaches once every page has been shown, at 7 % of a core. So builds are compared interleaved, in one session.
  • Recordings: rec_c37e45 (stop 3) and rec_29b1ad (the tour build), the second pair; rec_36b9a3 (the tour open).

Open, for you

  1. No launcher on the pages. The tour starts from the guide or a story. The web's launcher is a lab page (/pages/phase4/tours). Natively it could be a button in the sidebar's header, or the overview's.
  2. The docked panel leaves the page 488 px at 1120. The web does the same: its reference capture shows the MCP table clipped. Here the bands' devices overflow at that width (Tokens' legend runs into Spend), which the layer never had to handle. Natively the window could grow by the dock's 420 px when a tour docks and give it back after. Or keep the page narrow and fix the bands' overflow.
  3. The one-prompt run by a real harness is owed. claude -p here failed on the CLI's own expired login, so the guide was driven over MCP by mcp.sh (curl) and guide-check.py. Run claude mcp add --transport http qpoint-guide-native http://127.0.0.1:7891/mcp and ask for the tour.
  4. The endpoint is on by default, on loopback. Any local process can drive the window: it can navigate, ring and point, but never press. For V1: a token, or off unless asked?
  5. Keyboard. As on the web, Esc and the arrows do nothing. Natively ⌘ and ⌘ (or ← →) could move the tour while it has focus.
  6. Waiting at this stop, from your D15–D17 rulings (design c131): recut and rename the worlds, so nina-mbp is the quiet default laptop and priya's is the pilot world; and the settings switch for the world. The first violation tour, the one D15 names, comes with c137. It uses this engine; "What's on this machine" is the plan's Inventory tour.
  7. Not ported:
    • Examples and drills: render functions over live components; natively they would be stories.
    • The tour menu lists only the native tour; the lab's five are governance tours over pages this app doesn't have.
    • The step action (stage, drill).
    • The chrome tint: the native window has no sticky chrome above the scrim except the pinned band, which the safe area already keeps clear of.

Ruled (2026-11-11, design c131 D20) and built

  1. The launcher: a Getting started (Help) section in the sidebar, gathering the tours with the other ways in. Built.
  2. The panel floats, locked to the window's right edge, never docked; resizing reveals what it covers. Built; when a step's highlight is under the panel, the panel says to widen the window.
  3. The real-harness run: done the same evening. Claude Code connected with the token and, from one prompt, started the tour, opened Models by way of the sidebar, pointed at the model list and answered from the live rows. Ten turns, 18 s, no errors, nothing pressed (harness-run.md).
  4. The endpoint stays on, with a per-launch token the agent must present (shown in Help). Built.
  5. Keys while the panel has focus: ← → move, Esc closes, the mouse still works. Built.
  6. The D15–D17 hand-on follows. D15 and D16 are built; D17 and the violation tour wait on qcontrol and c137.

The record is in CYCLE.md, under "Mark's rulings on both review stops, built".

Qpoint Brand Style Guide