High-Risk Workflow
Multi-approver, irreversible, cross-tenant operations — frozen evidence snapshots, named approvers, post-execution audit.
The hardest workflow ContextOS runs is the one with all three properties at once: irreversible (a destructive step that cannot be safely retried), multi-approver (more than one named approver required), and cross-tenant (the action affects records in a tenant other than the requester’s). This page specifies how the runtime handles that case.
Scenario: invoice credit adjustment
A finance operator requests a credit adjustment on an invoice issued to a counterparty tenant. The action is destructive (writes general-ledger entries that require a reversal entry to undo), delegated (acts on behalf of the operator’s corporate role), and cross-tenant (the recipient tenant must consent at policy level).
| Field | Value |
|---|---|
| Intent | finance.invoice.credit_adjust |
| Risk class | destructive |
| Adapters | adp_invoices.lookup, adp_policy.eval, adp_gl.post_credit_entry, adp_recipient.notify |
| Decision specs | finance.invoice.credit_adjust.eligibility, finance.invoice.credit_adjust.execute |
| Approval gates | GATE_FINANCE_LEAD, GATE_RECIPIENT_TENANT |
| Required evidence | invoice_lookup, policy.eval, recipient_consent_proof, tax_compliance_check |
End-to-end workflow
1. Receive the request
{
"request_id": "req_inv_22",
"session_id": "sess_inv_22",
"tenant_id": "tenant_acme_prod",
"user": { "user_id": "usr_finops_11", "delegation": { "scopes": ["finance.invoice.write"] } },
"agent": { "agent_id": "agt_finops", "workload_identity": "spiffe://contextos/agents/finops" },
"context_pack_refs": ["ctxpack.finops@3.1.0"],
"input": { "intent": "finance.invoice.credit_adjust", "message": "Issue credit memo on inv_8810 for INR 12000" },
"mode": "long_running",
"runtime": { "max_session_duration_ms": 14400000, "max_tool_calls": 12 }
}2. Compile
The Compiler emits a CompiledContext with:
runtime_controls.approval_gates_active = ["GATE_FINANCE_LEAD", "GATE_RECIPIENT_TENANT"]runtime_controls.must_escalate = ["tax_compliance_signal"]evidence_manifestlistsinvoice_lookupandrecipient_consent_proofas required.
3. Plan
{
"plan_id": "plan_inv_22",
"steps": [
{ "id": "s1", "tool": "adp_invoices.lookup", "params": { "invoice_id": "inv_8810" } },
{ "id": "s2", "tool": "adp_policy.eval", "depends_on": ["s1"] },
{ "id": "s3", "tool": "adp_recipient.notify", "depends_on": ["s2"], "approval_mode": "delegated", "requires": ["GATE_RECIPIENT_TENANT"] },
{ "id": "s4", "tool": "adp_gl.post_credit_entry", "depends_on": ["s3"], "approval_mode": "destructive", "requires": ["GATE_FINANCE_LEAD"] }
],
"decision_checkpoints": [
{ "decision_id": "finance.invoice.credit_adjust.eligibility", "after_step": "s2" },
{ "decision_id": "finance.invoice.credit_adjust.execute", "after_step": "s4" }
]
}4. Execute through the gates
s1 (read_only) → tc_901 → ok
s2 (read_only) → tc_902 → ok
[checkpoint] eligibility → DECIDED:eligible
s3 (delegated)
→ propose with frozen snapshot snap_a (sha256:e6f1...)
→ notify recipient tenant → recipient operator approves → GATE_RECIPIENT_TENANT closed
→ tc_903 → ok
s4 (destructive)
→ propose with frozen snapshot snap_b (sha256:5a3c...)
→ finance lead approves → GATE_FINANCE_LEAD closed
→ tc_904 → ok (gl entry posted, reversal_token issued)
[checkpoint] execute → DECIDED:approvedThe session is long_running; if either approval is delayed, the runtime persists a checkpoint after each Critic verdict and is resumable by session_id.
5. Post-execution audit
After s4 succeeds, the Critic computes the post-execution audit packet:
- reconciles the posted entry against
tax_compliance_check, - emits a
memory.decision_outcomewrite proposal withreversal_tokenso a future reverse step can resolve it without recomputation, - attaches the full scorecard to the DecisionRecord.
Approval gate contract
{
"gate_id": "GATE_FINANCE_LEAD",
"request_id": "req_inv_22",
"decision_id": "finance.invoice.credit_adjust.execute",
"approval_mode_required": "destructive",
"required_approver_role": "finance_lead",
"frozen_evidence_snapshot": {
"hash": "sha256:5a3c...",
"evidence_refs": [
"tool:adp_invoices.lookup:tc_901",
"tool:adp_policy.eval:tc_902",
"tool:adp_recipient.notify:tc_903"
],
"captured_at": "2026-05-04T10:14:00Z"
},
"proposed_action": {
"tool": "adp_gl.post_credit_entry",
"params": { "invoice_id": "inv_8810", "amount_inr": 12000, "reason_code": "billing_error_correction" }
},
"ttl_seconds": 7200,
"trace_context": {
"traceparent": "00-9d29...-7c41...-01",
"baggage": "session_id=sess_inv_22,run_id=run_inv_22"
}
}The approver receives the frozen snapshot. Once approved, no parameter on proposed_action can change. A divergent action requires a new gate proposal with a new snapshot hash.
Approval response
{
"gate_id": "GATE_FINANCE_LEAD",
"decision": "approve",
"approver": "user_finance_lead_77",
"approver_assertion": { "method": "webauthn", "token_ref": "auth_3z..." },
"rationale": "Vendor-side billing error confirmed; complies with policy R_BILLING_CORRECTION_V2.",
"decided_at": "2026-05-04T10:25:00Z"
}Audit artifact contract
The runtime persists one audit record per gate:
{
"audit_record_id": "audit_inv_22_GATE_FINANCE_LEAD",
"gate_id": "GATE_FINANCE_LEAD",
"request_id": "req_inv_22",
"decision_id": "finance.invoice.credit_adjust.execute",
"approval_mode_effective": "destructive",
"frozen_evidence_snapshot_hash": "sha256:5a3c...",
"approver": "user_finance_lead_77",
"approver_assertion": { "method": "webauthn", "token_ref": "auth_3z..." },
"proposed_action_hash": "sha256:71b9...",
"executed_action_hash": "sha256:71b9...",
"match": true,
"decided_at": "2026-05-04T10:25:00Z",
"executed_at": "2026-05-04T10:25:11Z",
"reversal_token": "rev_inv_8810_2026_05_04",
"trace_id": "9d29..."
}Two properties matter most:
proposed_action_hashandexecuted_action_hashmust match — the action that ran is the action that was approved.reversal_tokenis the only safe way to undo the operation; it lives in promoted memory under thedecision_outcomewrite class.
Approval + audit sequence
Error packets
Approval denied
{
"audit_record_id": "audit_inv_22_GATE_RECIPIENT_TENANT",
"gate_id": "GATE_RECIPIENT_TENANT",
"decision": "deny",
"approver": "user_recipient_finops_3",
"rationale": "Counterparty disputes credit basis; require formal billing dispute first.",
"frozen_evidence_snapshot_hash": "sha256:e6f1..."
}The Critic returns escalate; the DecisionRecord status becomes REJECTED; no GL entry is posted.
Policy denial mid-flow
{
"tool_call_id": "tc_902",
"status": "rejected",
"policy_decision_id": "pol_2210",
"error": {
"kind": "policy",
"code": "TAX_COMPLIANCE_BLOCK",
"message": "Tax compliance check failed; manual review required."
},
"metadata": { "rule_ids": ["R_TAX_COMPLIANCE_BLOCK"] }
}runtime_controls.must_escalate triggers; the runtime emits a must_escalate envelope to the operator’s queue and the DecisionRecord status becomes ESCALATED.
Cross-tenant invariants
- The
tenant_idof the requester (tenant_acme_prod) never grants access to the recipient tenant’s records; cross-tenant reads return only the consent record. - The recipient tenant approves at the policy level; the named approver is from the recipient tenant’s role registry.
- The audit record links to both tenants; the recipient tenant has reciprocal audit access through their Trust plane.
Failure modes specific to high-risk
- Approver assertion method is weaker than the gate requires (e.g., password instead of WebAuthn) — gate refuses.
proposed_action_hashdiffers fromexecuted_action_hash— runtime aborts and emits a security event.- Reversal token lost or unindexed — the action is uninvertible; mitigated by tier-
durablewrite of the token. - Snapshot freshness exceeded by the time the approver responds — runtime re-takes the snapshot and re-prompts the approver with the new hash.
- Gate TTL elapses without a decision — DecisionRecord status
DEFERRED; resumable by session_id within the long-running window.
Common misconceptions
- High-risk is not different code. It is the same canonical contract with stricter declarations on the spec, the gate, and the approver.
- Approval is not a notification. It is a typed verdict against a frozen evidence snapshot whose hash is recorded.
- Reversal is not “try the opposite.” It is invoking the operation pointed at by
reversal_token.