Quinn's daily-driver (brief A) tells her *what wants her attention*. Audit (brief I) tells her *what was done in her name*. Neither tells her *how her business is performing*. The `strategist` specialist already produces these reads ("the OF cohort cooled since Berlin"), but they only land as chat proposals. This brief adds a **pinned dashboard surface** — revenue trends, prospect funnel, cohort warmth, per-surface performance — so Quinn can answer "how am I doing this week" in one tap.
The dashboard is the **strategist's front-window**, not a separate specialist. It pulls from the same data sources strategist already reads (engagement_events, content_posts, agent_actions, tour_legs); the dashboard is the *visual* surface for those reads, while chat proposals remain the *conversational* surface.
## Designer skim
- **Headline UX**: One scrollable dashboard. Five panels: revenue · prospect funnel · per-surface performance · cohort warmth · tour ledger. Each panel has a default view, a strategist-narrated insight chip, and a "tell me more" tap that opens a chat thread with strategist for that slice.
- **Panels (5)**: T1 revenue · T2 funnel · T3 per-surface · T4 cohort warmth · T5 tour ledger.
- **Voice lean**: working register throughout — analytical, literary; hearth on insight chips when the news is good; plain when revenue dips or a cohort hard-flatlines.
- **Pair-with**: [strategist contract](./specialist-strategist.contract.md), [`day-in-life.flow.md`](./day-in-life.flow.md) (dashboard appears in the day flow when Quinn checks in on web companion).
**Default view**: a single number (current period gross), trend sparkline, comparison to prior equivalent period, breakdown chip stack (OF / Tryst / TS4Rent / PPV / tips / other).
**Insight chip** (strategist-narrated):
> Up 18% over last 30 days — OF subscribers carrying it. Tryst is flat.
**Tap-through**: opens chat with strategist scoped to "explain the revenue movement this period."
**Drilldown view (tap the headline number)**:
- Daily series with per-source overlay.
- Per-source share-of-revenue donut.
- "Big days" callouts (top 3 days; tap → audit drawer scoped to that day).
**Privacy**: per-leg revenue figures live in audit; T1 aggregates across all sources. Hotel/leg detail revenue stays in R drawer.
## T2 — Prospect funnel panel
**Default view**: stacked funnel — Free → DM → Tip → PPV → Subscribe → Booking. Counts per stage, conversion rates between stages, period delta.
**Insight chip** (strategist):
> 47 prospects entered the funnel this week, 8 reached PPV. The DM→Tip conversion is steady at 14%; below it the drop-off is from PPV pricing — strategist has a price-test proposal ready.
**Tap-through**: opens chat — strategist may propose an experiment (per [brief plan P4 conversion experiments]).
**Drilldown**:
- Per-stage list of prospects (links to brief B3 prospect drawer).
- Per-funnel-source breakdown (X-sourced vs Tryst-sourced vs cold).
- Cohort retention by entry-week.
## T3 — Per-surface performance panel
**Default view**: a row per Quinn-active N1+N2 surface (per [brief O](./O-surfaces-roster.brief.md)). Each row: post count (or bump count for N2 directories), engagement rate, conversion to funnel-stage-2+, period delta.
**Insight chip** (strategist):
> Instagram drafts are sitting unapproved 4 days on average — content-social wants you to either relax draft-approval there or accept the cooling effect.
**Tap-through**: opens specialist drawer for `content-social` (or relevant specialist), pre-filtered to this surface.
**Drilldown**:
- Per-surface time-series (posts × engagement).
- Per-surface auto vs Quinn-approved ratio (cross-references brief I trust panel).
> The October cohort is the warmest in 90 days — re-engage before December and they'll likely convert again. Earlier cohorts (Aug, Sep) are cooling; one nudge-DM cluster might revive Sept.
**Tap-through**: opens chat — strategist may propose a follow-up DM cluster targeting a cohort.
**Drilldown**:
- Per-cohort prospect list with funnel-stage snapshot.
- "Send a follow-up cluster" affordance — drafts a triage+content-onlyfans DM cluster scoped to a chosen cohort.
## T5 — Tour ledger panel
**Default view**: rolling list of past + active + planned legs (per [brief R](./R-tours-events-hotels.brief.md)). Per row: city, dates, planned revenue vs actual, net.
**Insight chip** (strategist):
> Berlin Oct over-performed (€4,920 vs target €4,200). Amsterdam under-performed (€2,100 vs €3,000). Worth interrogating the Amsterdam hotel choice — Adina worked, the canal-side property didn't.
**Tap-through**: opens leg-detail drawer (R2b) for the relevant leg.
**Drilldown**:
- Cumulative tour-only revenue ribbon.
- Per-city historical performance (cities Quinn has visited multiple times — what's the trend?).
The panels above (T1 revenue, T2 funnel, T3 per-surface, T4 cohort, T5 tour ledger) all draw on cross-surface data. Three concerns govern how that data is rolled up + how prospect-funnel paths across surfaces get credit. **Owned UX-side here; engineering owned at [_engineering-surface-metrics.md](./_engineering-surface-metrics.md)** (schemas + scheduler + attribution model implementations).
### §T-aggregate — Aggregation across surfaces
**What aggregates and what doesn't**:
| Panel | Aggregate-canonical? | Sources |
|---|---|---|
| T1 Revenue | **Yes** — sum across all surfaces with revenue signal | OF subs/tips, Tryst-driven bookings (per [surface-tryst.brief.md §9](./surface-tryst.brief.md)), Fansly, manual ledger entries, content PPV |
| T2 Funnel stage counts | **Yes** — counts roll across surfaces; per-source breakdown is a drilldown | Tryst profile-views, X impressions, OF subs, iMessage replies, etc. |
| T3 Per-surface | **No** — per-surface by definition; tier-gated empty-states honored per surface's `§canonical-facts` | Single-surface raw |
| T4 Cohort warmth | **Yes** — cohort defined by *first cross-surface touchpoint*; warmth weighted by all subsequent touchpoints | All touchpoints |
| T5 Tour ledger | **Yes** — per-leg revenue rolls across surfaces in the tour window | All revenue sources during leg dates |
**Read path**: panels read from `metric_aggregates` (the materialized rollup table). Engineering's rollup cadence: 15 min active window, 1h recent, daily older, immutable past 90 days.
**Freshness UI**: each aggregate panel shows a "computed N min ago" stamp in compact gray text (12pt). Tap to manually re-trigger rollup — `strategist` re-runs over the underlying surface_metrics. Per [T6b](#t6b--refresh-model), the pull-to-refresh affordance is intentionally low-affordance because inference costs real money.
**Per-surface contribution breakdown**: every aggregate panel has a `surface_breakdown` chip stack (e.g. T1 revenue: `OF 62% · Tryst 21% · Fansly 17%`). Tap a chip → drilldown filters to that surface.
**Tier-gating implication**: if Quinn is on Tryst Basic (no native analytics per [§canonical-facts](./surface-tryst.brief.md)), Tryst contributes nothing to view-count aggregates and shows `—` in surface_breakdown rather than `0` (zero would falsely suggest "no views" — `—` means "unmeasured"). T3 Tryst row shows the upgrade nudge; T1/T2/T4 aggregates honor the absence cleanly.
**Insight chip (strategist)**:
> Revenue's up 18% — OF carrying it (62% share). Tryst views aren't measured at your tier; jumping to Standard would let me tell you whether Tryst's quietly contributing.
- Anonymous touchpoints (profile_view with no identifier match) **aggregate only** — they count in T2 funnel top-of-funnel totals, never appear in per-prospect paths.
- Per-prospect paths are Quinn-only — never visible to coop peers (per [brief N](./N-provider-coop.brief.md)), never shared org-wide pre-explicit-consent (W §W4 deferred).
- Brief V data-export covers Quinn's full attribution graph as her data.
**Insight chip (strategist)**:
> Your warmest path this month is Tryst → iMessage → OF. The Tryst-first prospects who DM within 48h convert at 3× the rate of cold OF subs. Want me to draft a Tryst-bio nudge to point more of them to iMessage faster?
### §T-attribution-model — Model picker
A small chrome control in T2 + on prospect-detail.screen.md that selects which attribution model is in use for the displayed numbers:
- **Position-based** — 40% first / 40% last / 20% middle. Surfaces middle-funnel value.
**(?) info popover** explains the choice in plain voice:
> Different attribution models tell different stories. Time-decay is the balanced default — Cocotte gives more credit to recent touches without ignoring the first one. Switch to First-touch when you want to see what's bringing prospects in; Last-touch when you want to see what's closing. Same data, different lens.
**Persistence**: per-Quinn preference, stored in `users.attribution_model_pref`. Model selection updates instantly (no recompute — engineering computes all four models in parallel; the picker just selects which is displayed).
**Tap the (?)** → opens chat with strategist scoped to "help me pick an attribution model."
**Insight chip (strategist, when Quinn switches model)**:
> Switched to First-touch — Tryst's credit jumped to 78%. That's where prospects discover you. Switch back to Time-decay (default) to see what's actively warming them right now.
- **iOS**: a drawer (sibling to brief B's catalog) reached from chat-home's top-bar overflow OR by Quinn saying "show me the dashboard." The drawer dismisses with swipe-back to chat scroll position.
- **Web companion** ([brief G §G4](./G-web-surfaces.brief.md)): full-page view (G's CRM-style desktop affordance). Same panels, more drilldown density per panel since desktop has the screen real estate.
### T6b — Refresh model
- Default panel data is cached and refreshed by `strategist` once per vigil (per [brief Q](./Q-vigil-journal-auto-conversations.brief.md)) — "morning numbers" pattern.
- A subtle pull-to-refresh on the panel re-runs the strategist computation. Per-pull cost is real (LLM calls) so this is intentionally low-affordance.
- Streaming panels (revenue current-day, funnel current-day) update on engagement-event arrival via SSE/WebSocket on web companion. iOS uses push for high-stakes anomalies only (per [brief C](./C-notifications.brief.md)).
### T6c — Anomaly surfacing in chat
When `strategist` detects an anomaly (revenue spike, funnel collapse, cohort-warmth flatline), the insight chip changes register (plain) and **also** surfaces as a chat message — Quinn shouldn't have to open the dashboard to learn that something broke or surged. Chat is the canonical attention surface; the dashboard is for *intentional* analytical sessions.
### T6d — Comparison mode
A toggle at the top: `this week / 30d / 90d`×`vs prior / vs same period last year`. Each panel re-renders with delta callouts. Lean: comparison-vs-prior is the default for `this week`; comparison-vs-last-year is the default for `90d+`.
### T6e — Privacy on the dashboard
The dashboard is **operator-facing only**. Never exported, never embedded in outbound, never visible to coop peers (per [brief N](./N-provider-coop.brief.md) coop intel network is separate). Revenue figures are confidential per [brief K §K3-misc](./K-safety-blocklist.brief.md) — never quoted in outbound drafts.
## In-the-wild copy
**T1 revenue insight chip, good news** (hearth):
> Up 18% over last 30 days — OF subscribers carrying it. Tryst is flat.
**T1 revenue insight chip, anomaly** (plain):
> Revenue dropped 31% week-over-week. Two OF days missed scheduling because of the platform.api hiccup Tuesday. Audit has the details.
> Re-running strategist over 30 days. ~10s, ~$0.04 in inference.
**Comparison mode toggle hint** (working):
> Compared to last month, you're up across the board except Instagram. Tap a panel to dig in.
## Out of scope
- Marketing-funnel analytics for sites Quinn doesn't own (third-party attribution).
- Cross-org dashboards (single-Quinn for P0; multi-org with Demimonde is P5+).
- Export to PDF / CSV (defer; users will ask if needed).
- A/B test infrastructure UI — referenced in T2 conversion experiments but lives in a separate experiments brief if it grows.
- Tax / accounting view — Quinn handles separately; not a CocotteAI concern.
## Open questions
- **T-Q1** Refresh cadence — strict once-per-vigil or also on app-foreground? Lean: once-per-vigil + manual pull. Foregrounding alone shouldn't burn inference. `[blocking]`
- **T-Q2** Web-vs-iOS depth parity — should iOS show all panels at the same depth, or surface a "open in web" affordance for the densest views (e.g. cohort matrix)? Lean: iOS shows summary + key drilldowns; "open in web" for high-density grids like T4 matrix. `[blocking]`
- **T-Q3** Anomaly threshold — what counts as worth a chat surfacing vs just an insight-chip change? Lean: ±20% revenue WoW, ±10pp funnel-stage conversion shift, cohort flatline >2 weeks. Engineering-tunable. `[engineering]`
- **T-Q4** "Tell me more" handoff continuity — does the chat thread that opens from a panel keep that panel pinned at the top while strategist explains? Lean: yes, the panel pins as a card-style reference while the conversation flows below it. `[nice-to-have]`
- **T-Q5** Per-cohort experiments — when Quinn approves a strategist-proposed price test or DM-cluster from the dashboard, where does that action's progress surface afterward? Lean: in the dashboard panel that spawned it, with a "test running, day 3 of 7" status. `[nice-to-have]`
- **T-Q6** Attribution model default — Time-decay proposed (7-day half-life); confirm half-life against Quinn's actual sales cycle (SM-Q3 in `_engineering-surface-metrics.md`). `[engineering]`
- **T-Q7** Attribution per coop — should cross-coop revenue attribution be visible at all, or strictly per-coop-isolated? Lean: per-coop-isolated unless explicit coop-data-share consent. `[blocking once P5 multi-org lands]`
- **T-Q8** "Top paths" view — how many paths to show before consolidating to "(N single-touch paths)"? Lean: top 8 multi-touch + consolidated single-touch tail. `[nice-to-have]`
- [specialist-prospect-resolver.contract.md](./specialist-prospect-resolver.contract.md) — touchpoint linking (resolves which touchpoints belong to which prospect).
- [surface-tryst.brief.md §canonical-facts](./surface-tryst.brief.md) — tier-gating example (Basic tier shows `—` not `0` in surface_breakdown).