Skip to content

Platform Restructuring Design — Intelligent Triage Engine

Status: In progress (brainstorming phase) Date: 2026-04-16 Session: 41 Author: SD + Claude Code Origin: Gap analysis from Dr. Shrikanth meetings (April 2026) — 14 gaps identified against current platform state


Executive Summary

Curaway's current platform is a strong agentic pipeline (intake → clinical extraction → matching → forwarding) with 42 providers, 87+ API endpoints, and live patient data flowing. However, mapping against Dr. Shrikanth's clinical intelligence framework reveals 14 gaps that collectively represent a restructuring of the intake-to-coordination pipeline into an intelligent triage engine.

This is not 14 separate features. It is a layered system redesign with a new scoring model (PFS/HSS/FMS), structured intake (5 assessment dimensions), coordinator tooling, and a frontend monorepo supporting multiple stakeholders.


Gap Classification

The 14 gaps cluster into four groups:

Cluster Gaps Nature
A — Intake Intelligence #1 (PFS/HSS/FMS), #2 (5-Layer Intake), #3 (Intent/Emotional), #4 (Travel Readiness), #5 (Logistics), #6 (Financial) Revolution — new intake spine
B — Coordination & Services #10 (Pre-Travel Checklist), #11 (Post-Op Manual), #12 (On-Ground Support), #13 (Long-Term Engagement) Evolution — new features on existing platform
C — Provider Trust & Economics #7 (Consultation Routing), #8 (Provider Reports), #9 (Cost Estimate) Evolution — new features + new stakeholder views
D — Operational Polish #14 (Channel Preference) Evolution — enhancement to existing notification system

Approach: Cluster A gets the revolution treatment (new data model, new agent architecture, new scoring). Clusters B/C/D evolve on top — new features that consume the restructured data.


Part 1: 5-Layer Intake Architecture

Layers as dimensions, not a strict sequence

The 5 layers are independent assessment dimensions tracked in patient_state. Each has its own completion score. The agent advances layers adaptively, not in a rigid pipeline.

{
  "layers": {
    "intent_capture":      { "status": "complete",    "completion": 1.0  },
    "medical_status":      { "status": "in_progress", "completion": 0.6  },
    "travel_readiness":    { "status": "not_started", "completion": 0.0  },
    "logistics":           { "status": "not_started", "completion": 0.0  },
    "financial_readiness": { "status": "not_started", "completion": 0.0  }
  }
}

Layer definitions

Layer What it captures Key outputs
1. Intent Capture Why the patient is here, emotional state, fears, hopes, case type (elective/selective/urgent) Urgency score, emotional readiness score, case classification
2. Medical Status Clinical data — diagnoses, reports, labs, comorbidities, medications, allergies FHIR resources, ICD codes, risk factors, EHR snapshot
3. Travel Readiness Physical fitness for travel — mobility, oxygen, hospitalization history, escort needs Transport tier (T1-T4), travel fitness score, medical escort flag
4. Logistics Passport status, visa requirements, preferred timeline, companion arrangements Travel risk score, timeline feasibility, visa assistance flag
5. Financial Readiness Funding source, budget range, insurance status, payment preferences Patient Pricing Band (PV), budget qualification gate

Adaptive routing

The agent follows a preferred sequence (1 → 2 → 3 → 4 → 5) but adapts to patient behavior:

Trigger Behavior
Patient uploads medical report first Layer 2 advances immediately. Agent acknowledges, then circles back to Layer 1.
Patient expresses anxiety in first message Layer 1 captures emotional state on the fly. Agent responds empathetically.
Patient asks about cost immediately Signal bookmarked in Layer 5. Agent captures it, returns after medical/travel established.
Urgent case (cancer, trauma) Compress layers — ask only mandatory questions, skip Layer 1's "hopes" (tone-deaf for urgent).

Completion gates

The state machine enforces two hard rules:

  1. Matching cannot happen until Layers 1-4 are each ≥ 0.6 completion — replaces the current intake_complete_v2 gate
  2. Financial (Layer 5) must be captured before provider comparison is shown — anti-drop-off rule

Everything else is soft routing — the agent decides based on signals.

What already exists and maps to layers

Layer Existing code What's new
1. Intent Nothing New extractor for emotional signals, case type, aspirations, fears
2. Medical Clinical Context Agent, chat_extractor, lab_analyzer, risk_assessor, EHR builder No new agent — reuse everything
3. Travel Partial (risk_assessor covers comorbidity risks) New extractor for travel-specific fitness (oxygen, mobility, escort)
4. Logistics Nothing New extractor for passport, visa, timeline, preferred dates
5. Financial Multicurrency exists, no qualification logic New extractor for funding source, budget range → Patient Pricing Band

Part 2: Agent Architecture (A3 Model)

One Triage Agent + per-layer extractors

Decision: Single conversational agent (existing Intake Agent renamed to Triage Agent) with layer-aware prompting. Per-layer extractors pull structured data from each turn.

Rationale: - Conversations cross layers naturally — one agent handles this gracefully - Cost: one LLM call per turn, not five - Voice consistency: one brand voice across the whole journey - Matches existing architecture pattern (LLM handles conversation, specialized services extract structured data)

Conversation LLM (single Triage Agent)
  ├── Receives full layer state in context
  ├── Has layer-specific prompt snippets injected per turn
  └── Produces patient-facing response

Parallel extraction (after response):
  ├── Layer 1 extractor (emotional/urgency signals) — NEW
  ├── Clinical Context Agent — EXISTING, owns Layer 2
  ├── Layer 3 extractor (travel fitness) — NEW
  ├── Layer 4 extractor (logistics) — NEW
  └── Layer 5 extractor (financial) — NEW

Layer routing logic

# Conceptual:
next_layer = choose_next_layer(
    patient_state.layers,
    preferred_sequence=["intent", "medical", "travel", "logistics", "financial"],
    recent_signals=recent_messages,
    urgency=patient_state.urgency_score
)

The existing orchestrator's phase routing (identify_procedure, records_first, intake) evolves into layer-aware routing. The records_first path (Session 33 gates_v2) already does soft routing — this formalizes it.


