Version B · Full Multi-Agent v2 · Full Architecture

Sallie se Schoenen — Multi-Agent Returns Architecture

Four specialized agents · Supervisor orchestrator · Threaded state · Parallel defect track · Shared HITL

Architecture: LangGraph supervisor + 4 independent agent runtimes Agents: Orchestrator · Intake · Cross-Store Data · Inventory & Logistics · Warranty & Claims State: ReturnCaseState — versioned schema, threaded between agents HITL: Single shared supervisor dashboard (Anouk + Robin) Prerequisite: Same infrastructure as Version A + agent observability per agent
Supervisor Orchestrator (route, guardrails, state transitions) Intake Agent Cross-Store Data Agent Inventory & Logistics Agent Warranty & Claims Agent Shared HITL queue (Anouk + Robin) ReturnCaseState mutation / handoff point Resolution flow Inter-agent state handoff
Supervisor Orchestrator
LangGraph state machine · routes between agents · enforces guardrails · owns state transitions
route_to(agent, node) enforce_guardrail() merge_agent_state() escalate_to_hitl() close_case()
Owns ReturnCaseState (full schema, versioned) · state transition matrix · guardrail rules · case lifecycle
Intake Agent
Frontline intake · receipt verification · condition assessment · fraud/frequency check · policy routing
verify_receipt_data() analyze_shoe_condition() check_return_frequency() route_ticket()
Reads / Writes items[] · receipt_id · purchase_date · proof_verified · condition_verdict · customer_id · origin_store_id · resolution_pref
Cross-Store Data Agent
Federated receipt lookup · payment token trace · digital proof mint · re-entry to Intake
federated_sales_search() payment_token_lookup() generate_replacement_proof()
Reads / Writes customer_identifier · approx_date_range · card_last_four · proof_verified · enriched_transaction[] · replacement_proof_ref
Inventory & Logistics Agent
Multi-store stock matrix · atomic reservation locks · inter-store transfer manifests · dead-letter handling
query_stock_matrix() acquire_atomic_hold() create_interstore_transfer_manifest() release_expired_hold()
Reads / Writes sku · size · stock_matrix{} · hold_reservation_id · transfer_manifest_ref · lock_ttl · stock_source_store_id
Warranty & Claims Agent
Multimodal defect classification · evidence validation · supplier RMA creation · purchasing notification
check_photo_quality_compliance() classify_structural_defect() assemble_evidence_package() submit_supplier_rma_claim() notify_purchasing_lead()
Reads / Writes image_urls[] · fault_description · defect_classification · confidence_score · supplier_claim_id · rma_status · evidence_package_ref
End-to-End Multi-Agent Architecture — Version B
Supervisor Orchestrator LangGraph state machine · routes · guardrails · state transitions ReturnCaseState (versioned schema · threaded between agents · mutated at each ●) Customer presents item Eva · receipt + shoe photos + customer ID Orchestrator: route to Intake Agent ingest raw intake · create ReturnCaseState v1 state v1 Intake Agent verify_receipt_data(receipt_id, purchase_date) analyze_shoe_condition(image_urls[]) → condition_verdict check_return_frequency(customer_id) state v2 verdict → orchestrator Cross-Store Data Agent federated_sales_search(id, date_range) payment_token_lookup(card4, bank_ref) generate_replacement_proof(tx_id) → returns enriched state to orchestrator state v3 proof missing → Cross-Store Agent proof OK → Policy routing match found → orchestrator · proof_verified no match → HITL Orchestrator: Policy Routing evaluates: 30d window · unworn · resolution_pref · €150 cap refund ≤ €150 · refund desired → Execute Till Refund exchange desired → Inventory Agent defect suspected → Warranty Claims Agent out of policy / over cap → HITL Inventory & Logistics Agent query_stock_matrix(sku, size) acquire_atomic_hold(sku, store, ttl=48h) create_interstore_transfer_manifest() → returns hold/tansfer state to orchestrator state v4 hold confirmed no network stock API down Alternative Offer store credit / different product Warranty & Claims Agent check_photo_quality_compliance(images[]) classify_structural_defect(images[], desc) assemble_evidence_package() submit_supplier_rma_claim(supplier_id, data) → parallel: returns defect verdict + RMA state state v5 quality fail → re-capture prompt conf < 0.85 → HITL Anouk conf ≥ 0.85 → till remedy authorized RMA submitted (parallel) → notify → final Execute Till Refund execute_till_refund(amount, tender) Capped at €150 auto-approve Over cap → HITL (Anouk digital auth) refund complete over €150 Update Local Inventory shoes to stock · WMS/ERP update Shared HITL Dashboard Anouk: missing proof · policy edge · over-cap refund · defect review Robin: RMA status · evidence package · supplier claim follow-up Single queue · case re-enters at appropriate agent node re-entry → Cross-Store Agent re-entry → Inventory Agent re-entry → Warranty Claims Agent ⑥ Notify Customer notify_customer(outcome, delivery_details) customer_notified = True TERMINAL case.closed = True Dead-Letter: Lock Expired 48h TTL · inventory released to WMS customer_notified: hold expired INTER-AGENT STATE HANDOFFS Intake → Orchestrator: condition_verdict + proof_status Cross-Store → Orchestrator: enriched_transaction + proof_verified flag Orchestrator → Inventory Agent: sku + size + origin_store_id Orchestrator → Warranty Claims: image_urls + receipt_meta + fault_desc Warranty Claims → Orchestrator: defect_classification + rma_claim_id
Agent-by-Agent Information Flow & Outputs — Version B

