Cycles by week
Week of Sep 28

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

Started
11
Still open
74
Closed
8
Record entries
102
Commits
242
Captures
223
Releases · deploys
9
Home, showroom: verdict caption over six exhibits (floor, estate, org, …) at 200 people, attention state
c100Landing Pages24 captures · 16 log entries — the week's busiest recordSee all 24 shots ↓

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

c109Index

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.

started Oct 210 in the log
c108Honest States

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.

started Oct 28 in the log
c107qdash Cutover

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

started Oct 26 in the log
c106Sticky Title

The page title (layer UxPageTitle / Fable PageHeader, not the actor headers) joins c104's sticky band, which becomes two rows with scroll-direction modes.

started Oct 28 in the log
c105Cost Center

Re-evaluate the qdash /cost page against what the backend now serves, and re-draw it on the Organization / Inventory listing pattern

started Oct 14 in the log
c104Sticky Band

One sticky band for qdash detail pages: NavJumpPills and the global filter pin together, and table headers pin directly under them

started Oct 17 in the log
c101Qmap Surface

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.

started Sep 286 in the log
c100Landing Pages

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.

started Sep 2816 in the log

Still open 17

c99Nuxt Backend Interface

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

started Sep 272 wks · moved this week3 in the log
c67Teams

Refine the qdash /teams design — composition from c61 concepts, mapping workspace as the pre-SCIM write path, slim spend overview, credentials relocated

started Aug 148 wks · moved this week1 in the log
c95Trigger-Bar Column Picker

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

started Sep 252 wks · quiet 1
c94TODO Execution Process

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

started Sep 252 wks · quiet 1
c93Table Column Picker

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

started Sep 222 wks · quiet 1
c12Micro ProblemsMarket Analyst

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.

started Sep 212 wks · quiet 1
c92qcontrol New Pages

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

started Sep 183 wks · quiet 1
c90qcontrol Preview

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

started Sep 163 wks · quiet 1
c89Teams–Sessions Listings

First-pass mocks for Teams listing header upgrade and net-new Sessions listing page in phase1 dashboard style

started Sep 153 wks · quiet 2
c88Global Filter

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).

started Sep 153 wks · quiet 2
c7avoma-notesMarket Analyst

Explore and integrate Avoma notes data into extraction pipeline and dashboard visualizations.

started Feb 25parked
c4refinementMarket Analyst

Refine how extracted data is displayed in the dashboard and improve extraction quality where gaps exist.

started Feb 24parked
c3oauthMarket Analyst

Add Google OAuth to restrict dashboard access to @qpoint.io team members.

started Feb 20parked
c69Operating System

Methods & tooling retro — evaluate how we work against the design methodology, restore order, modernize the skill/agent tooling, and make the philosophy load-bearing

started Aug 15parked
c62build-partner

Build-partner portal — research, ideation, and a plan for a page that makes partners insiders

started Aug 8parked
c55agent-market-definition

Align the qcontrol agent-monitoring dashboard to specific personas and find market alignment — hypothesis-first, validated against calls later.

started Jul 24parked

Closed 8

c109Index

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.

closed Oct 2 · started Oct 210 in the log
c108Honest States

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.

closed Oct 2 · started Oct 28 in the log
c106Sticky Title

The page title (layer UxPageTitle / Fable PageHeader, not the actor headers) joins c104's sticky band, which becomes two rows with scroll-direction modes.

closed Oct 2 · started Oct 28 in the log
c104Sticky Band

One sticky band for qdash detail pages: NavJumpPills and the global filter pin together, and table headers pin directly under them

closed Oct 1 · started Oct 17 in the log
c66cost-center

Add unit-of-measurement toggle to qdash /cost page — switch display between currency ($) and tokens

closed Oct 1 · started Aug 14
c49Fix the Cloudflare Pages Deploy

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)*

closed Sep 30 · started Jun 11

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.

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

Oct 2

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.

Oct 2

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).

Oct 2

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).

Oct 1

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

Oct 2
  • 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:
    • NavVerticalSubmenu already supports a toggle-only parent (no to, plus match), 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.
Oct 2
  • decisions (2026-10-02): Mark answered Q1–Q9 and a Q10 (plan §9).
    • Defaults: index at /, a listing-links row under each section title, /inventory and /organization → /#section, a new DataMachineMicro component, 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).
Oct 2
  • Phase 1a (2026-10-02): done on qdash in the files c108 isn't touching. Uncommitted.
    • Sidebar: Inventory and Organization are disclosure buttons (controlled NavVerticalSubmenu with no to). Q5 changed mid-phase from open-only to toggle: a second click closes.
    • Landings: pages/inventory/index.vue and pages/organization/index.vue are deleted. movedTarget() in lib/moved-routes sends /inventory, /organization and /team to /#section in one hop.
    • Section data: INDEX_SECTIONS in lib/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_KEYS re-keyed; MCP adoption → /inventory/mcp-servers; the DLP tile → harnesses; connectors → /#inventory; /overview links and the Users crumb → /#section.
    • Checks: specs pass (27, including new movedTarget and INDEX_SECTIONS cases) and npm run check is 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.
