Skip to content

Asurion Command Center — Live Demo Runbook

Companion to prd.md §4.1, §12.1, §15, §17. Do not edit the Cursor plan file; this document is the operational source for presenters.


Roles

Role Responsibility
Driver (Jane) Clicks only on Executive Overview path; reads KPIs aloud sparingly.
Operator Starts stack, runs make demo-reset, then python simulator/emit.py (or Make target) at the Driver’s cue.
Tech backup Watches API logs / browser console; applies fallback lines if Bedrock or WebSocket fails.

Pre-flight (T−10 minutes)

  1. docker compose up --build -d from repo root; wait until API health returns 200 (curl -sf http://localhost:8000/health).
  2. Open dashboard: http://localhost:3080 (Compose default; change the port mapping in docker-compose.yml if it conflicts locally).
  3. Run make demo-reset once to establish baseline seed (Active Issues baseline matches PRD narrative 1,286 after reset in default seed).
  4. Close other bandwidth-heavy apps; prefer localhost demo (mitigates venue Wi‑Fi per PRD §17).
  5. Confirm Operator has simulator/scenario_1.yaml and simulator/emit.py ready; API base URL http://localhost:8000 unless overridden by COMMAND_CENTER_API.

Baseline numbers (PRD §4.1)

After reset, the UI should align with seeded state (exact values depend on db/seed.py; defaults target PRD copy):

KPI / element Expected at rest (default seed)
Active Issues 1,286 (open + in_progress issue sessions)
Claims in Progress 642
Next Best Actions Taken (%) 87% (PRD §17 plausibility — 120 approved / (120 + 18) ≈ 0.87)
Cost Avoided (MTD) $1.41M baseline; approve adds +$210 ticker delta
Customer Satisfaction 4.6 / 5 (P1 static, mockup parity)
Demo customer John Doe (cust_demo_001)
Demo device iPhone 14 Pro, IMEI 356789012345678 (dev_demo_001)
Claim id in narrative CLM-88122
Top Issues rows Device screen damage / Battery not holding charge / Device not powering on / Lost or stolen device / Accidental liquid damage

If your seed differs, update this table once and keep one canonical printout for judges.


Simulator trigger order (Scenario 1)

Executed by simulator/emit.py reading simulator/scenario_1.yaml:

Step Delay (YAML) event_type Purpose
1 0 ms device.damage_detected Opens new issue session; Active Issues +1
2 ~2000 ms claim.submitted Claim on session; timeline
3 ~500 ms payment.authorized Payment; triggers recommendation pipeline
4 (server) recommendation.generated Internal: AI card appears
5 (live) Driver clicks card → detail
6 (live) recommendation.approved + outcome Driver clicks Approve

Target spacing: damage → claim within ~2s (PRD §4.1 step 4); YAML uses delay_ms so total drift stays within ±5% for dry-run sign-off (PRD §15 item 2).


Live script (~90s journey + buffer)

0:00 — Landing
Driver: “Executive view — one pane for customer, device, and ops signals.” Wait for KPI skeleton ≤1s then numbers.

0:15 — Operator runs simulator
Say nothing for 2–3s; let KPI tick 1,286 → 1,287 (or your baseline +1).

0:25 — Timeline
Point to new timeline rows: damage → claim → payment.

0:35 — AI recommendation
Live High Impact card appears at the top of the AI panel: Approve repair — Screen damage. iPhone 14 Pro · Claim #CLM-88122. Below it sit four visual-stub cards (Preventive / Risk Detected / SLA Risk / Customer Comms) tagged visual stub per PRD §5.2 — call them out only if a judge asks.

0:45 — Drill-in (right-side panel, PRD §5.1 #11)
Click the live card. The right column loads the Customer & Device Detail: iPhone 14 Pro / IMEI / John Doe + email + phone + customer-since + View 360 Profile + four reason codes (coverage, battery, slot, inventory) + uBreakiFix Dallas · ETA 48h · inventory tight.

1:00 — Approve
Click Approve in the right panel. Within 5s: Active Issues −1 (1,287 → 1,286), Cost Avoided MTD +$210 (Replacement $250 − Actual $40), NBA % +0.1%, timeline appends outcome.recorded — Repair center assigned, alert Repair scheduled.

1:15 — Close loop
Alerts / activity shows confirmation; timeline shows Repair center assigned (or equivalent PRD string).

1:20 — Add Widget arc (≈30s, optional but on-script)
Click + Add Widget in the header. The full-screen modal opens with the chat on the left and the Pipeline tab auto-selected on the right, showing a ReactFlow DAG of the 8-node Clarifier graph. Driver: "This is the same Spine-Clarifier pattern from our R&D framework — LangGraph with a human-in-the-loop pause. Watch the nodes light up as each stage completes." Pick the "Cost avoided by region for the last 7 days as a chart" sample prompt (or type one). The pipeline graph animates in real time: contextLoader → intentExtractor → metricMatcher → gapDetector → questionPrioritizer nodes turn green with completion dots, then the graph pauses at the specSynthesizer node (amber "interrupted" state with HITL badge) and asks 1 question (e.g. "In one short phrase, what measure should this widget show?"). Driver answers (e.g. "Cost avoided in USD") and clicks Submit answers. The graph resumes, specSynthesizer → critic light up, and the right panel auto-switches to the Preview tab showing a live Recharts line chart driven by mock_data. Driver clicks Add to dashboard; the modal closes and the widget appears in the new My widgets rail under the KPIs. Driver: "Same Event → Context → AI → Action loop — but now applied to dashboard composition itself. Live data binding is the next slice."

Stop talking at ~2:00 of the v1 arc. Reserve remaining time for architecture + pattern slides (see pitch/) OR for the Part C live data binding arc below if Part C is on-script for this audience.


Part C — Live data binding arc (~3 min, on-script for the data-eng-audience demo)

Mirrors PRD v2.1 §C.6 timing table. Only run this section when the audience cares about Databricks lineage (it's the headline for engineering reviewers). For exec audiences, stop at the v1 90s arc.

Part C pre-flight (T−5 minutes — additive to the v1 pre-flight above)

  1. Confirm .env has live DATABRICKS_HOST / DATABRICKS_HTTP_PATH / DATABRICKS_TOKEN and AWS_PROFILE=hackathon-async (per README § Live Databricks integration (Part C)).
  2. aws sso login --sso-session hackathon so the api container's AWS_SESSION_TOKEN is fresh — Bedrock SQL gen will fail with ExpiredTokenException otherwise (the failure is loud and visible per ADR-008, but it costs you 30s of stage time you don't have).
  3. make seed-databricks-l3 --reset if you haven't seeded the workspace today (~25s); idempotent thereafter.
  4. Pre-warm. ~30s before showtime, hit the three Databricks-routed tile widgets via curl -sf -X POST http://localhost:8000/v1/widgets/<wid>/data -d '{"refresh":true}' > /dev/null so Bedrock's first-call cost (model warm-up) and the Serverless Starter cold-start are both amortized into the cache window before the audience sees the dashboard. The 300s cache_seconds per config/metric_routing.yaml covers a typical 3-min arc end-to-end.
  5. Reset YAML to default state: cost_avoided_mtd: MUST be backend: postgres at curtain. The §C.6.1 moment is the AUDIENCE's first time seeing it flip.

Part C arc — timing

Time (cumulative) Beat What the audience sees
0:00–0:20 The promise Driver: "v1 was synthetic data on Postgres. The hard problem isn't the dashboard — it's binding tiles to a real warehouse without inviting LLM hallucinations. Watch." Hover over any v1 KPI tile → green Postgres · Xs ago SourceBadge.
0:20–0:50 Add a Databricks-routed widget live Click + Add Widget. Type "claim volume in the last 30 days from the Asurion l3 schema". Clarifier resolves to claim_volume_l3_asurion, pauses at synthesizer, Driver answers "Single KPI, integer count". Click Add to dashboard. Tile appears in My widgets rail showing 5,000 (or whatever the live COUNT(DISTINCT claim_id) is) with a purple Databricks · Xs ago ▾ badge. Click the badge — generated SQL expands inline. Driver: "That SQL came from Bedrock, anchored to a metric_catalog row, validated by sqlglot, executed against workspace.l3_asurion.ev_claim. Five layers of safety; zero hallucinations."
0:50–1:20 Honest mocking Driver: "Watch what happens when Databricks goes away." Operator (in a separate terminal) runs docker exec 2026-hackathon-api-1 sh -c 'export DATABRICKS_TOKEN=bogus' then make up. Tile re-fetches; SourceBadge flips to amber Mock · live data unavailable. The other v1 tiles stay green-Postgres-live. Driver: "It didn't pretend. ADR-008: mocks are opt-in, never silent fallback. The widget's spec.mock_data is showing because the resolver explicitly chose it after Databricks was unreachable — and the badge tells you exactly why (databricks_auth_error)." Operator restores the real token + make up; tile flips back to purple.
1:20–2:30 §C.6.1 — Reroute an existing tile (see sub-section below) Cost Avoided (MTD) starts the demo green. Driver flips the YAML on stage. Tile's value AND SourceBadge change live.
2:30–3:00 Close Driver: "Same dashboard. One YAML edit. Different backend, same renderer, real data on both sides." Pause. Take questions.

§C.6.1 — Reroute an existing tile (1:20–2:30 sub-section)

The single most rehearsed moment in the Part C arc. Goal: the audience sees a tile they've been looking at the whole demo change source without any frontend change.

The setup. cost_avoided_mtd has been on screen for ~2 minutes showing $1.41M with a green Postgres · Xs ago badge.

The on-stage edit. Driver opens config/metric_routing.yaml in a side-by-side editor (Operator pre-positioned this terminal pane). The cursor is already on the cost_avoided_mtd block. Driver narrates and types:

1
2
3
4
5
   cost_avoided_mtd:
-    backend: postgres
+    backend: databricks
     sql_template: source_query
     cache_seconds: 60

Save. Run make up (~5-7s warm rebuild). The boot validator re-checks routing; the api comes back healthy. The tile's useWidgetData polling cadence (spec.data_intent.refresh_seconds = 60s) re-fetches on the next tick — Driver clicks the tile's manual refresh button to skip the wait. The tile re-renders:

  • Value drops from $1.41M (Postgres synthetic from outcomes) to ~$375k (Databricks live trailing-30d SUM over l3_asurion.ev_claim.cost_avoided_usd).
  • SourceBadge flips green → purple. Badge text: Databricks · Xs ago ▾.
  • Click the badge → generated SQL expands. The audience sees: SELECT COALESCE(SUM(cost_avoided_usd), 0) AS value FROM l3_asurion.ev_claim WHERE claim_started_dttm_utc >= current_timestamp() - INTERVAL 30 DAYS LIMIT 5000.

Driver delivers the line: "Same renderer. Same widget id. Same KPI tile. The data resolver looked up the routing for cost_avoided_mtd, saw databricks, asked the SQL generator for SQL anchored to the catalog row's source_query template, sqlglot-validated it, executed against the warehouse, returned the row. The frontend just re-rendered whatever the resolver gave it."

Pause. Let the audience absorb. Take a single Q if asked. Then optionally restore: edit YAML back to backend: postgres, make up, refresh — tile flips back to green Postgres · Xs ago $1.41M. (Most demos skip the restore — the purple state is the headline.)

Part C fallback lines

Cold-start visible (>5s on the §C.6.1 refresh). "Serverless Starter cold-starts on first query — that's why the runbook says pre-warm 30s before. Production runs on a Pro warehouse where this is sub-second. Phase 2 wiring." Don't apologize, don't speculate at length; the cache hit on the next call (within cache_seconds) is your proof.

Bedrock returns 503 / ExpiredTokenException mid-arc. Tile shows amber Mock · live data unavailable. Driver: "The ADR-008 contract just fired — Bedrock unavailable, the resolver returned the widget's baked-in mock_data and the badge is telling you so. Same mechanism as the killing-Databricks moment a minute ago." Operator (in private terminal) refreshes AWS SSO, make up, refreshes the tile. Do NOT pretend the tile is live during this gap.

YAML typo at the on-stage edit. Boot validator fires RuntimeError and make up exits non-zero. Driver: "And that's the boot validator catching what would otherwise be a silent runtime failure — every catalog metric needs a routing answer at startup." Operator fixes the typo (databricks is one s, not databriks); make up; demo resumes.

Stop talking at ~3:00 of the Part C arc. Total demo budget: 90s v1 + 30s Add Widget + 3 min Part C = ~5 min. Reserve remaining time for architecture + pattern slides.


Fallback lines (do not improvise under stress)

Yellow banner: “Reconnecting…” (WebSocket)

“The decision engine and database are still live — we lost the push channel for a second. I’ll refresh once; metrics reconcile on reconnect.”

Action: Single hard refresh; if still down, switch to backup recording (see backup-recording.md).

Bedrock / LLM slow or error (rationale empty or generic)

“The ranked action and reason codes are deterministic; the paragraph is an executive explanation layer. In production we’d enforce SLOs; here we use the same template fallback we’d ship for resilience.”

Action: Do not reload; point at reason codes. API uses ADR-003-style template when model unavailable.

KPIs look “wrong” after one click

“MTD cost avoided is baselined from historical synthetic outcomes so one approval shows a credible increment, not the whole program value.”


Post-demo Q&A hooks (optional one-liners)

  • “Why not Pub/Sub + BigQuery?” → ADR-001: same pattern (durable + hot + pub/sub), faster hackathon path; production mapping on architecture slide.
  • “Is the LLM deciding?” → No: rules + weighted features pick the action; model only narrates within reason codes (PRD §10).
  • Connected chips green? → Visual stubs; no outbound integrations in MVP (PRD §3.2, open-questions-resolved.md).
  • “Why are 4 of the 5 AI cards labelled visual stub?” → PRD §5.2 explicitly cuts Risk Detected / SLA Risk / Customer Comms badges from P0; Preventive is also a stub here. Only the live High Impact card runs through the real decisioning pipeline; the others demonstrate the panel’s future shape on the same architecture (§20 reusability).

Backup recording slot

After a clean dry-run, follow backup-recording.md — the v1 90s arc steps are listed first, the Part C ~3 min arc (the data-eng demo headline) is the second block. Prefer saving the MP4 to artifacts/backup-demo.mp4 (create artifacts/ locally; the path is gitignored via .gitignore line 7 artifacts/*.mp4). After saving, leave the file at exactly artifacts/backup-demo.mp4 so the demo machine can play it from the runbook tab without path edits.

Operator handoff (Part C close-out 2026-05-06): the backup video itself is gated on a human driver — Phase E2 of docs/plans/completed/part-c-demo-ready.md ends at "operator records and saves to artifacts/backup-demo.mp4". Every prerequisite the recording depends on (env, seed, pre-warm script, on-script narration, §C.6.1 reroute timing, fallback lines) is captured in backup-recording.md and the §C.6.1 sub-section above. When the operator finishes the recording, replace this block's last sentence with the recording date so future readers know the artifact is current.


Add Widget fallback lines

LLM (Bedrock) slow or unreachable

"The clarifier ranks questions and validates the spec deterministically — the model only fills the slots. The default mode is live Bedrock per ADR-008; if the modal shows the rose 'LLM unavailable' banner, that's the system telling you Bedrock failed cleanly instead of pretending to succeed. For demos on machines without AWS, run make up-offline ahead of time — the dashboard header shows an 'Offline mode' pill and the same flow runs against the deterministic MockLlm end-to-end."

Action: If the demo is meant to be live and you see the error banner, kill the session, fix AWS creds (or the model id — usually BEDROCK_MODEL_ID=us.anthropic.claude-haiku-4-5-20251001-v1:0 for tool-use), make up, and re-run. If the demo is offline-by-intent, restart with make up-offline so the offline pill is visible the whole time. Do not expect the live path to silently substitute MockLlm — that fallback was removed by ADR-008.

Validation error in the right pane

"The Pydantic discriminator caught a malformed spec — same gate that production would enforce. Adjust the answer on the left or restart the session."

Action: Click Cancel in the chat footer (or the modal Close), reopen via + Add Widget, and try a tighter prompt.


Reset discipline (PRD §15 item 10)

After each full run-through:

make demo-reset

Confirm three consecutive full passes during rehearsal (simulator → approve → KPIs → Add Widget → feed). The reset truncates the widgets table along with everything else (see backend/app/seed.py) so chat-built widgets do not leak between runs.