Agent Input / Tool / Output / State Contract

AgentInput from previousCore toolsOutput to orchestratorState fields owned
Orchestrator Raw intake from Eva (till UI); verdict from Intake Agent route_to() · enforce_guardrail() · merge_agent_state() · escalate_to_hitl() · close_case() Route decision per state transition matrix; guardrail enforcement result Full ReturnCaseState (versioned schema); state_transition_history[]; guardrail_decisions[]
Intake Agent Raw intake: receipt images, shoe photos, customer ID, reason code, resolution_pref verify_receipt_data() · analyze_shoe_condition() · check_return_frequency() proof_verified (bool) · condition_verdict · frequency_flag · route_recommendation items[] · receipt_id · purchase_date · proof_verified · condition_verdict{ is_worn, defect_suspected, score, confidence } · customer_id · origin_store_id · fraud_flag
Cross-Store Data customer_identifier · approx_date_range · card_last_four (from Intake/Orchestrator) federated_sales_search() · payment_token_lookup() · generate_replacement_proof() match_found (bool) · enriched_transaction[] · replacement_proof_ref · no_match flag proof_verified (set True if found) · enriched_transaction[] · replacement_proof_ref · federated_search_id
Inventory & Logistics sku · size · origin_store_id · customer_location_pref (from Orchestrator) query_stock_matrix() · acquire_atomic_hold() · create_interstore_transfer_manifest() · release_expired_hold() stock_matrix{} · hold_reservation_id or no_stock flag · transfer_manifest_ref · lock_ttl · stock_source_store_id stock_matrix · hold_reservation_id · transfer_manifest_ref · lock_ttl · stock_source_store_id · dead_letter_flag
Warranty & Claims image_urls[] · fault_description · receipt metadata (from state, via Orchestrator) check_photo_quality_compliance() · classify_structural_defect() · assemble_evidence_package() · submit_supplier_rma_claim() · notify_purchasing_lead() quality_verdict · defect_classification{ fault_type, is_manufacturing_fault, confidence } · supplier_claim_id · rma_status · evidence_package_ref supplier_claim_id · defect_classification · rma_status · confidence_score · evidence_package_ref · claim_history[]
Shared HITL Full ReturnCaseState at escalation point; elapsed time; escalation_reason; actions attempted Anouk/Robin action via dashboard; supervisor_action_callback() → state update supervisor_resolution · supervisor_notes · resolution_path_taken escalation_timestamp · escalation_resolved · supervisor_id · supervisor_notes · re_entry_point

Parallel Track Detail — Warranty Claims Agent

StepToolInputOutputTiming
1. Quality gatecheck_photo_quality_compliance()image_urls[]pass/fail + missing_angles[]Immediate
2. Re-capture (if fail)till UI promptmissing_angles[]Customer re-captured imagesLoops to step 1
3. Defect classifyclassify_structural_defect()images[], fault_description{ fault_type, is_manufacturing_fault, confidence }After quality pass
4a. Conf ≥ 0.85—classification resultTill remedy authorized (parallel with RMA); customer notifiedParallel with step 4b
4b. Conf < 0.85—classification resultEscalate to Anouk; high-res prompts to till UIHITL path
5. Evidence packageassemble_evidence_package()images + receipt_meta + classificationStructured evidence package (PDF / JSON)After classification
6a. API availablesubmit_supplier_rma_claim()supplier_id, evidence_package, case_datasupplier_claim_id · submission_statusAfter step 5
6b. No APIManual notification to Robinevidence_package (email/dashboard)Robin action required; case tracks rma_status = PENDING_SUBMISSIONAfter step 5
7. Status trackernotify_purchasing_lead()claim_id, status updateRobin notified; case state updatedOn every status change
ReturnCaseState — Schema Comparison: Version A vs. Version B

Version A — Single Schema

One schema, mutated in place by the single orchestrator's nodes. Simpler — no inter-agent version negotiation.