Oct 2
  • Phase 2 (2026-10-02): layer and demos built. Uncommitted; no version bump.
    • Layer, new: DataMachineMicro (data/machine/Micro.vue) and DataIndexSection (data/index-section/).
    • Layer, backwards-compatible props: DataRankedBars micro / bare; DataDonutChart hideLegend.
    • 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: null renders "—", not DataMetricValue's spinner. The whole card is a real NuxtLink.
      • A #mark slot holds the projected glyph.
      • It is the same 4-row subgrid as DataMachine, so DataMachineGroup needs 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), with micro 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.
    • Design site: demos at /components/data-machine/data-machine-micro and /components/data-machine/data-index-section, with six scenarios plus every device form, and a composed three-section page. Fixtures in app/data/index-micro-fixtures.ts (35 micros, in the shape Phase 4 will use). Demo helpers: components/index/MicroDevice.vue and ProjectedMark.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.
Oct 2
  • 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 origin feat/new-pages.
    • What's in it: the 19 files under crates/qdash/ui/app as they stood at 13:10, including the two staged landing deletions.
    • Checked before committing: 572 specs, bible-check clean. 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 has NavVerticalSubmenu match / v-model:open, so the commit runs on the published layer.
    • Still to do: Phase 1b and Phase 2 (the layer DataMachineMicro / DataIndexSection and the design-site demos) are untouched and still uncommitted.
Oct 2
  • 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 a listing and its listingTitle, plus byListing().
    • The DataIndexSection demo gained a layout switch: 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.
Oct 2
  • 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 df57642 and 9a2df40 (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.ts wires the listings' own composables; useSkillListing exposes a five-feed state.
      • New components/index/MicroDevice.vue and components/lib/ProjectedRing.vue. / renders three DataIndexSections.
      • 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 check clean.
    • Built and pushed: dist regenerated (ba39df37, layer 0.9.28) and pushed to feat/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.
Oct 2
  • Phase 5, documentation (2026-10-02):
    • Captures: 8 shots, from c109-index-qdash.json (:3030; subjects page/index, component/nav-vertical-submenu, page/teams) and c109-index-design.json (the demos).
    • Archive entry 2026-10-02-c109-index.
Oct 2
  • 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 / /#organization directly. 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 /overview stays routable by URL.
    • Dist regenerated after each (4d6e4605, d05ebdd7).
    • Gotcha: the shared :3030 dev server's watcher missed batch edits. Touching each file one at a time (with a short pause) got them picked up.
Oct 2
  • 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: IndexMicroProto and IndexProtoSection.
    • Captures: threads rollup-labels (3) and micro-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): DataIndexSection cards (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, minColumn 190 and a 28 px title. DataMachineMicro card (inherits) and a 14 px bold title. DataRankedBars microLabels="beside".
      • Lockfiles committed in all six consumers.
      • qdash: 0fbee449 (roll-down labels); dist 5d7dd5da, built from a clean worktree of HEAD so the c110 session's in-progress Activity files stay out. Verified on the :3034 clone. Pushed to feat/new-pages (d05ebdd7..5d7dd5da).
      • Record: capture c109-qdash-index-cards (thread micro-cards) is now the archive entry's hero; HISTORY's c109 entry has an after-close note; the DataMachineMicro demo has a card control.

c108 Honest States

Oct 2
  • 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.
Oct 2
  • 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.
Oct 2
  • part 1 (2026-10-02) — chassis + the false all-clears, review stop. qcontrol f76fa091, local on feat/new-pages, not pushed.
    • Chassis: feedState() (error first; a failed poll after a load stays ready); shell useBackendHealth, 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; layout BackendBanner (D2 banner, D5 "last updated" tag); lib SkeletonRows.
    • Rollups: postureBand averages scored harnesses only, and avg and coverage are null when 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-check clean.
    • 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.mts gained api: 'slow' | 'down' (page or action) to simulate the backend. It matches paths starting /api/, because nuxt dev serves source modules like /_nuxt/composables/api/….
    • Concurrent session: the c106 sticky-title port is working in the same ../qcontrol tree (PageHeader, useDetailTitle, 13 detail pages, layouts/default.vue; layer 0.9.26 committed as 2dacfeaa). 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-bands successPct … : 100 (tool success with no judged calls).
Oct 2
  • 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 on feat/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), a BarList state port, 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 /api held 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-state percent … : 100 for 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.
Oct 2
  • 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 covers useToast + failReason, ToastStack in 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-check clean, 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.