Part 3: Three-Score System (PFS / HSS / FMS)

PFS — Patient Fitness Score (0-100)

"Is this patient ready for medical travel?"

Computed from Layers 1-4:

Layer Input Contribution
Intent Urgency, case type, emotional readiness Modifier (urgent cases proceed despite lower fitness)
Medical Age, comorbidities, risk_assessor output, lab values Dominant component
Travel Mobility, oxygen, escort needs → transport tier T1-T4 Secondary component
Logistics Passport readiness, visa status, timeline feasibility Modifier (feasibility gate)

Output: 0-100 score + transport tier + is_blocking flag

Relationship with risk_assessor: PFS consumes risk_assessor output as one input to Layer 2's contribution. Risk_assessor remains authoritative for clinical risk items. PFS is a scorer, not a rule engine — rules live in dedicated modules. This boundary makes future subsumption easy (~1 week of mechanical work) if PFS ever needs to absorb risk logic.

HSS — Hospital Suitability Score (0-100)

"Is this hospital right for this patient?"

Computed per provider for a given patient:

Input Source Contribution
Clinical fit for diagnosis Existing matching engine v2.1 (graph traversal, OFFERS) Primary
Outcome data Existing provider success_rate, annual_cases Primary
Accreditation level Existing HAS_ACCREDITATION Secondary
Facility capability match ADR-0018 facility readiness score Secondary
Language/cultural fit Existing language_services, language_concordance Modifier
Cost band alignment with PV New — from Layer 5 Modifier (gates out-of-band hospitals)

Output: 0-100 score per provider + critical gap flags

FMS — Final Matching Score / Conversion Probability (0-1)

"Will this match convert?"

Input Source
PFS From layer scoring
HSS From provider scoring
Historical conversion rate Learned from feedback_records table
Patient preference alignment Existing preferences data
Channel preference match Gap #14 — modifies outreach approach

Output: 0-1 conversion probability, used to rank providers + inform coordinator urgency

Relationship to existing matching engine

The existing weighted scoring formula (clinical_relevance 0.25, outcome 0.20, semantic 0.10, cost 0.15, travel 0.10, accreditation 0.10, preferences 0.10) becomes the internal implementation of HSS. PFS and FMS are new. The existing engine is not replaced — it's reframed.


Part 4: Frontend Architecture

Monorepo with separate apps

frontend/
  packages/
    shared-core/          ← Types, API client, business logic (pure TS)
    shared-web/           ← Web UI components (React + DOM)
    shared-native/        ← React Native components (future)
    patient-app/          ← curaway.ai
    coordinator-app/      ← coordinator.curaway.ai
    provider-app/         ← provider.curaway.ai (Phase 1)
    facilitator-app/      ← facilitator.curaway.ai (Phase 3)
    mso-app/              ← mso.curaway.ai (Phase 2)
    admin-app/            ← admin.curaway.ai (Phase 0)
    mobile-patient/       ← React Native Expo (post-seed)

Rationale: Clean separation per stakeholder, independent deployment, shared component reuse, mobile-ready. Not micro-frontends — each app runs on its own URL, no runtime composition.

Pragmatic phasing: Start with 3 apps (patient, operations, clinical), extract to 7 as scope diverges:

Phase Apps
Phase 0-1 patient-app, operations-app (coordinators + facilitators + admin), clinical-app (providers + MSO)
Phase 3+ Extract facilitator-app, mso-app, admin-app when scope diverges

Patient app changes

Progress rail redesign:

✓ About You               ← Layer 1
◉ Health Profile           ← Layer 2
○ Travel Readiness         ← Layer 3
○ Planning                 ← Layers 4+5 combined
──────────────────────────
○ Finding Matches
○ Compare & Choose
○ Next Steps
  • Per-phase completion ring (reuse existing EHR completeness ring pattern)
  • Partially filled state (◑) when patient jumps ahead
  • Layer transitions not strictly linear — ring fills as data arrives from any turn

Layer summary cards in chat:

Fires when a layer first reaches completion threshold (0.8):

┌──────────────────────────────────────────────┐
│ ✓ Health Profile Complete                     │
│                                               │
│ • Bilateral knee osteoarthritis (ICD M17.11)  │
│ • Prediabetes (HbA1c 6.3%)                   │
│ • No blocking risk factors                    │
│ • 3 of 5 mandatory documents uploaded         │
│                                               │
│ Anything I got wrong? You can correct me      │
│ anytime.                                      │
└──────────────────────────────────────────────┘

Rules: - Fire once per layer (high-water mark — no repeat cards) - Always shown (not skippable) — reinforces progress, builds trust - Includes "anything I got wrong?" prompt for error correction

Summary panel redesign:

Patient's live dashboard of what Curaway understands, organized by layer:

ABOUT YOU
  Case type: Elective
  Primary concern: Mobility limitation
  Emotional readiness: Moderate anxiety about outcomes

HEALTH PROFILE
  Diagnosis: Bilateral knee osteoarthritis (M17.11)
  Comorbidities: Prediabetes (HbA1c 6.3%)
  Risk level: Low (no blocking factors)
  Documents: 3 of 5 mandatory uploaded

TRAVEL READINESS
  Transport tier: T1 — Standard
  Fitness: Cleared for travel
  Medical escort: Not required

PLANNING
  Passport: Valid until 2028
  Preferred dates: June–July 2026
  Budget range: $6,000–$10,000
  Funding: Out-of-pocket

No changes needed: Sidebar, chat input, rich content cards, EHR drawer, document upload flow.

Coordinator app

Case queue dashboard: - All assigned cases at a glance, sorted by urgency - Color-coded alerts: red (escalation), amber (deadline), green (on track) - Filterable by case phase, transport tier, destination city - "Next action" — single most important thing to do

Case detail — 4 tabs:

Tab Contents
Patient Overview Layer summary with full detail + PFS/HSS/FMS scores + matched provider
Timeline & Transport Journey timeline, transport bookings, vendor assignment with [+ Book] actions
Communication Human-to-human coordinator ↔ patient chat thread
Documents & EHR Shared EHR viewer + document checklist with coordinator actions (flag missing, request upload)