# Version A — single writer, sequential mutations # All mutations by the one orchestrator runtime case_id: str customer_id: Optional[str] origin_store_id: str purchase_date: Optional[datetime] # datetime, not str receipt_id: Optional[str] items: List[ReturnItem] resolution_type: Literal["REFUND","EXCHANGE","DEFECT_REMEDY","PENDING_REVIEW"] proof_verified: bool = False defect_detected: bool = False condition_verdict: Optional[ConditionVerdict] # NEW: structured CV output hold_reservation_id: Optional[str] supplier_claim_id: Optional[str] escalation_reason: Optional[str] customer_notification_status: Literal["NOT_SENT","SENT","FAILED"] = "NOT_SENT" # NEW dead_letter_reason: Optional[str] # NEW: for expired lock path closed: bool = False closed_at: Optional[datetime] agent_audit_log: List[AgentDecisionLogEntry] # NEW: observability

Version B — Versioned Schema, Agent-Owned Fields

Same base schema but: (1) version field for agent-to-agent negotiation; (2) each agent declares which fields it owns; (3) schema version must match before merge.

# Version B — schema versioning + agent ownership # Orchestrator owns full schema; agents declare owned_fields schema_version: Literal["1.0"] # NEW: required for agent merge case_id: str # Owned by Orchestrator customer_id: Optional[str] # Owned by Intake Agent origin_store_id: str # Owned by Intake Agent purchase_date: Optional[datetime] # Owned by Intake Agent receipt_id: Optional[str] # Owned by Intake Agent items: List[ReturnItem] # Owned by Intake Agent resolution_type: Literal[...] # Owned by Orchestrator (policy routing) proof_verified: bool # Owned by Cross-Store Agent defect_detected: bool # Owned by Warranty Claims Agent hold_reservation_id: Optional[str] # Owned by Inventory Agent supplier_claim_id: Optional[str] # Owned by Warranty Claims Agent escalation_reason: Optional[str] # Owned by Orchestrator owned_by: dict[str, str] # NEW: field → agent_name mapping last_modified_by: str # NEW: which agent last wrote modified_at: datetime # NEW: timestamp of last write customer_notification_status: Literal[...] # Owned by Orchestrator closed: bool # Owned by Orchestrator agent_audit_log: List[LogEntry] # Per-agent entries; owned by Orchestrator
Why versioning matters in B: When Warranty Claims Agent writes defect_classification, it stamps last_modified_by = "warranty_claims_agent" and modified_at. If the schema changes (e.g., a new field added), agents can check schema_version before merging. Prevents silent field collisions when multiple agents touch the same case concurrently.
Agent-Level Observability & Evaluation — Version B Specific

Version B's multi-agent separation creates observability advantages that Version A does not have. Each agent can be evaluated independently, failures are isolated, and you know which agent made a wrong decision — not just that the pipeline failed.

Per-Agent Eval Dimensions

AgentWhat to measureHowTarget
Intake AgentReceipt verification accuracy; condition classification agreement with human label; routing accuracy (did it route to the right next agent?)Weekly sample of 50 cases compared against Anouk's historical decisions; CV condition score correlation with human-labeled "worn/unworn"≥ 90% routing accuracy; condition agreement ≥ 85% before removing HITL for wear decisions
Cross-Store Data AgentFederated search recall (did it find the transaction when it existed?); false positive rate; replacement proof artifact delivered to customerCompare search results against known transactions in a test set; measure customer receipt of digital proof artifactRecall ≥ 95%; zero false positives on payment token lookup (conservative threshold)
Inventory & Logistics AgentStock matrix accuracy vs. physical count; atomic hold success rate; double-booking incidents; dead-letter lock expiry ratePeriodic physical stock audit vs. agent's stock_matrix; track hold_expires_without_pickup rateStock accuracy ≥ 95%; double-booking = 0; dead-letter rate < 5% of holds
Warranty & Claims AgentDefect classification accuracy (fault type + manufacturing vs. wear); confidence calibration; evidence package completeness; RMA submission success rateLabeled dataset of defective vs. non-defective footwear; compare agent classification vs. expert label; track RMA outcomes (approved/rejected) vs. agent confidenceFault type accuracy ≥ 85%; manufacturing vs. wear accuracy ≥ 90%; RMA approval rate tracked over time

Failure Isolation — What Breaks When

If this agent fails…Impact in Version AImpact in Version BVersion B advantage
Intake Agent downWhole pipeline stops; no intake can be processedPipeline stops at intake; other agents unaffected; queue builds at intake onlyOther agents still operational for cases already past intake
Cross-Store Agent downReceipt lookup fails; cases route to HITL onlyReceipt lookup fails; cases route to HITL only; Inventory and Warranty agents still work for cases with verified proofPartial pipeline continues for cases that don't need cross-store lookup
Inventory Agent downExchange path stops; refund + defect paths unaffectedExchange path stops; refund + defect paths fully operational; existing holds not affectedTwo of three resolution paths still live; no full outage
Warranty Claims Agent downDefect path stops; refund + exchange paths unaffectedDefect classification + RMA stops; customer remedy path may still work via Intake; RMA only affectedCustomer-facing remedy can still resolve; only back-office RMA delayed
Orchestrator downEverything stopsEverything stops (same as A)No advantage — orchestrator is single point of control in both