Oct 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") + ToastStack in 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 catch at all, or a bare return 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.
Oct 2
  • embedded build (2026-10-02). Release binary from HEAD (bf351751, dist includes c108), on a fresh seed copy: qdash-r31-check 34/34 routes clean in slow / down / up; qdash-d3-check 12/12.
Oct 2
  • 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 used absolute, which anchored it to the document's bottom, below the fold on any long page (Users: y=1273 on a 900 px window). fixed restores the intended float, and the toast stack moves to bottom-16 so 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.mts gained fail:/api/x (writes only) and failget:/api/x.
    • qdash-r31-check gained 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-ui runs npm ci in the same directory and breaks a live nuxt dev (503) until it restarts.

c107 qdash Cutover

Oct 2
  • 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.ts edit;
    • 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.
Oct 2
  • 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 over git+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.js pre-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.
Oct 2
  • rebase (2026-10-02): Mark asked to rebase from main (C10). A trial ran in a throwaway worktree:
    • feat/new-pages onto origin/main 8fffe91d: one commit (587c235e) conflicts in qevents CHANGELOG.md and examples.rs, both mechanical. cargo check passes and make schemas regenerates 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 new c107/cutover branch in its own worktree. The c99/* branches stay as they are. feat/new-pages lands with --force-with-lease, and the archive tags have to come first.
Oct 2
  • 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 c4d0e007 and Opus 598df17e. Discarded the stray working-nav.ts edit; it's already in Fable.
    • P1. Pushed the annotated tags archive/qdash-ui-gen2→d52ff77b, archive/qdash-opus-5.5→598df17e and archive/c99-compare→4bd30359.
    • P2. Rebased in worktree qcontrol-c107 on c107/cutover, identical to the trial. 186 commits now sit on origin/main 8fffe91d.
    • P3 and P4. a83234e9 (move only) and 18cdaef5 (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). Then 98f17218 (qcontrol twin c16).
    • Verified on the embedded release binary:
      • 556 specs and bible-check pass;
      • 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/dlp slowest at 3.1 s.
    • Correction to ui-preservation.md: the :7882 seed 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-final and cutover, 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 main stays unchanged and new work lands on the new-pages branch.
      • feat/new-pages force-pushed to 98f17218 (lease c8152d9a). origin/main was 8fffe91d before and after; local main untouched. The branch is 0 behind and 186 ahead of main, 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.
      • ../qcontrol reset to the new tip (its tree was clean). The gen-2 dev server on :3030 was stopped. npm ci and 556 specs pass there. Launch config qdash-app (:3030, NUXT_LOCAL_LAYER=1, seed :7882 via qdash-seed) serves Organization → Users with no console errors.
      • Repointed: design CLAUDE.md, .claude/launch.json (qdash-app/qdash-seed; qdash-app-opus removed), the /todos page registry and todos-pages.json (base :3030), and memory (qdash-active-app, c107, the index).
      • Teardown: removed the qcontrol-c99-fable, qcontrol-c99/_compare and qcontrol-c107 worktrees and the local c107/cutover branch; stopped :3032. Kept the qcontrol-c99/claude-code-opus-5.5 worktree, because a parked session's cwd and an untracked .nuxtrc are in it; remove it with git worktree remove once that session is done. qcontrol-c99/_seed/ stays, because qdash-seed uses it.
Oct 2
  • opus wrap-up (2026-10-02). Mark asked whether the "parked Claude session" in the Opus worktree needed anything.
    • It didn't. Session 2e2a1c24 was deleted on 2026-09-28. What was left was an orphaned tail -f | ugrep watcher on its parity log, which lsof had labelled claude.
    • Stopped the watcher and removed the worktree. The branch and the archive/qdash-opus-5.5 tag hold the code; the untracked .nuxtrc is already superseded by H3.
    • The run recipe was tested from the tag: npm ci, 1,660/1,660 specs, and /team/users renders on :3031 against 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-opus plan is marked superseded.
    • The c99 report page has an outcome card linking to STORY.md and REVIEW-OPUS.md.
Oct 2
  • 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 on design-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 ../qcontrol release binary and restarted qdash-seed, so :7882 now serves the promoted app.
    • Opened c108 · Honest States for the R31 pass.
    • PR #713 is parked; no reviewer outreach.

c106 Sticky Title

Oct 2

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.

Oct 2

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.

Oct 2

Mock refinements + cleanup (2026-10-02):

Oct 2

Design refinements + documentation (2026-10-02):

Oct 2

Phase 1 + 2 — the layer and its docs (2026-10-02):

Oct 2

Phase 3 + 4 — release and the qdash port (2026-10-02):

Oct 2

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

Oct 2
  • superseded in part by c109 (2026-10-02): Mark ruled (c109 plan §9 Q9):
    • /inventory and /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.
Oct 1
  • 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 fixture app/data/landing-trend.ts gives 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 in app/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.
Sep 30
  • phase3 (2026-09-30): Mark asked for "a phase 3 to the pages index". Added the phase3 PagePhase (registry type + pageHref, subjects.ts path match), a Phase 3 card on /pages, and /pages/phase3 listing the c100 pages. The bake-off moved to app/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.
Sep 30
  • 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.
Sep 30
  • 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 into app/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/teams column.
    • At 1,500 people the flag count saturates ("40 of 40 teams flagged").
    • Unassigned has to be pinned last, or seriation leads with it.
Sep 30
  • 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 new app/data/landing-story.ts holds each lens's headline, one-line story, story order and lever verb. Lens selects (UxSelectInline) sit in every DataMachine's #title-right and 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 #title replaces the title text and keeps the title's type. The title prop becomes optional, and a standalone card is now max-w-full.
      • UxSelectInline inherit makes 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 #title when the choice changes what the card is, and #title-right when it changes how the same subject is shown.
      • Documented as a copyable DataMachine demo preset (per component_philosophy §4 "base + curated presets") plus a #title overflow scenario, UxSelectInline inherit scenarios, 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; reserve stays 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: #title picks the subject; #title-right picks a parameter or view of it; a subject with a parameter carries both. fadeKey covers 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 with solid + thin it's the meter. LeverMicro's meter now is <UxPercentBar solid outlined thin /> everywhere (Coverage, Active, Retention, Harness), and the design-local mono flag is gone.
      • "+N more teams" is a button: it opens the rest into the list and folds back ("Show top 6").
      • Also documented: a UxPercentBar demo scenario, the registry entry and a layer CLAUDE.md note.
Sep 30
  • 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 grew landing-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) and landing-viz.ts (inks, colour jobs, squarify, unit grid, frame components).
    • Built by the main thread: #2 landing-team-people-field (5 forms) and #8 landing-beyond-data (X1–X9 with keep / maybe / kill).
    • Built by parallel background builders: #3 landing-inventory-estate-bakeoff (alluvial · bowtie · switchboard · pixel body), #4 landing-inventory-supporting (4 cards × best-prior vs fresh), #5 landing-fleet-directions (A–H incl. live qmap), #6 landing-fleet-supporting (who-runs-what, shifts, loading dock), #7 landing-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 beside UxPopover once 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-breakdown demo (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
Sep 30
  • 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 LandingTeamBreakdown on 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 / rollup to landing-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.
Sep 30
  • 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; LandingMockSidebar mirrors the current AppSidebar; LandingMockBar is mock-only (world knobs, show parts, parts bin).
    • One URL-backed world across the mocks (useLandingMock, ?scale/state/period/parts).
    • LandingMockSlot names 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.
    • 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 into landing-home-parts.ts (not exported).
Sep 30
  • 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's buildStrip), 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 (UxPercentBar solid, drawn by the sibling's LeverMicro), which doesn't take the ink.
Sep 30
  • 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 a UxSelectInline scoped to its group. The picks live in the URL (?v.adoption= · ?v.cost= · ?v.risk=), a reserve of 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
Sep 30
  • shipped + documented (2026-09-30):
    • Committed as design c3e9202a and deployed.
    • The live site lost every hover card and title switcher: npm run deploy builds 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 (design 56ce1068). 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-bakeoffs and -landing-mocks.
    • Mark, same day: the Team mock's People slot defaults to skyline (?v.people=field keeps field + list), the Team hero defaults to the matrix (?v.hero=tilemap keeps the tile map), and /pages lists Phase 0 first and _meta last.
Sep 28
  • 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.
Sep 28
  • rulings (2026-09-28): Mark's answers in rulings-prompt.md:
    • /fleet becomes 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, /pages pattern, overview registry 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.
Sep 28
  • 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.
Sep 28
  • team-lens-bakeoff (2026-09-28): the shared fixture world app/data/landing-fixtures.ts has 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 (registry overview, 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

Oct 1

Stage 1 (2026-10-01). Initial prompt; evaluation of the nine cost-bearing feeds, eight lenses, value ranking and backend asks.

Oct 1

Kick-off (2026-10-01). Mark's answers (evaluation §9):

Oct 1

Phase 1, mock round 2 (2026-10-01, awaiting Mark's review):

Oct 1

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

Oct 1

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.

Oct 1

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.

Oct 1

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.

Oct 1

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.

Oct 1

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.

Oct 1

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.

Oct 1

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

Oct 1

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).

Oct 1

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).

Oct 1

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).

Oct 1

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).

Oct 1

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.

Oct 1

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).

Oct 1

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.

Oct 1

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".

Oct 1

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).

Oct 1

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).

Oct 1

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.

Oct 1

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.

Sep 30

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

Oct 1

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).

Oct 1

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.

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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.

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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).

Sep 30

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

Sep 30
  • session close (2026-09-30):
    • Pushed: main pushed 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.ts and brief.md must be edited together when the brief changes.
    • Open outside the cycle: design-f39.pages.dev still served the site without a login on 2026-09-30, while design.internal.qpoint.io is behind Access. Mark is handling the Cloudflare side.
Sep 28
  • 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 display group; "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.
Sep 28
  • 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.
Sep 28
  • 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.md stays as the reference and its TLDR count is corrected (13 served, not 14).
Sep 28
  • 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 in app/data/brief-c101.ts, kept in step with designer-brief.md). It is a static route, so c99's report-only [project]/[id]/report.vue stays 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 / EndpointPawn where 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 — note subtitle (parseCycleMd.ts, cycles [id]/index.vue); c99's card keeps its old text. It was verified in the browser pane on the live :3000 dev server: no console errors, and all doc and component links resolve.
Sep 28
  • published (2026-09-28): design d1bb0687 (c101 paths only; c100's uncommitted work was left in the tree) was deployed as deploy → fbefb99d. It is live: _deploy.json reads d1bb0687, 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 is https://design.internal.qpoint.io/cycles/design/c101/brief, behind Access (Mark set up the designer's access). The first deploy attempt had no GITHUB_TOKEN in a non-interactive shell; zsh -ic 'npm run deploy' works.

c111 Cycles by Week

Sep 28
  • Checked: /cycles/weeks (0.6 s) and /cycles/weeks/2026-09-28 render 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 static weeks dir wins over [project]); both redirects 301 with the week kept; /cycles and /pages/_meta link to /cycles/weeks; the week view's links point at /cycles/weeks/<monday>.

c99 Nuxt Backend Interface

Sep 28
  • 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, ToneText and StatTile;
      • lib now returns every port row;
      • lib/monitored is the one home of the V1 rule, and one house plural carries counts (SIGNOFF V12);
      • LAYER-CANDIDATES gained 47 components, 14 fixes and an Amendments table.
    • 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.
Sep 28
  • 2026-09-28 · S4b, S4c and S4d.
    • S4b verified the whole app (63470928; design a57bb884):
      • 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 /lab scenarios;
      • 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.
Sep 28
  • 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

Sep 28
  • 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-bakeoff for the /team landing 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=)

Home, showroom: verdict caption over six exhibits (floor, estate, org, …) at 200 people, attention state
Home, showroom: verdict caption over six exhibits (floor, estate, org, …) at 200 people, attention state
Stage 3 composed mocksSep 30
Team hero as lens cards: one DataMachine per lens, lever-strip §3 'Top 6 + more', three columns
Team hero as lens cards: one DataMachine per lens, lever-strip §3 'Top 6 + more', three columns
Stage 3 composed mocksOct 1
Team hero as three grouped cards (adoption · cost · risk), each titled by a lens select — the DataMachine title-switcher pattern
Team hero as three grouped cards (adoption · cost · risk), each titled by a lens select — the DataMachine title-switcher pattern
Stage 3 composed mocksOct 1
Team hero as the tile map at 1,500 people
Team hero as the tile map at 1,500 people
Stage 3 composed mocksOct 1
Team, matrix hero (Mark's default) over the coverage skyline (Mark's default) and the four doors
Team, matrix hero (Mark's default) over the coverage skyline (Mark's default) and the four doors
Stage 3 composed mocksOct 1
Home seen as Finance: spend and waste exhibits carry the ink
Home seen as Finance: spend and waste exhibits carry the ink
Stage 3 composed mocksSep 30
Home on first run: the designed discovery strip instead of empty exhibits
Home on first run: the designed discovery strip instead of empty exhibits
Stage 3 composed mocksSep 30
Home with the pixel variants: floor as bake-off #5's pixel field, org as bake-off #2's one org field
Home with the pixel variants: floor as bake-off #5's pixel field, org as bake-off #2's one org field
Stage 3 composed mocksSep 30
Endpoints listing — after todos-2026-09-25 plan 02
Endpoints listing — after todos-2026-09-25 plan 02
Sep 30
Team detail — Data — after todos-2026-09-25 plan 13
Team detail — Data — after todos-2026-09-25 plan 13
Oct 1
Teams (solo) — after todos-2026-09-25 plan 12
Teams (solo) — after todos-2026-09-25 plan 12
Sep 30
Workspace detail — payments-core — after todos-2026-09-25 plan 11
Workspace detail — payments-core — after todos-2026-09-25 plan 11
Tool detail — Glob — after todos-2026-09-25 plan 10
Tool detail — Glob — after todos-2026-09-25 plan 10
Tools listing — after todos-2026-09-25 plan 09
Tools listing — after todos-2026-09-25 plan 09
Skill detail — deploy — after todos-2026-09-25 plan 08
Skill detail — deploy — after todos-2026-09-25 plan 08
Skills listing — after todos-2026-09-25 plan 07
Skills listing — after todos-2026-09-25 plan 07

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

Teams (solo) — after todos-2026-09-30 plan 01
Teams (solo) — after todos-2026-09-30 plan 01
Users (solo) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Users (solo) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Teams (solo) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Teams (solo) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Nav — Monitor · Govern + Secure · Admin (c103 plan 01 + Mark's reorder)
Nav — Monitor · Govern + Secure · Admin (c103 plan 01 + Mark's reorder)
Oct 1
Activity listing (was Sessions) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Activity listing (was Sessions) — c103 final (2026-10-01, after corrections + layer 0.9.24)
Seed at 24h: one served day — every trend is an em-dash and the tile drops its spark (the case for a fixed-90d trend window)
Seed at 24h: one served day — every trend is an em-dash and the tile drops its spark (the case for a fixed-90d trend window)
Now + Trend — Variations (c103 plan 03 Part B)Oct 1
1,500 people, 40 % of days not collected, a spike day: every gap drawn as a gap or an em-dash, never a zero
1,500 people, 40 % of days not collected, a spike day: every gap drawn as a gap or an em-dash, never a zero
Now + Trend — Variations (c103 plan 03 Part B)Oct 1
§6 degradation lab at 200 people, 30d: every form × S2–S6, three auto-checks per cell (D direction · M magnitude · R driver)
§6 degradation lab at 200 people, 30d: every form × S2–S6, three auto-checks per cell (D direction · M magnitude · R driver)
Now + Trend — Variations (c103 plan 03 Part B)Oct 1
c109Index18 shots

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

B · micro cards: every micro on white with 12 px rounded corners and a soft two-layer shadow, on the app's page colour; 14 px bold titles, data as today, 16 px gaps; section titles at 28 px
B · micro cards: every micro on white with 12 px rounded corners and a soft two-layer shadow, on the app's page colour; 14 px bold titles, data as today, 16 px gaps; section titles at 28 px
Micro cards (design prototype space)Oct 2
qdash / on layer 0.9.29 — Mark's pick, preset B: every micro a white card (12 px corners, 14 px padding, soft shadow) with a 14 px bold title, 16 px gaps, 28 px section titles, roll downs with 10 px bold labels. (Activity here carries the c110 session's in-progress rework.)
qdash / on layer 0.9.29 — Mark's pick, preset B: every micro a white card (12 px corners, 14 px padding, soft shadow) with a 14 px bold title, 16 px gaps, 28 px section titles, roll downs with 10 px bold labels. (Activity here carries the c110 session's in-progress rework.)
Micro cards (design prototype space)Oct 2
A · today, for reference: qdash after the labels pass — flat micros, 16 px bold titles, 48 px gaps, 24 px section titles
A · today, for reference: qdash after the labels pass — flat micros, 16 px bold titles, 48 px gaps, 24 px section titles
Micro cards (design prototype space)Oct 2
C · micro cards with the data shrunk: 13 px titles, 16 px values, 6 px segment bars, 12 px sparks, 10 px corners, 12 px gaps
C · micro cards with the data shrunk: 13 px titles, 16 px values, 6 px segment bars, 12 px sparks, 10 px corners, 12 px gaps
Micro cards (design prototype space)Oct 2
Every preset side by side: Inventory's first ten micros under A–E as each ships
Every preset side by side: Inventory's first ten micros under A–E as each ships
Micro cards (design prototype space)Oct 2
D · the whole section on a white card (16 px corners, soft shadow), micros flat inside at the small data sizes
D · the whole section on a white card (16 px corners, soft shadow), micros flat inside at the small data sizes
Micro cards (design prototype space)Oct 2
E · white section card holding the micros as sunken tiles, small data, 10 px gaps
E · white section card holding the micros as sunken tiles, small data, 10 px gaps
Micro cards (design prototype space)Oct 2
Third pass (Mark: "even more gap, bigger titles"): micro titles 16 px bold ink, the grid at 48 px between rows and between columns; roll-down labels stay 10 px Inter bold beside each hairline bar. (Activity shows 6 micros here: another session is reworking its band at the same time.)
Third pass (Mark: "even more gap, bigger titles"): micro titles 16 px bold ink, the grid at 48 px between rows and between columns; roll-down labels stay 10 px Inter bold beside each hairline bar. (Activity shows 6 micros here: another session is reworking its band at the same time.)
Small labels on the roll downsOct 2
A failed save (D3): a routing chip rejected — inline ✕ on the panel, a toast, the chip reverts
A failed save (D3): a routing chip rejected — inline ✕ on the panel, a toast, the chip reverts
Honest states — final (parts 1–3)Oct 2
Alerts with qdash unreachable: no "Nothing an alerting policy would fire on ✓"
Alerts with qdash unreachable: no "Nothing an alerting policy would fire on ✓"
Honest states — final (parts 1–3)Oct 2evolution →
Compliance loading: the attention strip waits instead of "✓ all 0 findings mapped"
Compliance loading: the attention strip waits instead of "✓ all 0 findings mapped"
Honest states — final (parts 1–3)Oct 2evolution →
Cost Center loading: spend tiles "—", breakdown and tables wait, no "No spend yet"
Cost Center loading: spend tiles "—", breakdown and tables wait, no "No spend yet"
Honest states — final (parts 1–3)Oct 2evolution →
Data Protection with qdash unreachable: no "No sensitive file access ✓", tiles "—"
Data Protection with qdash unreachable: no "No sensitive file access ✓", tiles "—"
Honest states — final (parts 1–3)Oct 2evolution →
A failed save (D3): the evidence export fails — inline ✕ beside the button and a toast
A failed save (D3): the evidence export fails — inline ✕ beside the button and a toast
Honest states — final (parts 1–3)Oct 2evolution →
Findings with qdash unreachable: the banner, every count "—", no "Fleet is clean"
Findings with qdash unreachable: the banner, every count "—", no "Fleet is clean"
Honest states — final (parts 1–3)Oct 2evolution →
Models listing loading: skeleton rows, not "No model usage captured yet"
Models listing loading: skeleton rows, not "No model usage captured yet"
Honest states — final (parts 1–3)Oct 2evolution →

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

qdash /inventory/harnesses at rest: Inventory / Harnesses at 28px on the sidebar's first hairline, the global filter on the title row; no backing
qdash /inventory/harnesses at rest: Inventory / Harnesses at 28px on the sidebar's first hairline, the global filter on the title row; no backing
Phase 4 — in qdash (0.9.27)Oct 2evolution →
Scrolled down: the title pinned at 15px, the pills docked under it as the outlined compact bar with 16px below them — a 94px band (the Installs table sits in a horizontal scroll box, so its header scrolls rather than pins)
Scrolled down: the title pinned at 15px, the pills docked under it as the outlined compact bar with 16px below them — a 94px band (the Installs table sits in a horizontal scroll box, so its header scrolls rather than pins)
Phase 4 — in qdash (0.9.27)Oct 2evolution →
Pill jump to Surface: the band holds compact through the smooth scroll and the heading lands 16px under it
Pill jump to Surface: the band holds compact through the smooth scroll and the heading lands 16px under it
Phase 4 — in qdash (0.9.27)Oct 2evolution →
qdash harness detail (Claude Code) at rest: the page title at its full 28px (detail pages dropped their 15px), the actor header and the jump pills below
qdash harness detail (Claude Code) at rest: the page title at its full 28px (detail pages dropped their 15px), the actor header and the jump pills below
Phase 4 — in qdash (0.9.27)Oct 2evolution →
Scrolled down: Harnesses pinned at 15px beside the compact filter (it shrank in 500ms), a 54px band on surface-sunken-subtle with the 7px + 28px shadow; the page scrolls under it
Scrolled down: Harnesses pinned at 15px beside the compact filter (it shrank in 500ms), a 54px band on surface-sunken-subtle with the 7px + 28px shadow; the page scrolls under it
Phase 4 — in qdash (0.9.27)Oct 2evolution →
Scrolling down: the title pins beside the Filter at 15px with its hairline, the Filter shows values only, the pills dock under the title — grey-350 outline, black semibold, the active pill purple bold with a 2px ring — and the shadowed band is 90px; the Installs header pins right under it
Scrolling down: the title pins beside the Filter at 15px with its hairline, the Filter shows values only, the pills dock under the title — grey-350 outline, black semibold, the active pill purple bold with a 2px ring — and the shadowed band is 90px; the Installs header pins right under it
Phase 1 — on the layerOct 2
Filter bandCompact off: the Filter keeps its labels while pinned, so the right column (8 + 65 + 8) sets the band instead of the title and pills
Filter bandCompact off: the Filter keeps its labels while pinned, so the right column (8 + 65 + 8) sets the band instead of the title and pills
Phase 1 — on the layerOct 2
Pill jump to Sessions: the band holds compact through the smooth scroll and the heading lands 16px under it; the Sessions pill takes the ring in 200ms
Pill jump to Sessions: the band holds compact through the smooth scroll and the heading lands 16px under it; the Sessions pill takes the ring in 200ms
Phase 1 — on the layerOct 2

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

At rest: filter on the title row, pills below the tiles, no backing; the readout shows --q-sticky-top 81px (8 + 65px filter + 8)
At rest: filter on the title row, pills below the tiles, no backing; the readout shows --q-sticky-top 81px (8 + 65px filter + 8)
Sticky bandOct 1
Fable /inventory/providers/detail (Anthropic): pills and filter pinned as one band, the Harnesses ledger header pinned under it
Fable /inventory/providers/detail (Anthropic): pills and filter pinned as one band, the Harnesses ledger header pinned under it
Sticky bandOct 1evolution →
Fable /inventory/skills/detail (deploy): the band over the Installs and Sessions ledgers, header pinned under it
Fable /inventory/skills/detail (deploy): the band over the Installs and Sessions ledgers, header pinned under it
Sticky bandOct 1evolution →
Before c104 (today's per-page wrapper, header at top-0): the pinned header slides under the pills and filter, which cover its first and last columns
Before c104 (today's per-page wrapper, header at top-0): the pinned header slides under the pills and filter, which cover its first and last columns
Sticky bandOct 1
Filter only (pills off): the band is still 81px, the filter's height; the header pins under it
Filter only (pills off): the band is still 81px, the filter's height; the header pins under it
Sticky bandOct 1
Pill jump to Sessions: the heading lands 16px below the band (97px) and its pill lights
Pill jump to Sessions: the heading lands 16px below the band (97px) and its pill lights
Sticky bandOct 1
Pinned: filter and pills side by side at 8px over the band backing; the Installs ledger header pins directly under it at 81px
Pinned: filter and pills side by side at 8px over the band backing; the Installs ledger header pins directly under it at 81px
Sticky bandOct 1
Wide ledger (14 columns): UxOverflowX arms horizontal scroll, so this header gives up pinning while the ledgers that fit keep it
Wide ledger (14 columns): UxOverflowX arms horizontal scroll, so this header gives up pinning while the ledgers that fit keep it
Sticky bandOct 1

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.

Promoted app /overview on the Meridian seed (was /fleet in gen 2)
Promoted app /overview on the Meridian seed (was /fleet in gen 2)
Promoted app (cutover)Oct 2evolution →
Promoted app /alerts on the Meridian seed
Promoted app /alerts on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Promoted app /campaigns on the Meridian seed
Promoted app /campaigns on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Promoted app /compliance on the Meridian seed
Promoted app /compliance on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Promoted app /cost on the Meridian seed
Promoted app /cost on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Promoted app /dlp on the Meridian seed
Promoted app /dlp on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Promoted app /organization/endpoints on the Meridian seed (was /team/endpoints in gen 2)
Promoted app /organization/endpoints on the Meridian seed (was /team/endpoints in gen 2)
Promoted app (cutover)Oct 2evolution →
Promoted app /findings on the Meridian seed
Promoted app /findings on the Meridian seed
Promoted app (cutover)Oct 2evolution →
Activity listing (was Sessions) — after todos-2026-10-01 plan 01
Activity listing (was Sessions) — after todos-2026-10-01 plan 01
Activity listing (was Sessions) — before todos-2026-10-01 plan 01
Activity listing (was Sessions) — before todos-2026-10-01 plan 01

Releases & deploys

Layer releases 9

v0.9.31Oct 2v0.9.31: DataRankedBars labelWidth 'auto' — label column fits the longest label, bars fill the rest
v0.9.30Oct 2v0.9.30: DataHistoryGraph opt-in stacked + maxHeight (design c110)
v0.9.29Oct 2v0.9.29: index micros as cards (design c109) — DataIndexSection cards, DataMachineMicro card, DataRankedBars microLabels beside
v0.9.28Oct 2v0.9.28: index micros (design c109) — DataMachineMicro, DataIndexSection, DataRankedBars micro/bare, DataDonutChart hideLegend
v0.9.27Oct 2v0.9.27: sticky band polish (design c106) — the backing fades in at its height, title shrink on its own 500ms clock, lighter shadow and backing, 16px under docked pills
v0.9.26Oct 2v0.9.26: the sticky band grows a title (design c106) — UxStickyBand title, UxPageTitle pins and settles, NavJumpPills docks and compacts, Filter bandCompact
v0.9.25Oct 1v0.9.25: gap-aware DataMetricSpark + DataHistoryGraph (design c103) — a day not collected draws as a gap, not a zero
v0.9.24Oct 1v0.9.24: c104 sticky band (useStickyBand, UxStickyBand, UxOverflowX, DataTable pinned thead), c103 DataMachine #value-below + alignFooters, DataHistoryGraph hover/legendWrap, DataMetricTrend ≥1k fix
v0.9.23Sep 30v0.9.23: DataHoverBreakdown, DataMachine #title/fill/reserve/fadeKey, UxPercentBar outlined, UxSelectInline inherit

Design-site deploys 0

No deploys recorded this week.

Note: Deploys come from this checkout's deploy-branch reflog, which starts 2026-10-16.

Qpoint Brand Style Guide