Vendor management: Searchable directory filtered by city + capabilities + transport tier. Select → fill booking details → create → patient notified.

Escalation panel: Triggered by recovery alerts (pain ≥7, missed check-in). Shows trigger, history, action buttons (call patient, call facility, dispatch transport, contact surgical provider, log resolution).

Coordinator analytics: Active/completed cases, avg escalation response time, CSAT, vendor reliability.

Coordinator access to patient AI chat — Three-tier model

Tier Access Gate
Tier 1: Summary Layer completion cards + extracted data Default for all coordinators
Tier 2: Full transcript Read-only AI conversation Patient consent (coordinator_chat_access) + Flagsmith flag
Tier 3: Annotated Full transcript + flag messages for review Tier 2 + elevated role (coordinator_senior)

Audit trail on every coordinator action:

coordinator_audit_log
  id: UUID PK
  coordinator_id: UUID FK → tenant_members
  case_id: UUID FK → cases
  action: ENUM('viewed_summary', 'viewed_transcript', 'flagged_message',
               'created_booking', 'dispatched_transport', 'sent_message',
               'escalated', 'resolved_escalation', 'modified_case')
  target_type: VARCHAR(50)
  target_id: UUID
  metadata: JSONB
  ip_address: VARCHAR(45)
  user_agent: TEXT
  created_at: TIMESTAMPTZ

Stakeholder app matrix

Stakeholder Unique views Shared from shared/ When App
Patient Conversation UI, progress rail, transport panel, comparison EHR viewer, doc viewer, rich cards Now patient-app
Coordinator Case queue, timeline, vendor selector, escalation EHR viewer, doc viewer, patient summary Phase 5 operations-app
Provider Case inbox, quote builder, redacted records EHR viewer (redacted), doc viewer Phase 1 clinical-app
Facilitator Delegated case view, task list Patient summary, doc viewer, chat Phase 3 operations-app (initially)
MSO Doctor Clinical review workspace, opinion form EHR viewer (full clinical), doc viewer Phase 2 clinical-app (initially)
Admin Tenant dashboard, RBAC, system health Minimal Phase 0 operations-app (initially)
Vendor Booking inbox, availability Minimal If marketplace evolves

EHR viewer redaction levels

One component, data filtered by API based on role:

Viewer Sees Hidden
Patient Everything Nothing
Coordinator Everything Nothing (Curaway staff)
MSO Doctor Full clinical Non-clinical preferences, financial
Provider Clinical + relevant logistics Identity (until arrival), financial, other quotes
Facilitator Delegated scope only Anything outside delegation consent

Part 5: Transport / Coordinator Services

Fully designed in separate spec: docs/specs/deferred/coordinator-services-transport-spec.md

Key decisions: - Coordinator Services Framework with service_type enum (transport first, then translator, companion, ground_staff) - Hybrid model: scheduled transfers coordinator-assigned, emergency dispatch coordinator-managed - Transport tiers T1-T4 driven by travel fitness (Layer 3 → PFS) - Vendor registry (coordinator_vendors) with migration path to full provider type - Patient sees assigned provider details but doesn't choose - Coverage in both origin and destination countries - Repatriation in scope (air ambulance)


Part 6: Gap Integration Map

How all 14 gaps connect and depend on each other:

