Documentation home

Refund Agent Example

The retail refund agent is a real server-side worker pattern for guarded business actions.

Lifecycle

The worker claims the next ledger entry, derives risk context, marks the row as guarding, calls POST /api/sentinel/action/guard with refund:{ledger_entry_id}, writes a simulated execution only on allowed or later-approved decisions, creates Proof Pack evidence before final execution, and reports the outcome back to HaltState. Denied, pending, expired, and engine-failure decisions do not write refund execution records.

Ledger states

StatusMeaning
NEWWaiting for the worker.
GUARDINGWorker is asking HaltState for authority.
ALLOWEDPolicy allowed execution.
APPROVAL_REQUIREDHuman approval is required; no execution yet.
DENIEDPolicy denied execution.
EXECUTEDSimulated ledger write completed under policy authority.
ERRORWorker or engine failed and execution did not proceed.

Operator command

HALTSTATE_REFUND_AGENT_API_KEY=$HALTSTATE_API_KEY \
  python services/retail_refund_agent.py --once

Sample ledger row JSON

{
  "ledger_entry_id": "lge_demo_low_001",
  "refund_id": "rf_demo_low_001",
  "agent_id": "retail-refund-agent",
  "action": "refund.create",
  "status": "NEW",
  "amount": {
    "value": 126,
    "currency": "USD"
  },
  "idempotency_key": "refund:lge_demo_low_001",
  "risk": {
    "duplicate_refund": false,
    "stale_window": false,
    "suspicious_reason": false,
    "customer_attempts_24h": 1
  },
  "redaction_status": "customer data hidden"
}

Sample live feed event JSON

{
  "schema": "haltstate.live.event.v1",
  "agent_label": "retail-refund-agent",
  "source": "refunds",
  "action": "refund.create",
  "decision": "ALLOW",
  "amount": {
    "value": 126,
    "currency": "USD"
  },
  "reason_code": "within_policy_limit",
  "proof_status": "hash-only proof",
  "redaction_status": "customer data hidden",
  "latency_ms": 18,
  "ledger_entry_id": "lge_demo_low_001",
  "refund_id": "rf_demo_low_001"
}

Sample Proof Pack JSON

{
  "proof_id": "pf_demo_low_001",
  "ledger_entry_id": "lge_demo_low_001",
  "refund_id": "rf_demo_low_001",
  "agent_id": "retail-refund-agent",
  "action": "refund.create",
  "decision": "ALLOW",
  "policy_label": "Retail Refund Policy v1",
  "reason_code": "within_policy_limit",
  "proof_status": "hash-only proof",
  "signature_status": "hash-only proof",
  "redaction_status": "customer data hidden",
  "hash": "sha256:f90f0254d15ed86b24214b4b9bb8c3219ce0869b63cac1ee4004f322bf59eabd"
}

Expected outcomes

  • ALLOW: low-risk refund writes one simulated execution row and reports success.
  • APPROVAL_REQUIRED: medium-risk refund pauses; no execution row is written until a later approved retry.
  • DENY: high-risk, duplicate, stale, suspicious, or over-limit refund never executes.

Protected refund endpoints

The public live board and live feed are the public proof surfaces. Raw refund endpoints are protected operator APIs. Unauthenticated requests to /ops/api/refunds/agent/status and /ops/api/refunds/ledger are expected to return 401 or 403, or an intentionally sanitized response. They must not expose raw customer, ledger, policy, approval, or operator data publicly.

Public live data

The live board can show safe amount, currency, action, decision, proof status, latency, reason code, refund ID, ledger ID, hashed references, and redaction status. It must not show customer names, emails, card data, raw order payloads, tenant IDs, raw policy IDs, approval IDs, API keys, or operator secrets.

Why the ledger is server-side

The refund demo uses a server-side ledger because the important proof is not that a browser can display rows; the proof is that a worker can attempt a business action, ask HaltState for authority, and refuse to write execution when the policy denies or pauses the action. The ledger lets operators verify transitions, idempotency, and duplicate execution prevention without touching real money or customer data.

Implementation notes

Keep the HaltState call as close as possible to the side effect. The agent may plan and draft freely, but the wrapper around the actual action should be the place where authority is checked. That wrapper should send only the context required for policy evaluation: safe identifiers, normalized amounts, action names, risk flags, schedule windows, and redaction status. Raw customer payloads and secrets should stay in the business system or protected operator tooling.

Operational evidence

For each action, preserve the decision, the worker outcome, the idempotency key, safe resource references, latency, proof status, and redaction status. This evidence supports incident response and control narratives because it shows what the system did at runtime rather than only describing what the policy document intended. HaltState supports alignment work; it is not a substitute for legal advice or a compliance certification.