Skip to content
Press / to search

High-Risk Workflow

Multi-approver, irreversible, cross-tenant operations — frozen evidence snapshots, named approvers, post-execution audit.

Implementation GuideLast reviewed: Edit on GitHub
At a glance

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).

FieldValue
Intentfinance.invoice.credit_adjust
Risk classdestructive
Adaptersadp_invoices.lookup, adp_policy.eval, adp_gl.post_credit_entry, adp_recipient.notify
Decision specsfinance.invoice.credit_adjust.eligibility, finance.invoice.credit_adjust.execute
Approval gatesGATE_FINANCE_LEAD, GATE_RECIPIENT_TENANT
Required evidenceinvoice_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_manifest lists invoice_lookup and recipient_consent_proof as 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:approved

The 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_outcome write proposal with reversal_token so 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_hash and executed_action_hash must match — the action that ran is the action that was approved.
  • reversal_token is the only safe way to undo the operation; it lives in promoted memory under the decision_outcome write 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_id of 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_hash differs from executed_action_hash — runtime aborts and emits a security event.
  • Reversal token lost or unindexed — the action is uninvertible; mitigated by tier-durable write 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.