Layer 1 (Intent/Emotional) ──────────────────────┐
Layer 2 (Medical Status) ────────────────────────┤
Layer 3 (Travel Readiness) ──┬───────────────────┼──→ PFS
Layer 4 (Logistics) ─────────┘                   │
Existing matching engine ────────────────────────┤──→ HSS
Facility capabilities (ADR-0018) ────────────────┤
Layer 5 (Financial / PV) ───────────────────────┤
PFS × HSS × historical conversion ──────────────┼──→ FMS
Transport (Gap #12) ←── Layer 3 output            │
Cost estimate (Gap #9) ←── HSS + transport cost   │
Pre-travel checklist (Gap #10) ←── Layers 3+4     │
Post-op manual (Gap #11) ←── transport panel       │
Provider reports (Gap #8) ←── HSS + FMS + outcomes │
Consultation routing (Gap #7) ←── PFS + Layer 1    │
Channel preference (Gap #14) ←── FMS modifier      │
Long-term engagement (Gap #13) ←── post-case data  │

Part 7: Intent Capture Extraction Schema (Gap #3)

Extraction approach: infer first, ask explicitly for gaps

The Layer 1 extractor reads signals from whatever the patient says in the first 2-3 turns. If specific signals are missing after that, the agent asks targeted follow-up questions.

Extraction schema

{
  "layer_1_intent": {
    "case_type": {
      "value": "selective",
      "confidence": 0.85,
      "source": "patient mentioned doctor recommendation + waitlist"
    },
    "urgency_score": 0.6,
    "emotional_state": {
      "readiness": "anxious_but_willing",
      "primary_fear": "going_abroad",
      "primary_hope": "pain_free_mobility",
      "fear_intensity": 0.5,
      "hope_intensity": 0.8
    },
    "decision_stage": {
      "value": "comparing_options",
      "confidence": 0.9
    },
    "trigger_event": {
      "description": "NHS waitlist 18 months",
      "category": "waitlist"
    }
  }
}

Enums

Field Values
case_type elective, selective, urgent
readiness ready_and_researched, anxious_but_willing, hesitant_exploring, desperate
primary_fear complications, cost, distance_from_home, language_barrier, quality_of_care, unknown_outcome, travel_fitness, none
primary_hope pain_free_mobility, improved_appearance, survival, quality_of_life, faster_treatment, cost_savings, better_care
decision_stage just_exploring, comparing_options, ready_to_commit, decided_on_destination
trigger_category waitlist, cost_prohibitive, doctor_recommendation, worsening_symptoms, insurance_denial, referral, self_research

Enums will extend as patient data reveals new patterns.

Urgency score computation

Factor Weight
case_type: urgent = 1.0, selective = 0.6, elective = 0.3 0.40
decision_stage: ready_to_commit = 1.0 → just_exploring = 0.25 0.25
trigger_category: worsening_symptoms = 1.0, waitlist = 0.7, self_research = 0.3 0.25
fear_intensity (inverse — desperate patients score higher urgency) 0.10

How Layer 1 feeds PFS and HSS

  • PFS: Intent is a modifier (0.15 weight). Urgent cases boost PFS even with lower medical/travel scores (fast-track).
  • HSS: primary_fear adjusts matching weights indirectly — fear of quality_of_care increases accreditation weight; fear of language_barrier increases language concordance weight.
  • FMS: hesitant_exploring + just_exploring lowers conversion probability. Coordinator knows to nurture, not push.

Part 8: Financial Readiness Schema (Gap #6)

Patient Pricing Band (PV)

{
  "layer_5_financial": {
    "funding_source": "out_of_pocket",
    "budget_range": {
      "min_usd_cents": 500000,
      "max_usd_cents": 1000000,
      "flexibility": "soft_ceiling"
    },
    "insurance": null,
    "financial_timeline_pressure": false,
    "qualification": "qualified"
  }
}

Funding source enums

out_of_pocket, insurance_domestic, insurance_international, employer_sponsored, government_program, medical_loan, family_sponsored

Qualification gate

Status Meaning Platform behavior
qualified Budget overlaps with ≥3 providers Proceed to matching
stretch Budget overlaps with 1-2 providers only Agent informs: limited options, offer to adjust range
mismatched No providers in range Agent redirects: shows typical range for procedure+destination, suggests alternatives
incomplete Insufficient data Layer below threshold, matching blocked

Agent conversation design

Financial questions come after Layers 1-4 (patient has invested in the process). Agent never asks "what's your budget?" directly. Instead:

"For knee replacement in Turkey, patients typically spend between $6,000 and $12,000 including travel and recovery. Does that range work for you, or should I focus on a different bracket?"

Anchors with market range, patient self-selects.

Conditional: Insurance details

If funding_source includes insurance, additional mandatory fields: - Insurance provider name - Policy type (domestic / international travel) - Pre-authorization status (not started / in progress / approved / denied)

Some providers accept specific insurers — affects HSS cost_alignment scoring.


Part 9: Scoring Configuration (Gap #1 — Configurable)

All weights, thresholds, and parameters live in config/scoring.yaml with Flagsmith runtime override per key. Same pattern as config/model_registry.yaml.

config/scoring.yaml

pfs:
  weights:
    medical: 0.45
    travel: 0.25
    logistics: 0.15
    intent_modifier: 0.15
  medical_penalties:
    blocking_factor: 25
    high_severity: 10
    moderate_severity: 5
    missing_mandatory_doc: 5
    max_penalty: 75
  travel_tier_scores:
    T1: 100
    T2: 75
    T3: 50
    T4: 25
  logistics_scores:
    passport_valid: 40
    visa_feasible: 30
    timeline_realistic: 30
  thresholds:
    ready: 80
    conditionally_ready: 60
    needs_attention: 40

hss:
  weights:
    clinical_relevance: 0.25
    outcome_score: 0.20
    semantic_match: 0.10
    cost_alignment: 0.15
    travel_score: 0.10
    accreditation: 0.10
    preferences: 0.05
    facility_readiness: 0.05
  cost_alignment:
    soft_ceiling_multiplier: 1.2
    soft_ceiling_score: 0.5
    outside_range_score: 0.0
  facility_readiness:
    critical_gap_penalty: 0.15

fms:
  weights:
    pfs: 0.30
    hss: 0.35
    preference_alignment: 0.15
    historical_conversion: 0.20
  bias: -0.5
  default_historical_conversion: 0.5
  thresholds:
    high_conversion: 0.7
    moderate: 0.4
    low: 0.1

layer_completion:
  matching_threshold: 0.6
  summary_card_threshold: 0.8
  financial_required_before: "provider_comparison"

Each top-level key (pfs, hss, fms, layer_completion) is also a Flagsmith JSON flag. Code loads YAML defaults, Flagsmith overrides at runtime. Enables A/B testing of scoring weights without deploys.

PFS formula

PFS = (medical_component × 0.45) + (travel_component × 0.25)
    + (logistics_component × 0.15) + (intent_modifier × 0.15)

medical_component (0-100):
  base = 100
  - (blocking factors × 25 each, capped at 75)
  - (high severity × 10 each)
  - (moderate severity × 5 each)
  - (missing mandatory documents × 5 each)

travel_component (0-100):
  T1 = 100, T2 = 75, T3 = 50, T4 = 25

logistics_component (0-100):
  passport_valid = 40, visa_feasible = 30, timeline_realistic = 30

intent_modifier (0-100):
  urgency_score × 100
  Urgent cases boost PFS by up to 15 points even with lower medical/travel

HSS formula

Existing matching engine v2.1 reframed:

HSS = (clinical_relevance × 0.25) + (outcome_score × 0.20) + (semantic_match × 0.10)
    + (cost_alignment × 0.15) + (travel_score × 0.10) + (accreditation × 0.10)
    + (preferences × 0.05) + (facility_readiness × 0.05)

cost_alignment: gates against Patient Pricing Band
  Within PV range = full score
  Within 120% of PV max (soft_ceiling) = 0.5
  Outside PV = 0 (filtered unless no alternatives)

facility_readiness: from ADR-0018
  Critical gap penalty: -0.15 on total HSS + patient-facing note

FMS formula

FMS = sigmoid(w1 × PFS/100 + w2 × HSS/100 + w3 × preference_alignment
            + w4 × historical_conversion + bias)

Initial weights: w1=0.30, w2=0.35, w3=0.15, w4=0.20, bias=-0.5
Default historical_conversion: 0.5 (no data yet — becomes data moat as feedback accumulates)

Relationship with existing matching engine

The existing weighted scoring formula becomes the internal implementation of HSS. PFS and FMS are new. The existing engine is not replaced — it is reframed.

Relationship with risk_assessor

PFS consumes risk_assessor output as one input to the medical component. Risk_assessor remains authoritative for clinical risk items. PFS is a scorer, not a rule engine — rules live in dedicated modules. Future subsumption (~1 week effort) is enabled by keeping these as separate pure functions with a clean interface.


Part 10: Layer Completion Criteria (Gap #2)

Completion = mandatory signals captured / total mandatory signals.

Layer 1 — Intent Capture

Signal Mandatory Weight
Case type (elective/selective/urgent) Yes 0.30
At least one fear or concern Yes 0.25
At least one hope or goal Yes 0.25
Decision stage No 0.10
Trigger event No 0.10

Complete at 0.80 (case_type + fear + hope).

Layer 2 — Medical Status

Signal Mandatory Weight
Primary diagnosis identified Yes 0.20
At least one document uploaded + analyzed Yes 0.20
Medications confirmed (or "none") Yes 0.15
Allergies confirmed (or "none") Yes 0.10
Age captured Yes 0.10
Comorbidities assessed No 0.10
Risk assessment complete No 0.10
Gender captured No 0.05

Complete at 0.75 (diagnosis + document + meds + allergies + age). Maps closely to existing intake_complete_v2 gate.

Layer 3 — Travel Readiness

Signal Mandatory Weight
Mobility status Yes 0.30
Oxygen dependency Yes 0.20
Recent hospitalization (30 days) Yes 0.15
Transport tier assigned Auto-computed 0.20
Companion traveling No 0.15

Complete at 0.65 (mobility + oxygen + hospitalization → transport tier auto-computes). Most patients (T1) complete this in one turn.

Layer 4 — Logistics

Signal Mandatory Weight
Country of residence Yes 0.25
Passport status Yes 0.25
Preferred travel timeline Yes 0.25
Visa awareness No — auto-derived from country pair 0.15
Companion arrangements No 0.10

Complete at 0.75 (country + passport + timeline). Country may already be captured in Layer 2 — if so, Layer 4 starts at 0.25.

Layer 5 — Financial Readiness

Signal Mandatory Weight
Funding source Yes 0.35
Budget range (min-max) Yes 0.35
Budget flexibility No 0.15
Insurance details Conditional (if insurance) 0.15

Complete at 0.70 (funding source + budget range). If funding_source includes insurance, insurance details become mandatory.


Part 11: PFS Remediation Behavior

PFS recalculates on every turn that adds layer data. Agent behavior adapts based on the current PFS band.

PFS 80-100: Ready

Proceed to matching immediately. No remediation needed.

PFS 60-79: Conditionally ready

Matching proceeds but agent flags gaps and coordinator is notified.

Agent behavior:

"I've found some strong matches for you. Before we look at them, I want to flag a couple of things that could affect your journey: • Your passport expires in 3 months — some visa processes take 20-25 days • You mentioned occasional breathing difficulty — confirming travel clearance with your doctor would be wise

Would you like to see the matches now, or address these first?"

Patient decides. Coordinator sees: "PFS 72 — passport timeline tight, travel fitness unconfirmed."

PFS 40-59: Needs attention

Matching is blocked. Agent enters focused remediation loop.

Agent behavior:

"There are a few things we need to sort out before I can find the right hospitals: 1. ⚠️ Your HbA1c is 9.2% — most hospitals require below 8% 2. ⚠️ No medical documents uploaded yet

Let's work through these. Would you like to start with uploading your records?"

Remediation loop: 1. Agent identifies blocking gaps, presents prioritized list 2. Asks patient to address one at a time 3. Suggests concrete actions per gap type: - High HbA1c → "Your local doctor can help. Upload updated results when ready." - Missing documents → "Most useful would be your latest X-ray or MRI." - Expired passport → "Renewal takes 2-6 weeks. We can continue in parallel." - Travel fitness concern → "Ask your doctor for a travel fitness certificate." 4. After each turn, PFS recalculates 5. If PFS crosses 60 → offer matching 6. If patient disengages → intake reminder notification (24h cooldown, existing system)

The agent never dead-ends — every blocking gap gets a concrete next step.

PFS 0-39: Not ready

Matching not available. Agent is honest but supportive.

Agent behavior:

"I want to be straightforward. Based on what we've discussed, traveling for surgery right now may not be the safest option: • Your INR is 1.8 — bleeding risk that needs resolution • You were hospitalized last week — surgeons want 4-6 weeks of stability

This doesn't mean surgery abroad isn't an option — the timing needs to be right. I'll save everything so you don't start over."

Key behaviors: - No matching at all - All layer data persists for return visits - Email summary option (patient takes to local doctor) - Coordinator notified for follow-up call in 4-6 weeks - No nagging reminders — patient needs medical stabilization, not nudges

Re-evaluation cycle

PFS is not computed once — it recalculates on every data-changing turn:

Turn 12: PFS 52 (HbA1c blocking)
Turn 15: Patient uploads new HbA1c of 7.8%
Turn 15: PFS recalculates → 68
Agent: "Great news — your updated HbA1c is within range.
        I can now start finding matches. Ready?"

No manual intervention needed. Agent detects threshold crossings automatically.

Coordinator visibility across all bands

Coordinator case queue shows PFS band for every case:

CRW-2026-00247  Aisha M.   TKR · Istanbul   PFS: 78  ● Conditionally ready
  Gaps: passport timeline tight

CRW-2026-00251  James R.   CABG · Chennai   PFS: 48  ● Needs attention
  Blocking: HbA1c 9.2%, no documents

CRW-2026-00255  Wei L.     Bariatric · Bangkok  PFS: 32  ● Not ready
  Blocking: INR 1.8, recent hospitalization
  Next check-in: May 15 (6 weeks post-discharge)

Coordinator can intervene at any band — call patient, offer help, adjust timeline. Platform handles common path automatically; coordinator adds human touch when it matters.


Part 12: Travel Fitness Questionnaire & Scoring (Gap #4)

Two-track assessment

Track When Questions
Quick screen (3 questions) Always Mobility, oxygen, recent hospitalization
Extended assessment (5+ questions) If quick screen flags risk Specific conditions, episode frequency, doctor's travel advice, escort preference

Quick screen: "Can you walk unassisted or do you use a wheelchair? Any oxygen or breathing support? Have you been hospitalized in the last month?"

All clear → T1, Layer 3 complete in one turn.

Any flag → extended questions probe specifics.

Scoring algorithm

Factor Score range T1 T2 T3 T4
Mobility 0-30 Walking unaided Wheelchair for distance Full wheelchair Bedridden
Oxygen 0-25 None Intermittent Continuous
Hospitalization 0-20 None in 30 days Within 30 days Within 7 days
Comorbidity load 0-15 Low High severity Multiple blocking
Doctor travel advice 0-10 Cleared / not asked Advised caution Advised against

Tier assignment

travel_fitness_score = sum of all factors (0-100)

0-20:   T1 — Standard
21-45:  T2 — Assisted
46-70:  T3 — Medical
71-100: T4 — Critical

Auto-override rules (regardless of score)

  • Continuous oxygen → minimum T3
  • Bedridden → T4
  • Doctor advised against travel → T4 + agent flags strongly
  • Hospitalized within 7 days → T4

All configurable in config/scoring.yaml under travel_fitness key.


Part 13: Logistics Layer Schema (Gap #5)

Data schema

{
  "layer_4_logistics": {
    "country_of_residence": "GB",
    "passport": {
      "status": "valid",
      "expiry_date": "2028-03-15",
      "months_remaining": 23
    },
    "visa": {
      "required": true,
      "status": "not_started",
      "estimated_processing_days": 15,
      "auto_derived": true
    },
    "timeline": {
      "preferred_start": "2026-06",
      "preferred_end": "2026-07",
      "flexibility": "flexible_within_month",
      "feasibility": "feasible"
    },
    "companion": {
      "traveling_with": true,
      "relationship": "spouse",
      "companion_visa_needed": true
    },
    "travel_risk_score": 0.2
  }
}

Visa auto-derivation

Derived from country pair lookup, not patient questions:

patient_country + destination_country → visa_requirement

Reference table covers all 8 destination countries. Agent informs rather than asks:

"Since you're traveling from the UK to Turkey, you'll need an e-Visa — it's online and takes about a day."

Timeline feasibility

Checks preferred timeline against lead times:

Factor Minimum lead time
Passport renewal (if expired) 2-6 weeks
Visa processing From lookup table
Provider quote turnaround 5-7 days
Pre-op medical prep (if PFS flags) 4-8 weeks
Coordinator booking 1-2 weeks
feasible:    preferred_start > today + sum(lead_times)
tight:       within 1 week of cutoff
infeasible:  preferred_start < today + sum(lead_times)

If infeasible, agent suggests adjusted timeline.

Travel risk score

travel_risk = (passport_risk × 0.35) + (visa_risk × 0.30) + (timeline_risk × 0.35)

passport_risk:  expired = 1.0, <3 months = 0.6, valid = 0.0
visa_risk:      not_started + long processing = 0.8, in_progress = 0.4, obtained/not_needed = 0.0
timeline_risk:  infeasible = 1.0, tight = 0.5, feasible = 0.0

Part 14: Consultation Routing (Gap #7)

Three consultation types

Type Purpose Who delivers
MTC (Medical Travel Consultation) Non-medical triage — is patient a good candidate? Automatable (AI + coordinator)
Teleconsultation First medical opinion for vague symptoms Doctor via video
MSO (Medical Second Opinion) Validates confirmed diagnosis Specialist via video

Routing logic

Layer 1 signals Route to
just_exploring + no diagnosis MTC
just_exploring + vague symptoms Teleconsultation
comparing_options + confirmed diagnosis MSO (optional)
ready_to_commit + confirmed diagnosis Skip — proceed to matching

MTC is largely automated — the Layer 1-4 intake process IS the medical travel consultation. Patients completing layers with PFS ≥ 60 have effectively passed MTC.

Schema

{
  "consultation_routing": {
    "recommended_type": "mso",
    "confidence": 0.8,
    "reasoning": "Confirmed TKR diagnosis, comparing options",
    "patient_accepted": null,
    "scheduled": false
  }
}

Routing is a recommendation, not a gate. Patient can skip.


Part 15: Cost Estimate Breakdown (Gap #9)

Estimate structure

Curaway produces the cost estimate (not the hospital). Full breakdown justifies service fee and prevents direct booking.

Category Line items Source
Medical Procedure, hospital stay, surgeon, anesthesia, implants, follow-ups Provider quote
Travel Flights, accommodation, ground transport, escort (if T2+), visa Platform estimates + transport bookings
Recovery Recovery facility, nursing, physiotherapy Recovery provider quote
Curaway service Coordination fee Platform fee schedule
Contingency Recommended buffer (configurable %) Percentage of total

Patient-facing display

COST ESTIMATE — TKR Bilateral · Acibadem Maslak, Istanbul

Medical                                    $7,200 - $8,500
  Procedure + hospital (5 nights)          $6,500 - $7,500
  Implants                                 $500 - $700
  Post-op follow-ups (2)                   $200 - $300

Travel                                     $1,200 - $1,800
  Flights (London → Istanbul return × 2)   $600 - $900
  Hotel (3 nights)                         $300 - $450
  Ground transport (T1)                    $150 - $200
  Visa (e-Visa)                            $50

Recovery (optional)                        $1,500 - $2,000

Curaway Coordination                       $XXX

Contingency (10%)                          $1,000 - $1,300
                                          ─────────────────
ESTIMATED TOTAL                           $10,900 - $13,600

Curaway fee model

Per-provider contract determines model:

fee_models:
  percentage:
    default_rate: 0.15
    min_fee_usd_cents: 50000
    max_fee_usd_cents: 500000
  tiered:
    brackets:
      - max_medical_usd_cents: 500000    # Under $5K
        fee_usd_cents: 75000             # $750
      - max_medical_usd_cents: 1500000   # $5K-$15K
        fee_usd_cents: 150000            # $1,500
      - max_medical_usd_cents: null       # $15K+
        fee_usd_cents: 250000            # $2,500

When generated

After provider quotes arrive (Phase 1 quoting flow), before patient commits. The estimate is the decision-making artifact.

Budget comparison

Estimate includes comparison against Patient Pricing Band: - Within budget → green indicator - Slightly over → amber with options to adjust - Significantly over → flag with alternative destinations


Part 16: Post-Seed Features (Gaps #8, #10, #11, #13, #14)

Gap #8 — Provider Performance Reports

Weekly reports to hospitals building bilateral trust.

Data point Source
Leads sent case_shares table
Response time (avg/min/max) provider_quotes timestamps
Quote-to-selection conversion cases selected / quoted
Common rejection reasons feedback_records
Patient demographics (aggregated) Layer 1-2 data
Comparison to platform average Aggregated

Format: PDF via QStash cron + email via Resend. Dashboard in provider-app.

Gap #10 — Pre-Travel Checklist

Auto-generated from Layer 3+4 + provider requirements.

Medical section: Records compilation, hospital invitation letter, consent forms, travel fitness certificate (T2+), medication list for customs.

Travel section: Passport check, visa application, flights, hotel, transport confirmation, travel insurance, companion arrangements.

Each item has status (done/pending/not needed), deadline, and action button. Rendered as rich card + persistent checklist in transport panel.

Gap #11 — Post-Op Manual

Per-procedure + per-patient, generated after surgery.

Sections: recovery timeline (day-by-day), medication schedule, warning signs, complication routing (which specialist for which complication), follow-up schedule, emergency contacts.

Generated by LLM using procedure template + patient EHR. Reviewed by coordinator before release.

Gap #13 — Long-Term Engagement

Deferred entirely. Subscription model (annual second opinions, priority teleconsultations, health monitoring) depends on post-procedure outcome data and business model validation.

Gap #14 — Channel Preference Detection

Signal Detection
Initiates via WhatsApp Auto-set WhatsApp
Uses voice input Flag voice preference
European patient Default email
Middle East patient Default WhatsApp
Explicit ask "How would you prefer us to reach you?"

Stored on patient profile. Notification system routes through preferred channel. FMS modifier: channel match improves conversion probability.


All Gaps — Resolution Status

Gap Status Where documented
#1 — PFS/HSS/FMS ✅ Complete Part 3, Part 9
#2 — 5-Layer Intake ✅ Complete Part 1, Part 10
#3 — Intent/Emotional ✅ Complete Part 7
#4 — Travel Readiness ✅ Complete Part 12
#5 — Logistics ✅ Complete Part 13
#6 — Financial Readiness ✅ Complete Part 8
#7 — Consultation Routing ✅ Complete Part 14
#8 — Provider Reports ✅ Complete (light) Part 16
#9 — Cost Estimate ✅ Complete Part 15
#10 — Pre-Travel Checklist ✅ Complete (light) Part 16
#11 — Post-Op Manual ✅ Complete (light) Part 16
#12 — On-Ground Support ✅ Complete Separate spec: coordinator-services-transport-spec.md
#13 — Long-Term Engagement ✅ Deferred Part 16
#14 — Channel Preference ✅ Complete (light) Part 16

Edge Cases

Scenario Handling
Patient completes Layer 5 before Layer 1 Layers tracked independently. Signal bookmarked. Agent circles back. No blocking.
Layer 2 data contradicts Layer 1 emotional state (patient calm but high-risk medical) PFS weights medical over emotional. Agent flags the risk gently.
Patient refuses to answer Layer 1 questions Layer 1 defaults to "neutral" emotional state. Does not block progression. Agent notes skip.
Travel fitness assessment changes after initial transport booking Coordinator cancels future bookings at old tier, rebooks at new tier. Completed legs unaffected.
PFS drops below matching threshold mid-intake (new comorbidity discovered) Matching blocked. Agent explains what's needed. Coordinator notified if case was already advanced.
Financial qualification gates out all matched providers Agent explains budget mismatch. Offers options: adjust budget, different destination, different procedure timing.
Multiple layers complete on same turn Multiple summary cards stacked in chat. Rare but handled.
Patient corrects data after layer summary card Layer completion may drop temporarily. No re-fire of summary card. Summary panel updates live.
Coordinator views transcript without patient consent Tier 1 (summary only) is default. Tier 2 requires explicit consent record. API enforces gate.
Layer extractor fails (LLM timeout) Non-blocking. Layer completion stays at previous value. Retried on next turn.
Patient's visa auto-derivation is wrong (dual citizenship) Agent asks to confirm: "I see you may need an e-Visa for Turkey. Is that correct, or do you hold another passport?" Patient corrects; visa status updated.
Timeline infeasible but patient insists Agent explains risks. If patient proceeds, coordinator flagged. Case proceeds with timeline_risk: 1.0 feeding PFS.
Provider quote exceeds patient PV significantly Cost estimate shows mismatch. Agent offers: adjust budget, different provider, different destination, or staged approach.
Patient is MTC candidate but asks for MSO directly Respect patient choice. Route to MSO. Log the skip for analytics.
Consultation routing confidence low Agent presents options to patient: "Based on what you've told me, a teleconsultation might help clarify your diagnosis. But if you'd prefer to go straight to comparing hospitals, we can do that too."
Cost estimate changes after initial generation (new quote, updated transport tier) Re-generate estimate. Notify patient with diff: "Updated estimate: travel costs increased by $200 due to medical escort requirement."
Channel preference changes mid-journey Update profile. All future notifications route through new channel. No retroactive changes.

Implementation Phasing

This restructuring maps to ADR-0018's existing phase structure:

ADR-0018 Phase Restructuring scope New effort
Phase 0: Foundation Monorepo setup, shared component extraction, coordinator_audit_log +1 week
Phase 1: Provider Flow Provider app (clinical-app), cost estimate integration +1 week
Phase 2: Risk + MSO Consultation routing (Gap #7) Included
Phase 3: Facilitators + Coordinators Operations-app, coordinator tooling +2 weeks
Phase 5: Coordination Lifecycle Timeline manager, transport integration +1 week
New: Intake Restructuring 5-layer intake, triage agent, PFS/HSS/FMS, per-layer extractors 3-4 weeks

Total new effort: ~8-9 weeks on top of existing ADR-0018 phases.

Recommended sequence: Intake restructuring first (it's demo-critical), then Phase 0 monorepo setup, then remaining phases in ADR-0018 order.


Part 17: LangGraph Runtime Integration

Decision: Adopt LangGraph as runtime, not full Deep Agents harness

Deep Agents (LangChain's opinionated harness, July 2025) is built for coding-agent use cases (virtual filesystem, todo planning). Curaway's use case is conversational clinical triage — we need the graph infrastructure, not the coding-agent scaffolding.

Adopt: - LangGraph compiled graph for Triage Agent - LangGraph checkpointing (AsyncPostgresSaver → Railway PostgreSQL) - LangGraph parallel sub-nodes (map-reduce for extractors) - LangGraph interrupt() for coordinator handoff at PFS thresholds - LangGraph native streaming (replaces custom SSE) - LangGraph production middleware (retry with backoff, per-node timeouts)

Skip: - Deep Agents virtual filesystem — not relevant - Deep Agents write_todos planning tool — not relevant - Deep Agents task tool for child agents — LangGraph sub-nodes are sufficient

A3 architecture expressed as LangGraph

Supervisor Node: Triage Agent (create_react_agent)
  ├── tools: choose_next_layer(), generate_response()
  ├── parallel sub-nodes (map-reduce):
  │     ├── intent_extractor (structured output)
  │     ├── clinical_context_agent (existing, refactored as node)
  │     ├── travel_extractor (structured output)
  │     ├── logistics_extractor (structured output)
  │     └── financial_extractor (structured output)
  ├── code nodes:
  │     ├── pfs_scorer (pure function — deterministic)
  │     ├── hss_scorer (pure function — deterministic)
  │     ├── fms_scorer (pure function — deterministic)
  │     └── route_by_pfs (conditional edge — deterministic)
  ├── interrupt nodes:
  │     ├── coordinator_handoff (PFS < 40)
  │     └── matching_gate (PFS >= 60 + layers >= threshold)
  └── state: patient_state TypedDict (layers, scores, transport_tier)

Deterministic behavior guarantees

LLMs are non-deterministic. The system around them is fully deterministic.

Deterministic (code — no LLM involved): - Graph topology (compile-time edges) - PFS/HSS/FMS scoring (pure functions, config/scoring.yaml) - Transport tier assignment (rule-based, auto-overrides) - Matching threshold gates (configurable thresholds) - Layer completion scoring (weighted sum) - Visa auto-derivation (lookup table) - Timeline feasibility (arithmetic) - Routing after PFS evaluation (conditional edges)

Non-deterministic (LLM — flexibility is a feature): - Triage Agent's conversational response (tone, wording) - Triage Agent's layer routing choice (which question next) - Extractor signal identification (did the patient express fear?) - Confidence scores on extracted signals

Key principle: LLMs handle conversation and extraction (where flexibility is a feature). Code handles scoring, routing, and gates (where predictability is mandatory).

Traceability

Every step of every patient's journey is reconstructable.

LangGraph checkpointing provides: - Full state snapshot after every node execution - Time-travel debugging (replay any turn) - Resume-from-failure (patient resumes from last successful node)

Integration with existing Langfuse: - LangGraph native Langfuse callback handler traces every LLM call - Langfuse shows: why the LLM said this (prompt, completion, model, tokens) - LangGraph checkpoint shows: what the system state was when it said this

Together: "At turn 14, patient state was X, PFS was 78, agent chose to ask about travel because Layer 3 was at 0.0, response generated by claude-sonnet-4-6 with this prompt."

Audit tables

Three new audit tables for healthcare compliance:

graph_node_audit_log — every graph node execution:

id, case_id, turn_number, node_name, node_type (llm/extractor/scorer/router),
input_hash (SHA-256), output_hash, state_before (JSONB), state_after (JSONB),
decision_made, decision_reason, model_used, duration_ms, created_at

scoring_audit_log — every PFS/HSS/FMS computation:

id, case_id, score_type (pfs/hss/fms), score_value, config_version (hash of scoring.yaml),
inputs (JSONB), component_breakdown (JSONB), threshold_crossed, threshold_direction,
previous_score, created_at

extraction_audit_log — every extractor output:

id, case_id, turn_number, layer (intent/medical/travel/logistics/financial),
extracted_signals (JSONB), confidence_scores (JSONB), completion_before,
completion_after, model_used, input_text, created_at

Tamper detection: input_hash and output_hash in graph_node_audit_log create a chain. Each turn's input_hash must match the previous turn's output_hash. If state is modified retroactively, the chain breaks.

Prompt abstraction compatibility

The existing prompt abstraction system (app/services/prompt_loader.py, config/prompts/) is fully compatible. Each LangGraph node consumes prompts via the same load_prompt() API.

Phase contexts → layer contexts:

config/prompts/
  layer_contexts/              ← NEW (replaces phase_contexts for v3)
    intent_capture.yaml
    medical_status.yaml
    travel_readiness.yaml
    logistics.yaml
    financial_readiness.yaml
    remediation.yaml
    multi_layer.yaml
  phase_contexts/v2/           ← KEPT for v2 rollback

New function in prompt_loader.py (~50 lines):

load_layer_context(active_layer, layer_state, pfs_band)

Same pattern as load_phase_context() — same YAML structure, same caching, same locale fallback. Flagsmith prompt_version: v3 activates layer-aware prompts. v2 keeps working as fallback.

Caching improves: Layer contexts are more stable than phase contexts (patient stays in same layer for multiple turns). Higher cache hit rate.

New YAML files needed: 4 base extractors + 4 example files + 7 layer contexts = ~15 files.

Net new code in prompt_loader.py: ~50 lines for load_layer_context(). Existing load_prompt(), cached_system_message(), A/B variant support, locale fallback — all unchanged.

Implementation effort

Component Effort
Triage Agent as LangGraph graph 1 week
Extractors as parallel sub-nodes 1 week
LangGraph checkpointing → PostgreSQL 2-3 days
Langfuse integration with LangGraph 1 day
Audit tables (3 new) + Alembic migrations 2-3 days
Hash chain integrity 1 day
interrupt() at PFS thresholds 1 day
SSE streaming migration 2-3 days
Prompt abstraction: layer contexts + loader 2-3 days
Total ~3-4 weeks

This overlaps significantly with the "Intake Restructuring" phase — they are the same work.