The generic assistant path — Discover through Live, then Guest on the phone.
The template-agnostic MASTER build contract for every surface an assistant passes through — in the 8-section shape (design-canon.md § “Assistant-flow mockup structure”) the five per-assistant flow files inherit.
card → live → monitored → reactivated pre: Overview → Personalize → Connect → Try · post: Pulse → Overview → Personalize → Connect mobile 375 default · desktop 1180 for seated sheets & splits · tablet 768 progressive status color = exceptions only · white glows onlyWidths here sample a fluid continuum — content
scales continuously; structure steps only at sm 640 · md 768 ·
lg 1024; radius/hairlines/pills never scale. Kit: design-canon.md
U8.
This file is the canonical, template-agnostic structure an assistant moves through on MystFlo — every surface of its life, regardless of which template it is: the Explore pre card → share → Team → the pre detail sheet (Overview → Personalize → Connect → Try) → activation and its five real outcomes → the Pulse wall, status ladder, Needs your attention inbox (8c) and post detail sheet → edit-class gating while live → “Waiting on you” → reactivation → the split → Billing. It is the PRIMARY build contract for these surfaces (mockup-artifact-first): the numbered archetypes in docs/design/archetypes/ are the per-frame pass-bar, and the five per-assistant flow files in this folder inherit this file's structure and must not contradict it. Frames are drawn on On-Brand Support (TMPL-9P3X) as the worked example — that content is illustrative; the structure, slots and locks are the contract.
prd-as-*.md.ASST-* id lead everywhere (cards, sheets, usage rows); template name steps down to the sub-line. Pre-activation surfaces carry template identity (TMPL-*).+N doorway; sort required-not-connected first; verbs Reconnect / Pending only; never a cost signal.activate-assistant pipeline produces, drawn as full states, not a spinner.
FOUNDER LANE — one generic assistant, six phases · numbers = this file's frames
§1 DISCOVER §2 SET UP §3 ACTIVATE §4 LIVE
┌────────────────┐ ┌────────────────────────┐ ┌───────────────┐ ┌─────────────────────┐
│ 1 Explore │ │ 3 Overview │ │ 7 Activation │ │ 8 Pulse wall │
│ pre card │──►│ 4a·4b Personalize │──►│ five │──►│ 8b status ladder │
│ 1b Share │ │ (phone·browser) │ │ outcomes │ │ 9·9b·9e post sheet │
│ 2 Team │ │ 5·5b Connect+pickers │ │ (R12) │ │ 10·11 post tabs │
└────────────────┘ │ 6 Try │ └───────────────┘ │ 12 Waiting on you │
└────────────────────────┘ └──────────┬──────────┘
│ pause · stop
§6 MONEY §5 CHANGE ▼
┌─────────────────────┐ ┌───────────────────────────────────────┐
│ 15 Billing rows │◄──│ 13·13b Reactivation │◄──────── from §4
│ wallet · usage │ │ 9c·9d·13c·13d Edit-class gating (A6) │
│ by assistant │ │ 14 The split — apps · funds · Brain │
│ │ │ 14d Share rises inside the Brain pane │
└─────────────────────┘ └───────────────────────────────────────┘
pre detail tabs: Overview → Personalize → Connect → Try (frames 3–6)
post detail tabs: Pulse → Overview → Personalize → Connect (frames 9–11 · 9c · 9d)
Phase vocabulary: no single PRD
locks a journey for the template-agnostic master, so this file uses the canon U10 fallback
order — discover → set up → activate → live → change → money — which is also section 6's
§1–§6 grouping. Per-assistant flow files reproduce their own PRD's journey diagram verbatim
instead. The lifecycle state machine itself (activate → run → pause/resume/stop →
reactivate, every transition audited and billed) is owned by
prd-pl-assistant-lifecycle.md; the pre-tab pipeline by
prd-pl-activation-wizard.md.
Whoever opens it lands on a preview of this assistant — they can look around without an account.
Archetype: assistant-summary-card.md.
Whoever opens it lands on a preview of this assistant — they can look around without an account.
Whoever opens it lands on a preview of this assistant — they can look around without an account.
Archetype: assistant-summary-card.md (both variants).
It reads your Brain — prices, policies, hours, FAQs, and your brand voice — and answers guests in the voice you confirmed. Anything it can't ground in your knowledge gets handed to you.
Archetype: assistant-detail-tabs.md.
Warm Host: A steady, friendly host who knows the answers and never rushes anyone.
What it answers on its own — Brain values are prefilled below.
Full Brain readiness — what's confirmed, what still needs you — lives on Connect →.
prd-pl-voice-card.md surface (a), AC-SOUND-01/02/08 ↗): display + skin choice only — Warm Host selected, Your voice locked (coming soon) — never a gate, renders from CODE constants (AC-SOUND-09). Shows for chat assistants + content generators. Per-state drawings: on-brand-support.html frames 3/3b/3t.expands in place — Google Sheets · Google Calendar · Gmail · Slack · Shopify · Calendly · Airtable
focusSection co-edit form — retired from this door, not deleted.canActivate → Activate (white). Live → View in Pulse. Full label set: #sec-5c and explore.html #f9.Connect white/no-chevron → Connected ⌄ → Reconnect ⌄ → Pending ⌄, disconnect/reconnect in ITS menu). The badge carries a caret ONLY when ≥2 apps are actually in play for that role — real alternatives, or several connected at once. Single-app rows get no caret and NO ⊘ coming soon placeholder (that affordance is deleted, not stubbed). Today with a caret: Storage (3 destinations) · Waitlist+Launch Communication (WhatsApp + Resend). Without: this frame's Communication and Payment, Alerts, AI Model.Both tiers drawn per R22. Archetype: assistant-detail-tabs.md.
The three leftover honesty rules on one compact frame. Connect is finished (no Reconnect). Wallet is still loading. Brain has one Optional row — not a blocker. Header is quiet Continue to Try, never amber Complete Setup, never Activate.
usePaymentMethods / the first payment fetch is in flight. A first-paint Wallet ✕ is a FAIL only after the bar has settled (~1s). Does not rewire canProceed.ready: true). Contrast #sec-5, where Dates & capacity is a blocker and “before it can take a booking” is correct.bc-act, no amber class) even while its status glyph is dim ○; amber is reserved for a row the gate itself flags blocking (never re-derived from status alone — a required field the gate marks satisfied stays muted even if its display status is unverified). This frame previously rendered "Add in Brain →" amber on the Optional row, contradicting its own "not a blocker" note — fixed to match #sec-5.canActivate is still false (Try not finished) → quiet Continue to Try. Amber Complete Setup is only for incomplete Connect/Personalize (or guests). Activate is white primary and only when canActivate. Full four-label set: explore.html #f9.As a founder setting up Retreat Booking, the Brain Check says Prices is missing. I tap Add in Brain → and my actual playbook takes over the screen — the same book I read on Brain — with the Teach your Brain bar under it. I tap the bar, type my prices, tap Read, and I watch my chapter fill in. I hit Close and I'm back on the exact Connect step I left, with the row already re-read. No form I've never seen before, and nothing half-visible behind a column.
WALKTHROUGH — one door, the real page, FULL SCREEN (Peyton 2026-09-12: "takeover for now")
1 Connect · 03 Brain Check Prices ○ · "Add in Brain →" (frame 5, unchanged)
2 Book TAKES OVER the screen the REAL /brain/book, chapter 03 full-cover portal, z 10300
scaffold + "Teach your Brain ›" + the Teach bar docked
the Connect sheet stays mounted UNDERNEATH, never visible
3 Tap the bar the peek rises inside the takeover no dim — the chapter stays readable
4 Type · Read the sheet takes the material the peek never asks (v5.27)
5 She SEES the chapter update her prices, in her own book drafted — Save to Brain confirms
6 Close back on the SAME Connect tab the row has already re-read
6a Closed before saving row: Prices ⚠ · draft ready — Save to Brain still the blocker; Brain ✕
6b Closed after saving row: Prices ✓ Confirmed · just now (frame 5's plain ✓ row)
GEOMETRY, corrected 2026-09-12: this is NOT frame 14's 40/60 split. Production renders the
Book as createPortal(<div class="ink-book fixed inset-0 bg-black">) — it covers the whole
viewport. Same slide-over plumbing (PageSlideOver 'brain'), different geometry. Frame 14's
Connects and funds destinations ARE real 60/40 page panes and keep the split.
Retired FROM THIS DOOR (not deleted): the focusSection co-edit form. Accepted trade (Peyton
2026-09-10): some setup-flow confusion, in exchange for removing the messy left co-edit
panel from the assistant path.
AC-BRAINGATE-09 — the row still names the chapter (What you sell → chapter 03); the pane opens the Book scrolled to that chapter.AC-BRAINGATE-11 — glyph / action tone unchanged: a real blocker stays loud amber until the row re-reads; while the pane is open the row reads Adding….PageSlideOver on the REAL /brain/book (Teach bar included) — never <BrainPage focusSection>'s co-edit pane.AC-BRAIN-213 — geometry corrected 2026-09-12 (Peyton: "takeover for now"). The Book renders as a full-cover portal (PlaybookBookPage → createPortal(<div class="ink-book fixed inset-0 flex flex-col bg-black">), z 10300 + zIndexOffset) — it covers the whole viewport, and the host sheet stays mounted underneath but is never visible. The earlier drawing of a left 40% pane with the assistant sheet beside it was wrong. The Book's own Close (or Esc, or the wizard's back chevron) closes the layer via onEmbeddedClose — never navigate('/brain').Teach your Brain › and the bar open the same peek.focusSection's form for their own stories; nothing there is redrawn by this frame. If a later ruling retires it elsewhere, that is its own frame.BrainCheckStatus (useBrainReadiness.ts:109) has no draft member — ready · missing · thin · junk · stale · unverified — so "Draft ready in your playbook — Save to Brain to confirm" needs a status the readiness read can see (NEW, PRD debt · #4714). Glyph stays the blocker's ⚠, action is the existing degraded-state verb Review in Brain → (opens the Book at the draft). What the Book itself shows after Read is wave 2 (brain.html f-pb-peek-read).--fg-*; the bar's glass is the ink mix .06 + blur; nothing gold anywhere in this flow — the lantern stays with real blockers on the Connect side.Both tiers drawn. Archetype: assistant-detail-tabs.md · Book frames: brain.html#f-pb-bar / #f-pb-peek.
Every Connect row is TWO controls with one job each. Badge = which apps are in play for the role (default seeded from Personalize/channel choices) — carries a ▾ only when ≥2 apps are actually in play. Status button = connection lifecycle only (Connect white/no-chevron → Connected ⌄ → Reconnect ⌄ → Pending ⌄); disconnect/reconnect/switch-account live in ITS menu. The two never conflate.
Pass 3 (2026-08-10) adds one rule that runs through every frame below: there is ONE control species, and an impossible action is greyed and explained — never removed. Wherever a connection's lifecycle is shown — the row, and every app inside an expanded picker — it is the same button with its chevron INSIDE it. The disambiguation list's old Connected ✓ text + underlined Disconnect link is deleted. A connected status button ALWAYS carries its chevron, and a menu item that can't fire (Disconnect on MystFlo AI, Reconnect while Pending, a row-level action on a multi-app row) renders greyed with its reason on the line beneath it. 375 first, then the 640 stack boundary, then desktop.
Why this does NOT reopen the badge-caret rule: the two controls are asked different questions. The badge answers “which app?” — with one app in play there is no list, so a caret would open onto nothing, and that affordance stays deleted (2026-08-09 stands). The status button answers “what can I do with this connection?” — and there is always an answer, including “not this one, and here's why.” The test: does opening it tell her something the collapsed state didn't? A one-app badge: no. A menu with a greyed, explained item: yes.
Read the two arrows separately. The badge ▾ appears once, on Storage (3 real destinations) — one app in play everywhere else, so no caret and no ⊘ coming soon row behind an empty arrow (the 2026-08-07 placeholder stays deleted). The status ⌄ appears on EVERY connected row including AI Model, because every connection has an answer to “what can I do here?” — even when the answer is “nothing, and here's why” (AI Model's menu, two frames down). Below 640px every row stacks the status button onto its own line — one rule, all rows (see the 640 pair below).
Two apps in play on one role — the badge NAMES both and earns its ▾ (several connected at once counts the same as real alternatives). The channel picks were made in Personalize; the badge default reads them back. No AI Model row — WAITL1 uses no AI (absence, not exception).
One app in play, so the target is unambiguous and Disconnect fires directly — no ellipsis, no which-app step. Two taps from collapsed to done. The standalone "Switch account" button (T1164) is retired into this menu; its Active-assistant muted/live behavior is shipped (frame 9d). .dim = muted-but-tappable (it opens an explainer), which is a different thing from .off = greyed-and-explained in the next two frames.
This is the pass-3 rule at its hardest case. Nothing here can fire — and the control does NOT collapse to a bare "Connected" chip. The chevron stays, the menu opens, and it answers the question the founder actually had: can I turn this off? — no, and here's why. That is real content, not a stub. Contrast with the badge: a one-app badge caret would open onto a list that says nothing the collapsed badge didn't, which is why THAT affordance is still deleted. Build: this retires ConnectionStatusButton's hasAnyMenuAction fallback for role rows — see the build note at the foot of this section.
AI Model was never the only case — this row is the other half of the same defect. The 2026-08-10 ruling names "Storage and AI Model", and this is Storage: MystfloStorageRow, the internal, zero-click destination. Structurally it IS the AI Model frame directly above — nothing external exists to disconnect, so its one item is .off and the menu still opens to say so. Note the badge carries no ▾: internal storage has no picker, so control 1 has nothing to open (2026-08-09 badge rule, untouched) while control 2 still answers what can I do here?. Drawing both Storage rows together is deliberate — fixing one and not the other is exactly how this shipped half-done the first time.
Same badge word, one caret's difference, and a different reason entirely — that is why these two are drawn side by side. This is StorageRoleRow, which DOES own a picker (three destination groups), so "disconnect" isn't the verb that applies: the founder doesn't sever storage, she sends it somewhere else. The item greys and points at the badge — the same ROUTE as the multi-app row two frames down, reached by a different road. Read this against AC-EXPLORE-17b, not AC-EXPLORE-17: Storage is a pick-one-of-N role, so it is explicitly NOT the "≥2 apps running at once" ambiguity case and never says "N apps run here". It greys under AC-EXPLORE-21 (an item that cannot fire) — 17b's "keeps a LIVE row-level action" governs the ambiguity rule, and does not license a live Disconnect that has nothing to disconnect. Build: the badge name inside the reason is READ FROM THE ROW, never hardcoded — same derivation lesson as the multi-app count (#3310); a founder who has picked Google Sheets must read "Pick a different destination in Google Sheets ▾ above."
Pending used to simply OMIT Reconnect — correct behavior, invisible reasoning. Greyed-and-explained keeps the menu's shape identical across all four states, so the founder learns one menu instead of four, and the verb ledger stays honest: Pending means we're waiting on the provider, so Reconnect genuinely cannot help. Disconnect stays live — walking away is always hers.
The correctness rule is unchanged: an action never fires against an unnamed app. What changes is how that's expressed. Pass 2 routed it as a hand-off — Disconnect… put the BADGE into a "which app?" mode. Pass 3 states it plainly instead: a row-level disconnect is one of the things that isn't possible here, so it takes the same greyed-and-explained treatment as MystFlo AI, and the founder is sent to the badge — which was always the control that answers "which app?". The two controls now never touch. Three taps to act (badge ▾ → that app's Connected ⌄ → Disconnect), one species the whole way.
This frame replaces the old “DISCONNECT WHICH APP?” list. Gone: the Connected ✓ green text and the underlined Disconnect link — two elements, neither of them a button, doing control 2's job in a second species. Each app now carries the identical status button, one tier down (.mini: 10.5px, same pill, chevron inside), and its menu is the same menu — Disconnect, Reconnect, Switch account, greyed-and-explained where they don't apply. The list has one title, not two: it is always “which apps are in play”, never re-titled by whatever the founder was trying to do.
Down here the app IS named, so the action is live and the label says the target out loud — “Disconnect Resend”, never a bare “Disconnect” that the founder has to trust. WhatsApp is untouched and keeps sending. This is the tap that the greyed row-level item pointed her to.
Never a bare row-level "Reconnect" when two apps run: the status line NAMES the broken app while still collapsed (B2's reserved slot — the descriptive line stays put). WhatsApp is untouched and keeps sending.
Expanded, each app carries its OWN status button — and health is carried by the button's own label + colour (Reconnect, amber), which is exactly how the row-level button carries it. No separate Expired chip beside a link: one control per app, saying its state and holding its actions. Reconnecting never touches WhatsApp.
Picking an app that isn't connected surfaces Connect — white, and the one legitimate no-chevron state: there is no connection yet, so control 2 has no lifecycle to hold and the button IS the action. That is not the collapsed-affordance defect pass 3 bans — it's the difference between “this control has more to say” (chevron) and “this control does one thing” (no chevron). Tapping it opens the LEFT co-edit slide sheet (next frame), never a nested modal. The ⊘ Gmail row is legal HERE — inside a multi-app picker it's a real roadmap alternative among ≥2 live groups, not a placeholder propping up an empty caret.
Sends your launch emails from your own address.
◄ tap the peek edge to go back — your setup is untouched
Stack-rule decision (this pass): one structural boundary at sm 640px for ALL Connect rows — below it every status button drops to its own line, above it every row is inline. Pass 1 mixed the two (Communication stacked at ~600 while Alerts/Storage stayed inline because their content happened to fit) — content-driven per-row reflow is exactly what canon U8 bans: structure changes at NAMED breakpoints, nowhere else. A list where sibling rows disagree reads as two different row types.
Inline tier of the same three rows, one carrying the expired state — the named-app status line sits in B2's reserved slot, so row height never jumps and the status column stays aligned.
Both controls drawn open together so the relationship reads at mid-tier: the row menu anchors under its own trigger and says what it CAN'T do plus where to go; the badge's list expands in the row's own space and carries the live buttons. The reason line renders here identically to 375 — it is not a hover tooltip, so nothing about it is desktop-only.
Connect (white, no chevron — the button IS the action) → Connected ⌄ → Reconnect ⌄ → Pending ⌄ (T336 five-state contract). Chevron INSIDE the pill, never a caret parked beside it. The identical control renders one tier down (.mini) for every app inside an expanded picker. Its menu holds Disconnect / Reconnect / Switch account (T1164 retired into it; Active-muted behavior shipped 2026-08-17)..off (--fg-30, cursor:not-allowed, aria-disabled, no red on a dead Disconnect) with its reason on an always-visible line underneath — never a hover tooltip. Three live cases: MystFlo AI (product gate) · Reconnect while Pending (waiting on the provider) · any row-level action on a multi-app row (no named target).Connect → PageSlideOver slides the real Connects page in from the LEFT (R35 mechanic, frame 14) — never a nested modal. Shipped.Sends your launch emails from your own address.
◄ tap the peek edge to go back — your setup is untouched
⊘ coming soon placeholder. Unchanged by pass 3 — AC-CONN3-01 ↗ (§ Connect apps rule 7/7a).Connect white/no-chevron · Connected ⌄ · Reconnect ⌄ · Pending ⌄ — and its menu is the ONLY home for Disconnect / Reconnect / Switch account (T1164 standalone button retired) — AC-CONN3-01 ↗ · AC-EXPLORE-18 ↗.hasAnyMenuAction's static role="status" chip is retired for role-mode rows; interactive={false} (the picker-modal categories) is untouched — NEW (PRD debt · pass 3).ai_model (“MystFlo AI is built in — there's nothing to disconnect.”) · Switch account… (“MystFlo AI is built in — there's nothing to switch.”) · Reconnect while Pending · any row-level action on a ≥2-app role — NEW (PRD debt · pass 3).MystfloStorageRow (internal, no picker, no badge caret): “MystFlo Storage is where your records live — there's nothing to disconnect.” StorageRoleRow (owns the 3-group destination picker, badge caret present): “Pick a different destination in {badge} ▾ above.” — badge name DERIVED from the row, never hardcoded (#3310 lesson) — AC-EXPLORE-20 ↗ · AC-EXPLORE-21 ↗.ConnectionStatusButton (.mini tier), showing that app's own state and holding that app's own menu; the Connected ✓ text + underlined Disconnect link pair is deleted. Health is still three-state — a never-connected or just-disconnected app reads Connect, never “Connected ✓” — AC-EXPLORE-17 ↗ (control species is NEW (PRD debt · pass 3)).Disconnect… → which-app mode — NEW (PRD debt · pass 3)).AiModelPicker, badge "MystFlo AI", status "Connected", no badge caret — AC-EXPLORE-08 ↗.sm 640px for every Connect row — AC-CONN3-04 ↗.Connect, which opens the LEFT co-edit slide sheet (R35 / PageSlideOver, frame 14's mechanic) — never a nested modal — shipped.⊘ … coming soon stub. The stub announced an unbuilt FEATURE to justify an otherwise-empty arrow. A greyed item explains, in the present tense, why an action this control genuinely owns everywhere else doesn't apply HERE. Rule of thumb: legal when the item names an action the control already owns elsewhere; illegal when it names a feature that doesn't exist yet. ⊘ Gmail · coming soon inside a ≥2-group picker stays legal on its own separate grounds (a real alternative among real ones).disabled menu item can't reliably take keyboard focus either, so the hover/focus path fails twice over. Long-press is undiscoverable and collides with iOS selection. The reason is one short sentence: it costs a line and buys a founder who never has to guess. It renders identically at 375, 768 and desktop — a reason only desktop users can read is a reason the phone user doesn't have. Reuses the shipped .smenu-note vocabulary as .smenu-why, not a new overlay species (a tooltip over a menu is a second overlay on one job)..off = cannot act, reason inline, aria-disabled, cursor:not-allowed. .dim = muted but tappable, opens an explainer WITH actions (9d's Switch-account-while-Active .notice + “Pause to switch” / “Start a new instance →”). The dividing line: if the reason comes with a path forward the founder can take right now, it earns the notice panel; if it's purely informational, it's an inline line..off drops to --fg-30 flat..mini tier. The per-app button renders 10.5px/3px-9px visually but keeps the 44×44 hit area the row-level button already carries below sm (min-h-[44px] sm:min-h-0 in ConnectionStatusButton) — visual density is not hit density.DestinationPicker.tsx (2026-05-22 Template-first lock; the ① MystFlo Storage group remains the one honest drawn delta, #3251) — if copy reads awkwardly the fix is a component change, not a mockup rewrite.sm 640px for every Connect row — below it every status button drops to its own line, above it every row is inline. Canon U8: structure changes at named breakpoints only; pass-1's content-driven mix (Communication stacked at ~600 while Alerts/Storage stayed inline) is the defect this retires. AppRow.tsx's deliberate inline-at-all-widths cluster is knowingly reversed for the status control.⊘ coming soon still lives: only INSIDE a picker that already has ≥2 live groups (Gmail under Email; Supabase's create-new) — a roadmap alternative among real ones, never a stub propping up an otherwise-empty caret. AI Model stays caret-free permanently (#4959) — BYOK is deleted, not a second provider waiting to grant a caret..app-st "Connected ✓" + underlined .app-act "Disconnect" — DELETED and redrawn as per-app status buttons (those frames are replaced, not kept alongside); with them goes the C2-derived neutral-underline treatment for in-picker actions, which existed only to serve that shape. ② ConnectionStatusButton's hasAnyMenuAction fallback for role rows — the static role="status" chip with no chevron, which is exactly why Storage and AI Model render a bare "Connected" today. ③ Pass 2's Disconnect… / Reconnect… ellipsis labels and the which-app MODE they opened.(current) + coming soon single-provider expand (that frame is deleted, not redrawn). Also still in force from 2026-08-04/05/06/07: label/badge split · one Storage row, three destinations · verbatim picker copy · one list, no tiers · decision-in-Personalize, connection-in-Connect (the badge default reads those picks back).⊘ coming soon stub behind an empty one. Pass 3 governs control 2 only. The two rules disagree on the surface and agree underneath: show an affordance when opening it says something new.AppRow/RoleRow COMING_SOON_COPY shells and structural carets must be REMOVED. PR #3288 shipped pass 2's two-control split. Pass 3 adds: always-open status menu (retire the hasAnyMenuAction fallback for role rows; KEEP the interactive={false} branch for the picker-modal categories), .off disabled items + inline reason lines, per-app .mini status buttons inside pickers, the greyed row-level action on multi-app rows, and — added 2026-08-10 after design review caught it half-delivered — the explained Disconnect on BOTH Storage rows (MystfloStorageRow internal · StorageRoleRow picker-owning), which the ruling named alongside AI Model from the start. Pass 2 leftovers still open: multi-app badge + aggregated status, expired-names-the-app status line. Connect → slide sheet and Switch-account muted/live shipped 2026-08-17.design-lessons.md flex-col-row-container-stretches-bare-children): the new .mini button lands inside .pick-row, and the <sm stack rule puts flex-col on row containers. Wrap it — <div className="flex-shrink-0"><ConnectionStatusButton …/></div> — and audit EVERY direct child of any container that gains flex-col, in both render trees, before calling this shipped.Components: ConnectionStatusButton.tsx (T336 five-state, built — gains always-open menu, .off items, Switch account) · ChannelGroupRow.tsx BroadcastPickRow (carries the per-app .mini control; DisambiguateAppRow is the RETIRED pass-2 shape — do not rebuild it) · DestinationPicker.tsx (built, ① MystFlo Storage group shipped #3251) · AiModelPicker.tsx (no badge caret — product gate; gains the explained Disconnect) · MystfloStorageRow.tsx + StorageRoleRow.tsx (the two Storage rows — both gain the chevron + their own explained Disconnect; their file comments still describe the retired chevron-less fallback as correct and need rewriting with the fix). Contract: prd-pl-activation-wizard.md § Connect apps (rules 7a/9a CORRECTED to this pass in PR #3308, merged 2026-08-10 — plus AC-EXPLORE-20/21 minted and AC-EXPLORE-17 rewritten). Kit: design-decisions.md 2026-08-09 + 2026-08-10.
Pause anytime.
A test row on your sheet + the confirmation on your own WhatsApp. Free.
Both tiers drawn per R22. A real pre-activation chat sandbox is a deferred post-launch decision (ledger).
It reads your Brain — prices, policies, hours, FAQs, and your brand voice — and answers guests in the voice you confirmed. Anything it can't ground in your knowledge gets handed to you.
Brain readiness lives on Connect →.
tablet 768 — progressive: split engages where width allows, else the mobile pattern holds
Reconnect WhatsApp and add your policies to continue.
brain.html#f-pb-peek-m-wave1) — the pinned peek is week 2. Title Teach your Brain per AC-BRAIN-126 — the bar and the sheet share the one string.Your word for this instance — you can rename it anytime from its Details header.
Runs on your WhatsApp from the moment you activate. Pause anytime.
We'll add a test row to your sheet and send the confirmation to your own WhatsApp — so you see exactly what a guest sees. Free.
About 20 seconds. Stay on this screen.
outcome (c) — partially active
Both tiers drawn per R22; Pulse card twins for (c)/(e) above. Archetype: pulse-surface.md.
About 20 seconds. Stay on this screen.
WhatsApp rejected the message send, so we stopped before activating anything.
Still stuck? Message us — we'll look at the run.
Your signup page is open and taking names right now.
It's answering on your WhatsApp from right now.
$0.50 per session · pause anytime
Signups keep working. Only the launch blast is blocked until the wording is fixed.
Resubmitting goes back into review — same open-ended window.
.al-rows).pulse.html frame 3-chat (.row/.sec-marker/.qa-linkline/.qa-share/.qa-expand/.al-ledger) — the old .mb metrics band, the “Health” third column, and the Today/Earlier .act-row feed are retired from this frame (CSS stays for other frames still using it).‹ Newer · Page N of M · Older › pagination now live one door over, in the new Activity sheet (frame 9f). A “Load older” append button here is a FAIL.Archetype: assistant-detail-tabs.md. Lock: R37 (supersedes the 8-22 metrics-band/Today-feed drawing on this frame).
Archetype: assistant-detail-tabs.md. Locks: D-5, R37.
RecordsEntryRow under the card · Peyton 2026-09-02RecordsEntryRow (a bordered Link mounted under AssistantSummaryCardPost in Pulse.tsx) made the active wall ragged — some tiles had a tail, some didn't. The line moves INTO the card as the last zone: badge+controls → title → identity → status line → hairline → Runs → records slot → footer action. Same content as the old row: noun · sub-label · "N booked · M left" · chevron; sold out = amber dot + "sold out · N waiting", monochrome row, never a tint.mt-auto; a non-records card beside a records card gets its extra air above the pinned metrics block, never a blank hairline row./pulse?assistant=<id>&records=open (param name = build decision, CTO): the detail sheet opens on Pulse (R30) and the records sheet rises over it. Refresh, bookmark, second device all land in the same place — the deep-link requirement that justified the old route survives as a URL param.AssistantSummaryCardPost (records-contract-aware, guest-gated, collapse-to-zero); retire the RecordsEntryRow mount in Pulse.tsx.Archetypes: assistant-summary-card.md (slot), records-surface.md (the way in). Lock: R36.
?assistant=4L9 · roster is the FIRST item in the RIGHT slot, above the booking link (R37 — supersedes the full-width band)5 of 6 · needs-verdict first, then newest · 2 on the waiting list
Open kit › (frame 9b-k)..act-row grammar as the activity feed below — name · seats/spots on the sub-line; status is a dot + word on the right; verdicts render only on rows that can take one.AssistantDetailModal.post.tsx's Pulse tab (records-contract-gated), fed by the same useAssistantRecords hook the retired page used — one read, feeds the slot AND the sheet.?assistant=<id>&records=open opens the sheet on top of this tab; the old /pulse/:assistantId/records route becomes a redirect into it (not built).Frame 9b (On-Brand Support) stays the no-records twin. Archetypes: assistant-detail-tabs.md, records-surface.md. Locks: R36, R37.
program-launch-kit.html sec-8), NOT this template's own sheetAll 5 pieces · v1 · $3.00 kit + $0.02 rewrites. Open kit › to read, rewrite what's off, and take it with you.
LaunchKitReviewSheetBody — the tab no longer trades its whole body for that sheet.Open kit › is the one doorway into program-launch-kit.html sec-8's review sheet; nothing about that sheet's read/rewrite/take-away mechanics changes.program-launch-kit.html sec-7's existing note.Archetype: assistant-detail-tabs.md. Lock: R37.
nestedBackdrop rgba(8,8,10,.96) + blur · Escape / ✕ close THIS sheet only (broadcastCloseAll={false}) · URL ?assistant=9W2&records=openYour booking link is live. Share it and the first name lands here — usually within a day of posting.
aria-busy="true"; shimmer off under reduced motion.Nothing's lost — this is a connection problem on our end. Your bookings are safe.
Or ping us if it keeps happening.
?assistant=<id>&records=open / When resolved / Then the records sheet opens stacked over the post detail sheet's Pulse tab with the detail sheet still mounted beneath; ✕ and Escape close only the records sheet; refresh, bookmark, and a second device reopen it. (Replaces the AC-WSBK-23 "same full-screen destination" wording — amendment pending.)ModalWrapper presentation="sheet" with nestedBackdrop + broadcastCloseAll={false} (playbook §3 stacked-modal props), contentWidth="wide" so the grid uses the sheet; z-index above AssistantModalShell (build gap). The full-width sticky .sheet-header band carries title = noun · instance name, subtitle = the truth line, and the ✕ close control (44×44). The deep-link reason that justified the route survives: the sheet has a URL via the param.FilterChipGroup (icon-free chips, zero selected = unfiltered, no "All" chip) and PaginationBar sortable (‹ Prev · Page N of M · Next ›, right-aligned, hidden at ≤1 page, 20 rows/page, client-side). Never a third pagination or filter style./pulse/:assistantId/records → /pulse?assistant=<id>&records=open; AssistantRecordsPage retires once the sheet ships.RecordsSheet on ModalWrapper over the detail shell, reusing RecordsTable / RecordRow / RecordsEmptyState as-is; FilterChipGroup + PaginationBar wired.?records=open persisted like ?assistant= / ?handover=; cleared on close; ignored when ?assistant= resolves nothing.Tablet 768 not drawn in this file — the records-surface archetype's 768 rule holds (shell from desktop, rows still stacked, verdicts inline); workshop-booking.html 13b draws it. Archetypes: records-surface.md, sheet-slide-panel.md. Lock: R36.
nestedBackdrop + broadcastCloseAll={false} · the chips + pagination the tab's 5-row preview doesn't carry live HERERuns show up here as they happen.
nestedBackdrop, broadcastCloseAll={false}), showing the range chips, the full .al-ledger history, and ‹ Newer · Page N of M · Older › pagination — none of which render on the tab itself.‹ Newer · Page N of M · Older › pagination move here entirely — a pager on the tab itself is a FAIL (assistant-detail-tabs.md self-check 21).ModalWrapper presentation="sheet", nestedBackdrop, broadcastCloseAll={false}, contentWidth="wide" — one mechanic, two content sheets on the same tab..al-ledger shape (source mark already dropped) — no new row component for the fuller list.Archetype: assistant-detail-tabs.md, sheet-slide-panel.md. Lock: R37.
Peyton reversed the read-back ledger the same day it shipped: "keep the same design as the pre-activation, just show as saved text or selected — but as a preview, and can't be click." This frame IS that instruction, literally — same categories, same numbered .sm group headings, same .field-label / .field / .opt-radio row anatomy as the Configure step (workshop-booking.html sec-3b), reused unchanged. The only delta from Configure is the .pz-locked wash (Peyton: "maybe gray-out shade colour") and the removal of every click handler — no Edit, no per-row verb, on ANY row, Safe tier included. The A6 Safe/Structural/Identity split (fieldEditPolicy.ts) stops being a DISPLAY concept: every field renders through the exact branch ConfigFieldRenderer.tsx already ships for field.locked template-text (~L863) — read-only preview, no customize affordance — generalized here to text/radio/select. Drawn on the Workshop Booking instance from Peyton's 2026-09-03 live test.
This is what's set for this round — nothing here can be edited in place. To change any of it, start fresh with a new assistant → (the ⋯ menu, top right). Brain readiness lives on Connect →
Both options still show — the picked one just reads selected, not tappable.
Same box, same wash, as the Safe payment-ask field above it — pre-activation already drew this exact "locked" style for Meta templates. Nothing new; the whole tab now reads this way.
Runs on demand — whenever a guest messages this number.
Works the same whether they tapped your wa.me link or typed this directly — the AI reads intent, not just the word.
Pause is no longer a prerequisite for editing anything — there is nothing left on this tab that pausing would unlock. It stays what it always was: stop the assistant from running. "Start fresh with a new assistant" works from Active too (frame 9g's ⋯ menu note: "This one keeps running until you stop it").
Never a silent schema default. formatLockedFieldValue() already returns exactly this string for null/undefined (ConfigFieldRenderer.tsx L194-200) — reused verbatim, not invented. Showing a default as if the founder chose it would break the honesty line ("sounds like you — because you confirmed it does"): a value nobody confirmed isn't a fact yet, so it can't read as one.
ConfigChangeConfirmModal, saveInstantField, and the whole batch dirty-state bar have no caller left on this tab — see the "Build" note below.formatLockedFieldValue()'s existing "Not set yet" fallback, never a silent schema default..row .l .r ledger unique to post-activation. This frame reuses the Configure step's own components (.field-label/.field/.opt-radio) byte-for-byte — a founder who filled the form once recognizes it instantly on the way back in..pz-locked (opacity .84, saturate .9) is the one visual delta from an editable Configure step — Peyton's own "gray-out shade colour" instruction — applied uniformly across the .form-col, never per-row (a field is not "more locked" than its neighbor). It stops at the form column's edge; see the preview-rail note below for why the .pv-col is excluded..opt-radio.sel's filled dot among its un-picked siblings — recognition of what the choices WERE matters as much as which one was kept. Collapsing to a single value line (the retired ledger's move) is what made it read as a novel grammar instead of a mirror..pv-col entirely; Peyton caught it and was explicit: "keep the same design as the pre-activation, just shown as saved text or selected but as a preview and can't be clicked." That means the live-preview column stays too, not just the form..pv-col here is a byte-for-byte copy of pre-activation's own preview column (workshop-booking.html sec-3b — same Wheel Throwing Class sample, same both-variant stack, same "once your Flow is live" copy, same opacity on the unpicked-variant phone) — not restyled, not dimmed, not re-derived from 9c's own saved values. .pz-locked now sits on .form-col only (the fields/radios/inputs), never wraps .pv-col — the read-only wash is a form-column property, not a tab-wide one. The static preview illustration doesn't change just because the assistant went live, so it doesn't get a second "sample" label either — it reads exactly as it does pre-activation.ConfigFieldRenderer.tsx: the editLock branch (~L341-374, "Pause to change" / "Start fresh" per row) is deleted entirely, not simplified — its job (label + value, no button) already exists as the field.locked branch used by TemplateTextField (~L863); extend that same "no customize affordance" behavior to RadioField/SelectField/plain text so ONE locked path serves every type. AssistantSettingsTab.tsx: INSTANT_SAVE_RADIO_KEYS, saveInstantField, and the mounted ConfigChangeConfirmModal lose their only caller on this tab — remove them from the post-activation render path (they may still matter to ConfigureStep.tsx pre-activation, which is untouched by this lock).ConfigFieldRenderer.editLock.test.tsx, AssistantSettingsTab.editGating.test.tsx — both assert the now-fully-retired "Pause to change" / inline-Edit behavior, not just its strings. AC-LIFECYCLE-11/12 wording in prd-pl-assistant-lifecycle.md in the same PR.PreviewPanel/getPreviewRenderer pair `ConfigureStep.tsx` already renders pre-activation (the 2026-06-20 twin lock's "same getPreviewRenderer/personalizeFirst gate as pre"), fed the persisted config instead of in-progress form state. Do NOT wrap it in pz-locked or any other dimmed/read-only container (correction, same day — Peyton: "the preview is a static design visualisation... just have it stay the same") — it renders at full, unmodified opacity, identically to how ConfigureStep.tsx already renders it pre-activation. Only the typing-reactive affordance is inapplicable here (no cursor, no "live" pulse on the greeting bubble) since nothing on this tab accepts input — that's a behavioral no-op from having no in-progress form state to react to, not a visual dimming choice.Spec: prd-pl-assistant-lifecycle.md §A6 (amend). Archetype: assistant-detail-tabs.md § 2026-09-04 locks (superseding entry). Mobile: 13c ↓. Tablet 768: not drawn for this frame — when it is, follow this file's own D2-locked progressive pattern (sec-4e ↑: split engages where width allows, else the mobile pattern holds); the form column stays pz-locked like the two tiers drawn here, the preview column stays undimmed like pre-activation.
The header answers four questions in order, one line each: what is this one about (subject) · what kind of assistant is it, and which (spelled-out type + id) · what state is it in (status · price · since when) · what is it doing right now (activity). Health is not in the header — the Pulse tab's fixed Health row is its one home. Trigger type (“On-demand”) is setup, not state — it reads at the foot of the Personalize tab. The type word never appears twice: the auto-name stops embedding the template name at the source (instanceNaming.ts), so L1 is the subject alone.
Two items, deliberately. Run / Pause / Stop stay the A5 icon controls (▶ ⏸ ⏹, D-4 fixed order) — the menu never duplicates them. “Switch account…” stays in Connect's status menu (9d lock). The Personalize tab's “start fresh with a new assistant →” link opens this same chooser (frame 13's Reactivate/Start-fresh dialog), so there is one Start-fresh door, reached two ways.
createdAt. The dot is the only colour in the header.pulseLastRunSlotText. Health leaves (the Pulse tab's fixed four already carry it — printing it twice is what made a 1-run sample shout). Trigger type moves to the Personalize tab's foot.../mystflo-kit/design-decisions.md): ▶ ⏸ ⏹ always render in that order, then ⋯, then ✕ — never a swap. The inapplicable control gets .run-ic.off (dim, no hover) instead of disappearing: Active → ▶ off; Paused → ⏸ off. Matches shipped code (AssistantDetailModal.post.tsx ~L1583, disabled= + aria-label="Already active") and the summary card's own A5 rule (.p-controls span.off) — this frame previously drew a swap and would have regressed working code if built verbatim.IdentitySubline (AssistantCardPrimitives.tsx L78-105) into a PostIdentityBlock that renders L1-L4 from { name, subject, displayType, displayId, status, pauseReason, costPerRun, createdAt, activity }; the post card keeps using the same primitive so card ↔ modal never drift (D-4's original point). Header markup: AssistantDetailModal.post.tsx L1466-1558 — delete the meta line's health span and the trigger-type span.displayType: presentation-layer, no migration — src/lib/instanceNaming.ts gains getDisplayType(templateId, templateName) = a small override map (WSBK01 “Workshop Booking Assistant”, EVBK01 “Event Booking Assistant”, RTBK01 “Retreat Booking Assistant”, 9P3X “On-Brand Support Assistant”, WAITL1 “Waitlist + Launch Assistant”) with fallback `${templateName} Assistant`. Same file, L118/L124: return the subject alone, not `${templateName} (${subject})`. A display-side strip handles already-stored names.Archetype: assistant-detail-tabs.md § 2026-09-04 locks (post header). Card twin: assistant-summary-card.md D-4 note. Mobile: 13g ↓.
Post-activation adds one thing to frame 5b's contract: a run-status risk. Switching a connection mid-run can land a message or a charge on the wrong account, so while the assistant is Active the Switch-account item is muted — visible, still tappable, and it explains itself. Everything else is 5b unchanged: one control species, chevron inside, impossible actions greyed rather than removed. 375 first, then desktop.
Mobile tier for this frame lives with the rest of the phone journey — 13d · mobile ↓ (one note, both tiers; the file's §5 desktop / §6 mobile split).
No standalone "Switch account" button (T1164 retired) and no badge caret — one app in play per role here, so the badges carry nothing. Both rows still carry their status chevron, because the status button always has something to say (5b's pass-3 rule). The action lives in that menu; while Active it stays visible but MUTED, and tapping it opens this notice instead of acting. Reconnect (same-account repair) is unaffected and still appears if a connection breaks.
Paused (or Stopped) lifts the mute — the menu item goes live and resolves through the existing verdict-matrix mechanic (ALLOW / ALLOW+REPROVISION / HARD-BLOCK), then Resume. On a MULTI-app row this item greys out with its reason and points at the badge, exactly like Disconnect does (frame 5b) — the row-level control never guesses which account she meant.
.dim flavour, and that survives 5b's new greyed-item rule rather than collapsing into it. 5b's .off is "cannot act, here's why" as a flat inline line. This item is different in kind: it IS tappable, and what it opens is a decision with two live paths ("Pause to switch" / "Start a new instance →"). The dividing rule, now written once for the whole system: a reason that carries actions gets the notice panel; a reason that is purely informational gets the inline line. Mobile mirrors added this pass — 9d was desktop-only, which canon U8 doesn't allow for a signed frame.Spec: prd-pl-assistant-lifecycle.md §A6 (to be updated to this shape). Archetype: assistant-detail-tabs.md.
Ana's name is filled in per person. Wrong words, wrong dates, wrong link? Edit in Personalize → — this screen only reviews, tests, and sends.
This can't be unsent, and there's no retry. Nothing goes out until you tap it.
One mechanic — PageSlideOver, one target union, one settle, one return promise ("your setup is untouched") — but not one geometry. Apps and funds slide in as 60/40 page panes, because the founder is doing a small errand and the assistant sheet beside it is the context she needs. Brain takes over the whole screen, because she is reading and correcting her own playbook — a book does not fit in 40% of a viewport, and the beat that matters (seeing her chapter fill in) is invisible in a column. Production already draws the line here: PlaybookBookPage renders createPortal(<div class="ink-book fixed inset-0 bg-black">) at z 10300, while the apps/funds targets render as panes. Same plumbing, different shape — corrected 2026-09-12 after this frame drew all three alike.
Reconnect to keep replies going out from this number.
◄ tap the peek edge to go back — your setup is untouched
Runs draw from this. Nothing else is charged.
◄ tap the peek edge to go back — your setup is untouched
Connect still has no Billing link. The only setup path into Billing is the card chip on Top up. Same slide mechanic, same host — the pane swaps destination.
The card Top up will charge. Invoices and usage stay on Billing — not on Connect.
◄ tap the peek edge to go back to Top up — Connect never opened Billing
One component (`PageSlideOver`, `modalTokens.slide.split.*`), same 0.45s expo settle, same peek-edge/Esc return:
| Connect-tab row | Left pane opens | Anchored at |
| 01 Apps (Reconnect / first connect) | Connects page | that app's row |
| 02 Funds (tap the balance) | Top-up pane | amount + card chip |
| Card chip on Top-up | Billing page | the card / payment-method block |
| 03 Brain (Add/Edit in Brain) | Brain page | that section |
/brain/book with the Teach bar — drawn at 5d.focusSection co-edit form in this frame's left pane "for the mechanic," retiring it from the 5d door only. Peyton reviewed the preview and ruled the distinction doesn't hold: when the user clicks Add to Brain it should not open that left-side field panel — it should open the designed playbook with the Teach bar. Destination (1) above is now redrawn as the Book, so this frame no longer contradicts 5d or the shipped behaviour (AC-BRAIN-213 ↗). The co-edit form remains drawn only where 14b / 14d still show it — each still owed its own re-rule, and neither is a Brain-Check door.focusSection co-edit field panel this frame used to draw. Correcting a fact is one mechanic everywhere: tap the bar → the peek → type → Read. A founder never meets a form she has not seen before on this path.corrections[] contract (#4715).Spec: modal-slide-choreography-architecture.md.
Frame 14 draws the split at rest. These are the moments between “she taps Connect” and “she's back on her row”, plus the tier the split doesn't engage at. Drawn on the Connects destination — it is the only one of the destinations that can leave the tab — but loading, error, settle and abandon are mechanic-level and read identically for Top-up, Change card, and Brain.
Two rulings run through every frame below. ① The geometry does not mirror for Connect. LEFT 40% stays the real page, RIGHT 60% stays the host wizard — the 2026-07-26 axis lock holds here with no Connect-specific exception (reasoning in the design notes). ② The connect form IS the pane's content, never a sheet inside it. The pane opens already focused on the app the row named; there is no directory to walk back through and no second overlay.
Sends your launch emails from your own address.
You'll land back on Connect with this row ticked.
The split engages at ≥1024 only (modalTokens.slide.split.engageBreakpoint) — so 768–1023 gets the same push 375 does. This is the right answer, not a shortfall: 40/60 of a 1024 viewport is 410/614, and a 614px host pane falls below the 640px stack boundary the Connect rows just locked (AC-CONN3-04 ↗) — every row would restack while she's away, so the surface she returns to isn't the one she left. The push freezes the wizard exactly as it was. Wording correction to R35 note (d): it reads “Mobile 375: no split on any destination” — the real rule is below 1024, on every tier, and 375 is only its narrowest sample. Scope: this rules the R35 destination split only; the separate open question about the Personalize preview split at 768–1023 (activation PRD, flagged 2026-07-24) is a different surface and is NOT decided here.
◄ tap the peek edge to go back — your setup is untouched
Sends your launch emails from your own address.
Resend didn't accept that key. Copy it again from Resend — it starts with re_ and has no spaces.
◄ tap the peek edge to go back — your setup is untouched
Launch emails will send from your own address.
◄ taking you back to Connect…
One more thing — where should the signups land?
Connect — never a red the founder can't act on from the right — AC-CONN3-01 ↗ · shipped.PaneScopeContext containment stays for genuinely secondary asks raised from inside a pane (a permission prompt, a resource picker overlay) — AC-PANE-01 ↗ · AC-PANE-03 ↗.ConnectionModal's body must become a form component the Connects page can render inline, and ConnectsPage needs a focus prop + masthead strip in the same shape BrainPage.focusSection / TeamPage.focusTab already use. That is a component extraction, not a new overlay mode.Connect). The highlight is the signal — no spatial “on the left” line. Submit fires → Connecting…. Success → Connected ⌄ + a transient emerald line that clears. Failure → back to Connect + the warn line. Frame 14's existing frames label the pane-open moment Connecting… / Reconnecting… — that verb belongs to the post-submit state; at pane-open nothing is connecting yet. Same correction applies to destination (2)'s Reconnecting….Connected ⌄; a permanent green line would become another thing to skip.{templateId, role, app}) alongside the sessionStorage bridge the Connects page already keeps for the auth round trip, and the return URL already has the parameter that reopens the wizard.Components: PageSlideOver.tsx (page: 'connects' shipped) · ConnectsPage.tsx (embedded + focusProvider + masthead strip shipped) · ConnectionModal.tsx (body extracted to an inline form) · PaneScopeContext.tsx (shipped #2248 — containment already works). Spec: modal-slide-choreography-architecture.md §1. Kit: design-decisions.md 2026-06-23 + 2026-07-26.
Wallet ran dry on a chat assistant. Target behaviour (#4522, not shipped): for 15 days her customers still reach her on Slack; after that nothing is relayed and nothing is sent to the customer — the only signal is in-app, until she tops up. Three surfaces that already show the pause each get one honest line — the status line, badge and colour do not change (D-3).
RunIssueSheet as pulse.html 4b) is the ONE detail surface — the 2026-08-22 “one attention pattern” lock stands, so the Needs-attention ROW is unchanged. The card footer caption is the glance signal on the wall. The Connect-tab wallet notice sub-line echoes the same state. Nothing new is invented: three surfaces that already show the pause get one more honest line each. top-up lands (any time) ─────────────────────────────────────────────┐
▼
┌───────────┐ wallet can't ┌──────────────────────┐ day 15 ┌──────────────────────┐
│ Active │ ─cover a reply─►│ Paused · wallet_empty│ ─────────►│ Paused · wallet_empty│
│ (chat) │ │ GRACE · relaying │ │ STEPPED · not relaying│
└───────────┘ │ Slack ◄─ every msg* │ │ customer ◄─ nothing │
▲ │ card: “12 days left” │ │ card: “no longer │
│ │ sheet: runway + next │ │ reach you” │
└────── resumes ────────┴──────────────────────┴───────────┴──────────────────────┘
* TARGET (#4522). Shipped today: first message relays, every later one during the pause is dropped.
| Surface | Grace (day 1–15) | Stepped down (day 16+) |
|---|---|---|
| Card status line | Wallet empty — top up to keep running (D-3 verbatim, unchanged) | same — unchanged |
| Card footer caption | Messages still reach you · 12 days left | New messages no longer reach you |
| Card action | Top up → | Top up → |
| Attention row | Wallet empty — top up to keep running · View issue (unchanged) | same — unchanged |
| Sheet badge | amber Paused (today’s sheet hardcodes red Error — build finding) | amber Paused |
| Sheet lead | Paused — wallet empty | Paused — new messages no longer reach you |
| Sheet why | Replies are paused. New messages still come to you on Slack to answer yourself — for 12 more days. | The wallet has been empty for 15 days, so messages stopped coming to you on Slack. Nothing gets answered until you top up. |
| Sheet runway | Day 3 of 15 · until Sep 18 | — |
| Sheet next | After Sep 18, new messages stop coming through to you. Top up any time and everything resumes. | Top up any time — replies and Slack alerts pick up the moment it lands. |
| Sheet time | Paused Sep 3 | Paused Sep 3 · stopped reaching you Sep 18 |
| Sheet CTA | Add funds | Add funds |
| Connect notice sub-line | Paused until you add credit — it resumes the moment your top-up lands. Messages still reach you on Slack for 12 more days. | Paused until you add credit — it resumes the moment your top-up lands. New messages no longer reach you until you do. |
truncate. If “Messages still reach you · 12 days left” cannot fit beside “Top up →” at the card’s width, render the day-count clause alone (“12 days left”) — the number is the part that must survive, never the prose.payment_failure (the #4516 shared branch) — this caption is a third branch keyed on chat runtime + wallet_empty, exactly the split the D-3 amendment already anticipated.grace_ends_at (or the pause timestamp the step-down cron reads + the 15-day constant). Pulse already carries last_paused_at (“Status since”), so the day count is derivable client-side today — but only if the step-down job uses the SAME timestamp, otherwise the sheet says “1 day left” while the cron already stopped relaying. Prefer the backend exposing the end date over the client re-deriving it.pause_reason value. The UI must never infer “stopped” from “today > day 15”: the two would drift by a cron tick and the founder would read the wrong sentence. If it is a new pause_reason, the D-3 resolver maps it to the SAME amber Paused + verbatim line (no new colour, no new badge word).flowPattern.runtime === 'chat'; confirm the post card / Pulse stats already carry it (it decides whether “Messages still reach you” is even true — a platform-triggered assistant has no customer messages to relay).wallet_empty_paused daily reminder should carry the same day count and the same day-15 change. Copy owner: chief-writer; mechanism: chief-cto.RunIssueSheet.tsx renders a red Error badge for every caller, including wallet / budget pauses — contradicts D-3 (amber for a retryable wallet state, red for Failed only). The sheet should take the badge from the owning rule: amber Paused for wallet / limit / setup pauses, red Error for a failed run, lantern Needs attention for a chat leftover (pulse.html 1q already draws that).ConnectWalletFunds.tsx paused sub-line “top up to resume it yourself” is stale for wallet_empty since #4496 (top-up auto-resumes). Keep it for payment_failure; wallet_empty reads “it resumes the moment your top-up lands.”contentWidth="prose"). Cards: 375 one column, 768 two-up, 1180 three-up, caption rule identical. No per-state tablet frame is owed — the rule covers states not yet drawn.This is what's set for this round — nothing here can be edited in place. To change any of it, start fresh with a new assistant → (the ⋯ menu, top right). Brain readiness lives on Connect →
Runs on demand — whenever a guest messages this number.
768 is a sample of the U8 continuum between 375 and 1180, not a third layout: the four header lines, the context line, and the .field-label/.field/.opt-radio rows are identical to desktop 9c/9g; only the measure changes (24px gutter, form spans the sheet). Paused / empty-field states at 768 are the desktop crops at this measure — not redrawn (Paused is byte-identical body to Active regardless of tier). The rest of the live flow at 768 stays as it was: not yet drawn — desktop and 375 are the contract.
768 is a rule, not a third layout (U8). The sheet is the same content column at every width — 375 edge-to-edge, 768 and 1180 a full-width band with the prose capped at 720 (contentWidth="prose", sheetHeight="content", softBackdrop). The stepped-down sheet at 768 is the 375 drawing at this measure; the Pulse wall is two cards up with the identical caption rule; the Connect-tab notice is the 375 drawing inside the seated sheet at gutter 24. One drawing here so the band + column are seen once; every other 8e state inherits it.
RecordsEntryRowArchetypes: assistant-summary-card.md, pulse-surface.md.
Both tiers drawn per R22. Archetype: pulse-surface.md (self-check #6).
#attention-panel. No #health-alerts fallback.isAssistantNeedsAttention + resolvePulseHealth in src/lib/assistantStatus.ts. UI: AttentionPanel.tsx.375 phones. Pulse Overview companion: pulse.html frames 1 / 1c / 1-m. Archetype: pulse-surface.md.
Two states of ONE card, stacked for comparison — a real wall never shows both for the same assistant.
RunIssueSheet as pulse.html 4b) is the ONE detail surface — the 2026-08-22 “one attention pattern” lock stands, so the Needs-attention ROW is unchanged. The card footer caption is the glance signal on the wall. The Connect-tab wallet notice sub-line echoes the same state. Nothing new is invented: three surfaces that already show the pause get one more honest line each. top-up lands (any time) ─────────────────────────────────────────────┐
▼
┌───────────┐ wallet can't ┌──────────────────────┐ day 15 ┌──────────────────────┐
│ Active │ ─cover a reply─►│ Paused · wallet_empty│ ─────────►│ Paused · wallet_empty│
│ (chat) │ │ GRACE · relaying │ │ STEPPED · not relaying│
└───────────┘ │ Slack ◄─ every msg* │ │ customer ◄─ nothing │
▲ │ card: “12 days left” │ │ card: “no longer │
│ │ sheet: runway + next │ │ reach you” │
└────── resumes ────────┴──────────────────────┴───────────┴──────────────────────┘
* TARGET (#4522). Shipped today: first message relays, every later one during the pause is dropped.
| Surface | Grace (day 1–15) | Stepped down (day 16+) |
|---|---|---|
| Card status line | Wallet empty — top up to keep running (D-3 verbatim, unchanged) | same — unchanged |
| Card footer caption | Messages still reach you · 12 days left | New messages no longer reach you |
| Card action | Top up → | Top up → |
| Attention row | Wallet empty — top up to keep running · View issue (unchanged) | same — unchanged |
| Sheet badge | amber Paused (today’s sheet hardcodes red Error — build finding) | amber Paused |
| Sheet lead | Paused — wallet empty | Paused — new messages no longer reach you |
| Sheet why | Replies are paused. New messages still come to you on Slack to answer yourself — for 12 more days. | The wallet has been empty for 15 days, so messages stopped coming to you on Slack. Nothing gets answered until you top up. |
| Sheet runway | Day 3 of 15 · until Sep 18 | — |
| Sheet next | After Sep 18, new messages stop coming through to you. Top up any time and everything resumes. | Top up any time — replies and Slack alerts pick up the moment it lands. |
| Sheet time | Paused Sep 3 | Paused Sep 3 · stopped reaching you Sep 18 |
| Sheet CTA | Add funds | Add funds |
| Connect notice sub-line | Paused until you add credit — it resumes the moment your top-up lands. Messages still reach you on Slack for 12 more days. | Paused until you add credit — it resumes the moment your top-up lands. New messages no longer reach you until you do. |
truncate. If “Messages still reach you · 12 days left” cannot fit beside “Top up →” at the card’s width, render the day-count clause alone (“12 days left”) — the number is the part that must survive, never the prose.payment_failure (the #4516 shared branch) — this caption is a third branch keyed on chat runtime + wallet_empty, exactly the split the D-3 amendment already anticipated.grace_ends_at (or the pause timestamp the step-down cron reads + the 15-day constant). Pulse already carries last_paused_at (“Status since”), so the day count is derivable client-side today — but only if the step-down job uses the SAME timestamp, otherwise the sheet says “1 day left” while the cron already stopped relaying. Prefer the backend exposing the end date over the client re-deriving it.pause_reason value. The UI must never infer “stopped” from “today > day 15”: the two would drift by a cron tick and the founder would read the wrong sentence. If it is a new pause_reason, the D-3 resolver maps it to the SAME amber Paused + verbatim line (no new colour, no new badge word).flowPattern.runtime === 'chat'; confirm the post card / Pulse stats already carry it (it decides whether “Messages still reach you” is even true — a platform-triggered assistant has no customer messages to relay).wallet_empty_paused daily reminder should carry the same day count and the same day-15 change. Copy owner: chief-writer; mechanism: chief-cto.RunIssueSheet.tsx renders a red Error badge for every caller, including wallet / budget pauses — contradicts D-3 (amber for a retryable wallet state, red for Failed only). The sheet should take the badge from the owning rule: amber Paused for wallet / limit / setup pauses, red Error for a failed run, lantern Needs attention for a chat leftover (pulse.html 1q already draws that).ConnectWalletFunds.tsx paused sub-line “top up to resume it yourself” is stale for wallet_empty since #4496 (top-up auto-resumes). Keep it for payment_failure; wallet_empty reads “it resumes the moment your top-up lands.”contentWidth="prose"). Cards: 375 one column, 768 two-up, 1180 three-up, caption rule identical. No per-state tablet frame is owed — the rule covers states not yet drawn..mb band + Today/Earlier feed is retired from this frame.?assistant=4L910 seats · 7 booked · 3 left · synced 2 min ago
5 of 6 · needs-verdict first, then newest · 2 on the waiting list
All 5 pieces · v1 · $3.00 kit + $0.02 rewrites.
program-launch-kit.html sec-8's mobile twin (sec-8-m), not a new sheet on this frame.Your booking link is live. Share it and the first name lands here — usually within a day of posting.
Nothing's lost — this is a connection problem on our end. Your bookings are safe.
Or ping us if it keeps happening.
We'll bring you straight back to this list.
/pulse?assistant=…&records=open while signed out → ProtectedRoute → sign-in. Return-to back to the sheet is a build gap (no platform-wide return-to exists — named, not invented). No row, count, or name renders before auth.?assistant= resolves no assistant she owns (RLS returns nothing) → both params are dropped and Pulse renders her own wall. No sheet, no count, no "permission" wording — byte-identical to a deleted assistant. (Replaces the old in-surface "This list isn't here" state — there is no surface without the assistant. NEW (PRD debt) against AC-WSBK-31.)workshop-booking.html 13b; every control — verdicts, ⋯, ✕, chips, Prev/Next — is ≥44×44.Runs show up here as they happen.
It reads your Brain — prices, policies, hours, FAQs, and your brand voice — and answers guests in the voice you confirmed. Anything it can't ground in your knowledge gets handed to you.
It reads your Brain — prices, policies, hours, FAQs, and your brand voice — and answers guests in the voice you confirmed. Anything it can't ground in your knowledge gets handed to you.
Both tiers drawn per R22. Archetype: assistant-detail-tabs.md (post-tab list + self-check #7).
Editable “Edit” rows below are the pre-#4432 Personalize tab, kept here for history only. Peyton's 2026-09-04 lock (Option B) replaced this with the read-only locked mirror — nothing on any row is clickable, and setup changes happen only by starting a fresh assistant. Build from 9c / 13c ↓, never from this frame. The header below also predates the four-line hierarchy (9g) — left unfixed since the whole frame is historical.
Changes take effect on the next run. Nothing already answered is rewritten. Brain readiness lives on Connect →.
Changes take effect on the next run. Brain readiness lives on Connect →.
Archetype: assistant-detail-tabs.md.
Nobody gets the same wave twice.
Wrong words? Edit in Personalize →
101–500 people is the $0.50 band. This one can't be unsent, and there's no retry — nothing goes out until you tap it.
We'll tell you the moment it's approved — you don't have to check back.
Your signup page is live and collecting. We'll put this back on your Pulse card the moment there's someone to send to.
No recipients, no charge.
Rename it first? Autumn retreat support ✎
375 — the same seven steps stack vertically, one box per row, the thread running down the left.
The 02b row is the bypass the “Don't ask me next time” checkbox buys — shipped today (`ReactivationConfigReview.tsx:134`). Preflight still runs; only the chooser disappears.
This is what's set for this round — nothing edits in place. Start fresh with a new assistant → (⋯, top right). Brain readiness lives on Connect →
Works the same whether they tapped your wa.me link or typed this directly — the AI reads intent, not just the word.
Same string ConfigFieldRenderer.tsx's formatLockedFieldValue() already returns for an empty value — never a silent schema default standing in as if the founder chose it.
.field/.opt-radio reflow full-width, same as the pre-activation Configure step at this width — no bespoke mobile row grammar. Paused renders the identical .m-body, header only differs (see 13g). Preview, corrected 2026-09-04: renders exactly what this instance's OWN pre-activation mobile Personalize frame draws — workshop-booking.html sec-3's full-inline preview (both variants, stacked below the form, no dock), copied verbatim, un-dimmed, outside the .m-body.pz-locked wrapper. NOT this file's own D2-locked slide-up-dock pattern (sec-4e's .pvpill/bottom-sheet) — an earlier pass here used that dock instead, on the theory that it's the current canonical mobile-preview mechanism; Peyton's "carry over whatever pre-activation actually draws, unchanged" ruling reversed that in favor of matching this specific instance's actual source frame byte-for-byte. Flag for whoever owns D2/workshop-booking.html next: that source frame (sec-3) itself doesn't use the dock either — it predates the D2 lock (`design-decisions.md` "D2 — mobile Personalize preview is Variant A: slide-up on demand") and is stale relative to it. Copying it verbatim here means 13c-m inherits that same drift rather than fixing it; the fix, if wanted, belongs at the source (bring workshop-booking.html sec-3 up to D2 first), not invented independently in the post-activation mirror.Mobile tier of 9g ↑. Same four lines, same order; L1 wraps to two lines at most (line-clamp-2, the existing title rule), L2–L4 are single-line and truncate from the right. The control cluster keeps its 44px hit areas and never wraps under the title.
Below: the Pulse tab body, unchanged (frame 9). The header is the only thing this frame draws.
The type is never printed twice. Naming it (✎) promotes the founder's word to L1 and drops the type to L2 — the booking crop's shape.
Same two items as desktop. Pause / Stop stay ⏸ ⏹. “Switch account…” stays in Connect's status menu (13d).
Mobile tier of 9d ↑. Both rows keep their status chevron even where the badge carries none — the two arrows answer different questions (5b). The muted Switch account… is the .dim flavour: tappable, and what it opens is a decision with two live paths, so it earns the notice panel rather than 5b's inline .off reason line.
No badge caret (one app per role) and no standalone button — Switch account lives in the status menu, visible but MUTED while Active; tapping it opens this notice, never acts. Reconnect still appears if a connection breaks. Cropped to the apps section under demonstration; AI Model / Storage (B3) are omitted from the crop, not the tab.
Paused lifts the mute — same item, same place, now live; it opens the switch on the app it targets, then Resume. The menu's SHAPE never changes between Active and Paused, so she learns one menu and only a line's muting moves. On a multi-app row this item instead greys out with its reason and points at the badge, exactly like Disconnect (frame 5b).
The host split is already signed at 14. This frame is the next beat: Share anything, from inside that Brain pane. Two panels stay two panels. The sheet never unfolds a second 40/60 inside the 40%.
WALKTHROUGH — one job, two panels · keep this chrome for now
1 Assistant rises do something · bottom sheet
2 Brain slides from left go somewhere · 40% page pane · frame 14 at rest
3 Share anything rises SAME sheet as /brain, contained in the pane
not a centered dialog · ModalWrapper presentation="sheet"
4 Empty → proposal → honest-empty still two panels · frames (1)(2)(3)
5 Close section editor returns · assistant never left
Why it can look like a card: the sheet chrome (reveal gap, 18px radius, pane dim)
is one size down. The page peeks above a viewport sheet; Brain peeks above this
one. Accepted for now — do not invent a second Share mechanic or fill-the-pane swap.
Broken (never drawn) [ digest 16% | share 24% | assistant ]
Target [ opaque stacked Share | assistant 60% ]
The one line guests hear first. Your assistants quote this back.
flushSplit) so the editor does not paint through the composer.ModalWrapper presentation="sheet" (rise, reveal gap, radius) contained in the pane — never a centered confirm./brain at ≥1024 keeps f15’s internal 40/60 — that sheet owns the full stage. brain.html f15 ↗ModalWrapper is the sheet host. presentation="sheet" is the locked rise. The card-on-Brain look is that chrome one size down (pane peek, 18px radius, pane dim). Accepted for now — do not swap the left pane or invent a second Share surface.BrainStackedFillsDigest. The co-pane column is only when this sheet owns the viewport. Rejected: B (swap the pane) · C (park the assistant for full-stage f15).Components: BrainShareSheet.tsx · BrainSplitHost.tsx · ModalWrapper.tsx presentation="sheet" · useSplitLayout. Spec: modal-slide-choreography-architecture.md §1. Sibling frame: brain.html f15.
Same push, same peek-edge/Esc return, on every destination — this Brain example is drawn once and stands for Connects and Top-up too. Change card is the next frame.
Runs draw from this. Nothing else is charged.
The card Top up will charge.
Connect never opened Billing.
There is no split below 1024, so every state below is the same full-screen push — the 768 tablet tier is this same frame, wider (drawn in the desktop half). The peek edge is the only way back, on every state.
The wizard already told us which app — only Resend's own form is loading.
Sends your launch emails from your own address.
Resend didn't accept that key. Copy it again from Resend — it starts with re_ and has no spaces.
Going back now leaves the row exactly as it was — nothing half-saved.
Launch emails will send from your own address.
◄ taking you back to Connect…
Leaving the push is navigation, not cancelling. Nothing submitted → nothing saved and no confirm dialog; already submitted → it lands on its own and this row flips itself.
No push reopens — the job it was opened for is done. She never presses a “continue” to get her own work back.
Read your site, paste anything, drop a file, or link a doc.
presentation="sheet" rise as desktop, full-width because there is no split below 1024. Not a dialog. Do not invent a third column here.Runs draw from this. Nothing else is charged.
App costs (WhatsApp, Stripe) go to your connected accounts.
Both tiers drawn per R22.
Copy on these frames is provisional — Chief Product draft 2026-09-25, pending Peyton’s approval (#5311). Placement and structure are the contract; strings may still change.
dialog (a sheet at 375) with a read-only list and a single primary action. Support’s ⏸ and ⏹ render dimmed on its card for as long as a booking assistant is live. Both assistants are charged only when used, so a waiting booking card costs nothing.Copy on these frames is provisional — Chief Product draft 2026-09-25, pending Peyton’s approval (#5311). Placement and structure are the contract; strings may still change.
768 samples the U8 continuum; it isn’t a third layout. Same rule as 8e: the Overview reflows and the sheet is one column capped at 720. Wall cards follow the Pulse wall’s own two-up step, and the blocked dialog is the centered dialog.
Copy on these frames is provisional — Chief Product draft 2026-09-25, pending Peyton’s approval (#5311). Placement and structure are the contract; strings may still change.
.off, never removed). In context: frames 8, 8b. Full-page seating: pulse.html.presentation="sheet" — 375 bottom sheet + desktop seated sheet, full-width band chrome. In context: frames 3, 9b, 10. Pass-bar: archetypes/assistant-detail-tabs.md, sheet-slide-panel.md.wa.me/{phone} share row, no booking prefill. In context: frame 9b.Open kit › into the existing LaunchKitReviewSheetBody; amends the 2026-08-22 "kit body replaces the whole tab" exception. In context: frame 9b-k.‹ Newer · Page N of M · Older › pagination the tab's 5-row preview doesn't. In context: frame 9f.BYOK picker deleted — not later. The live row is #sec-5 / #sec-5b: MystFlo AI, paid per run, no key to set up, no caret, no own-key group.
AiModelPicker.tsx has no provider dropdown and never will on this contract. MystFlo chooses the model. The Active row has no caret.sheet | airtable | stripe), which makes it easy to assume it's a connectable Storage provider. It is not — there is no connect flow. Showing it struck-out here is cheaper than someone re-deriving that later."$1,890" → "$1890" is not a price change, but a string comparison says it is — and that is what makes the Brain's stale-listing flag untrustworthy (#3320). Structured entry removes the ambiguity where it is created rather than guessing at it later.USD / EUR / GBP / IDR. $ alone means USD, AUD, CAD, SGD or NZD — a symbol meaning five things cannot be compared, summed, or safely quoted to a customer in another market. ONE currency per offering; mixed-currency tiers are not a real case and are not drawn.display is composed ONCE at save (from USD 1,890) and stored. It is never recomposed at render, so the D1 rule holds: no surface derives a price. The tiers underneath are what let an assistant answer “how much is the private room?”.Apr 12–19 & Oct 4–11 — two occurrences. A single start→end row cannot hold it. Each occurrence is one date or a range; “+ add another” repeats it.Service.duration exists. “7 nights, 8 days” is how LONG it lasts, not WHEN it runs — a retreat has two occurrences and one duration. It never belongs in the date control.prd-pl-brain.md § “Structured value beside the written form”; acceptance AC-OFFVAL-01..08.brain.html 28g (the offering correction editors). Same field types, same rules — this frame is the wizard's rendering of them..off + always-visible reason line, no hover tooltip): Disconnect on ai_model, Reconnect while Pending, any row-level action on a ≥2-app row. Every app inside a picker carries the same button one tier down (.mini) — the Connected ✓ text + underlined Disconnect link pair is DELETED, and with it the pass-2 “Disconnect… → which-app MODE” hand-off; the badge owns “which app” at all times. Expired tokens still name their app collapsed. Connect on an unconnected pick → left co-edit slide sheet (shipped). Stack rule: one boundary at sm 640, every row. 375 + 640-pair + 768 + desktop tiers drawn./brain/book in on the left (T1086 lock kept) with the docked bar; the peek rises inside the 40% pane (14d rule), never asks; the draft lands in the Book and Save to Brain confirms it (v5.27 unchanged) — closed before saving the row stays a blocker, "draft ready — Save to Brain" (NEW status). The focusSection co-edit pane is retired from this door (not deleted). 375 = stacked overlay, bar opens the full sheet in wave 1.?assistant=<id>&records=open. Supersedes the under-card RecordsEntryRow. Not built.LaunchKitReviewSheetBody; the kit body no longer replaces the whole tab. Not built.ModalWrapper sheet, nestedBackdrop + broadcastCloseAll=false, header-band title + subtitle + ✕, FilterChipGroup + PaginationBar idioms, every state (populated · empty · loading · warm-stale · cold error · signed-out · not-owner). Routed page + slide-over ban retired; deep link via URL param (name = CTO). 768 not drawn here (workshop-booking 13b). Not built..sm group headings, .field-label/.field/.opt-radio row anatomy), every field showing its saved state, nothing clickable on ANY row including Safe tier — no Edit, no per-row verb, no confirm dialog. The A6 Safe/Structural/Identity split (fieldEditPolicy.ts) stops driving display; a uniform .pz-locked wash is the only visual delta from an editable form. ONE top context line points to "Start fresh with a new assistant" (header ⋯ menu) as the only way to change anything — pausing unlocks nothing. AC-LIFECYCLE-11 needs a policy-level rewrite, not just wording.instanceNaming.ts), so the type word is never printed twice..dim = tappable, opens a reason WITH live paths (this frame's notice panel); .off = cannot act, purely informational reason on an inline line (5b). Reconnect stays available in every state; on a multi-app row Switch account greys out and points at the badge, same as Disconnect. Shipped 2026-08-17. Cropped, apps section only; mobile tier at 13d.PageSlideOver has a live 'connects' case, ConnectsPage takes no focus prop, and ConnectionModal's body needs extracting to an inline form. Two questions left deliberately open: expired-draft / cross-device return, and whether a return that landed a further choice should reopen the pane.wallet_empty — “Messages still reach you · N days left” while relaying, “New messages no longer reach you” once stopped — beside the #4516 “Nothing lost” shared branch. No customer-facing message exists in either state. Mirrored into assistant-summary-card.md self-check item 25. Ships only with #4522./pulse/:id/records page is retired into a redirect; deep-link via a URL param on the sheet (?assistant=<id>&records=open — name = build decision, CTO). Supersedes #2924's route lock and the records-surface PageSlideOver/slide-over ban; R30/R31 stand (four tabs, flag-row on the card). Frames 8d · 9b-r · 9e.contentWidth="wide", nestedBackdrop, broadcastCloseAll={false}): the records sheet (9e, unchanged) and the NEW Activity sheet (9f), which now owns the range chips + ‹ Newer · Page N of M · Older › pagination that no longer render on the tab itself. Amends R36's placement: the records roster is the RIGHT SLOT's first item, not a full-width band between the metrics/quick-actions pair and activity. Amends the 2026-08-22 "generation-kit keeps its own full-body review sheet" exception — generation is now a typed slot (piece-readiness + "Open kit ›") like every other type, not a whole-tab swap. 375 stays one column, same order: exception → metrics → slot → activity. Assistant files never redraw this tab — they carry a .revisit card to the matching master frame + a short slot-delta list. Frames: 9b (chat) · 9b-x (exception) · 9b-r (records) · 9b-k (generation) · 9e (records sheet, unchanged) · 9f (NEW Activity sheet).Mirrored into kit `design-decisions.md` + archetypes: `assistant-detail-tabs.md`, `assistant-summary-card.md`, `pulse-surface.md`.