Teams
Refine the qdash `/teams` design — composition from c61 concepts, mapping workspace as the pre-SCIM write path, slim spend overview, credentials relocated
Why
c61 covered both qdash pages but the work diverged: integrations ran 11 iterations, got layer extractions, and shipped to feat/control-center; teams stopped after one day at research + a single 4-concept ideas mock. The research is strong (10-product competitive scan, ranked JTBD, 4 built concepts + two composed-stack candidates) but nothing was iterated, composed, or shipped. Splitting teams into its own cycle gives that half the same refinement arc integrations got — without redoing any research.
The page itself has real problems the research surfaced: "Spend by team" duplicates Cost Center's table from the same /api/costs.by_team field (with a cross-footing bug between the two); team "management" is a free-text string typed into a hidden inline cell; the credentials table near-duplicates /identity with a cruder risk formula; and the most important under-served job — mapping observed identities to the real org — has no designed surface at all.
Objective
Deliver iterated design mocks composing the c61 teams concepts into a ship-ready page recommendation, with the four product decisions applied (see teams-refinement-plan.md). Ends at a review checkpoint with Mark — qdash/backend changes are a gated follow-on, not in this cycle's initial scope.
Scope
In:
teams-refinement-plan.md— locked IA recommendation (section order tied to ranked JTBD) + decisions record- Design iterations on the design site:
teams-ideas-v2(composition bake-off: Stack A vs Stack B),teams-ideas-v3(mapping workspace + credentials-gist exploration),teams-ideas-v4(visual/affordance pass + adoption strip) - page-registry entries per mock (group
admin) - Checkpoint presentation: chosen stack, mapping form factor, credentials gist, spend overview treatment, Cost Center EXP-gate question
- (scope grew 2026-08-14/15, per Mark's iteration prompts) the page arc v5–v8 (states & scale, state machine + component audit, component-native pass, person expand card) and the Teams-strip series (
teams-strip-*: metrics, axis, portals, overdrive, swarm, bites, levers, horizons, windows) — each thread documented asstrip-*-prompt.md/-plan.mdin this directory
Out:
- Any qcontrol/qdash code changes before the checkpoint (ship track documented in the plan doc, gated on review)
- SCIM/IdP implementation (stays a projected mock)
- Re-research — c61's
research-teams.md,research.md§2, andteams-ideas.vueare inputs, not open questions
Key Changes
- Cycle split (2026-08-14): Created from c61's teams stream — see
initial-prompt.mdandteams-refinement-plan.md. - teams-ideas-v2 (2026-08-14):
/pages/teams-ideas-v2— composition bake-off. Coda Stacks A ("accountable roster") and B ("teams first") each rendered as a full composed page with the four decisions applied: one merged caveat, mapping coverage % in the summary strip, risk-story roster with per-person identity-gist chip (→ /identity), unmapped band (A) vs mapping drawer (B), slim team cost overview with share bars + "Cost Center →" handoff, adoption strip (fleet-level in A, per-team in B). Verdict: Stack A with B's card language — J1 is the top job, IA doc calls the page a Fleet lens, and 4 free-text teams don't earn cards as the organizing unit pre-SCIM. v3 opens: mapping form factor (band/drawer/sub-route), identity-gist depth, adoption slot, Cost Center EXP gate. Type floor corrected to text-11 (v1 used text-10, which silently renders 16px). - teams-ideas-v3 (2026-08-14):
/pages/teams-ideas-v3— the write path designed. Three mapping form factors on A's spine: inline band (expands in place, cheapest interruption), slide-over drawer (full evidence one-at-a-time, but modal and fights bulk), sub-route/teams/mapping(queue/dormant/history tabs, org rail, Okta-remapped lifecycle new→mapped→dormant→archived with disable-don't-delete). Identity gist at three depths (chip only / chip + method / icon + posture summary strip). Verdict: band primary with "open workspace →" escalation to the sub-route; drawer cut; gist = chip + conditional posture strip (appears only while consumer keys > 0). - teams-ideas-v4 (2026-08-14):
/pages/teams-ideas-v4— single composed ship candidate in the shipped-integrations idiom (heavy-rule sections: text-18 bold + 3px grey-300 rule + text-11 why-line). Stack A spine with v3 verdicts folded in. Remaining calls made and annotated: adoption folds into deltas (people stat + team-chip pills, no separate strip at 14 people), team drill-down is filter-in-place (team detail page deferred to SCIM day), mapping band ships collapsed. Ends with the 5-item checkpoint agenda (composition, mapping model, gist depth, adoption/drill-down calls, Cost Center EXP gate). - Verification (2026-08-14): All three pages SSR 200 on the live dev server, Tailwind rescan via nuxt.config touch after each new file.
- Registry section split (2026-08-14): New
teamspage group ("Teams & Users — People, teams, and identity attribution pages") between Security and Admin; all four teams-ideas pages moved into it. Admin group description trimmed to "Org and connector administration pages". - teams-ideas-v5 (2026-08-14):
/pages/teams-ideas-v5— states & scale pass on the v4 composition. Four states: first-run (mapping workspace as onboarding hero, teams created in the act of assigning, no roster yet), all-clear (verdict "Nothing needs you", roster falls back to spend order as the attribution ledger, every conditional gone), attention·14 (v4 corrected — verdict line names the work, level-1 expand row designed with top_context chips, level 2 stays AgentExpandDetail), attention·214 (search primary, band drops "map here" above ~8 queue items and becomes pure escalation, team chips cap at top-5-by-spend + unassigned with the tail behind Cost Center). Corrections: verdict line above the strip in every state; amber grammar tightened to attribution debt only (alias, unassigned, band) — credential gist and spend outliers go neutral, severity lives on /identity and Cost Center. Fixtures mirror userRollups() keys + /api/costs by_team rows so the ship rewrite is transcription. New checkpoint item 6: period control (?period= on /teams vs pinning /cost?period=30d on handoff). - teams-ideas-v6 (2026-08-14):
/pages/teams-ideas-v6— state machine + component mapping. The four v5 states rendered from one template with a live UxTabGroup switcher (proof the design is conditionals over a single composition, not four designs); section × state matrix as the rewrite spec; onboarding progress line added to first-run ("3 of 8 assigned · $12 of $41 attributed"); vocabulary locked — assign (act) / mapped (state) / attributed (money), "map here ▾" corrected to "assign here ▾". Component audit against component-registry.ts (151 components) + qdash locals: table/chips/bars/search map cleanly (DataTable #details, UxTag, UxCode, UxPercentBar, UxTabGroup, UxAvatar — the last two used live in the mock); qdash PageHeader and StatTile are promotion candidates; three confirmed gaps — verdict line (shared need with c68 index), toned stat sub-line, dashed amber band (hand-rolled 3× in v5). Extraction shortlist ranked with one prerequisite: amber enters the layer tone vocabulary (UxPill stops at warn). Note: layer CLAUDE.md/catalog-skill are stale (~35 components) — component-registry.ts is authoritative. - teams-ideas-v7 (2026-08-14):
/pages/teams-ideas-v7— the four states rebuilt on real components, iterating from v5. Roster = layer DataTable: per-column #slots, #details expand in the house ExpandRow card (agents with UxCode context chips + UxPill danger), column search at scale (search: true on Person replaces the hand-rolled search bar), limit + #footer for the collapsed tails, numeric spend so column sort works. UxAvatar in every person cell (incl. first-run queue), UxTag for the scale filter chip. Teams section = v6's chip row cherry-picked whole, kept as one local functional component (TeamChipRow) so the ShareChip extraction boundary is pre-drawn. Findings from the swap: the column config IS the state machine (all-clear/attention/scale are one component + different column arrays and slot presence); DataTable seams — footer is bottom-right not a full-width tail row, and sort is header-label-based so risk-rank relies on row order until a riskScore column exists. Verdict line, toned stat subs, amber band, share chip stay hand-rolled — the four confirmed v6 gaps. - teams-ideas-v8 (2026-08-14):
/pages/teams-ideas-v8+app/components/teams/PersonExpandCard.vue— the person expand card designed. Avatar fix: v7 (and v1) crushed UxAvatar initials with a text override; the component's real sizes are small w-9/text-18, reg w-11/text-21 — override removed. Every person row in every state now expands (DataTable bareDetails + the c59 UxTableListExpandSection stack) into TeamsPersonExpandCard: (1) identity & attribution — reg avatar, mono email, source pill → /identity, alias explained (felix's @duck.com merge note), OS user/machines/first-last seen, team with change/assign write path; (2) open work — conditional, the risk story exploded into severity + description + verb rows; (3) agents & usage — agent rows with UxCode top_context chips + a usage line (tokens/% fleet, spend, model chips, tools/MCP). Card replaces the interim AgentExpandDetail at level 1; per-agent "detail →" stays level 2. Deliberate omissions: credential math (/identity), spend history (Cost Center), session logs (agent detail). Could-adds parked for checkpoint: activity sparkline, per-model spend, recent sessions, inline egress decisions. - teams-strip-ideas (2026-08-15):
/pages/teams-strip-ideas— the Teams strip gains a metric lens. Full catalog brainstormed (spend/adoption/risk/identity families × ranked jobs; per-team trends impossible — daily series is fleet-wide). Five lenses picked for a UxTabGroup switcher (c66 idiom, mode semantics — FilterGroup and dropdown rejected on the page): Spend (default, reconciles with Cost Center), $/person (honest cross-team comparison), Active now (only near-real-time signal), Risk (triage heatmap), Agents/person (adoption depth). Excluded with reasons: Tokens (Cost Center owns the unit toggle), Sessions, People (permanent sub-line anchor), riskScore (sort-only). Four bar semantics, one chip geometry: share-of-total (grey, sums to 100%), per-person scaled-to-max (% dropped from sub-line), fraction-of-self meter (success hue announces the switch), counts-with-severity (no bar — severity never encodes length; "1 Crit · 2 Elev" in words, "clear" quietly). Sort follows the lens desc, Unassigned pins last (amber value in every mode; per-identity denominators; "3 of 61 running" as mapping prompt). Two live strips — Meridian + scale, where the top-5 cap re-ranks per lens (Research/$-per-person, Support-Ops/Active, Core-Banking/Risk surface; none are top spenders). Ship notes: ?teamsBy= URL sync, tooltip = full stat sheet, per-chip estimated asterisk, teamRollups() as the fleet-rollups.ts sibling, by_team-vs-rollup unassigned seam handled by union. - teams-strip-axis (2026-08-15):
/pages/teams-strip-axis— nine live treatments of the Teams strip on a simplicity ↔ expressiveness axis, lensed baseline at 0, shared lens switcher where treatments can listen. Simplicity: −1 quiet chips (name+value pills, stat sheet on hover — the responsive collapse), −2 ticker (one prose line — the export/digest form), −3 one bar (single stacked proportional object — share-only, the first casualty of abstraction is lens flexibility), −4 headline (one verdict fact per lens). Expressiveness: +1 stat chips (all five metrics per chip — kills cross-team scanning, the tooltip does this job better), +2 fingerprints (normalized column shapes — interesting failure, demands expertise), +3 people cards (one state-colored dot per person — composition instead of aggregate; felix IS the red dot), +4 matrix (scoreboard table, every column keeps its own bar semantic — DataTable, nearly free, but it's the Cost Center table upgrade, not a strip). Axis punchline: the lens switcher exists exactly at the midpoint — simpler loses lenses one by one, richer stops needing them. Verdict: baseline holds the working state; the headline (−4) becomes the all-clear Teams voice (and the c68 landing candidate); people cards (+3) are the challenger to test at checkpoint, with a density question above ~12 people/team. - teams-strip-portals (2026-08-15):
/pages/teams-strip-portals+ thread docs (strip-portals-prompt.md/-plan.md, plus same-day retro backfillsstrip-metrics-prompt.md,strip-axis-prompt.md). Thesis: a visual means the data it summarizes; a portal proves it — the honesty stance made interactive. Six-law portal grammar (a mark opens what it depicts · hover previews, click commits + writes URL · every aggregate carries its receipt, discrepancies printed not smoothed · negative space is data · descent stops at real data · Esc ascends one level). One composed interactive strip at 26-team scale: Auto lens (data picks each chip's metric; small-caps lens tags; named comparators, no z-scores — "2.7× fleet median", never σ; Risk precedence absolute; sticky selection; degenerates to baseline when nothing is notable; membership = the briefing + residual archive), focus gesture (chip → people card with all five stats + stateful dots + "+N idle" door, siblings → quiet chips, focus = roster filter; per-team lens tabs cut), receipts (addends re-add to the headline; the by_team-vs-rollup seam printed in amber — "$4.02k attributed · $80 unresolved"; estimated-formula popover; descent floor = sessions), return door (bidirectional chip-dot ↔ roster-row hover highlight — /document-pattern candidate), residual chip ("21 teams · nothing notable · $5.4k" — opens the tail, where the matrix belongs), whisper line (fixed-height hover preview — the demoted hover-panel). Lab rejects on-page: hover peephole, per-chip lens tabs, recursive in-chip decomposition, z-scores. Checkpoint strip question now three-way: lensed baseline vs people-cards vs composed portal. - teams-strip-overdrive (2026-08-15):
/pages/teams-strip-overdrive+ thread docs (strip-overdrive-{prompt,plan}.md). Deliberate overshoot study — "how can we err too far in visual communication?" Six graph-heavy treatments of the scale world in the c62 house grammar (dependency-free viewBox SVG, hash jitter,<title>on every mark, halo labels; palette = the c62-validated categorical order + attribution amber, re-run through the dataviz validator this session — ALL PASS), each with a filed crime report: helix wall (metaphor debt — c62's own verdict — + unreadable amplitude), colony (misjudged organic area, aesthetic scatter, decorative cilia), growth rings (fabricated age + radial distortion), loom (hairball — the beauty is the crossings, the crossings are the noise), barcode (the designed survivor: DNA as texture — 214 real fixture bars, length=spend/color=state, every bar a portal; tamed with min bar width), cockpit (the anti-page: 6 FABRICATED-stamped sparklines, rainbow gauge, dual-axis panel, 18 pulses, red-as-frame). Autopsy: six-error taxonomy (metaphor debt · unreadable channels · fabricated levels · aesthetic sorting · ink without a question · motion/status as decoration), each pinned to its guilty treatments. The line, located: expressiveness errs the moment a channel stops answering a question and starts decorating one. Survivor graduates: barcode row as the focus-card interior above ~12 people + a fleet-texture band candidate for the 214-person roster header. - teams-strip-swarm (2026-08-15):
/pages/teams-strip-swarm+ thread docs (strip-swarm-{prompt,plan}.md). Course correction from overdrive per Mark — no metaphors, the data-swarm-ideas grammar applied verbatim to the teams world: every mark maps to one datum, axes chosen so the swarm's shape is the answer, selective ring+halo annotations, legends above,<title>everywhere (973 dots / 971 tooltips). Four plots: attribution swarm (x=team, y=log spend/person, color=state — Unassigned becomes an amber cloud of 61 people-shaped reasons), spend × presence audit field (x=log spend, y=time-since-active with quadrant guides "burning & present"/"spent & gone" — the amber mass drifting stale IS the mapping queue sorted by urgency; j.okafor ringed), shift swarm (one dot = one session, x=hour, y=team, r=tokens, color=model — the ci-pool's overnight band drawn as "pipeline hours — the alibi": the mapping suggestion's evidence made visible; honest because sessions are the descent floor), leverage field (x=sessions, y=tokens/session, total-consumption isoquants — sprinters vs grinders, same bill, opposite styles; Core-Banking + tail folded to grey per the fixed-order rule). Coda: the swarm chip — the strip chip's bar slot replaced by a one-row micro-swarm of its people; at 61 identities the overlap converges to the barcode's texture — the two survivors are one idea at two densities. Checkpoint strip-interior candidates now: share bar / barcode / swarm row. - teams-strip-bites (2026-08-15):
/pages/teams-strip-bites+ thread docs (strip-bites-{prompt,plan}.md). The swarm chip generalized: the metric switcher is the cognitive axis and each lens gets the micro-visualization that best answers its question, decided by live bake-offs (2–3 candidate chip rows per lens, winner pilled, verdict grounded in the dataviz form heuristics). Winners: Spend = micro-swarm (donut is the skill's literal anti-example; bar repeats the sub-line; only the swarm adds shape + outliers), $/person = dot-on-fleet-range (the "progress slider" made honest — position-in-distribution with min/median/max ticks, "2.4× median" drawn), Active = unit dots ≤12 with meter fallback (people are countable; continuous fill fakes continuity at n=9; same density threshold as the focus card — one rule system-wide), Risk = severity glyphs (findings are units not magnitudes; three squares answer one-person-or-systemic; heat cell re-introduces magnitude-by-color for a count), Agents = micro-histogram (the ratio hides its own question — same 2.3 mean, opposite cultures). Composed strip: UxTabGroup lens switcher, winning form follows the lens, every mark keeps<title>; portals' Auto composes on top. Principles table (lens → question → form → what it reveals that the bar hid) + the law: a micro-viz earns the slot only if it answers the lens's question better than the number beside it. The pie's obituary published. - teams-strip-levers (2026-08-15):
/pages/teams-strip-levers+ thread docs (strip-levers-{prompt,plan}.md). The cognitive pass — states → levers. Lens test: (a) unambiguous good direction, (b) attribution to a real action, (c) sub-quarter feedback loop. Audit of the current five: Spend keeps (the one honest state — accountability ledger); $/person → tooltip; Active-now → Auto lens + focus card (weather, but the only real-time signal); Agents/person → focus card (diagnostic, no good direction); Risk upgraded to Open, aged (danger_level is already conditions-based and findings subsume those conditions with workflow + timestamps — age of oldest adds the missing lever: an SLA). Revised set, one per cognitive job: Spend (micro-swarm) · Waste — idle->14d spend, hollow unit dots, ✓ today · Retention — 7d cohort return, filled/hollow dots with meter fallback, ◐ via /api/agents first_seen/last_active (NOT sessions — 200-row cap), explicitly not a dumbbell (one ratio isn't a trend) · Coverage — instrumented % of known machines, gap-emphasized meter, denominator honestly "machines we can see" (no MDM join) · Open, aged — glyphs + oldest-age words, terminal statuses per the backend's own projection. Mapping coverage (the page's most movable lever) headlines the verdict line, not a lens. Candidate ledger with receipts: cache leverage + premium share → Cost Center (harness/workload confounds; cost composition); Exposure-as-composed killed (2/3 of its data doesn't exist; consumer keys are /identity's per decision 3); egress surface → controls (per-agent counts double-count shared hosts; admin lever); guardrail posture → focus card (real lever via tool_calls decision_source). Thresholds anchored to data-max and printed in the whisper line. Follow-up (same day, per Mark): Tokens added as a sixth lens — Spend's native-unit twin (c66 principle: token counts are measured, dollars are estimated; same by_team rows, micro-swarm on a token scale; unit-toggle depth stays on Cost Center). Principle amended: one accountability job, two units. - teams-strip-horizons (2026-08-15):
/pages/teams-strip-horizons+ thread docs (strip-horizons-{prompt,plan}.md). The expansion round — additional data, additional windows, less-defensible territory explored with every danger named. Five schema discoveries (amend the levers ledger):file_accesswith sensitivity categories is live; quota posture captured (quota_5h/7d,overage_rejected);campaignshas target/direction/window/baseline (runway ✓, was ◐);attestations+controls.packsare literal maturity receipts; session shape rich (tool_kind, durations, exit codes, TLS flags,proc:<pid>uninstrumented-process markers). 21-window catalog tiered ✓◐▲✗ with dangers (Goodhart/privacy/counterfactual/composite/fabrication) and personas — nine new windows incl. friction tax, sensitive-touch surface, shadow-process delta, secret dwell, blowout ledger, unattended autonomy (agent-framed), quota headroom, posture regression. The drawn line: prompt-topic mining — technically small (DLP already reads content), socially a cliff (protect-the-author vs characterize-them); declined; defensible cousin = practice profiles at repo grain. Structural finding: growth is depth, not width — the strip is full at six lenses; the windows pour into the focus card / verdict line / other pages, exactly as the portal grammar predicted. Four graduates (mocked): policy dividend + friction tax as one build (the pair is receipts, either alone is propaganda); spend runway vs campaign (labeled projection, verdict-line breach); fleet-hygiene block as Coverage's descent floor; new-joiner ramp (the positive-direction counterweight). Behavioral drift held for daily aggregates (200-row sessions cap would break the descent-floor law). Capture roadmap (6): daily per-identity aggregates (highest leverage), posture-change events, repo identity from cwd, read-only IdP pull (un-gates offboarding risk from SCIM — roadmap reorder), latest-version feed, session outcome reason. - teams-strip-windows (2026-08-15):
/pages/teams-strip-windows+ thread docs (strip-windows-{prompt,plan}.md). The horizons graduates built at full fidelity, each in its assigned home — depth behind existing marks, not new dashboards: governance ledger (dividend + friction as one two-sided block; 38 enforced / 41 denied with the un-allowlisted MCP offender promoted to its one closing action; pair rule — neither panel renders alone; "enforced," never "prevented"); runway board (per-campaign teams, solid spent / dashed labeled projection / ceiling tick, breach verdict line); fleet-hygiene block (Coverage's descent floor — named laptops, aproc:shadow process, version-lag and zombie rows each with a closing action; receipt re-adds to the chip's gap of 3, with non-counting hygiene rows explicitly separated); ramp panel (three joiner small-multiples vs team p25–p75 bands incl. the stalled case with "check in →"; days-to-band as the enablement number); unattended autonomy (verdict line + six overnight sessions, agent-framed with the 22:00–06:00 threshold printed); secret-dwell and blowout receipt rows (dwell-not-counterfactual; receipt-not-target). All ✓-tier windows only. - CORRECTION (2026-08-15): The teams-strip-ideas/swarm-era claim "per-team trends impossible — the daily series is fleet-wide" is wrong as stated.
/api/costsapplies?team=scoping before its accumulation loop (web.rs ~2431–2625), so team-scoped totals (incl. cache_read_pct), by_model, and a per-team daily series are all reachable via N scoped fetches with zero backend work. The claim holds only for a single unscoped fetch. Design implications: per-team sparklines become buildable (portal law 5 no longer forbids them — the data exists); Cost Center's team table inherits cache/model split opportunities (c66 follow-on).
Decisions (Mark, 2026-08-14)
- Spend by Team — Cost Center is canonical;
/teamskeeps a slim team cost overview that cross-filters the roster and links to Cost Center's deeper team table. Single-sourced from/api/costs.by_team. - Team management — the mapping workspace (c61 concept 3) becomes the designed pre-SCIM write path (unassigned queue, evidence, suggestions, bulk assign, autocomplete). SCIM-day members/roles stays projected.
- Credentials — relocate the "Agent credentials & access" section to
/identity; explore how/teamscommunicates the high-level gist (compact per-user identity-source/risk indicator linking into/identity). - Ship scope — mocks first, checkpoint before any qdash/backend work.
Visual record
32 captures — heroes, page slices, and full-page renders. Click to view.
































In the archive
Artifacts
- initial-prompt.md
- thread: strip-axis — prompt
- thread: strip-bites — prompt + plan
- thread: strip-horizons — prompt + plan
- thread: strip-levers — prompt + plan
- thread: strip-metrics — prompt
- thread: strip-overdrive — prompt + plan
- thread: strip-portals — prompt + plan
- thread: strip-swarm — prompt + plan
- thread: strip-windows — prompt + plan
- initial-prompt.md