11 started, 8 closed, 17 carried live.
Busiest record: c100 Landing Pages (16 entries) · 57 carried cycles have gone quiet · layer v0.9.23 → v0.9.31
Home composed as a showroom floor: six exhibits from the bake-offs in the qdash shell, re-lit through five specialist lenses (?as=)
Commits
242 commits across 7 repos, on each repo's checked-out branch.
Cycles
Started 11
Execute Mark's 2026-10-01 product-review notes for /activity through /todos
Replace the Inventory and Organization landings with nav disclosures, and make the index page a stack of sections, each summarised by micro versions of the DataMachines on its listings.
Make qdash tell the truth while it loads, when the backend is down, and when a write fails. Apply bible rule R31 ("states are honest, end to end", adopted in c107) to the surfaces that currently show reassuring numbers they haven't measured.
Promote the Fable app to qcontrol/crates/qdash/ui/ (the path the binary embeds), land it on feat/new-pages / PR #713, archive the old ui and the Opus app as reachable tags, and tell the story of why
The page title (layer UxPageTitle / Fable PageHeader, not the actor headers) joins c104's sticky band, which becomes two rows with scroll-direction modes.
Re-evaluate the qdash /cost page against what the backend now serves, and re-draw it on the Organization / Inventory listing pattern
One sticky band for qdash detail pages: NavJumpPills and the global filter pin together, and table headers pin directly under them
Execute Mark's 2026-09-30 product-review notes (nav restructure, Activity, Teams cost + trend exploration, Users attention) through /todos
Execute Mark's 2026-09-25 product-review notes on the qdash UI, one page at a time, through the /todos process (c94)
Fold qmap into DataSurfaceSection. Draw a thing's Surface (what it reaches) as a scene of pixel pawns, as a second view beside the lists (Map ⇄ List). This starts with a design brief to a designer.
Design the three qdash "Design in progress" landings: Home /, /inventory and /team. Each is a 30 ft (300 ft for Home) view of its domain, made more of images than of text.
Still open 17
Audit every qdash page's data provenance, write the front-end data-interface bible (page → context component → library component; composables modelled on app.qpoint.io's), then plan and execute the conversion of the qdash UI's vibe-coded data layer onto it
Refine the qdash /teams design — composition from c61 concepts, mapping workspace as the pre-SCIM write path, slim spend overview, credentials relocated
Seat c93's UxColumnPicker on the right edge of c92's FilterTriggerBar as a default-but-optional add-on — one strip above every qdash listing table instead of two controls competing for the same edge
Turn the c92 todos workflow (Mark's per-page meeting notes → one plan per page → parallel narrow-context executors → record) into a repeatable process: a /todos skill that reads the notes straight from Logseq, a sheet grammar, a page registry, and the templates the c92 run used by hand
A checkbox popover that shows/hides a table's columns — UxColumnPicker on a new UxPopover primitive — prototyped on the design site, then extracted to q-nuxt-layer and wired into a qdash listing
Reshape market-analyst into a design tool first — the source of truth for Qpoint's problem space — by adding a micro-problem layer (use case → micro problem → observations) on top of the existing market lens, with a curated registry, extraction-proposed candidates, computed standing, product surfaces, document intake, and briefs/stories that cite problems.
Stand up the c90 qcontrol-preview pages in the real qcontrol app (qdash UI) — phase 1 the combined Teams, Users & Devices listing, alongside a qdash global filter that replicates app.qpoint.io's behaviour, then the remaining detail/listing pages
Assemble seven page mocks (Teams & Users, User Details, Team Details, Sessions, Session Details, Devices, Device Details) behind shared app chrome that mimics the real qcontrol shell, ahead of integration with the real app
First-pass mocks for Teams listing header upgrade and net-new Sessions listing page in phase1 dashboard style
Extract app.qpoint.io's global filter into q-nuxt-layer as presentational components (Phase 1), then design and build a v2 segmented-bar redesign (Phase 2).
Explore and integrate Avoma notes data into extraction pipeline and dashboard visualizations.
Refine how extracted data is displayed in the dashboard and improve extraction quality where gaps exist.
Add Google OAuth to restrict dashboard access to @qpoint.io team members.
Methods & tooling retro — evaluate how we work against the design methodology, restore order, modernize the skill/agent tooling, and make the philosophy load-bearing
Build-partner portal — research, ideation, and a plan for a page that makes partners insiders
Align the qcontrol agent-monitoring dashboard to specific personas and find market alignment — hypothesis-first, validated against calls later.
Closed 8
Replace the Inventory and Organization landings with nav disclosures, and make the index page a stack of sections, each summarised by micro versions of the DataMachines on its listings.
Make qdash tell the truth while it loads, when the backend is down, and when a write fails. Apply bible rule R31 ("states are honest, end to end", adopted in c107) to the surfaces that currently show reassuring numbers they haven't measured.
The page title (layer UxPageTitle / Fable PageHeader, not the actor headers) joins c104's sticky band, which becomes two rows with scroll-direction modes.
One sticky band for qdash detail pages: NavJumpPills and the global filter pin together, and table headers pin directly under them
Execute Mark's 2026-09-30 product-review notes (nav restructure, Activity, Teams cost + trend exploration, Users attention) through /todos
Execute Mark's 2026-09-25 product-review notes on the qdash UI, one page at a time, through the /todos process (c94)
Add unit-of-measurement toggle to qdash /cost page — switch display between currency ($) and tokens
Make push to main reliably deploy the design site to Cloudflare Pages *(2026-09-25: reframed as "make the build a manual local step", see PICKUP.md)*
Pages & components
What this week's captures picture — 53 pages, 4 components · 26 first captured this week. Each links to its evolution: every moment it was shot, across cycles.
Pages 53
Components 4
Log
Key Changes entries dated inside the week, from each cycle's record — newest first within a cycle.
c110 qdash TODOs — 2026-10-01 review
todos plan 01 executed (2026-10-02): Activity (todos-2026-10-01/01-sessions.md; no twin record). Row 1 is Total Sessions · Tokens · Cost: the Sessions and Harness Installs cards are archived (and useInstallationList left useSessionList with them); the per-day chart moved up from the history row as Total Sessions — val = sessions, provenance "N running" (+ the newest-200 cap wording), lanes compliant · non-compliant (keys stay clean / flagged), its day hover moved with it (TeamSessionsDayTip, shared with row 2). Tokens and Cost each carry their own Users ⇄ Teams toggle in #title-right: sessionsBand now sums per user (local part only — the harness left the label) and per team (teamOf from /api/teams via teamByUser; no team or no user → unassigned), provenance "top 3 users = N % of tokens" / "top 3 of 4 teams = N % of cost". Row 2 is Providers · Models · Harnesses as "Tokens per day" / "Cost per day" behind one Tokens ⇄ Cost toggle: usageByDay and byDay take an optional valueOf (default 1, so other callers are unchanged), lanes rank by that sum, topPct is a share of it, and dayTotals lets the hover's "other / none" make the day add up. Seed values confirmed in the pane — 7d: 52 sessions, 1 running; Tokens 24m, Users wei 3.3M · elena 3M · omar 2.5M (37 %), Teams Payments 8.1M · Data 5.6M · Frontend 5.3M (79 %); Cost $331, Users elena $70.25 · priya $57.05 · wei $37.65 (50 %), Teams Payments $156.22 · Frontend $69.86 · Data $63.06 (87 %); Models by tokens sonnet-4-6 · gpt-5.5-codex · haiku-4-5, by cost sonnet-4-6 · haiku-4-5 · opus-4-8. 30d: 200 sessions (newest 200); Tokens 93.6m, Users marcus 12.1M · wei 11.4M · tomas 10.2M, Teams Payments 38.1M · Data 21.9M · Platform 20.1M; Cost $1.5k, Teams Payments $699.26 · Data $316.64 · Frontend $244.50; Harnesses by cost Claude Code · Cursor CLI · Codex CLI (by tokens Claude Code · Codex CLI · Cursor CLI). Each Users ⇄ Teams toggle moves only its card, the row toggle moves all three descriptions / lanes / hovers, Cost still links to /cost, flagged=1 narrows every number (7d: 7 sessions, 3.3m tokens, $37). 01.6 needed bars: the plan's premise was wrong — under legendBelow DataHistoryGraph sizes its columns area to its natural width (~890 px at 30 days) and its shrinkable columns never shrink, so the charts broke out of their thirds; new TeamSessionsDayGraph keeps blocks up to 7 days and past that draws bars with 2 px day gaps, its own wrapper (w-0 min-w-full) keeping the natural width out of the card's min-content, and scoped rules holding the columns area to the card and letting thinned tick labels spill (tick labels only — LAYER-CANDIDATE: a fit prop). Index: c109's Activity micros follow the band, 8 → 6 (Total sessions · Tokens · Cost on the Users view · Providers / Models / Harnesses used on the tokens lens); / shows 52 · 24m · $331 · 4 · 7 · 6 at 7d. Tests npm test 586 → 587 + bible-check clean (installs + status-segments specs out; users/teams, tokens ⇄ cost ranking, usageByDay valueOf, compliant labels in). Decisions on their defaults: 01.1 Active Sessions not built (README Later), 01.2 user only, 01.3 UxTabGroup, 01.4 val = sessions with "N running", 01.5 row toggle right-aligned on its own line, 01.6 bars past 7 days (see above), 01.7 index 8 → 6. Mark, 2026-10-02, during the run: the toggles are black and white and shorter — UxTabGroup's definition changed in the layer (py-0 text-12 on a leading-5 line; selected bg-content text-surface, others transparent text-content, border-content; unreleased; dist waits on the release); a full-width hairline under row 2's toggle line (the page header rule's edges, 8 px above the row's titles); legend labels ellipsize again (the fit-graph tick rule had caught them). After shot todos-2026-10-01/after/sessions{,-full}.png; atlas pair public/cycles/design/c110-todos1001-sessions-{before,after}{,-full}.png (subject page/sessions). Committed qdash bd33012f (feat/new-pages, not pushed; dist not regenerated — the published layer 0.9.28 lacks the new UxTabGroup look), layer 85f9edb (main, not released), design registry description + this record in the design commit.
todos plan 01 corrected (2026-10-02, Mark): Mark, 2026-10-02: at 2k+ sessions (simulated) — the charts get a max height — DataHistoryGraph maxHeight (opt-in), 64 px on Activity (one constant, MAX_HEIGHT in TeamSessionsDayGraph; the unit coarsens so the tallest column fits — real seed 7d 48 px, 30d 28–56 px; sim 7d 44–56 px, 30d 44–52 px; never clipped). Total Sessions stacks compliant / non-compliant (DataHistoryGraph stacked, opt-in; row 2 stays side by side), $ amounts ≥ $1k get separators and drop cents (fmtMoneyBar in moneyShare, so every listing's ranked money bars: $3,409, $70.25). Mark, 2026-10-02: a dev-only ?sim=1 on Activity, ~2.6k sessions cloned from the seed (display testing; seed and cap untouched) — lib/session-sim.ts (2,556 over 30 calendar days, one 260 spike, ~15 % non-compliant, 14 running, deterministic, spec'd) behind a transport swap in useSessionList gated on import.meta.dev; a SIMULATED badge and subtitle in the header, no "newest 200" provenance, a simulated row opens the served session it was cloned from; the index keeps the real feed. At sim 30d: 2.6k sessions, Tokens 1.2b, Cost $19k (Teams Payments $8,849 · Data $4,167 · Frontend $3,003). npm test 587 → 593 + bible-check clean. Committed qdash 747d21e7 (2k fixes) + f6025fd4 (sim), layer bf5b909 (stacked + maxHeight, not released — 0.9.29, released meanwhile, carries the UxTabGroup look but not these), design registry + demo (stacked and maxHeight scenarios) + this line. Dist not regenerated (needs the layer release).
todos plan 01 shipped (2026-10-02, Mark: "make it so"): layer release, qdash dist, recapture. The v0.9.30 tag (d2642dc, DataHistoryGraph stacked + maxHeight) was pushed but never started a publish run, so 0.9.30 is not in the registry. Another session's v0.9.31 (3e060fd, DataRankedBars labelWidth 'auto') sits on top of it and is the published release carrying both props; that session committed all six consumer lockfiles at 0.9.31 (design efb2e7858, qdash 055e1365, bob-wire 2a42f56, app.qpoint.io f5faf10, www.qpoint.io 7b9c975, qflow e0e76f6; none pushed). qdash dist was regenerated against the published 0.9.31 (39782184 on feat/new-pages, not pushed). Checked that the build leaves out the dev-only ?sim=1: import.meta.dev compiles to sim:!1, simulateSessions/simWindow are tree-shaken, and only the dead badge-text branch and the sim_of ?? run_id fallback remain. The :3030 dev server was restarted in place (nuxt.config.ts touched, no content change) because its watcher was stale. The after shot was recaptured (todos-2026-10-01/after/sessions{,-full}.png: stacked Total Sessions, 64 px cap, black-and-white toggles, hairline), and the published c110-todos1001-sessions-after{,-full}.png were overwritten in place (manifest entries unchanged).
todos-2026-10-01 planned (2026-10-02): journal 2026_10_01, /Activity section. This produced 1 plan under todos-2026-10-01/: 01-sessions (Activity becomes two rows of three — Total Sessions · Tokens · Cost / Providers · Models · Harnesses by tokens ⇄ cost; Sessions and Harness Installs archived; Tokens and Cost get Users ⇄ Teams). No sweep. Mark, 2026-10-02: the Sessions card's child notes (Total Sessions, compliant / non-compliant) came before the call to nix that card; the per-day "Sessions started" chart is what moves up as Total Sessions, its lanes read compliant · non-compliant; row 2 is Providers · Models · Harnesses, with one Tokens ⇄ Cost toggle for the row; Tokens and Cost each get their own Users ⇄ Teams toggle. Baseline todos-2026-10-01/baselines/sessions{,-full}.png.
c109 Index
- kick-off (2026-10-02): read the founding docs (component philosophy, design methodology), the layer's DataMachine, DataSurfaceSection and NavVerticalSubmenu, c100 and c108. Inventoried every DataMachine on the 10 listings: 27 machines, a vocabulary of three or four devices, 6 with no headline value, 2 with switchers, most reading 0 while loading. Findings:
NavVerticalSubmenualready supports a toggle-only parent (noto, plusmatch), so the nav change needs no layer work.- About 16 feeds at listing cadence on one page is the main risk.
Wrote plan.md: nav, components, page, six phases, risks and Q1–Q9 for Mark.
- decisions (2026-10-02): Mark answered Q1–Q9 and a Q10 (plan §9).
- Defaults: index at
/, a listing-links row under each section title,/inventoryand/organization→/#section, a newDataMachineMicrocomponent, all machines, component demos before qdash, c100 closes on a note, history graphs become spark + period total. - Changed from the defaults: Activity joins as a third section (35 micros), and the nav is open-only (a click never closes a submenu).
- Defaults: index at
- Phase 1a (2026-10-02): done on qdash in the files c108 isn't touching. Uncommitted.
- Sidebar: Inventory and Organization are disclosure buttons (controlled
NavVerticalSubmenuwith noto). Q5 changed mid-phase from open-only to toggle: a second click closes. - Landings:
pages/inventory/index.vueandpages/organization/index.vueare deleted.movedTarget()inlib/moved-routessends/inventory,/organizationand/teamto/#sectionin one hop. - Section data:
INDEX_SECTIONSinlib/working-nav, shared with the sidebar. /page: an interim index (Home: three anchored sections, each with its links row). The summaries arrive in Phase 4.- Stale links fixed: "All harnesses" and the surface fallback →
/inventory/harnesses;LISTING_KEYSre-keyed; MCP adoption →/inventory/mcp-servers; the DLP tile → harnesses; connectors →/#inventory;/overviewlinks and the Users crumb →/#section. - Checks: specs pass (27, including new
movedTargetandINDEX_SECTIONScases) andnpm run checkis clean. In the browser: the redirect, toggle, persistence and arriving-in-a-section all work on the seed backend. - Phase 1b (deferred until c108 commits): crumbs on the 21 listing and detail pages c108 has dirty, plus
ToolAgents.vue/AccountHarnesses.vue"All harnesses →". Until then they work through the redirect.
- Sidebar: Inventory and Organization are disclosure buttons (controlled
- Phase 2 (2026-10-02): layer and demos built. Uncommitted; no version bump.
- Layer, new:
DataMachineMicro(data/machine/Micro.vue) andDataIndexSection(data/index-section/). - Layer, backwards-compatible props:
DataRankedBarsmicro/bare;DataDonutCharthideLegend. - Layer docs: CLAUDE.md catalog rows, plus migration notes for v0.9.28.
- Micro:
- Title 12 / med / muted (truncates), hairline, value 20 bold, the device filling the rest; about 188 × 53.
val: nullrenders "—", not DataMetricValue's spinner. The whole card is a real NuxtLink.- A
#markslot holds the projected glyph. - It is the same 4-row subgrid as DataMachine, so
DataMachineGroupneeds no change.
- Section: title (not a link), lede, dot-separated listing links, hairline, and a default auto-fill grid (180 px minimum per column), so columns line up across sections.
:grid="false"hands the layout back. - Devices:
- segment bar
legend="none"8 px; - ranked bars
micro: top-1 label · share over a 3 px meter (recommended), withmicro bare(3 hairlines) as the alternative; - donut → its segment bar (recommended), with a 20 px ring as the alternative;
- spark 16 px; projected = a 10 px dashed ring; attention = count +
SecuritySeverityTag.
- segment bar
- Design site: demos at
/components/data-machine/data-machine-microand/components/data-machine/data-index-section, with six scenarios plus every device form, and a composed three-section page. Fixtures inapp/data/index-micro-fixtures.ts(35 micros, in the shape Phase 4 will use). Demo helpers:components/index/MicroDevice.vueandProjectedMark.vue. - Verified light and dark at 1280, 800 and 375 px.
- Found along the way: DataMetricValue's null state is a spinner, not "—". That affects c108's plan, so it was flagged there.
- Layer, new:
- Phase 1a pushed (2026-10-02, from another session): Mark wanted the new nav in the branch going to a colleague, so the Phase 1a qdash work is committed as qcontrol
7b732d7d("Inventory and Organization are disclosures; / is the index") and pushed to originfeat/new-pages.- What's in it: the 19 files under
crates/qdash/ui/appas they stood at 13:10, including the two staged landing deletions. - Checked before committing: 572 specs,
bible-checkclean. In the browser on:3030,/inventory→/#inventory, Inventory toggles closed → open → closed on/, and it opens on its own inside/inventory/*. - Published layer: 0.9.27 (
be148b37) already hasNavVerticalSubmenumatch/v-model:open, so the commit runs on the published layer. - Still to do: Phase 1b and Phase 2 (the layer
DataMachineMicro/DataIndexSectionand the design-site demos) are untouched and still uncommitted.
- What's in it: the 19 files under
- Phase 2 review (2026-10-02): Mark's rulings (plan §9):
- names, scale and banner-only failure as built;
- ranked bars → 3 unlabelled bars;
- repeated titles → try both on the demo.
The demo fixtures turned out to cover only 20 of the 35 machines, so they now hold all 35, each with alistingand itslistingTitle, plusbyListing().- The
DataIndexSectiondemo gained alayoutswitch: flat with prefixed titles, or clustered with listing titles. - 3 bars are the default in both demos and in
IndexMicroDevice. - The layer and registry wording now names 3 bars as the pick.
- Checked in the browser: both layouts across Inventory, Organization and Activity.
Next: Mark picks a layout → release 0.9.28 → Phase 4.
- Layout pick + promotion (2026-10-02): Mark picked the flat grid with prefixed titles ("I already love this one, let's promote to qcontrol"). Phase 1a had already been committed as qcontrol
7b732d7d.- Phase 3: layer
df57642and9a2df40(v0.9.28), published by CI. Lockfiles refreshed in design, bob-wire, app.qpoint.io, www.qpoint.io, qflow and qdash (committed in each, not pushed). - Toggle defaults: Mark asked mid-phase that the Working and Experimental toggles start off. They now keep their choice in sessionStorage, and the old localStorage value is removed (
98853509). - Phase 4 (
52df31b6):lib/index-micros.ts+ spec (11 tests): 20 / 7 / 8 micros; null until ready with an empty device; Tool success with nothing judged reads null.composables/fleet/indexSummary.tswires the listings' own composables;useSkillListingexposes a five-feedstate.- New
components/index/MicroDevice.vueandcomponents/lib/ProjectedRing.vue./renders threeDataIndexSections. - Checked on the seed backend: 35 micros render, and the 7 listings checked match their machines value for value.
- Full suite 586 passing;
npm run checkclean.
- Built and pushed: dist regenerated (
ba39df37, layer 0.9.28) and pushed tofeat/new-pages(PR #713),bf351751..ba39df37. - Still open:
- Phase 1b crumbs on 21 pages + 2 "All harnesses" links (unblocked now that c108 has committed);
- R-1 poll load: ~24 feeds at listing cadence, no shared requests;
- Phase 5 docs;
- design-site c109 files uncommitted.
- Phase 3: layer
- Phase 5, documentation (2026-10-02):
- Captures: 8 shots, from
c109-index-qdash.json(:3030; subjectspage/index,component/nav-vertical-submenu,page/teams) andc109-index-design.json(the demos). - Archive entry
2026-10-02-c109-index.
- Captures: 8 shots, from
- Phase 1b + nav (2026-10-02): done and pushed to
feat/new-pages(ba39df37..d05ebdd7).- Breadcrumbs (
7133a7e8): the Inventory and Organization crumbs on 21 listing and detail pages link/#inventory//#organizationdirectly. The two "All harnesses →" links and the empty harness-install detail →/inventory/harnesses. In the browser, a crumb lands on its section, scrolled under the header. - Overview leaves the nav (
d37698ff, Mark): the index behind the logo is the overview now, and/overviewstays routable by URL. - Dist regenerated after each (
4d6e4605,d05ebdd7). - Gotcha: the shared
:3030dev server's watcher missed batch edits. Touching each file one at a time (with a short pause) got them picked up.
- Breadcrumbs (
- Micro-cards thread (2026-10-02, after close): prompt · plan.
- On qdash via the local layer (uncommitted): roll-down labels (
DataRankedBars microLabels="beside", ending at 10 px Inter bold); micro titles 12 → 16 px bold; section grid gaps 20 / 32 → 48 / 48. - Then in the design prototype space:
/pages/phase3/index-micro-variations, with presets A–E (today · micro cards · micro cards with small data · section card · section card with tiles) and every knob live.- Each micro can be a white, rounded, soft-shadowed card, or the whole section can be. The data shrinks to 13 px titles, 16 px values, 6 px bars and 12 px sparks.
- Section titles are a knob too, defaulting to 28 px (Mark: "a bit bigger").
- Design-local parts:
IndexMicroProtoandIndexProtoSection. - Captures: threads
rollup-labels(3) andmicro-cards(6). - Dev servers: watchers on this machine missed edits repeatedly, so I worked against my own restartable servers (design
:3000, a qdash clone on:3034). - Pick (Mark): preset B, micro cards ("excellent, let's go with the default at the top").
- Layer 0.9.29 (
87835a1,7e8a6b2):DataIndexSectioncards(default on) makes its micros white cards (12 px corners, 14 px padding, soft shadow, a hairline border in dark mode) with 16 / 16 px gaps,minColumn190 and a 28 px title.DataMachineMicrocard(inherits) and a 14 px bold title.DataRankedBarsmicroLabels="beside". - Lockfiles committed in all six consumers.
- qdash:
0fbee449(roll-down labels); dist5d7dd5da, built from a clean worktree of HEAD so the c110 session's in-progress Activity files stay out. Verified on the:3034clone. Pushed tofeat/new-pages(d05ebdd7..5d7dd5da). - Record: capture
c109-qdash-index-cards(threadmicro-cards) is now the archive entry's hero; HISTORY's c109 entry has an after-close note; theDataMachineMicrodemo has acardcontrol.
- Layer 0.9.29 (
- On qdash via the local layer (uncommitted): roll-down labels (
c108 Honest States
- kick-off (2026-10-02): plan drafted from the c107 harvest's B9–B11 rows, re-verified against the shipped app on
feat/new-pages. The copy and look for the loading and failed states are a design call (plan §3), and Mark makes it before any code changes.
- decisions (2026-10-02): Mark ruled on D1–D5:
- D1: "—" for metrics, skeleton rows for tables.
- D2: one page banner plus "—" when the backend is unreachable.
- D3: inline error and toast when a save fails; the control reverts.
- D4: posture with no agents shows "—" plus "No agents reporting".
- D5: a "last updated" tag after 2+ missed polls.
Work starts: chassis → rollups → the false all-clears, then a review stop with screenshots.
- part 1 (2026-10-02) — chassis + the false all-clears, review stop. qcontrol
f76fa091, local onfeat/new-pages, not pushed.- Chassis:
feedState()(error first; a failed poll after a load stays ready); shelluseBackendHealth, fed by the service client, where unreachable means no response, a timeout or 502–504, never a 404; the primitives mark feeds that failed with nothing loaded; layoutBackendBanner(D2 banner, D5 "last updated" tag); libSkeletonRows. - Rollups:
postureBandaverages scored harnesses only, and avg and coverage arenullwhen nothing is measured (the spec covers it). - Surfaces: Findings cards + ledger; Posture tiles, score, factor bars, history and risk table (two more all-clears found there: "All instrumented harnesses are hardened", "Not enough run history"); Compliance attention; Cost tiles + breakdown; Campaigns cards; Users roster.
- 566 specs,
bible-checkclean. - Visual record:
c108-states-{before,after}.json, 19 + 19 shots, six pages × loading / failed / ready plus a stale shot. "Before" is the pre-c108 embedded build on:7882: Findings with qdash answering 503 says "0 HIGH … No findings. Fleet is clean." "After" is:3030: banner + "—", skeleton rows, and the data kept with "Last updated 11s ago · retrying". capture.mtsgainedapi: 'slow' | 'down'(page or action) to simulate the backend. It matches paths starting/api/, becausenuxt devserves source modules like/_nuxt/composables/api/….- Concurrent session: the c106 sticky-title port is working in the same
../qcontroltree (PageHeader, useDetailTitle, 13 detail pages,layouts/default.vue; layer 0.9.26 committed as2dacfeaa). Its mid-edit PageHeader briefly broke two captures; both were retaken. My commit stages only my hunks, and its files are untouched. - Review notes: the stale tag sits a little tight against the floating filter bar. Not yet done: the other ~60 empty-state sites, the 14 silent write catches (D3 toast + inline), and
actor-bandssuccessPct … : 100(tool success with no judged calls).
- Chassis:
- part 2 (2026-10-02) — every empty state waits for its data. Mark: "got it, let's proceed" (group 1, then groups 2–3). qcontrol
e042a5d4(2a),786405aa(2b),26ae31f8(bible §16 wiring), all local onfeat/new-pages.- 2a, the remaining false all-clears: Alerts "nothing would fire ✓", Data Protection "No sensitive file access ✓" ×2 and "No secrets or PII ✓" (plus its tiles), Users "everyone covered", Identity, Posture installs, Policies custom controls. Adds lib
StateEmpty(the one place an empty message decides whether it may speak), aBarListstateport, and LAYER-CANDIDATES rows (SkeletonRows,StateEmpty, and the layer state port that would retire them). - 2b, the rest:
usePageState(): each feed registers with the component that created it, and a page gets one state over its running feeds; closed-gate and on-demand feeds don't count.- Inventory: the seven listings, where the filter-match and no-data copy both wait, and every detail panel.
- Organization / Activity: the listings, the team panels, the six session ledgers, the history bands and their provenance captions.
- Cost: the tables and the guardrail. Performance: the ledgers.
- Detail pages: a skeleton while loading and "—" when down; they used to render nothing. Endpoints no longer says "not found" while loading.
- Tools: the success rate is null with no judged calls.
- The stale tag gets room from the filter bar.
- Verified:
scripts/qdash-r31-check.mjs(new, reusable) loads 34 routes with/apiheld open, answering 503, and up; all clean. The first runs caught four copies the static scan had missed: "No spend or token targets yet", "No model observed", "No harness observed" (a provenance caption) and the Endpoints "not found". 569 specs. - Deliberately left: Settings / Reports "No page yet" (design placeholders), the /live filter popover, the policy filter's "No policy matches", AdjudicationCard "No adjudications yet" (only inside an already-loaded finding), and
policy-statepercent … : 100for a framework with no required controls (a definitional question, not a loading one). - Next: part 3, the writes. A toast (layer candidate) plus inline errors for the 14 silent catches, with the control reverting (D3), each forced to fail on a scratch seed.
- 2a, the remaining false all-clears: Alerts "nothing would fire ✓", Data Protection "No sensitive file access ✓" ×2 and "No secrets or PII ✓" (plus its tiles), Users "everyone covered", Identity, Posture installs, Policies custom controls. Adds lib
- pushed (2026-10-02, from another session): Mark asked for the branch to go to a colleague, so parts 1–2 and the part 3 work in the tree were committed and pushed to origin
feat/new-pages.- Parts 1–2 (
f76fa091,e042a5d4,786405aa,26ae31f8) and the layer 0.9.27 bump (5f24a817) were pushed as they were. - Part 3 is committed as
686cf266("honest states, part 3 — a failed save says so"): the 26 files the tree held at 13:23. That coversuseToast+failReason,ToastStackin the default layout, and the inline save errors across policies, the Govern sheet, controls and the evidence packet, campaigns, findings, integrations and the Users roster. - Checked before committing: 575 specs,
bible-checkclean, and /policies, /integrations, /campaigns and /organization/users all render on:3030. - Not done: no save was forced to fail, so no toast has been seen, and the "each forced to fail on a scratch seed" pass above is still open. If part 3 wasn't finished at 13:23, carry on from
686cf266.
- Parts 1–2 (
- part 3 (2026-10-02) — a failed save says so (D3). Mark: "go ahead". qcontrol
686cf266. That commit was made by a concurrent session (the c109 nav thread) during a commit sweep of the shared tree. It contains exactly this thread's part-3 changes with an accurate message; that session then regenerated the dist with c108 parts 2–3 in it (bf351751).- Shell
useToast+failReason("qdash is unreachable" vs "qdash rejected it") +ToastStackin the layout. Lib candidate:UxToast. - Silent writes that now report: campaign remove; evidence-packet export; egress decisions on Policies and the policy detail (now shown on P10's own save line); integration routing chips, save, disconnect and the setup modal (the last three had no
catchat all, or a barereturn false); team assignment on the Users roster. - Writes that already had an inline error now also toast (D3 "both"): campaign create, finding decisions, the Findings egress modal, control save, threshold save.
- Copy: "save failed — the backend rejected the control" (said even when qdash didn't answer) became "✕ Couldn't save the control — try again".
- Controls revert to server truth on failure.
- Verified:
scripts/qdash-d3-check.mjs(new) forces 12 write paths to fail. Each failing request gets a 503 from Playwright and never reaches the seed. All 12 show inline + toast. Not driven by the script but sharing tested code: the P15/P17 threshold editors and the Policies-list Approve/Block buttons. Live agent focus/reveal are intentional fallbacks and stay as they are. - Twice during the run, the shared dev server served stale transforms of files I'd edited while other sessions were committing in the same tree.
touching the changed files fixed it.
- Shell
- embedded build (2026-10-02). Release binary from HEAD (
bf351751, dist includes c108), on a fresh seed copy:qdash-r31-check34/34 routes clean in slow / down / up;qdash-d3-check12/12.
- close-out (2026-10-02). Mark: "make it so, screenshots, history, anything else".
- qcontrol
1154ae0a, four more sites found by the final captures and a wider sweep:- Data Protection "No sensitive access by user";
- Compliance's per-control "No active findings" (green);
- harness detail "No at-rest installs scanned";
- Surface panels, which no longer blame the build ("not served by this backend — restart qdash") when qdash is simply unreachable. The not-served note stays for a real 404.
e30d5220: the stale-data notice. A concurrent session (5e64694f) restyled it to float bottom-right but usedabsolute, which anchored it to the document's bottom, below the fold on any long page (Users: y=1273 on a 900 px window).fixedrestores the intended float, and the toast stack moves tobottom-16so the two never overlap.- Dists:
16c403df,eec2211e. - Final record:
c108-states-final.json, 13 shots in thread "final". Loading and failed states across Findings, Posture, Data Protection, Alerts, Compliance, Cost, Models, a tool detail page and Users; the stale notice; two failed saves with their toasts (evidence export, a routing chip). capture.mtsgainedfail:/api/x(writes only) andfailget:/api/x.qdash-r31-checkgained the four new phrases. Both checks pass on a freshly restarted dev server: 34/34 and 12/12.- Two operational lessons:
- With several sessions committing in one tree, the dev server's watcher drops events and serves stale transforms. A restart is the reliable fix.
make qdash-uirunsnpm ciin the same directory and breaks a livenuxt dev(503) until it restarts.
- qcontrol
c107 qdash Cutover
- plan (2026-10-02): wrote the cutover plan as a c99 D9 thread, then moved it here when Mark asked for its own cycle. Mark's rulings:
- proceed, and confirm with Tyler afterwards;
- land on
feat/new-pages/ PR #713; - discard the stray
working-nav.tsedit; - copy the bible into qcontrol;
- write a qcontrol twin record (c16);
- analyse the Opus and old-ui work first. The archive approach was put to me ("what do you recommend?"); my recommendation is recorded as C2 in the plan.
- harvest (2026-10-02): two read-only analyses.
- ui-preservation.md: no product feature or test is lost (372 → 553 specs). What has to carry over is build config: the dist is git-ignored in Fable, the layer path depth,
generate:dist, the isolated build dir, the port and API defaults. c99 never exercised the writes or live data, so the embedded build has to check both. Two plan corrections: there is no footer build stamp, and the layer installs overgit+ssh, not a packages token. - opus-harvest.md: 8 Opus fixes that Fable still lacks. Six small ones are ported in the cutover (P4b): the poll hold leak, polling in hidden tabs,
highlight.jspre-bundling, the integration form, the ✕ on a /live chip, and the duplicate-control guard. Opus bible §8 is adopted as a rule (loading and error states are not "empty"); its code pass is a follow-on.
- ui-preservation.md: no product feature or test is lost (372 → 553 specs). What has to carry over is build config: the dist is git-ignored in Fable, the layer path depth,
- rebase (2026-10-02): Mark asked to rebase from
main(C10). A trial ran in a throwaway worktree:feat/new-pagesontoorigin/main8fffe91d: one commit (587c235e) conflicts in qeventsCHANGELOG.mdandexamples.rs, both mechanical.cargo checkpasses andmake schemasregenerates byte-identical files.- Fable's 38 commits on top: only the README conflict.
- The result is 178 linear commits, with the Fable app byte-identical.
The plan now works on a newc107/cutoverbranch in its own worktree. Thec99/*branches stay as they are.feat/new-pageslands with--force-with-lease, and the archive tags have to come first.
- execution (2026-10-02), P0–P5 and P-S. Mark: "let's proceed".
- P0. The Fable tree was quiet: no edits for 3 hours, only its dev server. Pushed Fable
c4d0e007and Opus598df17e. Discarded the strayworking-nav.tsedit; it's already in Fable. - P1. Pushed the annotated tags
archive/qdash-ui-gen2→d52ff77b,archive/qdash-opus-5.5→598df17eandarchive/c99-compare→4bd30359. - P2. Rebased in worktree
qcontrol-c107onc107/cutover, identical to the trial. 186 commits now sit onorigin/main8fffe91d. - P3 and P4.
a83234e9(move only) and18cdaef5(rewire, bible + R31, README Lineage, Makefile). - P4b.
36e46b1d(H1/H2),f914e49a(H4),fefadeac(H5),56d3f138(H6). H3 and H7 went in with the rewire. - P5.
12bb5d21(dist against the published layer v0.9.25; the sibling layer was the same tag, clean). Then98f17218(qcontrol twin c16). - Verified on the embedded release binary:
- 556 specs and
bible-checkpass; - all 31 top-level routes and 21 detail URLs render; 13 old URLs redirect; 0 console errors;
- 10 write paths persist on a scratch seed (H4 confirmed: a stored config reopens filled);
- a live-db copy (2.9 GB, 4M events) renders every page, with
/api/dlpslowest at 3.1 s.
- 556 specs and
- Correction to ui-preservation.md: the
:7882seed binary embeds an older gen-2 dist, not the tag's. The gen-2 captures were taken from a binary built at the tag (:7893), with chunks identical to the tag's dist. - Visual record: two subject-keyed threads,
gen2-finalandcutover, 27 shots each (scripts/shot-programs/c107-{gen2,cutover}.json). No blank shots. - Story: STORY.md. Draft PR text: pr-713-body.md.
- Landed (P6–P8, 2026-10-02). Mark asked for one change, that the PR text address a generic reviewer, and asked for a sanity check that
mainstays unchanged and new work lands on the new-pages branch.feat/new-pagesforce-pushed to98f17218(leasec8152d9a).origin/mainwas8fffe91dbefore and after; localmainuntouched. The branch is 0 behind and 186 ahead ofmain, and PR #713 reports mergeable. It is retitled "qdash: new pages, and the c99 data-interface app becomes crates/qdash/ui", with the body from pr-713-body.md.../qcontrolreset to the new tip (its tree was clean). The gen-2 dev server on:3030was stopped.npm ciand 556 specs pass there. Launch configqdash-app(:3030,NUXT_LOCAL_LAYER=1, seed:7882viaqdash-seed) serves Organization → Users with no console errors.- Repointed: design
CLAUDE.md,.claude/launch.json(qdash-app/qdash-seed;qdash-app-opusremoved), the/todospage registry andtodos-pages.json(base:3030), and memory (qdash-active-app, c107, the index). - Teardown: removed the
qcontrol-c99-fable,qcontrol-c99/_compareandqcontrol-c107worktrees and the localc107/cutoverbranch; stopped:3032. Kept theqcontrol-c99/claude-code-opus-5.5worktree, because a parked session's cwd and an untracked.nuxtrcare in it; remove it withgit worktree removeonce that session is done.qcontrol-c99/_seed/stays, becauseqdash-seeduses it.
- P0. The Fable tree was quiet: no edits for 3 hours, only its dev server. Pushed Fable
- opus wrap-up (2026-10-02). Mark asked whether the "parked Claude session" in the Opus worktree needed anything.
- It didn't. Session
2e2a1c24was deleted on 2026-09-28. What was left was an orphanedtail -f | ugrepwatcher on its parity log, whichlsofhad labelledclaude. - Stopped the watcher and removed the worktree. The branch and the
archive/qdash-opus-5.5tag hold the code; the untracked.nuxtrcis already superseded by H3. - The run recipe was tested from the tag:
npm ci, 1,660/1,660 specs, and/team/usersrenders on:3031against the seed. - New: REVIEW-OPUS.md. It covers what the track built, the commits ported into the shipped app, what wasn't taken and why, where its evidence lives, and the tested recipe.
- The track's unstarted
report-opusplan is marked superseded. - The c99 report page has an outcome card linking to STORY.md and REVIEW-OPUS.md.
- It didn't. Session
- next steps (2026-10-02). Mark: "make it so, don't do any work on finding a reviewer, the work is parked there until ready."
- Path-change notes added to c105 and c106 (top of each plan, end of each CYCLE.md). c106's are committed. c105's are left in its untracked folder for that session to commit.
- Design pushed (
9196894e0→5790d25cf) and deployed, live ondesign-f39.pages.dev: STORY, REVIEW-OPUS and the c99 outcome card.- The c106 mock relies on layer work that isn't released yet. Until that session releases the layer and redeploys, the deployed mock renders its band without the title.
- Rebuilt the
../qcontrolrelease binary and restartedqdash-seed, so:7882now serves the promoted app. - Opened c108 · Honest States for the R31 pass.
- PR #713 is parked; no reviewer outreach.
c106 Sticky Title
Phase 0 mock (2026-10-02): /pages/sticky-title, design-local (useStickyTitleBand, components/sticky-title/). Verified headless: detail band 91 px down · 129 px up, listing 53 · 81, headers pin at the band's height in every mode, jumps land under the compact band, every mode flip Δpage 0 · Δcontent 0. Mark's mid-build question (no toggle — detect sub navs) → registration, and components auto-join a mounted band in Phase 1. Details in plan.md § Phase 0.
Phase 0 rework (2026-10-02): the real UxPageTitle pins instead of a teleported copy (Mark: use the actual title, as the Filter is used): a zero-height sticky box with a bottom margin reserving its rest height, restyled by mode. Re-verified, every flip Δ0 (after fixing a mid-animation rest measurement that moved the page 8 px). Fable's PageHeader wrapper needs flattening in the port. plan.md § Phase 0 rework.
Mock refinements + cleanup (2026-10-02):
Design refinements + documentation (2026-10-02):
- Archive:
2026-10-02-c106-sticky-title.
Phase 1 + 2 — the layer and its docs (2026-10-02):
Phase 3 + 4 — release and the qdash port (2026-10-02):
Polish on the live app — 0.9.27 (2026-10-02): Mark's pass on the ported band, tuned on the :3033 temp server.
c100 Landing Pages
- superseded in part by c109 (2026-10-02): Mark ruled (c109 plan §9 Q9):
/inventoryand/organization(was/team) are no longer pages. They become nav-only disclosures.- Their overview moves to
/as sections of micro DataMachines. - c100's Inventory and Team landing designs are retired. The bake-offs and variation pages stay on the design site as reference; their size ladders and the trend parts feed c109's micro form.
- c100 can close on its Home and Fleet findings. The "showroom floor" stays an idea for how
/grows later.
- trend-variations (2026-10-01): origin c103 todos plan 03 Part B — Mark's 2026-09-30 Teams block, "explore showing Roll down and historic … Volume over perfection" (prompt · plan; record in c103
CYCLE.md). The page is/pages/phase3/landing-trend-variations, Now + Trend — Variations. New fixtureapp/data/landing-trend.tsgives c100's world the daily series it never had (person → install → harness type → provider → model, every rollup a sum) plus a dated seed snapshot of real Meridian per-team cost (landing-trend-seed.ts,:7882, 2026-10-01). Parts inapp/components/landing/trend/:LandingTrendSpark(the qdash Spark replica),LandingTrendDraw,LandingTrendForm,LandingTrendRollDown.- §0 the Teams page as c103 Part A shipped it · §1 F0–F21 plus Activity's history row (AH, Mark's lean, 2026-10-01) · §2 seven roll-downs with history · §3 table cells · §4 breakdown over time (team → user · harness type → install · provider → model) · §5 toggles and title switchers · §6 a degradation lab with three auto-checks per cell · §7 keep / maybe / kill ledger.
- Levers in the URL: metric · subject · grouping · world (seed / 20 / 200 / 1,500) · window · trend window (follow the pill ⇄ fixed 90d) · Δ basis · state · gaps · volatility · ink · labels. A day not collected is a gap or an em-dash, never a zero.
- Shots
scripts/shot-programs/c103-trend.json(cycle c103). Open: AH rides on uncommitted layer props (legendWrap, history-graph hover); the ledger reads are mine, for Mark to overrule.
- phase3 (2026-09-30): Mark asked for "a phase 3 to the pages index". Added the
phase3PagePhase (registry type +pageHref,subjects.tspath match), a Phase 3 card on/pages, and/pages/phase3listing the c100 pages. The bake-off moved toapp/pages/pages/phase3/, and its old flat URL is retired (it was two days old and never captured). Every c100 mock goes here from now on.
- tilemap-variations (2026-09-30): Mark asked for variations on Form A (prompt · plan). They are at
/pages/phase3/landing-tile-map-variations, and every map is one design-local component,<LandingTileMap>(app/components/landing/TileMap.vue).- §1 Ink. Tiles can be grey, grey + status, or a hue picked from swatches or a free picker. The colour ramp is smooth or stepped (3 or 5).
- §2 Size ladder. The map runs from full width × 380 down to a DataMachine (200 × 88), a table cell (120 × 36) and a 48 × 16 glyph inside a sentence.
- §3 Labelling at DataMachine size. Six strategies: silent + note, numbered key, callouts, highlight, other bucket, paired list.
- §4 Spin. Four layouts, area by people or by the lens, three fill styles, people nested inside the tiles, eight-lens small multiples, and morph.
Early findings:- Grey needs reversed text ink: in dark mode the strongest grey tiles are light.
- Critical vs elevated survives grey only as a mark; the corner notch does that job.
- At 1,500 people, Waste saturates just as Violations did in bake-off #1.
- The other bucket's roll-up tile can become the hottest tile on the map.
- matrix-variations (2026-09-30): "Apply same prompt to Team × lens matrix" (prompt · plan). The page is
/pages/phase3/landing-matrix-variations, and every matrix is<LandingMatrix>(app/components/landing/Matrix.vue). Ink moved intoapp/data/landing-ink.ts, shared with the tile map, and adds diverging tones: worse is filled, better is hollow.- §1 Ink. Grey makes the matrix one picture. Per-job ink makes it read as eight separate charts.
- §2 Size ladder. It runs from the table down to a DataMachine texture, with a one-row team fingerprint in a sentence and in a listing column.
- §3 Labelling at DataMachine size. Six strategies, including labelling the short axis by transposing: lenses as named rows, teams as unlabelled columns.
- §4 Spin. Normalisation (per column, per row, rank, deviation from median), Bertin ordering including greedy seriation, cell marks (fill, dot, bar, numerals), row height = people, reader groups + focus column, and morph.
Early findings:- A one-row fingerprint is the matrix's gift to other pages: a candidate
/team/teamscolumn. - At 1,500 people the flag count saturates ("40 of 40 teams flagged").
- Unassigned has to be pinned last, or seriation leads with it.
- leverstrip-variations (2026-09-30): "Same treatment to the lever strip, try adding a select to some variations for choosing the lens" (prompt · plan). The page is
/pages/phase3/landing-lever-strip-variations. The chips are<LandingLeverStrip>, and the drawing inside each chip is<LandingLeverMicro>. A newapp/data/landing-story.tsholds each lens's headline, one-line story, story order and lever verb. Lens selects (UxSelectInline) sit in every DataMachine's#title-rightand on most variation headers. Each follows the page lens until you pin it to its own.- §1 Ink. Grey moves severity into shape: critical = a filled square, elevated = a hollow square, a hot person = a square.
- §2 Size ladder. It runs from every chip down to a rail, the top four, DataMachine rows, one pill, and a glyph.
- §3 Which chips at DataMachine size. The strip labels itself, so the small-size problem is selection, not labelling. Six strategies: top 3 + more, span, names only, micro only, lever verbs, ticker.
- §4 Spin. Chip shape, a micro-form picker, chip ground, sort + pins, multi-lens chips per reader, department groups, and FLIP morph.
Early findings:- Only 5 of the 8 lenses are levers (Violations · Coverage · Waste · Active · Retention). Usage, Spend and Harness are readings.
- Tinted chips are a sorted tile map with equal areas.
- Follow-up, title switcher (2026-09-30): Mark asked for "a DataMachine pattern where the title is a dropdown", with the lever strip's cards as the first instance. It is two layer changes (released in 0.9.23):
DataMachine #titlereplaces the title text and keeps the title's type. Thetitleprop becomes optional, and a standalone card is nowmax-w-full.UxSelectInline inheritmakes the select take the surrounding type, with the caret scaled to 0.5em.- The configuration is
<template #title><UxSelectInline v-model … inherit /></template>. - The rule: use
#titlewhen the choice changes what the card is, and#title-rightwhen it changes how the same subject is shown. - Documented as a copyable DataMachine demo preset (per component_philosophy §4 "base + curated presets") plus a
#titleoverflow scenario,UxSelectInlineinheritscenarios, registry slot and prop entries, and layer CLAUDE.md migration notes. All 7 DataMachines on the lever-strip page now use it.
- Follow-up, switch jitter (2026-09-30): switching the lens moved the card through four sources:
- the card width (322–351 px)
- the headline width (35–131 px, so the drawing started anywhere from 59 to 155 px)
- the name column
- the value column
The rule is to size to the domain, not the selection. Three pieces implement it:- layer
DataMachine fill: the card takes its column; the default shrinks to fit - layer
DataMachine reserve: the value slot is held at the widest option's headline LeverStrip columnsFrom: row columns are sized over every team × lens
Mark chose "the value takes min space, the drawing expands" as the default. The card and columns stay fixed and the bar absorbs the difference;reservestays as the no-motion alternative. §3 has Card width (Fill / Shrink to fit) and Value (Min / Reserve widest) controls. - Follow-up, fade (2026-09-30): a new layer prop, DataMachine
fadeKey. When the key changes, the description and body fade out and back in (out-in, 250 + 250 ms, the brand's 500 ms content transition). The title row stays put, so the select keeps focus. It is on every title-switcher card and in the demo preset. Grouped cards still align. - Follow-up, Harness parameter (2026-09-30): the Harness lens was unreadable. It is "Claude Code's share of each team's tokens", but the card only said "Harness", and the harness was a hidden page-level picker. Mark's fix is a harness select in
#title-right, shown only on Harness, with per-card harness state. The pattern rule is refined:#titlepicks the subject;#title-rightpicks a parameter or view of it; a subject with a parameter carries both.fadeKeycovers subject + parameter. Also added: a DataMachine demo scenario and layer CLAUDE.md wording. Still open from the critique: the Harness row mixes token share (the value) with adoption (the dots), and the log-scale swarm is hard to read at 16 px, so a share meter would fit better. - Follow-up, the meter formalized (2026-09-30):
- Harness now draws a share meter instead of the log-scale swarm. The value and the drawing say the same thing.
- The black-and-white Coverage bar became a layer option,
UxPercentBar outlined: the unfilled rest is an outlined surface track, and withsolid+thinit's the meter.LeverMicro's meter now is<UxPercentBar solid outlined thin />everywhere (Coverage, Active, Retention, Harness), and the design-localmonoflag is gone. - "+N more teams" is a button: it opens the rest into the list and folds back ("Show top 6").
- Also documented: a
UxPercentBardemo scenario, the registry entry and a layer CLAUDE.md note.
- bakeoffs (2026-09-30): Mark asked to "proceed to the next pages following the same deeply researched / introspective approach" (bakeoffs-prompt.md). Four research passes produced
research-{people-field,inventory-estate,fleet-floor,home-lenses}.md, and bakeoffs-plan.md set the page contract and rules. The shared world grewlanding-estate.ts(devices, installs incl. the shadow Hermes, harness → provider → model flows, accounts, MCP servers, skills, arrivals, exits by data class, shifts, attention reasons, identity-known-but-unseen people) andlanding-viz.ts(inks, colour jobs, squarify, unit grid, frame components).- Built by the main thread: #2
landing-team-people-field(5 forms) and #8landing-beyond-data(X1–X9 with keep / maybe / kill). - Built by parallel background builders: #3
landing-inventory-estate-bakeoff(alluvial · bowtie · switchboard · pixel body), #4landing-inventory-supporting(4 cards × best-prior vs fresh), #5landing-fleet-directions(A–H incl. live qmap), #6landing-fleet-supporting(who-runs-what, shifts, loading dock), #7landing-home-lenses(showroom + 5 lenses,?as=, c67 graduates per lens). - All eight are registered as phase 3. Every page was checked headless at 1440 with no console or hydration errors, and #1, #2 and #8 were also checked in the browser pane.
- bakeoffs-review.md collects every recommendation, the convergences (one pixel language for Home; the Claude Code question lives in Fleet F2; a first-run hero per page), five rulings to make, and the shared-module backlog.
- Follow-up, hover breakdowns (2026-09-30): every lens's hover now breaks the row's drawing into its people, with the ones to act on first:
- Coverage: devices per person
- AI usage / Spend: people largest first, bar vs the team's top person, value + share
- Violations: findings per person, critical then oldest
- Waste: the reclaim list: idle seats, most money first
- Retention: lapsed first
- Active: idle first
- Harness: each person's harness mix as a stacked bar
It's a design-local component,LandingHoverBreakdown(app/components/landing/HoverBreakdown.vue, a layer candidate besideUxPopoveronce qdash needs it). It provides the frame (24 px title, header lines), the columns (about 12 rows each, widening to the window, 28 px gap), the placement (above the pointer from its measured height, below when there's no room) and the extra bottom air. The page supplies#summary="{ width }"(the full-width drawing) and#row. - Follow-up, into the layer + shared (2026-09-30): the hover card became the layer's
DataHoverBreakdown(components/data/HoverBreakdown.vue, released in 0.9.23), documented on the design site: registry entry,/components/data/data-hover-breakdowndemo (interactive + pinned, empty / minimal / long-title / typical / overflow), index entry. Its width rules:- a one-line title, truncated only at
maxWidth - the card sizes to its content, at least its columns, up to
maxWidth
The per-lens builders moved out of the lever page into a design-local wrapper,LandingTeamBreakdown(app/components/landing/TeamBreakdown.vue). The three variation pages share it:- lever strip: every chip
- tile map: every tile on the page lens; a folded "+N teams" tile gets a plain card
- matrix: every cell on its column's lens, so one matrix gives all eight breakdowns
- a one-line title, truncated only at
- Built by the main thread: #2
- hover-breakdown (2026-09-30): "integrate DataHoverBreakdown into the various pages where appropriate" (prompt). The component is the layer's (released in 0.9.23) and was extracted by the sibling lever-strip thread. Every hand-rolled tooltip on the eight bake-offs is now
DataHoverBreakdown. The rule: a mark that aggregates hovers into what it's made of, the ones to act on first; a single thing gets the same frame, plain.- #1 team marks and matrix cells use the sibling's
LandingTeamBreakdownon the mark's lens. - #2 team labels → people, trouble first, with a state-composition bar.
- #8 X2 seat rows → the idle seat-holders.
- #3/#4 harness, provider and model nodes, ribbons, switchboard cells, body limbs, visibility rows, provenance buckets, arrival days and account bars → their installs, people or assets. Adds
personChainOf/providerUsers/rolluptolanding-inventory-data.ts. - #5/#6 zones, stations, loom cells, dial petals, matrix cells, heat cells and dock doors → people, machines, data classes and sending teams. Fleet builds its own cards, since its marks are per machine, and keeps them in
landing-fleet-data.ts. - #7 every exhibit mark, lens-aware. Org tiles use
LandingTeamBreakdown; queue rows stay plain. - Headless hover passes found no clipped cards and no console or hydration errors. Open: the Fleet directions page redraws in ~500 ms per pointer move in headless Chrome, likely qmap's software WebGL. Check it in a real browser.
- #1 team marks and matrix cells use the sibling's
- mocks (2026-09-30): "create a place to mock up phase 3 landing pages (index, inventory, teams) … composing these out of our various experiments" (prompt · plan). Stage 3 workspace:
/pages/phase3/mock(Home),/mock/inventory,/mock/team,/mock/parts(the parts bin, every part live with its source).- The qdash shell:
layouts/landing-mock.vue;LandingMockSidebarmirrors the current AppSidebar;LandingMockBaris mock-only (world knobs, show parts, parts bin). - One URL-backed world across the mocks (
useLandingMock,?scale/state/period/parts). LandingMockSlotnames each block's source and swaps variants in place (?v.<slot>=).- Shared parts:
LandingPartHeader(period pill),LandingPartVerdict,LandingPartDoors. - Parts manifest:
landing-parts.ts+ one per area. The Phase 3 index gains a "Composed mocks" section above the experiments. - First compositions (v1 per bakeoffs-review) by three parallel builders; the bake-off pages stay as the experiment record. 33 parts in the bin (3 shared · 6 team · 10 inventory · 17 home).
- Team: verdict · lens hero (tile map · lever strip · matrix, via the sibling components;
?lens=/?harness=) · people (field + needs you · blocks · skyline) · four doors. - Inventory: verdict with "Onboard" · estate hero (alluvial · switchboard · bowtie · pixel body; lens on the hero) · supporting 2×2 (collapses to one line when all clear) · census band (off by default) · seven doors · a designed first-run discovery strip.
- Home: Seen-as with per-lens counts · verdict/caption · queue (lenses only) · six exhibits (floor + org: as built · pixels) · lens feature panel · week · trust (promoted when the eyes are broken) · first-run discovery.
- Team: verdict · lens hero (tile map · lever strip · matrix, via the sibling components;
- Checked headless across states and variants with no console or hydration errors. Fixed one drift: the Teams door and the verdict ranked violation teams differently (22% vs 25% at 1,500); both now rank by open count.
- Open for Mark: the Team hero is greyscale (the variation pages' XL setting) while Home's org exhibit is grape; the lever strip renders client-only (a server/client mismatch in the sibling's
LeverMicro"clear" state); Home's floor-drawing code is copied from bake-off #7 intolanding-home-parts.ts(not exported).
- team-lens-cards (2026-09-30): Mark: "In the hero section, also add an option that pulls from the phase3/landing-lever-strip-variations option 1 … Create one for each of the lenses. Don't have title be dropdown … should create a three column layout."
- New part
LandingPartTeamLensCards: one DataMachine per lens (AI usage · Spend · Active · Violations · Coverage · Harness · Waste · Retention) in three columns. Each card holds the lever-strip §3 strategy 1 "Top 6 + more" rows (rows built as that page'sbuildStrip), with a plain title and the harness named in the Harness card's description. - Offered as the fourth Team hero variant,
?v.hero=cards. Team tiles and the people field are now grape (Mark, same day). - Open: the Active / Coverage / Harness / Retention meters stay black — they're the shared c100 meter (
UxPercentBarsolid, drawn by the sibling'sLeverMicro), which doesn't take the ink.
- New part
- team-lens-cards grouped (2026-09-30): Mark: "add another option with just three cards each with a title dropdown, maybe group the types of info per card."
LandingPartTeamLensCards mode="grouped"(hero?v.hero=cards3) shows three cards, each titled by aUxSelectInlinescoped to its group. The picks live in the URL (?v.adoption=·?v.cost=·?v.risk=), areserveof the group's headlines keeps the value slot steady, and the Harness pick adds the harness select in#title-right. Groups:- Adoption: AI usage · Active · Retention · Harness
- Cost: Spend · Waste
- Risk: Violations · Coverage
- shipped + documented (2026-09-30):
- Committed as design
c3e9202aand deployed. - The live site lost every hover card and title switcher:
npm run deploybuilds against the published layer, and all of c100's layer work was still uncommitted. Released layer 0.9.23 (DataHoverBreakdown; DataMachine#title/fill/reserve/fadeKey;UxPercentBar outlined;UxSelectInline inherit), refreshed the lockfiles in all five consumers, and redeployed (design56ce1068). Lesson: release the layer before deploying design pages that use it. - Visual record:
- heroes + fulls of the 11 bake-off and variation pages
- a 13-shot program of the composed mocks (
scripts/shot-programs/c100-landing-mocks.json): Home showroom / Security / Finance / pixels / first run · Team matrix / lens cards / 3 cards / tile map at 1,500 · Inventory alluvial / switchboard / all clear · the parts bin
- Archive entries
2026-09-30-c100-landing-bakeoffsand-landing-mocks. - Mark, same day: the Team mock's People slot defaults to skyline (
?v.people=fieldkeeps field + list), the Team hero defaults to the matrix (?v.hero=tilemapkeeps the tile map), and/pageslists Phase 0 first and_metalast.
- Committed as design
- kick-off (2026-09-28): four research sweeps (prior Home, Team and Inventory work; the Fable app's data surface) and a founding-docs review. Wrote plan.md, prior-work.md, viz-opportunities.md (altitude ladder; 20 opportunities T1–T7 / I1–I7 / H1–H6 with data status), the briefs (team · inventory · home) and the wireframes (team · inventory · home). Eight questions are open for Mark, led by what happens to
/fleet, the fourth placeholder.
- rulings (2026-09-28): Mark's answers in rulings-prompt.md:
/fleetbecomes the factory floor (inventory + people); brief-fleet.md and wireframe-fleet.md added.- Home = showroom floor with portals, with specialist lenses later (
Seen as:); the Home brief and wireframe were rewritten. - Explore beyond current data; X1–X9 were added to viz-opportunities.
- Design site first,
/pagespattern,overviewregistry group. - Endpoints and Sessions stay under Team.
- plan.md now explains the altitude rule (pros and cons; recommends "labels yes, bands no"), c67, and the time-window question. Five items remain open.
- rulings round 2 (2026-09-28):
- The altitude rule is relaxed into the abstraction ladder: the same data is shown more abstractly at higher altitudes, and each number is still computed in one place.
- c67's strip, lens set and horizon ideas are pulled in to the Team bake-off and the Home lenses.
- Landings obey the period pill.
- All five Home specialist lenses are in scope.
- The factory floor is an idea, drawn eight ways (A–H) in
landing-fleet-directions. - Nothing blocking. Next: fixture →
landing-team-lens-bakeoff.
- team-lens-bakeoff (2026-09-28): the shared fixture world
app/data/landing-fixtures.tshas scale 20 / 200 / 1,500, state attention / clear / first-run, and period 24h / 7d / 30d. It carries eight team lenses with colour jobs (volume · share · risk · gap) and a derived verdict. Bake-off #1 is/pages/phase3/landing-team-lens-bakeoff(registryoverview, phase 3), four forms on one control row: A tile map (squarified, area = people), B the c67 lever strip, C swarm rows (a dot per person), D team × lens matrix. It also has a lens ledger with my keep/move reads and six judging prompts. Early findings:- Worst-severity toning saturates at 1,500 people, when most teams hold one critical.
- First run renders as one big box. It needs a designed attribution-debt state, not a lens.
c105 Cost Center
Stage 1 (2026-10-01). Initial prompt; evaluation of the nine cost-bearing feeds, eight lenses, value ranking and backend asks.
Kick-off (2026-10-01). Mark's answers (evaluation §9):
Phase 1, mock round 2 (2026-10-01, awaiting Mark's review):
Review 1 (Mark, 2026-10-01): the filter trigger bar (Team quick filter) is removed for now. The ledger's toolbar keeps a standalone UxColumnPicker, and ?team= is gone from the mock. The data module still supports team scope (buildCostCenter(period, team)) for when filtering returns.
c104 Sticky Band
kick-off (2026-10-01): the six evaluation §7 decisions answered → evaluation.md §8. Band only when pinned; backing only when pinned; no stopgap, the header fix waits for the band's release; tables fit by default + one overflow primitive (built as UxOverflowX) (app.qpoint.io's #page-scroll-window approach rejected: the whole page slides sideways and every offset must target the custom scroller); c104 owns the fix and the 0.9.24 release; design mock first, then the Fable app :3032 (Mark, correcting :3030). Since both controls already pin at 8px, "only when pinned" makes the band a coordinator over stickies that stay in place, not one container they move into (plan.md §Architecture). Plan decisions P1–P6 confirmed by Mark as drafted (2026-10-01): var on the document root, NavJumpPills owns its pinning, band height counts every band control on the page, background over the content column only, NavJumpPills sets its targets' scroll-margin, stuck chip out.
header fix committed (2026-10-01): layer 11e80a9 DataTable: arm overflow-x only while the table overflows, so the thead pins. Local and unpushed. The Fable app resolves the sibling layer checkout, so it is already live on :3032 in dev, collision included; its package fallback is layer main, so layer main stays unpushed until 0.9.24.
Phase 1 layer pieces + Phase 2 mock (2026-10-01): layer 37ec2c8 (local, unpushed, on 11e80a9), alongside another session's uncommitted HistoryGraph/DataMachine work in the same tree (not staged). New composables/useStickyBand.ts (useStickyBand → { stuck }, useStickyBandMember), UxStickyBand (backing), UxOverflowX (a wrapper component, not the planned composable: consumers swap their div for it; measures scrollWidth because UxTableList puts a full-width div between box and table, the first try missed it). UxTableListHeader pins at var(--q-sticky-top, 0px); UxModal and an armed UxOverflowX reset the var to 0, since a header inside a scroll box would otherwise be pushed down by the band height. Both memberships opt-in (Filter band, NavJumpPills sticky): the Fable app reads the sibling layer live while c103 runs, so nothing joins a band there until Phase 4. Layer CLAUDE.md: catalog rows + "unreleased, ships as v0.9.24" migration notes. Mock: design /pages/sticky-band (qcontrol layout, Fable shell replica; Band/Before switch, Filter/Pills toggles, 14-column wide ledger, live --q-sticky-top readout) + page-registry.ts entry. Verified in the pane at 1440×900: band height 81px with the filter (8 + 65 + 8), 58px pills only, unset with neither; band backing at opacity 1 once pinned; ledger headers pin at 81 and the second pushes the first off; every pill jump lands at 97 (band + 16) with its pill lit (Notes, last, lights by the bottom rule); Before mode reproduces the collision (header at 0 under the pills and filter). Wide-table arming checked on :3032 instead (Activity at 1024: 1132 in 748 → armed, var 0px inside; at 1700 disarmed, header pins at 0) because the design dev server (:3000, another session's) kept serving the first OverflowX.vue — its watcher missed every later edit to that one file; restart it to see the wide ledger arm in the mock. Fable /inventory/skills/detail unchanged (old wrapper pins at 8, no console errors). Not done yet: /document-components docs for the new pieces.
release (2026-10-01, by the c103 session): while Phase 2 was being checked, c103's close released layer 0.9.24 (1bea0a7, tag pushed), which includes c104's 11e80a9 + 37ec2c8. So decision 8.3 (hold the release) was overtaken: the header fix and the opt-in band shipped before the Fable port. Lockfiles were refreshed in design (af1c7512), qcontrol ui/ (c5fb5520) and Fable (3d557e53). Layer CLAUDE.md's "unreleased" migration-notes heading relabelled to v0.9.24.
Phase 4, Fable port (2026-10-01): Fable 579b512c on c99/claude-code-fable-5.1 (local, unpushed; c103 was closed and the tree clean). layouts/default.vue mounts <UxStickyBand class="-mx-8"> in the relative wrapper ahead of GlobalFilterBar, whose Filter gains band. 11 detail pages swap <div class="sticky top-2 z-30 mb-6"><NavJumpPills> for <NavJumpPills sticky class="mb-6">; 28 components drop scroll-mt-20 from their sec-* pill targets (SessionReading's transcript/raw/surface anchors kept: not pill targets). UsersRoster onto UxOverflowX (tableEl.$el); DeviceCard's overflow-x-auto is a grid, not a table, left alone. npm test 553 passed + bible-check clean. Checked on /inventory/providers/detail?provider=anthropic: band 81px, jumps land at 97, the Harnesses header pins at 81. The pane was hidden for part of this (no rAF, smooth scroll stalls), so jumps were checked with instant scrolls.
Phase 3 + docs (2026-10-01): design b9f4c633. Six hand-rolled overflow-x-auto wrappers around UxTableList onto UxOverflowX (replica DataTable, qcontrol/teams, pages/control-center, phase1/{tools,files,plugins}; tableEl refs read $el). /document-components: UxOverflowX + UxStickyBand registry entries (layout group) and demos; NavJumpPills sticky/stickyTop (demo exposes them), Filter band, UxTableListHeader description. Layer 49e90f0 (pushed): the template comment above each new root moved inside it, because in dev a root-level comment makes the component a fragment and ref.$el becomes the comment node (the UxOverflowX docs demo 500'd on $el.classList); production strips comments, so 0.9.24 builds are unaffected. The design dev server's stale OverflowX.vue caught up by itself; the mock's wide ledger now arms on :3000.
Captures (2026-10-01): design 54b769d6. Shot programs c104-sticky-band.json (6 mock states: rest, pinned, jump, wide, filter only, before) and c104-sticky-band-fable.json (provider + skill detail on :3032), thread band; only the c104 manifest entries staged (the c100 session's manifest edits left in the tree).
c103 qdash TODOs — 2026-09-30 review
todos plan 01 executed (2026-10-01): Nav (todos-2026-09-30/01-nav.md; no twin record) — on the c99 Fable app (qcontrol-c99-fable, c99/claude-code-fable-5.1, :3032 → seed :7882). Rail (shell/AppSidebar.vue NAV): MONITOR Overview · Inventory · Organization · Cost Center · Activity / GOVERN + SECURE Policies · Compliance · Findings · Reports / ADMIN Integrations · Dashboard Settings · Account (dashed pending ? UxAvatar, no viewer identity served, 01.9); WHERE ARE WE, THE FLEET, WHAT GOOD LOOKS LIKE, ACT and PROVE retired. Mark, 2026-10-01: Monitor order Overview · Inventory · Organization · Cost Center · Activity (EXP items trail Activity). Mark, 2026-10-01: Cost Center is a top-level MONITOR item on the existing /cost vCost page, out of EXP, no move, no placeholder (01.4); Compliance un-EXP'd too. Mark, 2026-10-01: off-tree pages ride Experimental (01.3) — Experimental on adds Live Activity · Performance · Harness Identity under MONITOR and Security Posture · Data Protection · Campaigns · Alerts under GOVERN + SECURE. Routes (M.2, 01.1 item-level): 12 git mvs — /fleet→/overview (title Overview, 01.12), /team→/organization (landing + six crumbs read Organization, 01.6), /team/{teams,users,endpoints}→/organization/…, /team/sessions→/activity (crumbs/title left to plan 02, so the page still reads Team / Sessions), /controls→/policies (page keeps "Control Center", 01.7); the sweep rewrote 126 link lines in 62 files (re-grep → 0 outside the redirect table and its specs); Organization's submenu is Teams · Users · Endpoints, Activity is a plain item (Working list label Activity). New DesignInProgress landings /reports, /settings, /account (M.1, copy as drafted, 01.8). Redirects: c92's team-routes.global.ts existed only in the ui app — ported into the Fable app (app/middleware/team-routes.global.ts, table in lib/moved-routes.ts), c92's four entries re-pointed at the final paths plus /team/*, /fleet, /controls; verified in the pane: /team/sessions/detail?runId= → /activity/detail?runId=, /team/teams/detail?team=Data → /organization/teams/detail?team=Data, /users/detail?user= → /organization/users/detail?user=, /fleet → /overview, /controls/detail?policyId=p5 → /policies/detail?policyId=p5, hash kept; Back after a full-load redirect returns to the prior page. What survives of c92 team-nav's ruling: the equipment-vs-who split — Inventory = what's in the fleet (equipment), Organization (was Team) = who and from where (Teams, Users, Endpoints); Sessions left the who-group for a third axis, what happened (Activity); Fleet Overview still leads, as MONITOR · Overview; DesignInProgress landings, WorkingNav and lib/working-nav.ts reused; it revises only the /team/* paths. Decisions 01.2, 01.5–01.13 taken on defaults (01.13: c100's LandingMockSidebar untouched — flag for its next mock thread). npm test 537 → 542 (+1 working-nav, +4 moved-routes) + bible-check clean. Design side: todos-pages.json routes moved (7 ids, _readme notes :3030 no longer serves them) + new nav id; reference/pages.md rows moved, new Overview row, Sessions row aliased Activity. After shots todos-2026-09-30/after/{nav,teams,sessions}.png (+ -full); published public/cycles/design/c103-todos0930-{teams,sessions}-{before,after}.png (subjects page/teams, page/sessions; nav has no baseline). The c103 README index table still lists /team/* routes (coordinator's file). Committed c6843703 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 02 executed (2026-10-01): Activity, was Sessions (todos-2026-09-30/02-sessions.md; no twin record) — on the c99 Fable app (:3032 → seed :7882), files at plan 01's moved paths (app/pages/activity/{index,detail}.vue). Header: title Activity; no crumb on the listing (the :breadcrumb prop dropped, Overview's idiom, rather than the plan's empty array); Session detail crumb Activity /, tab "Claude Code · 6eb07b16 · Activity · qdash" (02.7). Table: DataTable title="Recent Work", the Status strip on the same row (02.8); Started already there — M.3 satisfied, no edit. Band (SessionsBand.vue, 4-up grid-cols-2 md:grid-cols-4): Sessions · Harness Installs · Tokens · Cost (02.4); Flagged card and the page's flaggedTo removed, the Flagged quick filter and the history's clean · flagged lanes kept (02.6); Tokens' device is now the top-3 tokens share and Cost (02.5, $, links /cost) carries the cost share. Trends (02.1): lib Spark in each card's #title-right, per-day over the loaded rows via dailyTotals (moved verbatim from detail-bands.ts into actor-bands.ts with its doc comment, re-exported; 02.2 — rows, not /api/costs.series); em-dash on 24h. Mark, 2026-09-30: "add historical/trend data to all of these" — reverses c92 day-series §D's sparkless band cards. Harness Installs (02.3): distinct endpoint × harness (host|system_id) among the filtered rows, device by harness, "N of M scanned" from useInstallationList(). Its trend is projected (M.4): distinct installs with a session each day, badged from the new ledger entry PROJECTED.session.installsPerDay (contract GET /api/history?axis=agent — c92 day-series §B, still 404), retired when §B lands. Seed values, Past 7 days, match the plan: Sessions 52 (1 running · 51 completed · 0 failed, ▲ 11); Harness Installs 26 (Claude Code 11 · Codex CLI 8 · Cursor CLI 4 · Other 3; "26 of 39 scanned installs ran a session · 1 session without a harness id"; per day 7·7·2·2·10·11·11, ▲ 11, PROJECTED); Tokens 24m (tomas · Codex CLI 1.7M, elena · Claude Code 1.2M / 1.1M; top 3 = 17 %; ▲ 6.65M); Cost $331 ($35.69 / $23.63 / $21.65; top 3 = 24 %; ▲ $66.07 red). Checked in the pane: 24h 11 sessions, all four trends em-dash, badge kept; 30d 200 rows, Sessions provenance "· newest 200 — the trend stops at the cap", installs 34 of 39 · 11 without a harness id; status=running → every headline 1; the Cost card lands on /cost. At 1440 px the Harness Installs spark + badge wrap under its title (the documented #title-right narrow-card behavior). Decisions 02.1–02.8 on defaults. npm test 542 → 543 (+1 installs/trends it; the flagged expects dropped) + bible-check clean. After shot todos-2026-09-30/after/sessions.png (+ -full); published public/cycles/design/c103-todos0930-sessions-after-p02.png (+ -full), subject page/sessions set by hand to continue plan 01's pair (capture now derives page/activity from the route); no before-p02 — plan 01's after is this plan's before (c92 -p07/-p08 precedent). Committed 5f436e12 on c99/claude-code-fable-5.1 (local, unpushed).
Activity usage history (2026-10-01, ad-hoc thread after plan 02 — activity-usage-prompt.md): on the c99 Fable app (:3032), /activity. Opened as "c104", filed here at Mark's request. Reverses plan 02's trends: Mark, 2026-10-01, "remove the sparklines, instead add providers, models, harnesses to the second row showing historical data for each (uses per day)". Spark left all four band cards, so the projected installs trend + badge went with it and the PROJECTED.session.installsPerDay ledger entry retired. History row (SessionsHistory.vue): Sessions started (clean · flagged) · Providers · Models · Harnesses, each "Sessions per day" (sessions using the item), top 3 only (Mark switched from 5; no Other lane), all on byDay's columns so they share one day axis and filter with the table; provenance "top N of M · X % of sessions"; "per day" moved from titles to descriptions. New lib usageByDay + sessionsBand.usage (actor-bands.ts). Providers is projected: list rows carry no provider (only ?run= detail serves account_provider), so inferredProvider reads harness then model family then harness vendor (Cursor CLI → Cursor, matching /api/providers' cursor routes); badged from the new ledger entry PROJECTED.session.providerOfSession (contract: provider on /api/sessions rows). Layout: the history row is a DataMachineGroup on the band's grid (grid-cols-2 gap-x-10 md:grid-cols-4), so each chart sits under its band card; past 7 day-columns a chart spans the row (a 30d chart is ~890 px). Band → history gap 60 px (mb-[60px]; mb-15 isn't on the scale). History bodies bottom-aligned (scoped CSS, a layer candidate). Hover: a day on any chart opens the layer's DataHoverBreakdown (v0.9.23) — date title, the day's sessions as metric, rows = swatch · full label · count, plus a dim "other" row on the top-3 charts so rows sum to the day. Layer changes it rides on (q-nuxt-layer working tree, uncommitted, under evaluation; Mark may roll back): DataMachineGroup alignFooters (opt-in 5-row cards, provenance on its own row so hairlines align with no reserved space; the default keeps the documented "a tall device never pushes a sibling's footer"); DataHistoryGraph legendWrap (false = one line, out of the chart's width, labels ellipsize with the full name on hover, tighter 6 / 12 px spacing, 12 px chart → legend instead of 32); DataHistoryGraph @hover / @leave (column index, date, values, resolved series, pointer; a listener turns the native block titles off); the hovered day gets a highlight (bg-surface-sunken-subtle = grey-50 in light + 1 px stroke-strong border, 4 px past the sides, 10 px above, 6 px below, no layout shift) and its label turns text-content. Activity opts into all of them; the app-side legend / footer CSS they replaced is gone. A lane-packing change (no gap for a zero series) was made and reverted at Mark's request. Gotcha: Tailwind didn't extract classes inside a template-literal interpolation (plain string literals now), and the design site needed a nuxt.config.ts touch to rescan the layer. npm test 543 → 546 + clean. Not yet done: design-site docs for the three layer props, a layer release (with c104's Table.vue, as 0.9.24), and the Fable commit (SessionsBand.vue, SessionsHistory.vue, actor-bands.ts + test, projected/session.ts, activity/index.vue — uncommitted).
todos plan 03 executed (2026-10-01): Teams, Part A (todos-2026-09-30/03-teams.md §A–§C; no twin record; Part B, the design-site "Now + Trend — Variations" page, follows in its own line) — on the c99 Fable app (:3032 → seed :7882), app/pages/organization/teams/index.vue → TeamsListing.vue. Roll-down (§A): teamRows sorts by spend, then tokens, unassigned last (03.2; Frontend now above Data at 7d); the Spend tile's ranked bars name up to six teams + rest (03.3), and its provenance drops "top N = …%" unless a rest exists ("top 4 = 100 %" said nothing). Trend (§B, served, 03.1): new useTeamCostSeries (composables/fleet/costs.ts) — one /api/costs?team=&period= per team under the pill (03.8) through a fan-out Transport under useResult (poll, single-flight, gf.ready kept); team names sorted into the query key so a spend reorder doesn't refetch; 12-team ceiling (03.5): above it no fetch, every cell an em-dash titled "per-team history needs /api/history". New lib team-cost-trend.ts: teamCostTrend zero-fills each team on the fleet series' day axis (no usage = $0; a failed fetch = null → em-dash), trendTotal sums the shown teams per day, sparkOf → [{ count }]. The table gains a Spend trend column after Spend (qdash Spark, downIsGood; the column picker can hide it); the Spend tile carries a spark when the window has ≥ 2 days. Two deviations from the plan: the tile spark is the shown teams' per-day sum, not the raw fleet series — under a quick filter the tile reads $63 (Data) and a fleet line under it would draw other rows than the number (unfiltered they are the same line: Σ teams = total_cost at 7d); and Spark's last-day label goes through a local fmtDay ($0 for a zero day), because fmtC(0) renders "—" and Data at 7d read "▼ —", Spark's own "no history" glyph. Seed values, Past 7 days, match the plan: Spend $331, rows Payments $156.22 · Frontend $69.86 · Data $63.06 · Platform $42.30 in tile and table, provenance "24.0M tokens", trend cells ▲ $39.86 · ▲ $21.65 · ▼ $0 · ▼ $4.56. Checked headless (Playwright on :3032, no console errors): 24h → every trend cell an em-dash, no tile spark (one-day axis); 30d → 29-day lines, Spend 909.21 · 403.76 · 324.48 · 288.75 (= by_team); column picker hides Spend trend; quick filter Data → one row, its line identical to the unfiltered one, the tile spark redrawn on Data alone. Data: ?period=7d&team=Payments → 156.2176…, 5 days; team=unassigned → 0, 0. §C (window-over-window delta, breakdown over time) left to Part B (03.4, 03.6). Decisions 03.1–03.5, 03.8 on defaults. LATER: useTeamCostSeries calls useCosts() for its day axis beside usePeople's own, so /api/costs?period= polls twice on this page (exposing usePeople's costs would fold them); above the ceiling the tile loses its spark too. npm test 546 → 550 (+1 people-rollups it, +3 team-cost-trend; 546 = 543 committed + 3 from the uncommitted Activity usage-history thread) + bible-check clean. After shot todos-2026-09-30/after/teams.png (+ -full, replacing plan 01's); published public/cycles/design/c103-todos0930-teams-after-p03.png (+ -full), subject page/teams set by hand to continue plan 01's pair; no before-p03 — plan 01's after is this plan's before. Committed fc0b32c8 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 03 corrected (2026-10-01, Mark): "move the sparkline to a slot right beneath the val" — no such slot existed, so q-nuxt-layer DataMachine gains #value-below (inside the value group, under the number + delta; w-0 min-w-full so it takes the value's width and never widens it). The Spend tile's summed daily spark moves there from :spark (card foot). "use the existing DataMetricTrend for our trends in the table, lose the red/green" + "make the sparkline fill the whole space, pushing trend to the end" → each Spend trend cell is a full-width neutral DataMetricSpark + DataMetricTrend (later half vs earlier half of the window, %, new trendChangePct() in lib/team-cost-trend.ts, +1 test), em-dash below two days or with no earlier spend; qdash Spark no longer used here. Layer fix found on the way: DataMetricTrend hid any change ≥ 1,000 (it tested the abbreviated string, "2k" > 0) — now tests the number. App fe86f40d (local); tests 553 + bible-check clean. Layer edits on disk only (machine/index.vue shares c104's uncommitted alignFooters work; metric/Trend.vue) — to ship with c104's 0.9.24.
todos plan 03 follow-up (2026-10-01, after close): plan 03A's LATER "/api/costs?period= polled twice" fixed — useTeamCostSeries opened its own useCosts() for the day axis beside usePeople's (same shell-period URL; useResult's single-flight is per instance). usePeople now returns costDays and the Teams page passes it in. Measured headless on :3032/organization/teams?period=7d: one ?period=7d per 3 s poll, was two. npm test 553 (unchanged) + bible-check clean. Fable d77bcc9e (local). Not fixed (pre-existing, harmless): the per-team fan-out runs twice at startup (when and url watchers both fire).
gap-aware (2026-10-01, after close — gap-aware-prompt.md · gap-aware-plan.md): plan 03B's LATER, "a day not collected draws as zero", fixed in the layer and released as q-nuxt-layer 0.9.25 (b1c57f7, tag 4c298c0, publish workflow green; migration notes in the layer CLAUDE.md). DataMetricSpark (via svgMachine.sparkChart): { count: null } or a bare null keeps its x slot and breaks the line; a fill closes each run to the baseline with the stroke on the top edge only; a lone known day is a dot. Gap-free data is byte-identical (six-case sparkChart snapshot, before = after). DataHistoryGraph: a point with values: null or missing: true keeps its slot and label, draws no lanes, a hatched area and a dashed baseline; hover reports missing; values: null no longer throws; a per-series null still reads as 0. qdash Spark (Fable a011f775): lifts the pen at a null day and dots a lone day — the design replica's fix ported back; Campaigns' three sparks unchanged; npm test 553 + bible-check clean. Demos: _demos/DataMetricSpark.vue (gaps line, gaps area, first run, nothing collected) and _demos/DataHistoryGraph.vue + history-graph-fixtures.ts (gappedWeekFixture: Wed values: null, Sat missing, Fri a real zero; notCollectedFixture), checked headless on :3000 against the installed 0.9.25. The components were first checked on :3032 (sibling layer, live) through a scratch page, deleted afterwards. Lockfiles to 0.9.25: design c251200d, bob-wire 49a348c, app.qpoint.io 903338d, www e2b77ce, qflow 96a4b62, qcontrol ui d52ff77b, Fable c4d0e007. Not changed: the trend page's design-local workarounds (its own gap-breaking drawer for F3/F4) stay until it's integrated.
todos plan 03 Part B executed (2026-10-01): Now + Trend — Variations, the design-site exploration page (todos-2026-09-30/03-teams.md Part B; decisions 03.6–03.9 on defaults; thread docs in c100 — prompt · plan, record line "trend-variations" in c100 CYCLE.md). Page /pages/phase3/landing-trend-variations (registry after Lever Strip, overview, phase 3; the Phase 3 index lists it). Fixture app/data/landing-trend.ts: buildTrendWorld derives a deterministic daily series from c100's people (tokens30 / 30 × weekday × volatility × adoption ramp, zero before first seen and through an idle tail), split by harness, costed per harness, then harness → provider → model through landing-estate ROUTES / MODELS (a model exists from its firstSeenDays, so the mix shifts); every rollup is a sum, so every drawing cross-foots. Knobs: world (seed / 20 / 200 / 1,500) · state (first-run = last 2 days known) · gaps (0 / 10 / 40 % of days not collected → null, fleet-level) · volatility (steady / bursty / spike). Seed snapshot (03.9) app/data/landing-trend-seed.ts: Meridian from :7882, captured 2026-10-01 — 81 served days (2026-04-03 → 2026-07-01), cost + tokens per team per day, served totals per period (7d fleet $331.44 · Payments $156.22 · Frontend $69.86 · Data $63.06 · Platform $42.30; 30d $1,926.20; all $4,211.15), window compositions, /api/teams roster; the 24h / 7d / 30d series are exact slices of all and Σ captured days = served at every period. Parts (app/components/landing/trend/, replicate-first): LandingTrendSpark (qdash Spark replica — breaks its line at a null day, which qdash doesn't), LandingTrendDraw, LandingTrendForm, LandingTrendRollDown. Sections: §0 Part A as shipped (Spend $331 rolled down, tile spark = Σ shown teams, Spend trend column; em-dash at 24h) · §1 F0–F21 + AH, Activity's history row (2026-10-01) · §2 R1–R7 roll-downs in the DataMachine seat at S2 / S3 / S4 · §3 seven cell forms, merged vs separate, three sizes · §4 F14–F18, F20, AH with the grouping lever · §5 F19 per card / per page + title switchers (#title metric, #title-right trend window, reserve, fadeKey) · §6 lab (forms × S1–S6 or free W × H, D / M / R checks) · §7 ledger (keep 10 · maybe 11 · kill 2 — F13 horizon, F21 delta-only), served-today column, live cross-foot table. Trend window follows the pill with a fixed-90d lever (03.8); on the seed, breakdown over time and sessions per day say "needs /api/history" (03.6). AH uses the uncommitted q-nuxt-layer DataHistoryGraph legendWrap + @hover / @leave (live layer on :3000; a rollback quiets its hover, nothing else depends on them). Checked headless at 1440 against :3000: 4 worlds × 5 windows + 6 lever states — no console or hydration errors, cross-foot clean on every state; fixture harness (worlds × gaps × states × windows × metrics × groupings) 0 failures; the fixture type-checks strict. No design lint / test scripts exist. Captures (program scripts/shot-programs/c103-trend.json, thread "trend"): public/cycles/design/c103-trend{,-full,-rolldowns,-models,-gaps,-gaps-full,-lab,-lab-full,-24h}.png. Committed 8c2372c0. LATER: a layer null path for DataMetricSpark and DataHistoryGraph (a not-collected day draws as zero there); the qdash Spark gap fix ported back; F1's DataMetricTrend prints "+35.98", not "$35.98".
todos plan 04 executed (2026-10-01): Users (todos-2026-09-30/04-users.md; no twin record) — on the c99 Fable app (:3032 → seed :7882), app/pages/organization/users/index.vue (plan 01's path). Supersedes c102 plan 14 (04.1) — Mark, 2026-10-01: "I ignored this in the previous plan, ours supersedes"; c102 14 §B's group-by-reason card is not built (04.4 keeps it as a later select option), and c102 plan 14 §A's Devices → Endpoints rename landed here: the roster column (cols.devices.name, width 100 px; key, shown('devices') and sort unchanged), its tooltip (no endpoints), the expand row's identity-grid label and the page subtitle. Lib (§A): PersonRow.reasons (attention grouped by kind, counted, worst first; a lone item keeps its verb-link) and PersonRow.severity; ATTENTION_SEVERITY (critical 4 · no identity 3 · detected-only 2 · elevated 1), attentionReasons, attentionSubjects (every row with attention — Elevated now counts, 04.3 — worst first, then issues, then spend), ATTENTION_SORTS (severity · spend · sessions · issues · name, 04.5); usePeople returns attention (from all rows, not the Team pill, 04.6) and registers a new attention filter key (FILTER_KEYS.attention: any + every reason label). Staged components (04.7, R3): components/lib/AttentionList.vue (ranked by a parent-owned key, stable ties, cap 5, the active sort's value right-aligned when it has a fmt, #footer {total, shown} / #empty) and AttentionReasons.vue (inline tone-labelled reasons, ×N counts, NuxtLink titled with the verb when to); both import nothing from lib/ (their item types are their own); two LAYER-CANDIDATES.md rows (DataAttentionList, UxAttentionReasons). Band (§B): the card is now Users needing attention (04.8) with a #title-right UxSelectInline by severity ▾; the old first-reason-wins builder and its r.detected read are gone (the band reads no field). Seed, Past 7 days, by severity: No identity (muted) no identity · priya detected-only · wei detected-only · felix detected-only · chen elevated posture (amber); by spend: priya $57.05 · wei $37.65 · chen $17.97 · felix $13.39 · No identity —; by sessions: wei 6 · priya 5 · felix 5 · chen 2 · No identity 1; by issues: all 1 (severity order kept); by name: chen · felix · No identity · priya · wei. Under the rows "Show in the roster ↓" (5 ≤ cap, so not "Show all N"), then seat holders PROJECTED "1 holds a seat, zero telemetry — investigate" — the badge sits beside its label, but at 1440 px the sentence wraps to a second line (the plan expected one). Expanded view = the roster (§C–§D, 04.2): an Attention column after Coverage (AttentionReasons, — when clean), sortable by severity; "Show in the roster ↓" sets attention=any and switches the strip's key to Attention (any · detected-only · elevated posture · no identity). Checked in the pane: clicking wei opens wei's roster row (identity grid reads Endpoints); wei's detected-only lands on /organization/endpoints/detail?host=wei-tower; Show in the roster → ?attention=any, 5 rows (wei · felix · priya · chen · No identity); elevated posture → chen alone; Attention ↓ → No identity, wei · felix · priya (detected-only ties keep the roster's own order, not spend), chen; All → 15 people; no console errors. Deviations: ATTENTION_SORTS is a typed array rather than as const (so it feeds AttentionList's sorts prop without a readonly cast); the new spec block builds its own rows/ann (the plan's snippet borrowed the personRows describe's locals). Decisions 04.1–04.8 on defaults. npm test 550 → 552 (+2 its; 550 = 547 committed + 3 from the uncommitted Activity usage-history thread) + bible-check clean; both Verify greps empty. After shot todos-2026-09-30/after/users.png (+ -full); published public/cycles/design/c103-todos0930-users-{before,after}.png (+ -full), subject page/users set by hand (publish left it unset). Committed c8a15b16 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 04 corrected (2026-10-01, Mark): "let's add a avatar to the user component" — AttentionList rows (Users needing attention) lead with a small UxAvatar beside the name, as in the roster; the No identity bucket gets a pending dashed "?" avatar. Rows align centre instead of baseline. npm test 552, delta 0 + bible-check clean. Committed e96e1b63 on c99/claude-code-fable-5.1 (local, unpushed).
todos plan 04 corrected (2026-10-01, Mark): "either add descriptions to these two data machines, or remove the description from activity" → added: Coverage "Known users the sensor has seen", Users needing attention "Identity, coverage or posture gaps" (Activity keeps "Users using AI agents"), so the band's value rows align. "a bit smaller avatar" → AttentionList avatars 36 → 24 px (!h-6 !w-6; UxAvatar has no smaller size). Committed 1a306a51. Then "let's remove" the seat-holders line → the PROJECTED "1 holds a seat, zero telemetry — investigate" footer is out of the attention card (the ledger value stays); committed on c99/claude-code-fable-5.1 (local). Tests 552 + bible-check clean throughout.
q-nuxt-layer 0.9.24 released (2026-10-01, Mark: "release the layer, commit work"): layer 845959e (c103: DataMachine #value-below, DataMachineGroup alignFooters / rowGap, DataHistoryGraph hover + legendWrap, legend wrap, the DataMetricTrend ≥ 1k fix) on top of c104's sticky band (useStickyBand, UxStickyBand, UxOverflowX, DataTable pinned thead), tagged v0.9.24, published by CI. Lockfiles refreshed and committed in design, bob-wire, app.qpoint.io, www.qpoint.io, qflow, qcontrol ui/ and the Fable app (which update-consumers.sh doesn't list — it was on 0.9.22). The Activity usage-history code was committed on the Fable branch as 92336c1a. Tests 553 + bible-check clean. Final shots of nav, Activity, Teams and Users published as c103-todos0930-*-final.png.
todos-2026-09-30 planned (2026-10-01): journal 2026_09_30 → 4 plans under todos-2026-09-30/ (01-nav, 02-sessions → Activity, 03-teams incl. design-site trend exploration, 04-users attention component); no sweep (General ignored). /todos grammar gains §Ignoring — CANCELED (item), #skip (subtree), BEGIN (cutoff), with !SKIP ME! read as an alias; README template gains ## Ignored.
c102 qdash TODOs — 2026-09-25 review
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.
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).
c101 Qmap Surface
- session close (2026-09-30):
- Pushed:
mainpushed to origin, including this cycle's commits and the other sessions' commits that were queued ahead of it. - Where it stands: the brief is with the designer, at
https://design.internal.qpoint.io/cycles/design/c101/brief. - Next:
- The designer's first round: their framing, the cast, and one real scene (Priya's harness).
- Then pick the next steps together; the engineering sequence waits in build-notes.md.
- Not done:
- qmap Phase 0. Commit its uncommitted work as-is, per Mark's ruling; it can run any time.
- Brief upkeep.
designer-brief.md,app/data/brief-c101.tsandbrief.mdmust be edited together when the brief changes.
- Open outside the cycle:
design-f39.pages.devstill served the site without a login on 2026-09-30, whiledesign.internal.qpoint.iois behind Access. Mark is handling the Cloudflare side.
- Pushed:
- kick-off (2026-09-28):
- Research sweeps: qmap's state, the 17 design cycles that touched it, qdash's Surface data, and the problem registry (prior-work.md).
- Mark's rulings:
- Map the elements the Surface section renders, including skills and harnesses.
- A design-site mock comes first.
- c100 is unrelated.
- Commit qmap's uncommitted work as-is (see build-notes.md).
- The first plan was rewritten, on Mark's steer, into a designer's brief (brief.md): six problems (P1–P6), 13 actors as pawns, the problems around the actors, links, deliverables, open questions, and one real Surface in the appendix. Mark cut the actor-configurations and constraints sections.
- Three companion research documents, linked from the brief's header:
- explorations.md: the qmap experiments reviewed from their captures. Category rugs around one subject (c21, c22), nested rugs (c25), dimming (c16) and regrouping in place (c5, c13) already work. P2, P4 and P6 are untouched. c26 flatland was never captured, and the policy-detail mock's map disagrees with its own table.
- pawn-inventory.md: only the Agent and the Endpoint (machine) have finished pixel art. Endpoint, Repo, Model, Tool and Account have no 3D form of their own. The 28 voxel placeholders aren't drawn to the c47 family.
- precedents.md: 13 external precedents, 8 patterns and 5 anti-patterns. The closest is Kiali: idle configured services are greyed and hidden by default, and undeclared outside hosts go to a catch-all node.
- Brief corrected with these findings: c47 was a brief, not finished art; the UxPixelArt link lives in the
displaygroup; "not allowlisted" can mean unreviewed or refused. - fixtures.md holds team, endpoint and fleet scenes from the seed. It also holds live MCP data showing three server states: configured + used, configured-never-used, and used-but-unconfigured. The third was added to P2.
- problem alternates (2026-09-28): Mark liked some of P1–P6 more than others and asked for alternates, starting with inventory jobs-to-be-done. problems-alternates.md has four sets: A inventory (nine cards: take stock, not on the books, watched, shelfware, where it lives, who answers for it, keep it current, what's new, duplicates), B governance, C investigation and D spend/enablement. It also has a crosswalk to P1–P6 and a suggested six-card inventory composition. Mark: "I like all of these… let's have an exhaustive set." Folded into the brief as twenty problems in six families:
- Stock S1–S4
- Coverage and hygiene C1–C5
- Exposure and risk R1–R5
- Decisions D1–D2
- Value V1–V3
- Telling T1
Each is a job statement with its question, what the map shows, data status and persona. P1–P6 and the overlapping alternates were merged (a merged-or-dropped table records how). Three are new: C3 know what's alive (the running flag, last active), R4 see what it could do (read vs write, not served) and T1 show it to someone new. The actor table gained the matching states. Deliverables gained a problem-coverage matrix, and the lens comps now draw from the families.
- designer brief (2026-09-28): at Mark's request (a designer should have great leeway in how they frame the problem; we supply constraints, goals, data and stories), designer-brief.md is a heavily edited version of
brief.md, about a quarter of its length (1,500 words against 5,400). It keeps the situation, the goal, the twenty questions as the viewer's own questions with a data mark (● 13 · ◐ 4 · ○ 3), the cast with the states that matter, and a short list of what's fixed. Everything else is left open, with the old open questions as starting points only. The first asks are the designer's framing, the cast, and one real scene. Dropped: the solution-shaped "map shows" lines, the prescribed deliverables, internal numbering and bookkeeping, and data fields.brief.mdstays as the reference and its TLDR count is corrected (13 served, not 14).
- explainer page (2026-09-28): the designer brief as a design-site page, Surface Map, at
/cycles/design/c101/brief(app/pages/cycles/design/c101/brief.vue, content inapp/data/brief-c101.ts, kept in step withdesigner-brief.md). It is a static route, so c99's report-only[project]/[id]/report.vuestays untouched. It shows:- Surface today: Priya's real Surface rendered with the live
DataSurfaceSection/DataSurfacePanel. - The goal.
- The twenty questions: six family cards with ● ◐ ○ data marks (13 · 4 · 3).
- The cast: 13 cards, using the real
AgentPawn/EndpointPawnwhere art exists and qdash's glyph or "?" where it doesn't, plus the harness pawn's four states. - What's fixed and what's open, what to see first, and material links. Those include this cycle's companion docs through
/cycles/design/c101/doc/….
The cycle page links to it through a**Report:**header. That header gained an optional— notesubtitle (parseCycleMd.ts, cycles[id]/index.vue); c99's card keeps its old text. It was verified in the browser pane on the live:3000dev server: no console errors, and all doc and component links resolve. - Surface today: Priya's real Surface rendered with the live
- published (2026-09-28): design
d1bb0687(c101 paths only; c100's uncommitted work was left in the tree) was deployed asdeploy→fbefb99d. It is live:_deploy.jsonreadsd1bb0687, and/cycles/design/c101/brief/serves Surface Map with the Surface panels and pawns. The cycle page carries the report card, and the doc routes render. The designer's URL ishttps://design.internal.qpoint.io/cycles/design/c101/brief, behind Access (Mark set up the designer's access). The first deploy attempt had noGITHUB_TOKENin a non-interactive shell;zsh -ic 'npm run deploy'works.
c111 Cycles by Week
- Checked:
/cycles/weeks(0.6 s) and/cycles/weeks/2026-09-28render with sections in order (verdict, viewer, Commits, Cycles, Pages & components, Log, Captures, Releases & deploys); non-Mondays show the error state;/cycles/<project>/<id>still resolves (the staticweeksdir wins over[project]); both redirects 301 with the week kept;/cyclesand/pages/_metalink to/cycles/weeks; the week view's links point at/cycles/weeks/<monday>.
c99 Nuxt Backend Interface
- 2026-09-28 · Stage 3 wave 2 and the S4 gate. Wave 2 built the rest (
60129fd7→6daac227), so all 43 routes are on the new app:- session detail;
- providers, accounts and harness installs;
- the four inventory details;
- integrations, compliance, framework and controls;
- data protection, cost and posture;
- the Working nav.
Parity after the wave's reviews and fixes: team 67, inventory-a 65, inventory-b 94, governance 68 and fleet-live 56, with 0 failing and 1 pending, a case that S4a then closed.- S4a (
c3817b51→e689c54e) landed the chrome levers the lanes asked for:- on
EntityMark,EntityChip,EntityAbsent,LedgerSection,ToneTextandStatTile; - lib now returns every port row;
lib/monitoredis the one home of the V1 rule, and one housepluralcarries counts (SIGNOFF V12);- LAYER-CANDIDATES gained 47 components, 14 fixes and an Amendments table.
- on
- Gate: 1614 specs, tier test 16/16, typecheck clean.
- S4b (verification): a full parity sweep with budgets, a Working-nav walk, and write parity on the scratch seed.
- 2026-09-28 · S4b, S4c and S4d.
- S4b verified the whole app (
63470928; designa57bb884):- parity: 273 cases and 78 SPA checks;
- budgets: 45/45, with the new app making 696 requests in 65 s against the reference's 2,866;
- a clean walk over the Working nav, the sidebar, the route map and 908
/labscenarios; - a new write-parity harness (
phase4/s4/write-parity.mjs): 46/46 verbs match on a scratch seed, and the shared seed was never written.
Its fixes: a refused stream's backoff, the Working nav's reads, a legacy integration route, and one egress request body. New SIGNOFF rows L4, K6 and ND6. - S4c, a whole-app Tyler-lens review in four lenses (
98fe7e92→598df17e), produced twelve rulings (R1–R12) and five disjoint fix groups:- one-line provenance headers in 334 files, with no cycle citations left in code;
- one clock option, one team join, and composed views that own their readiness;
- one column picker, and named verb-error ports;
- one error binding on every table.
Evaluation (phase4/s4/evaluation.md): adherence B+, clarity B+, consistency B+, simplicity A−. - S4d (design
4ea675e1) brought the law up to the code: bible v1.4, the contracts amendments, and registry v1.4 written out and checked against the code. It also wrote phase4/RECORD.md.
- S4b verified the whole app (
- 2026-09-28 · report-opus thread (planned, not executed). Mark asked what this track would add to the report page so that its work is evaluated too. The eight additions are planned, so the thread can be picked up later: report-opus-plan.md and report-opus-prompt.md.
c67 Teams
- Pulled into c100 (2026-09-28): Mark ruled that c100 (Landing Pages) "pulls from these ideas and builds the best ones". The strip forms (levers strip, micro-swarm) and the levers lens set become candidates in c100's
landing-team-lens-bakeofffor the/teamlanding hero. The horizon graduates are proposed as exhibits for the Home specialist lenses. Checkpoint items 7–8 (strip form and lens set) are decided there. See../c100.landing-pages/plan.md.
Captures
223 screengrabs taken this week, 143 of a subject with an evolution history.
Home composed as a showroom floor: six exhibits from the bake-offs in the qdash shell, re-lit through five specialist lenses (?as=)
















Now + Trend — Variations: the Teams page as Part A shipped it (§0) on a dated seed snapshot, then 22 trend forms + Activity's history row, roll-downs, table cells, breakdown over time, toggles, a degradation lab with auto-checks, and a keep / maybe / kill ledger








Index Micros — Variations: the index's micros as white cards with rounded corners and a soft shadow, smaller data, and the whole section on white; presets A–E and every knob live
















The titled band in the live qdash app (q-nuxt-layer 0.9.27): PageHeader's UxPageTitle pins beside the global filter, the jump pills dock under it, and the backing fades in a shade off the page with a two-layer shadow








One sticky band: the global Filter and NavJumpPills stay sticky where they sit and register with useStickyBand, which publishes --q-sticky-top; UxStickyBand backs them once pinned, table headers pin directly under the band, pill jumps land below it, and UxOverflowX lets only a too-wide table scroll sideways








The c99 Fable app promoted to crates/qdash/ui and embedded in the binary: the same seed, the restructured nav (Monitor · Govern + Secure · Admin), thin pages over the data-interface bible.










Releases & deploys
Layer releases 9
Design-site deploys 0
No deploys recorded this week.
Note: Deploys come from this checkout's deploy-branch reflog, which starts 2026-10-16.







