qdash TODOs — 2026-09-25 review
Execute Mark's 2026-09-25 product-review notes on the qdash UI, one page at a time, through the `/todos` process (c94)
Why
The 2026-09-25 review walked fourteen qdash pages and left a #QPT-Product block in the Logseq journal. c92 carried the previous two sheets (2026-09-23, 2026-09-24); c92 is now a long umbrella, so this sheet gets its own cycle. The process is the one c94 codified and the 2026-09-24 run proved: one plan per page, a preview Mark corrects before each page, one executor per plan, a review after.
Objective
- Ingest the 2026-09-25 journal block (verbatim in the README, four images copied to
assets/). - One plan per page under
todos-2026-09-25/with shared ground, run order, and decisions with defaults. - Baselines of every page in the sheet before any edit.
- Execute serially — preview → executor → review — with a record line per plan (no twin — R.4, after the move to the Fable app) and before/after shots published to the atlas.
Done looks like: every plan has an executed (or skipped) line here, its work committed (or on disk with the reason), and the Later list handed on.
Scope
- Design: this cycle directory;
scripts/shot-programs/todos-pages.json(routes refreshed for the/team/move);.claude/skills/todos/reference/pages.md(registry rows refreshed). - qdash UI pages: Harness, Endpoints, Model, Sessions, MCP servers, MCP server, Skills, Skill, Tools, Tool, Workspace, Teams, Team, Users — plus their band helpers and tests;
crates/qdash/src/web.rsonly where a plan needs a field. - Out of scope: the "execution session — Later" list in the same journal (User/Endpoint card, trigger-bar column picker design, Harnesses component refinement, consistent status pills) — listed in the README, not planned; Fleet overview and Inventory (marked "ignore").
Key Changes
todos-2026-09-25 planned (2026-09-29): Mark's 2026-09-25 product-review notes (journal 2026_09_25, #QPT-Product) turned into 15 per-page plans under todos-2026-09-25/ by seven parallel plan writers — README (shared ground, run order, 48 decisions with defaults) + 00-sweep (nothing to sweep; owners for four cross-page renames) + 01-harness (Installs rename, Versions · Skills up, egress panel; builds #after-<axis> Surface slots) · 02-endpoints (OS rolldown: no empty buckets, biggest first) · 03-model (More detail / default section out) · 04-sessions (exit/flags out, endpoint in, model + tools after user) · 05-mcp-servers / 06-mcp-server (MCP Servers · Tool Calls · Tools Used; Installs; More detail out) · 07-skills (Installs first; variable tile's title becomes its dropdown — layer 0.9.23, runs last) · 08-skill (Reach row out, host → endpoint, person → user, harness-detail column out) · 09-tools / 10-tool (type, Success Rate; Harnesses table trimmed; arguments → session link) · 11-workspace (Teams beside Users, Tools beside Skills; ordered only) · 12-teams / 13-team (Coverage via sensorCoverage(); Monitored Harnesses; Surface reordered) · 14-users (devices → Endpoints; attention card by reason). Registry refreshed for the /team/ move; shot program routes refreshed, mcp-servers + team added. Baselines wait on R.1 (:3030 proxies the live monitor, not the seed).
todos-2026-09-25 re-targeted (2026-09-30, Mark): "do your work on the Fable branch running on port 3032" — every plan re-written in place by seven parallel writers against the c99 Fable-track app (qcontrol-c99-fable, branch c99/claude-code-fable-5.1, crates/qdash/apps/claude-code-fable-5.1/, :3032 → seed :7882), holding the c99 data-interface bible (thin pages → context components → composables → lib rollups; R3/R4/R9/R17/R24). README shared ground rewritten; R.1 resolved (the Fable app reads its own seed), new R.3 (backend + layer read-only on this branch → 01.1 egress blocked, 10.1 alt blocked) and R.4 (this record only, no twin). Plan 07 no longer needs a layer release — c100's uncommitted layer change already carries DataMachine #title — so the run is plain sheet order. Baselines of all 14 pages captured from :3032 into todos-2026-09-25/baselines/. Test baseline: 539 + bible-check clean.
todos plan 01 executed (2026-09-30): Harness (todos-2026-09-25/01-harness.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Installs: the ledger heading (HarnessInstallsLedger.vue) and its jump pill (pages/inventory/harnesses/detail.vue SECTIONS) read Installs — this page only (01.2). Surface seats (shared, plans 11 and 13 build on it): surfaceSeats() in lib/surface-rollups.ts gives one seat per AXIS_ORDER axis (its panel when served, else none) — AXIS_ORDER's first real use; useSurface / surfaceView return seats; components/surface/Section.vue renders each seat's panel then an #after-<axis> slot (rendered whether or not the axis is served), default slot still last, so every other caller is unchanged. Order: Teams moved out of HarnessSurfacePanels.vue into a new fed HarnessTeamsPanel.vue (seated #after-users; plan 11 swaps it for SurfaceTeamsPanel); Versions · Skills seated #after-tools. On claude-cli the Surface now reads Models · MCP Servers / Repos & Workspaces · Tools / Versions (2 versions, v2.1.166 older) · Skills (7 distinct) / Users (14 people) · Teams (4 teams) — was Users · Teams above Versions · Skills; no Network Egress panel. Verified headless: after shot todos-2026-09-25/after/harness.png + -full, published as public/cycles/design/c102-todos0925-harness-{before,after}.png; Workspace, User and Harness-install detail still end on Skills; Team and Endpoint detail Surfaces unchanged (DOM read). npm test 539 → 540 (+1 surfaceSeats) + bible-check clean. Gotcha: :3032 first served a stale page transform that couldn't resolve the new component (Vue "Failed to resolve component" and no Teams panel); bumping the page's mtime fixed it, with no restart. Blocked (R.3): 01.1 network egress on the adapter surface needs the web.rs:5817 gate change (§D) — not done; the front end names no egress. Committed 780eea16 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 02 executed (2026-09-30): Endpoints (todos-2026-09-25/02-endpoints.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Endpoint Hosts rolldown: endpointsBand().osBars in lib/actor-bands.ts now keeps only buckets that hold a host and ranks them biggest first (stable sort — ties keep Mark's order, so unknown is last among equals); osSegments keep the fixed OS_BUCKETS order and their zeros (docblock says so); EndpointsBand.vue and the page unchanged (R4). This reverses the "zeros keep the shape stable" half of c92 decision 03.2; the unknown-bucket half stands. Decisions on defaults: 02.1 unknown ranked like any bucket; 02.2 keep the single unknown bar. On the seed (/api/endpoints?period=30d: 14 hosts, os: null on all 14) the tile now reads one full-width bar unknown 14 — was macOS 0 · Windows 0 · Linux 0 · Containers 0 · unknown 14; value 14, provenance "OS not reported yet — every host counts as unknown", Install Coverage (100 %, 9 fully · 5 partial · 0 unmonitored) and the ledger unchanged (the ledger sits higher by the four removed rows). Verified headless: after shot todos-2026-09-25/after/endpoints.png + -full, published as public/cycles/design/c102-todos0925-endpoints-{before,after}.png. lib/actor-bands.test.ts: the OS test re-worded and its bar expectations updated, +1 ranks OS bars biggest first, unknown included — npm test 540 → 541 + bible-check clean. Committed 9d99b827 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 03 executed (2026-09-30): Model (todos-2026-09-25/03-model.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). More detail removed: the at-rest appliance components/inventory/ModelDefaultOn.vue (heading "More detail", the "Configured as default" panel — 22 rows for claude-sonnet-4-6) is deleted with its mount in pages/inventory/models/detail.vue, its feed (useModel().defaultRows in composables/inventory/models.ts) and its rollup (modelDefaultRows / ModelDefaultRow in lib/model-rollups.ts). Jump pills removed (03.2 default): with one section left, the sticky NavJumpPills strip and SECTIONS go; the tiles' mb-8 separates the band from the Harnesses heading. Backend untouched (03.1 default, R.3): /api/models?model=claude-sonnet-4-6 still serves default_on (22 rows); types/api/model.ts keeps the field, marked "served, not rendered". The at-rest default stays visible on Endpoint detail's install config and Harness detail's default_models. On the seed the page now reads header (claude-sonnet-4-6, Anthropic, $1956.24) → tiles API requests 2.9k · Tokens 100m · Spend $1956.24 → Harnesses (3: claude-cli 72.7M · cursor-cli 19.7M · claude-desktop 7.62M tokens) and nothing below. Verified headless: after shot todos-2026-09-25/after/model.png + -full, published as public/cycles/design/c102-todos0925-model-{before,after}.png; no page error after the component delete (no HMR touch needed). lib/model-rollups.test.ts −1 modelDefaultRows — npm test 541 → 540 + bible-check clean. Committed 5493bb4f on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 04 executed (2026-09-30): Sessions (todos-2026-09-25/04-sessions.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). One file: the fed appliance components/team/SessionsLedger.vue (page, useSessionList(), sessionRow() and sessionsBand() untouched). Columns (04.2 + 04.3 defaults): harness · user · model · tools · session · started · duration · workspace · endpoint · cost (was harness · user · session · started · duration · workspace · model · tools · cost · exit · flags) — exit and flags (denied / sensitive / DLP pills) and their slots are gone; endpoint is new, the served host rendered as ▭ <host> mono linking to /team/endpoints/detail?host= with @click.stop (the AccountSessions idiom, ENTITY_GLYPH from utils/entity-chip). Quick filters (04.1 default): filterKey: 'status' moved onto duration and 'flagged' onto session, so the listing strip still offers Status and Flagged; risk / statusLabel stay on SessionRow, nothing in lib/ or composables/ went unused. On the seed the first row reads Claude Code · marcus@meridian.dev · claude-haiku-4-5 · 9 · f7fa1734 · 91d ago · 7m 45s · payments-core · ▭ marcus-fw · $5.85; the tiles (Sessions 52 · Tokens 24m · Flagged 7, Past 7 days) and the per-day history are unchanged. Verified headless: after shot todos-2026-09-25/after/sessions.png + -full, published as public/cycles/design/c102-todos0925-sessions-{before,after}.png; in the browser pane the strip's key select lists Status · Flagged, the endpoint cell lands on /team/endpoints/detail?host=marcus-fw, and ?flagged=1 shows 7 rows (the tile's 7 under the 7-day pill; the plan's 31 was a 30-day figure). User / Team / Workspace / Harness-install session tables keep their own exit/flags columns (not in the sheet). npm test 540, delta 0 + bible-check clean. Committed 2c072629 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 05 executed (2026-09-30): MCP servers (todos-2026-09-25/05-mcp-servers.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Tiles (05.1 · 05.2 · 05.3 defaults, R.2 title case): the fed appliance components/inventory/McpServersBand.vue retitles Servers → MCP Servers, Calls → Tool Calls, Tools exposed → Tools Used — labels only; values, provenance, to and every key stay (page, useMcpServerList(), McpServersLedger.vue untouched; ledger headers keep calls / tools and initialSort="calls"). lib/actor-bands.ts mcpBand().tools gains a doc comment: the served tools is COUNT(DISTINCT tool_name) over calls in the window, so "Used" is the honest word and nothing advertised is captured. On the seed at the default Past 7 days the band reads MCP Servers 5 (5 observed · 0 configured-only) · Tool Calls 113 (linear 29 · sentry 27 · postgres-readonly 21; top 3 = 68 %, 72 harness-server pairs) · Tools Used 11 (github 3 · linear 2 · playwright 2; top 3 = 64 %), matching curl 'localhost:7882/api/mcp-servers?period=7d'. Verified headless: after shot todos-2026-09-25/after/mcp-servers.png + -full, published as public/cycles/design/c102-todos0925-mcp-servers-{before,after}.png. Plan 06 reuses Tool Calls / Tools Used on the detail. npm test 540, delta 0 + bible-check clean. Committed 39552951 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 05 corrected (2026-09-30, Mark): "MCP Servers should be Count" — the listing's first tile is titled Count (was MCP Servers; 05.1's reading flipped), value unchanged (5). Fable 169111ba; after shot republished.
todos plan 06 executed (2026-09-30): MCP server detail (todos-2026-09-25/06-mcp-server.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Tiles (plan 05's words, R.2): the fed appliance components/inventory/McpServerTiles.vue retitles Calls → Tool Calls, Tools exposed → Tools Used, Configured on → Installs — labels only; Denied, values, provenance and the keys band.calls / band.tools / band.configured stay; lib/detail-bands.ts serverBand() gains doc comments on tools and configured. On linear (all-time) the row reads Tool Calls 226 (2 distinct tools · by 32 harnesses) · Denied 0 · Tools Used 2 (update_issue 118 · list_issues 108) · Installs 27 (11 hosts · transports: http); gap sentence unchanged (configured on 11 hosts · called from 14 · 0 configured but never called · 3 called without config). More detail removed (06.2 default): McpServerConfig.vue deleted with its mount in pages/inventory/mcp-servers/detail.vue, configRows out of useMcpServer(), serverConfigRows / ServerConfigRow out of lib/mcp-server-rollups.ts with their spec (−1); the page now ends at the Harnesses ledger. config stays on /api/mcp-servers?server= and in the contract type — it still feeds the Installs provenance and gap sentence; per-install url / command and env / header key names no longer render anywhere. 06.1 default: header Meta Configured on · 27 installs kept (behind Show All Metadata). Verified headless: after shot todos-2026-09-25/after/mcp-server.png + -full, published as public/cycles/design/c102-todos0925-mcp-server-{before,after}.png. npm test 539 (540 − 1) + bible-check clean. Committed 6774dcab on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 07 executed (2026-09-30): Skills listing (todos-2026-09-25/07-skills.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Order (§A): the fed appliance components/inventory/SkillsBand.vue moves the Skills tile after Invocations — tiles left→right Installs · Invocations · Skills by team ▾ (markup only; DataMachineGroup subgrid, sm:grid-cols-3 unchanged); the stale comment listing Installs as a picker view is corrected. The picker is the title (§C, 07.1 default): the UxSelectInline moves from #title-right into the layer's #title seat with inherit (20 px bold, primary caret, left-aligned, nothing at the right of the title row) and the tile gains :fadeKey="skillsView"; title="Skills" stays as the fallback text. 07.2 default: option labels Skills by team · Skills by people · Skills by harness · Skill drift (keys team / users / harness / drift unchanged). 07.3 default: no fifth measure. Layer (§B) — adopted dependency, not a blocker: the app consumes design c100's DataMachine #title + fadeKey and UxSelectInline inherit, uncommitted in the sibling layer checkout (read, not edited); Mark, 2026-09-30: assume the new DataMachine title selector will be adopted. Recorded as a new ## Unreleased layer ports this app consumes row in the app-root LAYER-CANDIDATES.md; a published-package build needs c100's change tagged (≥ 0.9.23) — under the 0.9.22 fallback the tile shows plain Skills (Team view only). No number moves (skillsBand() untouched). On the seed: Installs deploy 24 · review-pr 15 · commit 14 · db-migrate 7 · incident-runbook 4 · storybook 4 · dbt-model 3 ("25 of 39 scanned installs carry a skill"); Invocations em-dash ("a real zero"); Skills by team Data 4 · Payments 4 · Platform 4 · Frontend 3 ("of 7 skills · 4 teams"). Verified headless: after shot todos-2026-09-25/after/skills.png + -full, published as public/cycles/design/c102-todos0925-skills-{before,after}.png; Playwright on :3032 picked "Skills by people" → title reads Skills by people ▾, bars commit 14 · deploy 14 · review-pr 8 · db-migrate 7 · incident-runbook 4 · dbt-model 3 · storybook 3 ("of 14 people on scanned installs"), title row stayed put (y 191 → 191). npm test 539 (delta 0) + bible-check clean. Committed 99f18e0b on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 08 executed (2026-09-30): Skill detail (todos-2026-09-25/08-skill.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Reach row out (§A, 08.2 default): the caption "What the definition reaches for — read from the file, not from runtime" and its five tiles (Tools · Scripts · Placeholders · Load-time shell · Network) are gone — components/inventory/SkillReach.vue deleted with its mount in SkillDefinition.vue, reachTiles / ReachTile and definitionView().reachTiles out of lib/skill-rollups.ts, skillBodyStats / SkillBodyStats / LOAD_SHELL / NETWORK out of lib/skill-markdown.ts, with their three specs; SkillEditor.vue's frame takes Reach's mb-10 so Installs doesn't crowd the editor. This reverses c92 decision 12.2 (c15 CYCLE.md: Reach relocated from Surface to under the editor); placeholders and load-time shell stay marked inline in the rendered body. host → endpoint, person → user (§B, 08.3 default — plan 10 reuses): Installs headers read harness · endpoint · user · definition · version · sessions · last active (the lede says "the user behind the install"; the empty host cell reads "this endpoint"); Sessions headers started · harness · user · endpoint · tool calls · status; the Harnesses runtime ledger's host → endpoint (renders only once a harness emits skill calls); metadata People → Users 14, Hosts → Endpoints 14 (under More); the Installs tile provenance (skillBand() in lib/detail-bands.ts) reads "with this skill configured · 14 users · 14 endpoints · claude-cli, codex-cli". Keys unchanged. Harness detail link out (§C, 08.1 default): the Installs ledger's trailing open column ("harness detail →", live on all 24 rows on this seed) is removed; the row click still opens the Harness install — Playwright on :3032 clicked amara-mba's claude-cli row and landed on /inventory/agents/detail?agentId=e4dece09-…&from=inventory/skills, no console errors. On deploy (/api/skills?period=30d&skill=deploy: 24 installs · 14 users · 14 hosts, 24 of 24 with a runtime id) the editor frame is now followed directly by Installs. Verified headless: after shot todos-2026-09-25/after/skill.png + -full, published as public/cycles/design/c102-todos0925-skill-{before,after}.png; no stale-component error after the delete (no HMR touch needed). npm test 539 → 536 (−2 skillBodyStats, −1 reach tiles; the skillBand provenance assertion rewritten) + bible-check clean. Committed bcafde08 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 09 executed (2026-09-30): Tools (todos-2026-09-25/09-tools.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). kind → type (§A, 09.1 default): the ledger column header reads type (ToolsLedger.vue — headers now tool · type · server · invocations · harnesses · outcome · last used), the listing strip's key segment reads Type ▾ (All · builtin · mcp · skill) via a page-only registration override { ...FILTER_KEYS.kind, label: 'Type' } in pages/inventory/tools/index.vue, and the Tool type tile's description reads "Tools observed or configured, by type"; key kind, slot #kind, URL ?kind= and the shared FILTER_KEYS.kind (Harnesses still reads Kind) are unchanged. The global Filter bar's pill still reads kind: — the layer's FilterItem renders the raw key, not the def's label, so that half needs a layer change (off-limits under R.3; the plan's "filter pill says Type" missed this). Outcome tile → Success Rate (§B, R.2 + 09.3 defaults): ToolsBand.vue's third tile is titled Success Rate, description "Weighted by invocations", value 100 % with the ok · failed · denied donut kept (7d: 330 ok · 0 failed · 0 denied; tiles Tool type 26 — 8 builtin · 11 mcp · 7 skill, Invocations 330, none denied); the outcome column is unchanged; toolsBand() untouched. Verified headless: after shot todos-2026-09-25/after/tools.png + -full, published as public/cycles/design/c102-todos0925-tools-{before,after}.png; the Browser pane on ?kind=mcp showed the strip at Type/mcp and the tiles at 11 · 113 · 100 %. npm test 536 (delta 0) + bible-check clean. Committed a78bae42 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 10 executed (2026-09-30): Tool detail (todos-2026-09-25/10-tool.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882), Glob&kind=builtin; every edit in the appliances, the page untouched. Success → Success Rate (§A, R.2): ToolTiles.vue titles the tile Success Rate (and the not-judged fallback), the staged inventory.toolSuccess sentence reads "Success Rate needs judged invocations…"; band reads Invocations 298 · Success Rate 100 % (judged 298 · 298 ok · 0 failed) · Harnesses 31. Harnesses table (§B): ToolAgents.vue columns trimmed to harness · user · endpoint · invocations — tokens, spend and last active gone, host label → endpoint (key host unchanged; initialSort="invocations" holds); the shared agentLedgerRows is untouched (MCP server detail still reads lastMs); ToolConfiguredOn.vue's dead-branch host → endpoint too, and useTool's header comment now says the whole-run tokens/spend are served but not shown. Recent invocations (§C, 10.1–10.3 defaults): arguments → session in the same slot (when · harness · user · session · decision · outcome · duration) — 8-char mono shortHash(run_id) linking to /team/sessions/detail?runId=, @click.stop, — when null (first row 6eb07b16); arguments + output stay in the row expand; lede rewritten. Meta (§D, 10.4): ToolHeader.vue Kind → Type. Verified headless (Playwright on :3032): clicking 6eb07b16 opened Session detail for chen · Claude Code with the row not expanded (0 <pre> with navigation held), a plain row click still expanded to arguments + output (0 → 2). After shot todos-2026-09-25/after/tool.png + -full, published as public/cycles/design/c102-todos0925-tool-{before,after}.png. npm test 536 (delta 0) + bible-check clean. Flagged, not fixed: All harnesses → still links to the /inventory placeholder. Committed d6761f25 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 11 executed (2026-09-30): Workspace detail (todos-2026-09-25/11-workspace.md; no twin record, R.4) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882), payments-core. Ordered only (§A, 11.2) — now in place for plan 13: the only list is the order you get. 01 had put the seats in the lib, not in Section.vue, so the one-liner landed there: surfaceSeats(panels, only?) walks only ?? AXIS_ORDER, both useSurface and surfaceView (composables/inventory/surface.ts, a path the plan didn't name) pass only through, and surfacePanels sorts by only. Section.vue only gets the new prop doc. The two existing its (surfacePanels only, surfaceSeats) were edited in place, with no new test. Every other caller already passes its list in AXIS_ORDER, so nothing else moved. Workspace Surface (§B, 11.1): SURFACE_AXES = models · mcp_servers · tools · users · agents; Skills is seated #after-tools and Teams #after-users, so it reads Models · MCP Servers / Tools · Skills / Users · Teams / Harnesses, with Harnesses (Codex CLI 16 · Claude Code 13) alone. Skills: deploy 2 · review-pr 2 · commit 1 · db-migrate 1. Teams: Payments · 1 user · 29, which cross-foots with the Users axis (tomas · Payments · 29) and agents_detail runs 29. useWorkspace() returns teams via the Harness page's teamRows(), with no backend. Lede (11.4): "What runs here across all 29 sessions — models, MCP servers, tools and skills in use, and the people, teams and harnesses doing the work." SurfaceTeamsPanel (§C, 11.3): new components/surface/TeamsPanel.vue, lifted from 01's inventory/HarnessTeamsPanel.vue with the markup unchanged. Harness detail's #after-users now mounts it, and HarnessTeamsPanel.vue is deleted (no other user). The comments in HarnessSurfacePanels.vue and SkillsPanel.vue were updated. Verified headless: the after shot matches the plan's target, a scratch Harness shot matches after/harness.png pixel-for-pixel except for a 2×5px speck at the right edge outside the Teams panel, and a scratch Team shot is pixel-identical to baselines/team.png (its Surface is unchanged until plan 13). After shot todos-2026-09-25/after/workspace.png + -full, published as public/cycles/design/c102-todos0925-workspace-{before,after}.png. npm test 536 (delta 0) + bible-check clean. Committed d1ed1ca1 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 12 executed (2026-09-30): Teams (todos-2026-09-25/12-teams.md; no twin record, R.4). This ran on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882), /team/teams, taking defaults 12.1–12.4. The Teams tile is now Coverage (§C): the fed appliance components/team/TeamsListing.vue renders DataMachine title="Coverage", "People with a sensor on their endpoint", with unit="%" and a DataSegmentBar covered · partial · not seen in #right (the EndpointsBand pattern). It reads 100 %, 11 covered · 3 partial · 0 not seen, "14 of 14 seen by a sensor · 3 with detected-only installs". Quick filter Data (driven headless with Playwright from the design repo) gives 100 %, 1 covered · 2 partial, "3 of 3 seen by a sensor · 2 with detected-only installs", on one row. The local plural is dropped, and the Spend tile, table and page are unchanged. sensorCoverage() (§A), for plan 13 to reuse: sensorCoverage(c: { people: number; seen: number; partial: number }): SensorCoverage in lib/people-rollups.ts returns { pct, people, seen, covered, partial, notSeen, segments, provenance }. Its segments use Team detail's People-bar colours (success · warning · stroke-strong), and with no people it reads "no one assigned". It takes counts, so the listing sums its rows and Team detail counts its roster. It is served-derived, so there is no ledger entry and no ProjectedBadge. TeamRow gains partial (seen members with a detected-only install; the SAMPLE_TEAMS rows carry it, Platform 1). TeamsBand (§B, 12.2/12.4): coverage sums every row, including unassigned, and replaces the dead teams / unassigned / peopleTop. The sweep for them in app/ is clean. Tests (§D): two teamRows assertions and the teamsBand test were edited, and one sensorCoverage test was added. npm test 537 (536 → 537) + bible-check clean. The regression check (a scratch Users listing shot) matches baselines/users.png, so its projected Coverage (83 %, 15 seen · 18 known) is unchanged. After shot todos-2026-09-25/after/teams.png + -full, published as public/cycles/design/c102-todos0925-teams-{before,after}.png. Those manifest entries carry no subject, because subjects.ts has none for /team/teams. Committed d43c326c on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 13 executed (2026-10-01): Team (todos-2026-09-25/13-team.md; no twin record, R.4). This ran on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882), /team/teams/detail?team=Data, taking defaults 13.1–13.4 with one override: Mark, 2026-10-01: People → Coverage is a title change only ("I think the people -> coverage is just a title change"). So plan 12's sensorCoverage() is not wired into Team detail, and the plan's teamBand coverage / active trims and their spec edits were dropped. Tiles (§A), now three across (md:grid-cols-3) in the fed components/team/TeamTiles.vue: Coverage is the old People tile under a new title, with its value, segment bar and provenance unchanged (Data: 3 · 1 covered · 2 partial · 0 not seen · "3 seen · 0 not seen · 2 with detected-only installs"). Monitored Harnesses counts monitored installs only (13.1). teamBand().harnesses.val goes from installs to monitored, and a new installs field holds the whole, which the donut divides by. Data reads 7 (was 9), "of 9 installs · 2 detected-only · across 3 endpoints" ("devices" → "endpoints"). Spend is unchanged at $63.06. The Active tile is gone; band.active stays in teamBand, and TeamHeader's "Active 3 of 3" metadata row is unchanged (13.3). Surface (§C): C.1 was skipped because plan 11's ordered only had landed. pages/team/teams/detail.vue passes :only="SURFACE_AXES" = agents · models · mcp_servers · tools · workspaces · users · sensitive_files · egress (13.2: the last three follow, none served for a team today). On screen that is Harnesses · Models · MCP Servers · Tools · Repos & Workspaces, with no Endpoints panel. The Endpoints ledger and its jump pill stay. Tests (§B): the one teamBand harnesses spec was edited (val 3, installs 4, new provenance), and nothing was added or removed. npm test 537 (unchanged) + bible-check clean. The header and metadata are unchanged in the after shot todos-2026-09-25/after/team.png + -full, published as public/cycles/design/c102-todos0925-team-{before,after}.png. Committed e8208d41 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 14 skipped (2026-10-01, Mark) — not executed: Users — first "ignore the todo design pass, it's happening elsewhere", then "skip this plan, undo any changes". The executor was stopped mid-run; its uncommitted devices → Endpoints edits (UsersRoster.vue, UserExpandRow.vue, pages/team/users/index.vue) were reverted with git checkout; nothing was committed in either repo; Fable tree clean, npm test 537 + bible-check clean.
Outcome
Closed 2026-10-01 (Mark). Mark's 2026-09-25 review ran through /todos on the c99 Fable-track app (c99/claude-code-fable-5.1, :3032), one page at a time with a preview and a review per page: 13 of 14 page plans executed, 00-sweep a no-op (00.1 = no), plan 14 (Users) skipped by Mark. Fable commits 780eea16 → e8208d41 (14 commits incl. the 05 correction) — local only, not pushed; the copy pushed for Tyler's c99 evaluation is unchanged. Tests 539 → 537 + bible-check clean. Before/after pairs for 13 pages published to the atlas.
Shared pieces built: Surface #after-<axis> seats + ordered only (surfaceSeats()), SurfaceTeamsPanel, sensorCoverage() (Teams listing only — Team detail's Coverage stayed a title change, Mark 2026-10-01).
Carried forward:
- Blocked by R.3 (backend/layer read-only on this branch): 01.1 network egress on the Harness surface (
web.rs:5817gate); the Filter-bar pill still readskind:on Tools (layer shows the raw key). - Adopted dependency: Skills' title dropdown rides c100's uncommitted
DataMachine #title/UxSelectInline inheritseat (Mark: will be adopted) — a published-package build needs it released. - Open, unasked: Skills listing picker still says "Skills by people" (08.3's person → user didn't reach it); Tool detail's "All harnesses →" links to the
/inventoryplaceholder;/team/teamshas nosubjectinapp/data/subjects.ts, so its atlas pair is untagged. - Elsewhere: Users design pass and plan 14's rename (Mark: happening elsewhere); the execution-session Later list (README §Later).
Visual record
52 captures — heroes, page slices, and full-page renders. Click to view.



















