Version A vs. Version B — Head-to-Head for Group Decision

Read this with your team. The question is not which is "better" in the abstract — it's which one matches your current infrastructure, volume, and team structure.

Version A — Single Orchestrator · 6 Nodes

  • Faster to first value: Build case DB + receipt lookup + policy routing first. One state machine, one prompt context.
  • Simpler to debug: One agent runtime means one log stream. When something goes wrong, you know where to look.
  • Lower build cost: One agent to build, test, and deploy. No inter-agent state contracts, no schema versioning.
  • Natural for 4 stores: Four specialized agent runtimes for four stores is over-engineering at this scale.
  • HITL is a node, not a shared resource: Simpler — escalations go to one queue, re-entry is explicit in the state machine.
  • No agent-level isolation: If the orchestrator's defect node has a bug, the refund path is not affected (separate nodes) but there's no runtime isolation.
  • Harder to scale per-agent independently: Adding more sophisticated defect classification means upgrading the whole orchestrator deployment.
  • Observability is pipeline-level: You can see where the pipeline failed; harder to attribute a specific bad decision to a specific capability.
  • Best first build: Start here regardless. Version B is a migration path from A, not an alternative starting point.

Version B — Four Agents + Orchestrator

  • Agent-level isolation: Warranty Claims Agent can be upgraded, tested, and redeployed without touching the Intake Agent.
  • Independent agent evals: Each agent has its own accuracy metrics. You know the Cross-Store Agent is at 95% recall and the Defect Agent is at 82% — and can act on each independently.
  • Team scaling: If a second developer joins, they can own the Inventory Agent while another owns the Warranty Claims Agent. Clear ownership boundaries.
  • Parallel defect track: Warranty Claims Agent runs concurrently with the customer remedy path. Customer gets their refund while RMA is assembled — not sequential.
  • Schema versioning: When you need to add fields (e.g., a new supplier portal requires additional metadata), you version the schema and agents negotiate — no silent field collisions.
  • Multi-store scaling: If Sallie se Schoenen opens store 5, 6, 7 — the Cross-Store Agent's federation scope expands without touching the Intake Agent.
  • Higher build cost: Four agent runtimes, inter-agent state contracts, schema versioning, per-agent observability. Significantly more to build.
  • Inter-agent debugging: A failed case means tracing state through multiple agents. Requires observability investment from day one.
  • Orchestrator is still the single point of control: If it goes down, everything stops — same as Version A. The multi-agent separation doesn't fix that.
  • Premature at 4 stores: Unless you already have the infrastructure (federated POS API, WMS with lock semantics, supplier portal API), the extra complexity of Version B is not justified by the current scale.
Which Version to Build — Decision Framework for Your Group

Start with Version A if…

ConditionWhy it points to A
You have ≤ 5 storesMulti-agent separation doesn't pay back at this scale; one orchestrator is enough.
You're not sure what POS/WMS APIs exist yetVersion A's phased approach lets you discover infrastructure as you build. Version B requires you to know it upfront.
One small team (2–4 people) is building thisOne agent runtime = one codebase to maintain. Version B multiplies the surface area.
You need to show value in 8–12 weeksVersion A's phased rollout: case DB → receipt lookup → policy routing → stock resolve. Each phase delivers standalone value.
Supplier portals have no APIVersion B's Warranty Claims Agent auto-submission only works with an API. Without it, both versions generate packages for manual submission — no advantage to B.
You're not sure the defect classifier can reach 0.85Both versions have this dependency. Version A's CV-as-decision-support approach is the right starting point regardless.

Plan for Version B if…

ConditionWhy it points to B (later)
You expect to open more stores (≥ 6) within 12–18 monthsCross-Store Agent's federation scope grows; multi-agent separation handles this cleanly.
Different teams will own different parts of the systemClear agent ownership boundaries make this work. Single orchestrator blurs ownership.
The defect classifier will be a long-term R&D effortWarranty Claims Agent as a standalone runtime means you can iterate on it independently without destabilizing the intake flow.
Supplier portals do have APIs (or you've confirmed one major supplier does)Version B's automated RMA submission path is real — Version A would treat it as a tool call within the orchestrator, which works but doesn't scale with multiple suppliers.
You have an observability/infra team that can own per-agent monitoringVersion B's advantage in fault isolation only materializes if you instrument each agent properly.
You've already built Version A and are hitting its ceilingsVersion B is a natural migration path. You keep the same state schema, same tools, same HITL dashboard — you extract nodes into separate agent runtimes.