Deploy the Order Risk operator
Order Risk (op-order-sentinel) watches every open order next to its support thread and shipment record, and scores how likely each one is to miss the date you promised. When the score crosses your threshold, it proposes a hold, a reroute, or a notice to the account owner, and the deterministic executor carries the action out exactly once. This guide installs it from the marketplace, binds its connectors, tunes the threshold, writes its guardrail policy, and reads its first receipts.
Order Risk runs in production today inside BearScope, Fibric's flagship product, scoring live specialty-commerce orders against real Kustomer conversations and Magento order state. It has been live since April 2026. Operator packs are priced from $49/operator/mo, with action overage at $0.01/action; propose-only runs meter no actions.
What the operator does
The signal Order Risk works from is upstream of the carrier. A proof approval that has sat for two days, a paid order with no fulfilment, a customer who has already written in twice: by the time tracking says late, the risk has usually been visible in the order for a week. The operator senses three feeds through the connectors you bind it to:
- Open orders with line items, promise dates, and proof-approval state.
- Support conversations tied to each order, including reopen and escalation history.
- Shipment and tracking events from the moment a label is created.
From these it produces one risk score per open order. When a score crosses the threshold you set, the operator proposes an ExecutionPlan: place or release an order hold with the reason on the record, propose a reroute or expedite, or notify the account owner with the order, the signal, and the recommended fix. The plan is only a proposal. Every action in it passes through your trust policy before anything touches a live system, and every disposition leaves a receipt.
The operator holds no credentials of its own. It runs inside your tenant and acts through the connectors you have already authorized; revoking a connector revokes the operator's reach with it.
Prerequisites
Order Risk requires three connector roles. Each role accepts more than one connector, and the operator binds to the capability, not the vendor, so swapping Magento for Shopify later is a config change, not a redeploy.
| Role | Capabilities used | Supported connectors | Setup guide |
|---|---|---|---|
| Commerce | order.read, order.hold |
cn-magento or cn-shopify |
Connect Magento |
| Support | conversation.read, conversation.note.write |
cn-kustomer or cn-zendesk |
Connect Kustomer |
| Shipping | shipment.read |
cn-shipstation or carrier webhooks |
Connectors |
You also need the CLI installed and authenticated (CLI reference), and permission to apply policy in the workspace. Confirm the connectors are healthy before installing the operator:
fibric connectors list
fibric capabilities ls
Install it first with fibric connectors add <id> and verify it with fibric connectors test. The operator cannot be created until every capability it declares resolves to a healthy connection. If you want to rehearse the whole flow without live systems, the sandbox guide provides simulated order, support, and shipping connectors.
Install from the marketplace
Marketplace operators install as packs. fibric operators create --from pulls the pack, walks capability binding, and asks you to accept the guardrails the pack declares as its floor. New operators start in propose-only mode: they sense, reason, and propose, but no side-effecting action runs until you switch them live.
fibric operators create --from op-order-sentinel --name order-risk \
--bind order.read=cn-magento \
--bind order.hold=cn-magento \
--bind conversation.read=cn-kustomer \
--bind conversation.note.write=cn-kustomer \
--bind shipment.read=cn-shipstation
The operator now runs on its trigger, but every proposal parks instead of executing. That is the correct state to tune thresholds in: you can watch what it would do against real orders before anything is allowed to act.
Tune the risk threshold
Configuration is a JSON block passed at create time or updated later by re-running create with the same name. The parameters below are the pack's public surface; anything not listed keeps its default.
| Parameter | Type | Default | Description |
|---|---|---|---|
risk_threshold |
0–100 | 70 |
Minimum risk score before the operator proposes any action on an order. Lower values propose earlier and more often. |
propose_window_hours |
number | 72 |
How far ahead of the promise date the operator will propose. Orders whose promise is further out are scored but not acted on. |
max_holds_per_run |
number | 10 |
Cap on hold proposals in a single run. This bounds one run's proposals; the trust policy independently caps what can execute. |
notify_owner |
boolean | true |
Whether to include an account-owner notice alongside each hold proposal. |
release_when_clear |
boolean | true |
Propose releasing a hold the operator placed once the order's score falls back under the threshold. |
fibric operators create --from op-order-sentinel --name order-risk \
--config '{"risk_threshold": 80, "propose_window_hours": 48, "max_holds_per_run": 5}'
Start high. A threshold of 80 with a 48-hour window produces few, high-confidence proposals; watch a week of dry runs, then lower the threshold until the operator catches the orders your team was catching by hand. Tightening later is a config change; loosening should follow evidence in the receipts.
Write the guardrail policy
The trust policy is the deterministic half of the loop, and it is fail-closed: anything a rule does not explicitly allow is refused. The pack's configuration bounds what the model proposes; the policy bounds what can execute, and the policy wins. This is the mechanism that makes a runaway action, the classic 657-message flood, structurally impossible rather than merely unlikely.
# policy.yaml: governs the order-risk operator
policy: order-risk-guardrails
applies_to: order-risk
rules:
# internal notes are low-risk; allow them freely
- allow: conversation.note.write
# holds are allowed, but rate-limited and single-flight
- allow: order.hold
limit:
per: hour
max: 25 # a flood cannot exceed this
single_flight: order_id # never two holds in flight for one order
# owner notices are allowed, capped per hour
- allow: notify.send
limit:
per: hour
max: 25
# rerouting or expediting a shipment costs money: a person confirms it
- require_confirmation: shipment.reroute
# default is deny. nothing not listed above can act.
default: deny
Apply the policy and validate it statically. Validation tells you exactly what the operator can and cannot do, without running anything.
fibric policy apply ./policy.yaml
fibric policy validate order-risk-guardrails --against order-risk
max_holds_per_run is configuration the operator reads; limit.max is policy the executor enforces. Configuration shapes proposals, policy vetoes actions. If they disagree, the policy is the one that holds, and an empty or broken policy denies everything; it never falls open. The full guardrail model is covered in the guardrails guide.
Dry-run, then go live
A --dry-run shows you the exact ExecutionPlan the operator would submit, scored and ordered, but executes nothing. Run it a few times across a business day before you trust the threshold.
fibric operators run order-risk --once --dry-run
When the proposals match what your team would have done by hand, switch the operator live. Live mode does not bypass anything: every action still passes the trust policy, still takes its single-flight lock, and still deduplicates on its idempotency key.
fibric operators create --from op-order-sentinel --name order-risk --mode live
fibric operators run order-risk --once
If you need to stop it, fibric operators pause order-risk halts new runs immediately; in-flight actions complete under their single-flight locks and nothing new is proposed.
Read its receipts
Every disposed action leaves a receipt: the proposal exactly as the operator made it, the policy decision, the idempotency key, and the outcome. Blocked and deduplicated actions are receipted with the same fidelity as executed ones. Tail the stream to watch the operator work:
fibric receipts tail --operator order-risk
Each disposition answers a different operational question:
| Disposition | Meaning | What to do with it |
|---|---|---|
ALLOW |
A rule matched, its constraints passed, and the action ran. | Normal operation. The receipt records the rule that passed it. |
ALERT |
The action is parked for human approval, with the operator's reasoning attached. | Approve or decline from the console or CLI; approval executes the original action under its original idempotency key. |
BLOCK |
No rule matched, or a constraint failed. Fail closed; nothing ran. | If the proposal was legitimate, write the rule. If not, the policy did its job. |
DEDUP |
The same idempotency key was already applied; the retry collapsed into the original. | Nothing. This is the proof the same hold can never be placed twice. |
Open any receipt in full with fibric receipts show rc_… --json, and export the ledger for audit with fibric receipts export --since 7d. The receipt's anatomy, immutability guarantees, and query filters are covered in Receipts & audit. Ongoing observation, standing queries, and alerting on BLOCK rates are covered in the monitoring guide.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| No proposals in dry runs | risk_threshold too high, or propose_window_hours shorter than your fulfilment cycle. |
Lower the threshold in steps of 5 and widen the window; compare against orders your team held by hand last week. |
Every hold shows BLOCK |
Policy not applied, or applies_to names a different operator. |
Run fibric policy validate order-risk-guardrails --against order-risk; the fail-closed default blocks everything until a rule matches. |
| Holds stop mid-run with exit code 4 | The hourly limit.max was reached; the policy is capping the blast radius. |
Expected under load. Raise the cap only after reviewing the receipts that hit it. |
Repeated DEDUP receipts for one order |
The order re-crosses the threshold each run and the operator re-proposes the same hold. | Normal; the idempotency key absorbs it. Enable release_when_clear if holds should lift automatically. |
| Exit code 7 on a hold | Another action holds the single-flight lock for that order. | Wait for the in-flight action to complete; see Single-flight & idempotency. |
capabilities ls shows a capability missing |
The bound connector is unhealthy or was removed. | Run fibric connectors test against the connection; re-authorize or rebind the capability. |
Next steps
- Guardrails: value caps, confirmation tiers, and how to promote an
ALERTaction to unattended. - Monitoring operators: standing receipt queries and what a healthy
BLOCKrate looks like. - Deploy the Operations Analyst: ask why an order slipped, in plain language, over the same governed data.
- Operators and Operator packs: the concepts behind what you deployed.