Legend

9 Agents:
1️⃣ Pre-flight
2️⃣ Diplomat (friendly dunning)
3️⃣ Investigator (background research)
4️⃣ Escalator (Day 30-60+)
5️⃣ Tone Coach
6️⃣ Voice (ConvAI call)
7️⃣ Payment (4 channels)
8️⃣ Concierge (HITL gateway)
9️⃣ AAA Specialist (Day 65 Dynamic Discovery)
🎥 Architecture vs. demo coverage
This diagram shows the full 7-day design — 9 agents across 18 STEPs and 16 voice-call ending types. The demo video covers Beats 1-11, the largest slice that fits in 5 minutes (3-path routing, Day-7 friendly email, Day-65 AAA dynamic discovery, Voice 988 welfare SOP, 5 ARC-TESTNET USDC tx).

Honest gaps (designed & coded, simplified in recording):
• Beat 1 8-agent acknowledgement broadcast = visual render
• Beat 8 welfare halt = unit-tested, not live-fired on call
• Beat 9 reconciler classifies sub-$3 demo USDC as UNMATCHED

Full gap audit: _audit/BEAT_1_11_VS_SPEC_CONSISTENCY_2026-06-17.md + POST_HACKATHON_FIXES.md (14 items, P0-P3; P0-1 shipped).
Rendering... (320+ nodes, ~6-10s)
flowchart TB %% ================== Entry ================== Start([👤 Human operator uploads
contract + invoice
D-007]) --> P1 %% ================== Pre-flight ================== subgraph PreFlight[1️⃣ Pre-flight Agent] direction TB P1[Extract contract clauses
governing law / arbitration forum / late-fee rate
+ deposit_pct] P1Dep[💡 D-038 outstanding, NOT gross
Lawyers chase gross. We chase outstanding.
routing target = invoice − deposit_paid
e.g. 47300 gross × 50% deposit → 23650 outstanding] P1 --> P1Dep P1Dep --> P1A{Outstanding falls in which range?
D-031 sweet-spot × D-038} P1A -- "outstanding < $3K" --> Lite[🪶 Lite mode
Concierge 2-button card
Run Lite / Write Off] P1A -- "$3K-$40K outstanding ✅" --> InSpot[💼 Main flow — the demo] P1A -- "outstanding > $40K" --> Attorney["⚖️ Attorney-recommended mode D-021
Concierge 2-button card
Run full flow + attorney tag
OR provide 3 attorney referrals only
Note: we take ZERO referral fee"] P1B{Contract has governing-law clause?} P1 --> P1B P1B -- Yes --> Continue1[Load that jurisdiction's RAG] P1B -- No --> Fallback[Concierge 3-choice fallback:
Amicable / NY law / AAA arbitration] P1C["D-035 derives arbitration_forum_spoken
for Voice Phase 5
e.g. the American Arbitration Association in San Francisco"] P1 --> P1C end Lite --> LiteDip[Lite runs Diplomat only
no voice call, no demand letter] Attorney --> AttRefer["Pull 3 attorney referrals from config
D-021: 0% referral fee, pure goodwill"] InSpot --> Inv %% ================== Investigator ================== subgraph Investigator[3️⃣ Investigator Agent — D-025] direction TB Inv[Auto-runs at case start] Inv --> T1a[Tier 1a internal history
last 6 months of customer_replies
spec §3 Investigator] Inv --> T1b["Tier 1b external public records
US Secretary of State + OpenCorporates
❌ Skip on API failure, never block flow"] T1a --> PT{Customer pattern_tag classification
6 categories — D-026} T1b --> PT PT -- prior escalation --> Alert[🚨 Red alert
Pre-warm Escalator on Day 0] PT -- chronic late --> ToneFirm[Diplomat opens firm] PT -- occasional drift --> ToneStd[Diplomat opens standard] PT -- clean record --> ToneMax[Diplomat opens softest] PT -- new customer --> ToneStd2[Diplomat opens standard] T2[Tier 2 deep-dive on demand
LinkedIn + CourtListener litigation] end Alert --> Dip ToneFirm --> Dip ToneStd --> Dip ToneMax --> Dip ToneStd2 --> Dip %% ================== Diplomat Cadence + Scheduler ================== subgraph Diplomat[2️⃣ Diplomat Agent + D-035 case-state gate] direction TB CronStart["⏰ Cron scheduler — daily KST 09:00
Sweeps all active cases
Finds cadence steps due today
D-032 + D-007"] CronStart --> CadenceList[List today's due Day -7/0/7/14/30 cadence] CadenceList --> Dip[Diplomat receives each cadence trigger] Dip --> StateGate{🚨 Case state?
D-035 mandatory gate} StateGate -- normal active --> Draft[Draft email] StateGate -- frozen --> Pause[outreach_revoked event
Pause sending] StateGate -- human_owned --> RejectD[auto_reject_post_handoff
case belongs to operator] Draft --> Tone Pause --> WaitUnfreeze[Wait for case_unfrozen broadcast
or /case-unhold command] RejectD --> AuditOnly[Audit-only, no action] end %% ================== Tone Coach + reject loop ================== subgraph ToneCoachSeg[5️⃣ Tone Coach — Claude pinned, D-029] direction TB Tone[Check email draft tone] Tone --> ToneCheck{Tone score ≥ 8.5?} ToneCheck -- pass ✅ --> Q ToneCheck -- "❌ too aggressive
or off Judy's voice" --> ToneReject[Audit: tone_rejected
with reason] ToneReject --> ToneFix[Diplomat receives revision hint
e.g. opening too commanding, add 'hope you are well'] ToneFix --> Draft end %% ================== Pre-Approval Queue (TCPA windowing) ================== subgraph QueueSeg[6️⃣ Pre-Approval Queue — D-032] direction TB Q[Schedule to customer local time
email 1h / voice 4h / demand-letter 8h pre-approval] Q --> TCPAcheck["TCPA safe-time window check
US local: Tue/Wed/Thu 10-11 AM OR 2-3 PM
HARD BLOCK: customer local 19:00 - 08:00
Skip: US federal holidays"] TCPAcheck -- in window --> Conc TCPAcheck -- "out of window (e.g. customer local midnight)" --> QueueDelay[Defer to next legal window
Concierge shows wait time to Judy] QueueDelay --> Conc end %% ================== Concierge + SLA matrix ================== subgraph Concierge[8️⃣ Concierge Agent — D-024 + D-035] direction TB Conc[Receives approval request] Conc --> PriorityCheck{Priority?} PriorityCheck -- standard --> Daily[Bundle into daily KST 09:00
digest — no immediate push] PriorityCheck -- high_24h --> Push24[Slack push + TG DM immediately] PriorityCheck -- critical_immediate --> Page5[Page operator within 5 min
Slack @here + TG + optional phone] Push24 --> Watch1{Human ack within 22h?} Watch1 -- yes --> Done1[Resolved] Watch1 -- no --> Nudge[T-2h nudge:
'SLA expires in 2h'] Nudge --> Watch2{Ack within 24h?} Watch2 -- yes --> Done1 Watch2 -- no --> Breach[sla_breached audit event] Page5 --> Watch3{Human marks resolved?} Watch3 -- yes --> Done2[Resolved] Watch3 -- no --> RePage[Re-page at min 5/15/30
escalate to backup contact] Daily --> Slack3Btn{Operator clicks a Slack button} Done1 --> Slack3Btn Done2 --> Slack3Btn Slack3Btn -- Approve ✅ --> ApproveAct[Execute action] Slack3Btn -- Revise ✏️ --> ReviseModal[Slack modal
fill in revision hint] Slack3Btn -- Reject ❌ --> RejectModal[Confirm modal
cancel + re-plan] ReviseModal --> Dip end ApproveAct --> Sched[Schedule to customer local time
actually send] Sched --> Send %% ================== Outbound channel + retry ================== Send{Outbound channel?} Send -- email --> EmailResend[📧 Resend API send] Send -- voice --> VoiceDial[📞 Voice Agent 06
Check state before dialing] EmailResend --> EmailCheck{Resend response OK?} EmailCheck -- 200 OK --> EmailOK[Email lands in inbox] EmailCheck -- "❌ 5xx error or timeout" --> EmailRetry[Exponential backoff × 3
1s / 5s / 30s] EmailRetry --> EmailCheck EmailCheck -- "❌ 3 retries failed" --> EmailFail[Audit: email_send_failed
Notify Concierge
priority=high_24h] VoiceDial --> CanDial{can_dial passes?
D-035} CanDial -- account frozen --> SkipDial1[Voice dial skipped
Audit: voice_dial_skipped] CanDial -- case human-owned --> SkipDial2[Voice dial skipped
Audit only] CanDial -- TCPA block --> SkipDial3[Voice dial skipped
Permanent do-not-call] CanDial -- ✅ passes --> TwilioCheck[ElevenLabs ConvAI 'Sarah'
dials out via Twilio] TwilioCheck --> TwilioStatus{Twilio dial status?} TwilioStatus -- "✅ ringing → answered" --> ConvAI[Call begins → Voice 8 Phases] TwilioStatus -- "📩 voicemail" --> R11 TwilioStatus -- "❌ no-answer timeout" --> CallRetry[Audit + retry on next cadence] TwilioStatus -- "❌ busy / failed (Twilio error)" --> CallError[Audit: call_failed_technical
Notify Concierge priority=standard] EmailOK --> ResendHook EmailOK --> CustReply EmailFail -.-> Conc ConvAI --> VoicePhases %% ================== 🆕 Day 4 — Resend post-send webhook G1 ================== subgraph ResendWebhookSeg["🆕 📨 Resend Webhook G1 — open/click tracking (Day 4)"] direction TB ResendHook["📨 Resend post-send event stream
src/concierge/resend_webhook.py"] ResendHook --> RWEvent{event_type?} RWEvent -- email.opened --> RWOpen["Audit: email_opened
Update case_state.last_open_ts"] RWEvent -- email.clicked --> RWClick["Audit: email_clicked
Raise engagement_score"] RWEvent -- email.bounced --> RWBounce["Audit: email_bounced
Concierge priority=high_24h"] RWEvent -- email.complained --> RWComplain["Audit: email_complained
Trigger case_freeze immediately"] end %% ================== 🆕 Day 4 — Customer Reply Detector (F1/F2/F5/F8) ================== subgraph ReplyDetector["🆕 Customer Reply Detector — Day 4, src/agents/_utils.py"] direction TB CustReply["👤 Customer email reply
Resend inbound / IMAP"] CustReply --> DetectFanout["Run 4 detectors in parallel"] DetectFanout --> D_Disp["detect_dispute (F1)
Customer disputes invoice items"] DetectFanout --> D_Part["detect_partial_payment (F5)
Customer claims partial payment"] DetectFanout --> D_Ext["detect_extension_request (F8)
Customer asks for extension"] DetectFanout --> D_Prom["detect_promise_to_pay (F2)
Customer commits to a date"] D_Disp --> DetectMerge{Merge verdict
highest-confidence match} D_Part --> DetectMerge D_Ext --> DetectMerge D_Prom --> DetectMerge end RWOpen -.-> Audit RWClick -.-> Audit RWBounce --> Conc RWComplain --> FreezeBroadcast DetectMerge --> Reply %% ================== Voice 8 Phases ================== subgraph VoicePhases[STEP 8 — Voice Call 8 Phases, D-034] direction TB VPh1[Phase 1 verify identity
recording-consent disclosure] VPh1 --> VPh2[Phase 2 ask reason
11 excuse categories] VPh2 --> VPh3[Phase 3 negotiate payment date] VPh3 --> VPh3b["Phase 3b customer commits via email
D-034.2 cooperative path"] VPh3 --> VPh4[Phase 4 confirm
promise 24h email summary] VPh3 --> VPh5["Phase 5 escalation-notice close
cite arbitration_forum_spoken
+ 24h SLA"] VPh3 --> VPh6[Phase 6 conflict de-escalation] VPh1 --> VPh7[Phase 7 wrong party answered
do NOT disclose invoice details] VPh1 --> VPh8[Phase 8 graceful close
24h SLA] VPh1 --> VPhRecRefused["Customer refuses recording
D-035 new script
explain + 2 alternative paths"] end VPh4 --> CallEnd VPh5 --> CallEnd VPh6 --> CallEnd VPh3b --> CallEnd VPh7 --> CallEnd VPh8 --> CallEnd VPhRecRefused --> CallEnd %% ================== Post-call Webhook ================== CallEnd["📨 ElevenLabs call ended
post-call webhook fires — D-034.4"] CallEnd --> PostHook[HMAC verify → Flask /events/post-call] PostHook --> PostAudit1[Audit: voice_call_completed
incl. transcript + analysis + metadata] PostHook --> PostAudit2[Emit voice_call_completed in Band Room] PostAudit1 --> VR PostAudit2 --> VR %% ================== 16 reasons routing ================== subgraph VoiceEsc[STEP 9 ⭐ Voice Call 16 ending types — D-035 core] direction LR VR{How did the call end?} VR --> R1[1 customer refused recording
handoff=Y freeze=N 24h] VR --> R2[2 customer said do-not-call
handoff=Y freeze=Y 24h] VR --> R3[3 customer engaged counsel
handoff=Y freeze=Y 24h] VR --> R4[4 customer declared bankruptcy
handoff=Y freeze=Y 24h] VR --> R5[💥 5 customer welfare signal
handoff=Y freeze=Y CRITICAL] VR --> R6[6 wrong party answered
handoff=Y freeze=N standard] VR --> R7[7 customer not coherent
handoff=Y freeze=N 24h] VR --> R8[8 call dropped
handoff=N freeze=N standard] VR --> R9[9 customer silent 5+ sec
handoff=N freeze=N standard] VR --> R10[10 customer commits via email
handoff=N freeze=N standard] VR --> R11[11 voicemail left
handoff=N freeze=N standard] VR --> R12[12 customer cannot commit date
handoff=N freeze=N standard] VR --> R13[💥 13 customer emotional collapse
handoff=N freeze=Y CRITICAL] VR --> R14[14 customer wants to record us publicly
handoff=N freeze=N 24h] VR --> R15[15 customer persistently hostile
handoff=N freeze=N 24h] VR --> R16[16 language mismatch
handoff=N freeze=N standard] end R1 --> Handoff R2 --> Handoff R3 --> Handoff R4 --> Handoff R5 --> Handoff R6 --> Handoff R7 --> Handoff R8 --> Park R9 --> Park R10 --> Park R11 --> Park R12 --> Park R13 --> Park R14 --> Park R15 --> Park R16 --> Park %% ================== Welfare SOP ================== R5 --> WelfareSOP subgraph WelfareSOP[💥 STEP 11 Welfare-signal 5-step SOP — D-035] direction LR W1[1 Stop immediately
no more invoice / amount talk] --> W2[2 Do NOT play therapist
do NOT say 'I understand how you feel'] W2 --> W3[3 Offer 988 Suicide Prevention Lifeline
free · confidential · 24/7] W3 --> W4[4 Freeze account immediately
broadcast case_freeze] W4 --> W5[5 Emergency page operator
5 min: Slack + TG + optional phone] W5 --> WClose[Warm 30-second close
'please take care of yourself first'] end WClose --> Handoff %% ================== Case Handoff full chain ================== Handoff["🔴 Voice Agent submits to Concierge
case_handoff=true + reason"] Handoff --> ConciergeCard[Concierge posts Slack card
prominent red case_handoff badge
incl. transcript link] ConciergeCard --> HumanSeeCard[👤 Operator sees card in Slack] HumanSeeCard --> HumanClick{Which button?} HumanClick -- "✅ Accept handoff" --> WriteAccept[Audit: case_handoff_accepted
incl. ack_ts + operator_id] HumanClick -- "❌ Reject handoff" --> RejectHandoff[Audit: handoff_rejected
case stays active, Concierge re-queues] WriteAccept --> Broadcast[Concierge broadcasts case_owner_changed
to all 8 always-on agents
9th AAA Specialist only joins dynamically on Day 65] RejectHandoff --> Dip Broadcast --> StandDown1[Diplomat: cancel all future cadence] Broadcast --> StandDown2[Investigator: halt all probes] Broadcast --> StandDown3[Escalator: no Day 60+ activation] Broadcast --> StandDown4[Voice: reject all dials] Broadcast --> StandDown5[Payment: stop issuing paylinks] StandDown1 --> CaseHumanOwned([Case = permanently human-owned]) StandDown2 --> CaseHumanOwned StandDown3 --> CaseHumanOwned StandDown4 --> CaseHumanOwned StandDown5 --> CaseHumanOwned CaseHumanOwned --> ReopenPath{Will human re-try AI later?} ReopenPath -- "rare — e.g. customer improves after 6 months" --> HumanReopen["👤 Operator
Slack: /case-reopen case=... reason=..."] HumanReopen --> ReopenAction[Concierge receives command] ReopenAction --> R_R1[Audit: case_reopened] ReopenAction --> R_R2[Broadcast case_active_again to all 8 agents] R_R2 --> R_R3[Diplomat resumes: restart from review step] R_R2 --> R_R4[Investigator resumes: re-run Tier 1a/1b] R_R2 --> R_R5[Escalator resumes] R_R2 --> R_R6[Voice resumes: can_dial re-permits] R_R2 --> R_R7[Payment resumes] R_R3 --> ReopenCadence[Cadence restarts at review] R_R4 --> ReopenCadence R_R5 --> ReopenCadence R_R6 --> ReopenCadence R_R7 --> ReopenCadence ReopenPath -- case stays closed --> Closed([Permanently closed]) %% ================== Account Hold ================== Park[🟡 case_handoff=N / retry on next cadence] Park --> AHCheck{account_hold = true?} AHCheck -- yes --> FreezeBroadcast[Broadcast case_freeze
Audit: account_held] AHCheck -- no --> NextCadence[Continue to next cadence step] FreezeBroadcast --> FZ1[Diplomat: cancel scheduled email] FreezeBroadcast --> FZ2[Investigator: halt external API
internal history read-only OK] FreezeBroadcast --> FZ3[Escalator: pause Day 60+
cancel Day 55 voice] FreezeBroadcast --> FZ4[Voice: cancel scheduled dial] FreezeBroadcast --> FZ5[Payment: stop issuing new paylinks
BUT inbound webhook still processed] FZ1 --> CaseFrozen([Case = frozen]) FZ2 --> CaseFrozen FZ3 --> CaseFrozen FZ4 --> CaseFrozen FZ5 --> CaseFrozen CaseFrozen --> UnfreezeCheck{Unfreeze trigger?} UnfreezeCheck -- "Customer pays — non-legal" --> AutoUnfreeze[System auto-broadcasts
case_unfrozen] UnfreezeCheck -- "Operator decides to unfreeze" --> HumanUnhold["👤 Operator judges case can restart
e.g. customer cooled down
Slack: /case-unhold case=... reason=..."] UnfreezeCheck -- "Customer pays BUT case is legal/bankruptcy" --> OperatorSurface[Surface to operator for review
do NOT auto-unfreeze] HumanUnhold --> ManualUnfreeze[Concierge broadcasts case_unfrozen] AutoUnfreeze --> Dip ManualUnfreeze --> Dip OperatorSurface --> ManualReview[Operator manual review] %% ================== Customer Reply ================== Reply{Customer reply type?} Reply -- excuse --> Excuse[Look up excuse library
Featherless RAG D-029
31 excuse categories] Excuse --> Dip Reply -- partial payment --> Sub Reply -- paid in full --> Paid Reply -- Day 30 no reply --> Esc Reply -- 2+ excuses --> Esc Reply -- replies only after demand letter --> Dip %% ================== Sub-Cycle ================== subgraph PartialSub[STEP 15 Partial-payment flow — D-028] direction TB Sub[Customer paid part — e.g. $3K of $8K] Sub --> SubDip[Diplomat asks for new completion date] SubDip --> Sub3btn[Concierge 3-button card] Sub3btn -- Approve ✅ --> SubReset[Reset cadence to customer date] Sub3btn -- Override ✏️ --> SubModal[Slack modal — pick date + reason] Sub3btn -- Treat as default ❌ --> SubConf[Confirm modal → jump to Escalator] SubReset --> Dip SubModal --> Dip SubConf --> Esc SubLimit{partial-payment count == 2?} Sub --> SubLimit SubLimit -- yes --> NoApprove[Concierge removes Approve button
only Override + Treat-as-default remain] end %% ================== Escalator + Day 55 30-min cancel + Day 65 AAA ================== subgraph Escalator[4️⃣ Escalator Agent — Day 30-60+] direction TB Esc[Escalator joins room] Esc --> EscCB[Draft cost-benefit card] EscCB --> EscMode{Mode?} EscMode -- in_spot main flow --> EscFull[Full demand-letter flow] EscMode -- lite --> EscSkip[Skip — lite mode does not escalate] EscMode -- attorney --> EscTag[Demand letter + attorney-recommended tag] EscFull --> D55Check{Day 55 voice trigger?
D-035 mandatory state check} D55Check -- "frozen / human-owned" --> D55Skip[Skip — audit only] D55Check -- "active + prior escalation / chronic late" --> D55Auto[Auto-trigger ConvAI — D-027] D55Check -- "active + other patterns" --> D55HITL[Route through Concierge approval] D55Auto --> D55CancelWindow["⏰ 30-minute cancel window — D-027
Concierge shows audit-only card
with 'Cancel before dial' button"] D55CancelWindow --> D55Wait{Human clicks Cancel within 30 min?} D55Wait -- "no — default no-click" --> Day55Fire[ConvAI dials] D55Wait -- "yes — human vetoes" --> D55Cancelled[Audit: day55_cancelled_by_operator
dial cancelled] Day55Fire --> Day60[Day 60 demand letter
cites arbitration_forum_spoken] D55HITL --> Day60 D55Skip --> Day60 D55Cancelled --> Day60 Day60 --> Day65[⭐ Day 65 Dynamic Agent Discovery
query Band Registry
capability=aaa_arbitration] Day65 --> SpecJoin[AAA Specialist Agent joins room
self-introduces] SpecJoin --> SpecRecs[Provides AAA filing details
fees / timeline / required docs] SpecRecs --> EscFinal[Escalator drafts final demand letter
using Specialist input] EscFinal --> Concierge_DemandLetter[Concierge surfaces demand letter for human approval] Concierge_DemandLetter --> SendDemand[Send demand letter] SendDemand --> Reply SendDemand --> Settle[💰 Customer agrees to pay] end %% ================== 4 channels + TW SWIFT ================== subgraph PaymentSeg[7️⃣ Payment Agent — 4 channels, D-019 + D-022 + D-030 + D-033] direction TB Settle --> PayShow[Generate deterministic checkout URL
URL is generated, NOT via LLM] PayShow --> PayCh{Customer picks channel} PayCh -- "USDC crypto ⚡" --> AutoUSDC["Circle ARC chain auto-receive
seconds · gas-free · D-033
🆕 Day 4 MVP = polling, see LP1-LP5
webhook swap on Day 5+"] PayCh -- "Credit card via Stripe" --> AutoStripe[Stripe webhook auto-confirms] PayCh -- "US ACH 💳" --> ACHWait PayCh -- "US Wire (USD) 🏦" --> WireWait PayCh -- "Taiwan SWIFT outbound (display only) 🇹🇼" --> TWSwift["D-022: we only DISPLAY Taiwan bank SWIFT details
we never originate funds, never handle FX
customer initiates on their side
same /payment-received command"] WireWait[Bank deposit lands
no auto webhook from bank] ACHWait[Bank deposit lands
no auto webhook from bank] TWSwift --> SwiftWait[Bank deposit lands
no auto webhook from bank] WireWait --> HumanWire["👤 Operator checks bank app
Slack: /payment-received case=... amount=... channel=wire"] ACHWait --> HumanACH["👤 Operator: /payment-received case=... amount=... channel=ach"] SwiftWait --> HumanSwift["👤 Operator: /payment-received case=... amount=... channel=swift_tw"] HumanWire --> ManualWire[Payment Agent receives command
mark invoice paid] HumanACH --> ManualACH[Payment Agent receives command
mark invoice paid] HumanSwift --> ManualSwift[Payment Agent receives command
mark invoice paid] AutoUSDC --> StateCheck AutoStripe --> StateCheck ManualWire --> StateCheck ManualACH --> StateCheck ManualSwift --> StateCheck StateCheck{Case state?
D-035} StateCheck -- "active" --> Close[Mark invoice paid
broadcast case_closed] StateCheck -- "frozen, non-legal" --> AutoUnfreezePay[Auto-unfreeze + close] StateCheck -- "frozen, legal/bankruptcy" --> SurfaceLegal[Surface to operator review] StateCheck -- "human-owned" --> SurfaceHuman[Surface to operator
do NOT auto-close] end Close --> Paid([💰 Invoice closed]) AutoUnfreezePay --> Paid SurfaceLegal --> ManualReview2[Operator confirms] SurfaceHuman --> ManualReview2 %% ================== /case-status anytime query ================== HumanStatus["👤 Operator wants live case status
e.g. 'where's ABC Trading now?'"] --> StatusCmd["Slack: /case-status case=case-1234"] StatusCmd --> StatusFetch[Concierge receives command] StatusFetch --> Fetch1[Pull full timeline from audit_trail.jsonl] StatusFetch --> Fetch2[Pull current owner state from case_db] StatusFetch --> Fetch3[Pull hold/handoff flags from case_db] Fetch1 --> StatusReply Fetch2 --> StatusReply Fetch3 --> StatusReply StatusReply[Concierge replies via Slack ephemeral message
operator-only — no channel noise
shows full timeline + ownership + state] StatusReply --> HumanRead[👤 Operator reads, decides next step] HumanRead -.choose.-> HumanUnhold HumanRead -.choose.-> HumanReopen HumanRead -.choose.-> ManualClose[Manually close case] HumanRead -.choose.-> NoActionNeeded([No action — case is fine]) %% ================== Audit Trail ================== subgraph Audit[STEP 18 Audit trail — audit_trail.jsonl, D-024 + D-035] direction LR Aud1[Basics: request / response / pause / resume] Aud2[D-028: cadence reset / extension reject / auto-cancel] Aud3[D-030: payment manual ack / payment auto webhook] Aud4[D-031: path select / lite skip / attorney referral] Aud5[D-032: outbound scheduled / executed / revoked] Aud6["D-035 new 8 types:
handoff request/accept · account freeze/unfreeze
SLA pre-breach/breach · emergency page · post-handoff auto-reject"] Aud7["D-034.4: voice_call_completed + transcript"] end Conc -.-> Audit Handoff -.-> Audit FreezeBroadcast -.-> Audit Sub -.-> Audit PostHook -.-> Audit StatusFetch -.-> Audit HumanReopen -.-> Audit HumanUnhold -.-> Audit %% ================== 🆕 Day 4 — Case State resilience layer D4-D8 ================== subgraph CaseStateSeg["🆕 Case State resilience layer D4-D8 — Day 4, src/agents/_case_state.py"] direction TB CSStore["📁 11 per-case JSON files
src/agents/case_state/*.json"] CSStore --> CS_D4["D4 audit-trail-driven recovery
rebuild_all_from_audit()
rebuild all state after crash"] CSStore --> CS_D5["D5 HITL SLA poller
list_pending_hitl_cases()
proactively scan pending → Concierge push"] CSStore --> CS_D6["D6 cost budget cap
add_cost() default \$0.50/case
overrun → forced handoff"] CSStore --> CS_D7["D7 restart idempotency
events_seen_count
0 duplicate events on restart"] CSStore --> CS_D8["D8 audit-replay correctness
28 distinct event types
0 drift verified"] end CS_D4 -.crash recovery.-> CronStart CS_D5 -.SLA push.-> Conc CS_D6 -.overrun trigger.-> Handoff CS_D7 -.-> Audit CS_D8 -.-> Audit %% ================== 🆕 Day 4 — Live USDC Settlement Layer LP1-LP5 ================== subgraph LiveUSDCSeg["🆕 Live USDC Settlement Layer LP1-LP5 — Day 4, src/payments/recoverflow_*.py"] direction TB LP1["🛒 LP1 · Buyer simulated payment
tools/simulate_buyer_payment.py
(demo: 4 US buyer personas)"] LP1 --> LP2["📤 LP2 · Circle ARC-TESTNET transfer
POST /developer/transactions/transfer
buyer wallet → receiving wallet
state: INITIATED → COMPLETE (~5-30s)"] LP2 --> LP3["🔭 LP3 · Wallet Poller every 10s
src/payments/recoverflow_wallet_poller.py
poll receiving balance + list INBOUND tx
first-launch baseline mode to skip historic tx"] LP3 --> LP4["📝 LP4 · payment_received audit
data/audit_trail.jsonl
+ refId → case_id reverse lookup"] LP4 --> LP4R["🧮 LP4R · Reconciler 4-state classify
src/payments/recoverflow_reconciler.py
aligned to outstanding_balance_usd (D-038)
flock + atomic rename — no double-credit"] LP4R --> LP4Full["✅ FULL
paid_in_collection ≥ outstanding
case → settled"] LP4R --> LP4Part["🟨 PARTIAL
0 < paid < outstanding
case → partially_paid
continue chasing remainder"] LP4R --> LP4Over["💜 OVERPAID
paid > outstanding
refund ticket triggered"] LP4R --> LP4Unm["❓ UNMATCHED
refId does not map to a case
enter unmatched queue
Concierge manual assignment"] LP4Full --> LP5["📧 LP5 · Resend real receipt email
src/payments/recoverflow_notify.py
deliver to supplier inbox with tx_id
Circle explorer link · bilingual template"] LP4Part --> LP5 LP4Over --> LP5 end LP5 -.cancel cadence.-> Conc LP4 -.-> Audit AutoUSDC -.same inbound path.-> LP3 %% ================== Styling ================== classDef d035 fill:#ffe4e1,stroke:#dc143c,stroke-width:3px classDef critical fill:#ff6b6b,stroke:#8b0000,color:#fff,stroke-width:3px classDef freeze fill:#fff3cd,stroke:#856404 classDef handoff fill:#ffcccc,stroke:#dc143c classDef happy fill:#d4edda,stroke:#28a745 classDef xfactor fill:#ffd700,stroke:#ff8c00,stroke-width:3px classDef humanaction fill:#e1f5fe,stroke:#0277bd,stroke-width:2px classDef errorpath fill:#ffe0e0,stroke:#c62828 classDef day4 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef detector fill:#fff9c4,stroke:#f57f17,stroke-width:2px class ResendHook,RWEvent,RWOpen,RWClick,RWBounce,RWComplain,CSStore,CS_D4,CS_D5,CS_D6,CS_D7,CS_D8,LP1,LP2,LP3,LP4,LP4R,LP4Full,LP4Part,LP4Over,LP4Unm,LP5,P1Dep day4 class CustReply,DetectFanout,DetectMerge,D_Disp,D_Part,D_Ext,D_Prom detector class StateGate,CanDial,VR,Handoff,Park,FreezeBroadcast,CaseFrozen,CaseHumanOwned,P1C,StateCheck d035 class R5,R13,WelfareSOP,W1,W2,W3,W4,W5,WClose,Page5 critical class FZ1,FZ2,FZ3,FZ4,FZ5,Pause freeze class StandDown1,StandDown2,StandDown3,StandDown4,StandDown5,RejectD handoff class Paid,Close,AutoUnfreezePay,Done1,Done2 happy class Day65,SpecJoin,Alert,EscFinal xfactor class Start,HumanSeeCard,HumanClick,HumanWire,HumanACH,HumanSwift,HumanUnhold,HumanReopen,HumanStatus,StatusCmd,HumanRead,ManualClose,HumanSeeCard humanaction class EmailRetry,EmailFail,CallRetry,CallError,ToneReject errorpath