One orchestrator · Six functional nodes · Shared case state · Phased deployment
Customer presents shoes at till. Eva captures receipt images + shoe photos + customer identifiers. First node consumes raw intake and produces a structured condition verdict.
If receipt is missing or unreadable, agent attempts federated search across all 4 Randstad stores + e-comm records using partial identifiers. No phone calls required.
proof_verified = True, replacement proof artifact minted → re-enters policy_check.Applies the 30-day window, unworn requirement, return-type preference, and €150 refund cap. Routes to the correct resolution path. Rules are deterministic.
For exchange cases: queries real-time stock across all 4 stores + warehouse. Attempts atomic hold (48h TTL) on best alternative location. Creates transfer manifest if hold succeeds.
For defect-suspected cases: checks photo quality first, then runs multimodal defect classification. Separate parallel track handles supplier RMA assembly. Confidence threshold gates HITL.
Any case that cannot be fully resolved by the agent — no proof match, worn item disputed, over-€150 refund, borderline defect — routes to a single supervisor dashboard. Anouk or Robin action it; case re-enters the flow at the appropriate node.
Every terminal resolution emits a notification before the case closes. No silent closures. Channels: SMS + email. Also fires on hold expiry and on HITL status changes.
customer_notified = True → case can close.
| Stage | Input | Tool / Action | Output | State Mutation |
|---|---|---|---|---|
| ① Intake | Receipt images, shoe photos (3+), customer ID, reason code | verify_receipt_data · analyze_shoe_condition (CV) | Receipt validity result; condition score; is_worn flag; defect_suspected flag | proof_verified · condition_verdict { is_worn, defect_suspected, score, confidence } |
| ② Cross-Store | customer_identifier, approx_date_range, card_last_four (optional) | federated_sales_search · payment_token_lookup · generate_replacement_proof | Matched transaction OR no-match signal; digital proof artifact (if found) | proof_verified = True; enriched transaction data; replacement_proof_ref |
| ③ Policy | purchase_date, is_worn, defect_suspected, resolution_pref, refund_amount | compute_days_since_purchase · evaluate_policy_compliance · check_refund_cap | Route signal: REFUND / EXCHANGE / DEFECT / HITL; cap check result | resolution_type · escalation_reason (if HITL) · cap_authorization |
| ④a Stock | sku, size, origin_store_id, dest_pref (customer location) | query_stock_matrix · acquire_atomic_hold · create_interstore_transfer_manifest | Stock matrix; hold_id (or no-stock flag); transfer manifest; collection date | hold_reservation_id · transfer_manifest_ref · stock_source_store_id |
| ④b Defect | image_urls[], fault_description, receipt metadata (from state) | check_photo_quality_compliance · classify_structural_defect · submit_supplier_rma_claim | quality verdict; fault_type; confidence; RMA claim_id; purchasing notification | supplier_claim_id · defect_classification · rma_status · confidence_score |
| ⑤ HITL | Full ReturnCaseState; elapsed time; actions attempted; reason for escalation | escalate_to_supervisor · supervisor_action_callback | Anouk's resolution action; supervisor notes; resolution path chosen | escalation_resolved · supervisor_notes · resolution_path · resolution_time |
| ⑥ Notify | outcome_type, delivery_details (refund / exchange / defect / claim / expiry), customer contact | notify_customer_sms · notify_customer_email | Notification delivery confirmation; customer_notified flag | customer_notification_status · notification_channel · notified_at |
| ◆ Close | All accumulated state fields | case.close() — only permitted when customer_notified = True | Case closed; final audit log entry; metrics emitted | case.closed = True · closed_at · final_audit_entry |
| Guardrail | Trigger | Action | Fallback |
|---|---|---|---|
| Refund cap €150 | execute_till_refund amount > €150 | Route to HITL; do not auto-refund | Anouk digital approval via supervisor dashboard |
| Defect conf < 0.85 | classify_structural_defect confidence < 0.85 | Route to HITL (Anouk physical inspection) | High-res re-capture prompts sent to till UI |
| Photo quality fail | check_photo_quality_compliance = False | Hold case; prompt till UI to re-capture | Loops back to intake_eval; case stays open |
| Stock API down | query_stock_matrix throws / times out | Route to HITL; do not guess stock | Anouk manual phone check (old path as fallback) |
| Hold expiry (48h) | TTL elapsed; customer hasn't collected | Lock auto-expires; inventory released to WMS | Customer notified before expiry + at expiry |
| No match (cross-store) | federated_sales_search returns empty | Route to HITL; case stays open | Anouk manual store-by-store check |
| Out of policy | Worn item vs. change-of-mind; >30 days; no defect claimed | Route to HITL; do not force resolution | Anouk supervisor review; policy exception decision |
| No customer notification | Attempt to close case with customer_notified = False | Block case closure | System prevents close; flag for ops review |
Which bottlenecks does Version A actually resolve, and which does it not yet touch?