Examples
Fraud Review Loop
Runtime flow
| Stage | In this example |
| --- | --- |
| Provider | OpenAI scorer — fraud likelihood + patterns (submit_score) |
| Loop + Guards | Review loop — evidence-required, confidence-threshold |
| Channel | Analyst reviewer — human-only on analyst_review / disposition |
| Integration | Case system / payment hold release after terminal states |
| Evidence | fraud_score, flagged patterns, transaction context per transition |
1Provider (scorer) → Loop + Guards → Channel (analyst) → Integration (case system) → EvidenceWhat this example shows
Fraud queues move faster than human teams can triage manually. This pattern uses AI scoring for prioritization and keeps final decision authority with a human analyst. Every escalation and disposition remains attributable for audit — not auto-block without human path on escalated cases.
Loop diagram
1IDLE --[ingest_flag]--> FLAGGED --[start_scoring]--> SCORING2SCORING --[submit_score]--> PENDING_REVIEW3PENDING_REVIEW --[dismiss_case]--> DISMISSED (terminal)4PENDING_REVIEW --[analyst_review]--> REVIEWED --[close_case]--> CLOSED (terminal)Actors
| Actor | Type | Role | Guards that apply |
|---|---|---|---|
| transaction ingestor | automation | Flags incoming transactions | none |
| risk scorer | ai-agent | Computes fraud likelihood and patterns | evidence-required, confidence-threshold |
| analyst reviewer | human | Final disposition on escalated cases | human-only |
Key annotated snippet
1"cmt">// @no-typecheck2import OpenAI from "openai";3import { createOpenAIActorAdapter } from "@loop-engine/adapter-openai";4 5const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });6const scorer = createOpenAIActorAdapter(openai, { modelId: "gpt-4o" });7 8const { actor, decision } = await scorer.createSubmission({9 loopId: "fraud.review",10 loopName: "Fraud Review",11 currentState: "SCORING",12 availableSignals: [{ signalId: "submit_score", name: "Submit Score" }],13 instruction: "Score fraud risk and provide suspicious patterns.",14 evidence: { merchantId: "m-42", ipRisk: "high", velocitySpike: true }15});16 17await engine.transition({18 aggregateId: "txn-884422" as never,19 transitionId: "submit_score" as never,20 actor,21 evidence: {22 ...decision,23 fraud_score: decision.confidence,24 flagged_patterns: ["velocity_spike", "new_device", "geo_mismatch"],25 transaction_context: { amount: 1480, currency: "USD" }26 }27});What emitted events look like
1{2 type: "loop.transition.executed",3 loopId: "fraud.review",4 aggregateId: "txn-884422",5 transitionId: "analyst_review",6 fromState: "PENDING_REVIEW",7 toState: "REVIEWED",8 actor: { type: "human", id: "analyst@bank.com" },9 evidence: { disposition: "confirm_fraud", caseId: "FR-92011" }10}