review-3.md
Review stop 3: the section, the scorecard, the budget
2026-11-10. Design c131 Phase 2, step 6 ("How close we got"). The Inventory section is native: the overview and all seven listings with their detail pages (Providers with the account page, Harnesses, Models, MCP Servers, Skills, Tools, Repos & Workspaces), on priya-x1's world, in the Qpoint skin, light and dark. The table expand row (the extra stretch) and the skill file are in the layer. The qnative atlas on the design site holds 69 captures from this phase: 47 of app pages, 9 doc pages, 6 of the skin, 5 data components, the ranked bars and the scorecard.
The section
| Listing | Detail | Captures |
|---|---|---|
| Providers | provider, account | p2-providers |
| Harnesses | harness (merged with the install detail) | review stop 2 |
| Models | model | p2-models |
| MCP Servers | server | p2-mcp |
| Tools | tool, with the expand row | p2-tools |
| Skills | skill, with the skill file | p2-skills |
| Repos & Workspaces | workspace | p2-workspaces |
Each page was built from a spec measured on qdash :3030 at 1120 × 720, compared with the web, and fixed. Fleet → personal held for every page:
- users, hosts, teams and orgs leave;
- instances read as harness types;
- each web oddity was decided rather than copied, and the decision is in CYCLE.md.
The scorecard
36 rows, one per web layer component the section uses (crates/layer/src/scorecard.rs; Dev › Components › Scorecard shows them all, and each doc page shows its own).
| How it was built | Rows | Fidelity |
|---|---|---|
| Drawn with GPUI primitives | 30 | 28 at 3, 2 at 2 |
| The kit, as is | 2 | UxIcon (Lucide), UxTabGroup (TabBar, segmented) |
| Composed from the kit | 0 | — |
| Not built yet | 3 | AgentPawn, UxAvatar, UxSelectInline: no page needed them (Skills uses a segmented switch where the web has a select) |
| Translated away | 1 | PeopleOwnerCard: on one machine the owner is you |
Fidelity 2, and why:
- DataRankedBars: stacked labels end in an ellipsis where the web breaks words. GPUI wraps only at word breaks.
- Skill Markdown: text runs carry no border, so placeholders and shell spans are tinted instead of outlined. The web's own outlines don't render either.
What the kit had and what it didn't. The kit carried the shell:
- the title bar, the sidebar, scrolling, the spinner;
- Lucide, the whole catalog;
- the segmented tabs.
None of our vocabulary is in the kit. Its DataTable is a different design: fixed-height virtual rows and its own look. So every component the pages are made of was drawn, and 28 of the 30 came out indistinguishable from the web at a glance.
The HTML and CSS the kit lacked, and what stood in:
- Grid layout. Subgrid,
fit-content,auto-fill minmax,auto auto 1frand table auto layout became flex tracks with fixed row heights. Where a width had to be known, a zero-height probe learns it, one frame late. - Sticky and scroll. For
position: sticky, the page reads its own scroll offset and draws a pinned copy in an overlay. Scroll-spy andscrollIntoViewread the scroll handle. - SVG. Polylines, arcs and
currentColorlogos became canvas paths and recoloured images, cached per logo and colour. - Text.
break-wordsbecame an ellipsis. Inline outlines became tints. highlight.js became a line tokenizer for the four grammars the web registers, mapped to the web's token table. No syntect: the plan's budget worry did not come true. - Interaction.
- The native
<select>became a click that cycles. - The Headless UI popover became anchored and deferred.
- The expand row: per-row reactive refs became page-held open keys, which fixes the web's closing on sort. StretchBox's measured height became an animated max height with the same easing.
- The native
- Not ported yet:
- keyboard focus on the file tree and the expand row;
- the sticky thead;
- the skeleton pulse.
Effort and lines of code. The whole phase ran on 2026-11-10: from the kick-off to the section complete, eleven commits between 17:37 and 20:35. The layer is 7,913 lines:
| Part | Lines | What |
|---|---|---|
editor.rs | 954 | EditorFrame, FileTree, CodeBlock with its tokenizer, the Markdown preview |
data/devices.rs | 765 | DataRankedBars, DataSegmentBar, DataMetricSpark, DataDonutChart |
table.rs | 737 | DataTable, DataListingBar, the expand row |
data/machine.rs | 629 | DataMachine, Group, Micro, IndexSection |
ux.rs | 503 | pills, chips, avatars, honest empty states |
data/surface.rs | 487 | the Surface family |
nav.rs | 467 | PageHeader, ActorHeader, NavJumpPills |
data/{value,format,palette}.rs | 648 | number formats (Intl compact, money, ago), the palette |
| theme, tokens, fonts, scorecard, lib | 454 | the token bridge and the Qpoint theme |
demos/ | 2,250 | the doc pages, every scenario live |
The app's pages, router, shell and Dev section come to 5,840 lines on top. types is 3,109 lines, generated from qdash's TypeScript.
What it says about c130 D5 and c131 R8 (a tokens-only brand; a kit component before a drawn one): taken literally, a tokens-only brand on the kit's components gives the kit's design in our colours. The pages reached ours because the layer was drawn: about 5,400 lines of components, at fidelity 3 for 28 of 30. The ruling for V1 is yours:
- keep D5, and accept the kit's look;
- or amend it to "our layer, drawn on GPUI, the kit for the shell". That is what this phase built.
The budget
Both release builds were measured in one session on one display: c1's spike (4b24a2a) and this phase (044bc32 plus the walk hook). c1's recipe was used (README Footprint): strobe 0.26.0 attached by PID for 60 s after a 5 s settle, footprint and ps as the cross-check, QPOINT_DATA=synthetic, idle with no pointer, awake and unlocked. Startup is the app's own clock from main to the first render, the median of three cold starts. strobe's insights flagged nothing in any recording.
| c1, the spike | c2, the section | Change | |
|---|---|---|---|
| Binary (release, stripped) | 17.9 MB | 23.2 MB | +5.3 MB |
| Private memory, window, idle on the first page | 51 MB | 62 MB | +11 MB |
| … after every page shown once | — | 116 MB | +54 MB over the first page |
| RSS, window | 62 MB | 76 MB · 91 MB after the walk | |
| Private memory, tray only | 15 MB | 21 MB | +6 MB |
| CPU, idle | 0.005 % of a core (3.0 ms in 60 s) | 0.005 % (2.9 ms) · 0.003 % after the walk | none |
| Wakes per second | 0.88 | 0.90 · 0.75 after the walk | none |
| Startup | 262 ms (257, 262, 277) | 254 ms (247, 254, 266) | none, within noise |
- The binary.
- About 1.1 MB of the growth is assets:
- the three bundled worlds, +0.85 MB;
- five static Inter faces in place of two variable ones, +0.2 MB;
- the logos, 50 KB.
- The other ~4.2 MB is code: the layer, the pages, the generated types with their serde.
- No syntect: the tokenizer is ours.
- About 1.1 MB of the growth is assets:
- Memory at rest is 11 MB over the spike on a page that shows far more.
- The walk (
QPOINT_SPIKE_WALK_AFTER) shows all 16 Inventory pages, 2 s each, and returns to the overview.- Private memory goes from 62 MB to 116 MB.
- 46 MB of the growth is GPU memory: IOSurface +26 MB, IOAccelerator +20 MB. The heap grows 8 MB.
- Four walks in a row read 125, 127, 125 and 129 MB, so it is not a leak. It levels off after the first walk.
- It fits GPUI's atlases (glyphs at each size and weight, the logo images, canvas paths) filling once and staying. The kit never shrinks them.
- The repository holds no cache, and the shell keeps only the page on screen.
- This is the V1 budget's real line item. Whether to release the atlases when the window closes to the tray is a question for V1.
- The spike's display spread: today's c1 window reading (51 MB) sits with its 11-09 reading (52 MB), not the 11-10 one (80 MB). Per-display rows are still owed.
- Recordings:
rec_efd19b(c1, window);rec_1e4cd5(c2, window);rec_b2e442(c2, after the walk);rec_141fce(c1, tray);rec_6ab80f(c2, tray).
Open, for you
- The brand ruling (c130 D5, c131 R8), from the scorecard above. Keep tokens-only on the kit's components, or amend to "our layer drawn on GPUI, the kit for the shell"?
- Side-by-side captures on one world. The plan restarts the
:7882seed on the one-host database for one capture run, so:3030shows the same rows as the native pages. That restarts a server other sessions use, so it has not been done. So far each page was measured against qdash on the fleet world at the same size. Run the restart, or are the measured specs enough? - The extra stretch, read against its full list.
- Done: the expand row at fidelity 3 to the eye, open rows held on stable keys, horizontal scroll only when the table is too wide.
- Not done: columns sized to content across every row (declared widths stand in), the height re-tracked when nested rows open, quiet nested rows, the new-row flash, the sticky header, and keyboard with AccessKit.
- Per-page calls left with you:
- git captured locally for workspaces (cheap on one machine);
- the real SKILL.md bytes, or a bundle's contents, shown locally;
- one arbitrary provider per model, a server limit;
- OAuth on an MCP server, kept as the fleet-wide event it is served as;
- the skill runtime ledgers, which wait for data.
- The budget's atlases: keep them, or release them when the window closes to the tray (V1).
Next, unless you redirect: the Tour stretch. That is the guide engine with qp_id targets, focus and the docked panel, Info View, and the qpoint-guide MCP driving the native app over an in-process loopback server.
Ruled (2026-11-11, design c131 D18–D19) and built
- The brand (D18): our layer drawn on GPUI with our tokens; the kit keeps the shell. The scorecard is ratified as built.
- Side-by-sides: no seed restart; the measured specs stand.
- The extra stretch: all four remaining items are done: the sticky header, keyboard and AccessKit, content-sized columns with the height re-tracked, and quiet nested rows with the new-row flash.
- The five per-page calls: accepted as proposed.
- The atlases: GPUI frees the GPU atlases with the window. The app now also releases its caches and the allocator's free pages on close. The tray after a walk and a close is 48 MB; a tray-only start is 22.
The record is in CYCLE.md, under "Mark's rulings on both review stops, built".