Skip to content

Controls and governance

This page maps each control in the desk to what an auditor or a risk team asks about: financial controls (SOX and the COSO framework), AI risk management (the NIST AI RMF and ISO/IEC 42001), and the OWASP Top 10 for LLM applications. It also describes how people oversee the agents while they run.

What this mapping is

The mapping names each framework's functions and themes, not its clause numbers. It is a starting point for an assessment of a real deployment, not a certification. A real deployment adds its own processes: model approval, incident response, vendor contracts.

The control matrix

Control Enforced by Evidence SOX / COSO NIST AI RMF ISO/IEC 42001 OWASP LLM
The agent cannot move money; it proposes Tool design: no ERP command tool Tool list; every scenario Authorization Manage Use of AI systems LLM06 Excessive Agency
Each decision goes to the role the policy names OPA routing; the workbench checks the role PolicyRoutingTest, ap_test.rego Authorization and approval Govern, Manage Use of AI systems LLM06
The ERP checks the decider's authority again, with the decider's own token ERP authority matrix AuthorityMatrixTest Segregation of duties; authorization limits Manage Use of AI systems LLM06
A bank change needs a call-back and a second person ERP vendor master BankChangeVerificationTest; bank-change-fraud Segregation of duties; fraud prevention Manage Use of AI systems LLM06
Nothing pays a vendor with an unverified bank change, or a repeated invoice number OPA and the ERP bank-change-fraud, injected-invoice Fraud prevention Manage Use of AI systems LLM01 Prompt Injection
Nothing pays an invoice after a credit memo was requested for it OPA (creditMemoRequested) ap_test.rego Authorization; fraud and error prevention Manage Use of AI systems LLM06
A tool the policy does not name is refused OPA allowlist ap_test.rego IT general controls: change management Govern AI system life cycle LLM06
Mail never reaches the agent; a model with no tools reads it into a typed reading Occlude quarantine; the reader QuarantineDeclarationsTest, ReaderWiredTest; the injection scenarios Information integrity Measure, Manage Data for AI systems LLM01
A case whose mail tried to give instructions cannot move money OPA (instructionsSeen) injected-reply Information integrity Manage Data for AI systems LLM01
A vendor's claim becomes a fact only when the ERP confirms it Occlude's one endorsing gate vendor-names-the-po Information integrity Measure Data for AI systems LLM01, LLM09 Misinformation
A proposal may cite only ids that a tool returned OPA (ungroundedCitations) GroundingGateTest Supporting documentation Measure AI system life cycle LLM09
Vendor-written text reaches the agent only shaped like a reference VendorReference, CaseInputRenderer VendorReferenceTest, CaseInputRendererTest Information integrity Manage Data for AI systems LLM01, LLM05 Improper Output Handling
Decidable cases are settled by rules, never by a model DMN decision tables ResolverTest; the determinism check Consistent application of policy Map, Manage AI system life cycle LLM09
The rules' proposals go through the same policy and deciders ResolverDesk ResolverDeskTest Authorization Manage Use of AI systems —
Every proposal records what produced it Provenance DecisionFlowTest, ResolverDeskTest Audit trail Govern, Measure AI system life cycle; information for interested parties —
Every read and refusal of quarantined mail is recorded, signed and chained Occlude's record RefusalLogTest Audit trail Govern Data for AI systems LLM02 Sensitive Information Disclosure
Stored agent history is encrypted Nessy's storage codec (AES-256-GCM) ReaderWiredTest IT general controls: access Manage Data for AI systems LLM02
People can pause the agents at runtime GuardedAgents; the workbench and /api/oversight OversightTest Monitoring activities Manage Use of AI systems LLM06
Each case's agent has a budget GuardedAgents, AgentBudget OversightTest Monitoring activities Manage Use of AI systems LLM10 Unbounded Consumption
At most 3 letters to one recipient on a case MailTools MailToolsTest — Manage Use of AI systems LLM10
A case left with nobody acting goes to a person NeedsPerson; the rules' sweep NeedsPersonTest, ResolverDeskTest Monitoring activities Manage Use of AI systems —
The desk's proposals and Nessy's waiting approvals agree ApprovalDrift ApprovalDriftTest Monitoring activities; completeness Manage Use of AI systems —
The auditor's trail shows the facts each approver was shown Nessy's approval facts; TrailController DecisionApiTest Audit trail Govern, Measure AI system life cycle —
The whole desk is measured before a change ships ap-eval: 29 scenarios, attacks, confidence intervals The results IT general controls: change management Measure AI system life cycle LLM01, LLM09

A decision's provenance

Every proposal records what produced it:

Field What it names
proposer rules or agent
agentModel The agent's model. None for a proposal from the rules.
readerModel The model that reads vendor replies
deskBuild The desk's git commit
playbook The agent's playbook
rules The decision tables
policy The routing policy, as OPA held it when the proposal was routed

Each document is named by the first 12 hex digits of its SHA-256. The case view, the auditor's trail (/api/cases/{id}/trail) and the workbench show the provenance with each proposal. To answer "why did the desk do this?", compare these values with the versions in the repository's history.

People's oversight while the agents run

Every input for a case agent passes one door, GuardedAgents. There, two controls apply.

  • Pause the agents. A controller pauses the agents on the workbench, or with POST /api/oversight/agents/pause. The switch is stored, so it survives a restart, and every change is recorded with who made it and when. While the agents are paused, the rules keep working. Anything an agent would be told is held, and its case goes to a person. When a controller resumes the agents (POST /api/oversight/agents/resume), each held input goes to its agent, oldest first.
  • A budget for each case. A case's agent may use 12 turns or 200,000 input tokens, whichever comes first (ap.agents.budget.turns, ap.agents.budget.input-tokens). Past that, the agent is told nothing more, and the case goes to a person. In the full runs, the busiest scenario used about 50,000 input tokens for each case.

Metrics, and the alerts to set

The desk publishes these counts through Micrometer and the actuator (/actuator/metrics):

Metric What it counts
ap.proposals{proposer, action} Proposals that reached a person
ap.cases.settled{by, status} Cases resolved or put on hold, by the rules or by the agent
ap.rules.escalated{why} Cases the rules gave to an agent, and why
ap.occlude.refusals{reason} Operations the quarantine refused
ap.agents.held{reason} Inputs held by a pause or by a spent budget
ap.agents.paused 1 while the agents are paused
ap.approvals.drift{side} At the last check: pending proposals for which Nessy lists no waiting call (unheld), and calls Nessy lists as waiting on a person with no proposal (unseen). Each is confirmed by a second reading.

Nessy publishes a meter for each model call, gen_ai.client.operation.duration, and the desk exposes it with its own. Its tag gen_ai.response.finish_reasons is length for an answer cut off at the output limit, and error for a failed call; error.type names the failure. The desk does not count these again.

  • The meter counts the calls of the case agents and of the quarantined reader together.
  • A call that Nessy retries counts once for each attempt. A retry inside the vendor's own SDK is part of one attempt and is not counted apart.
  • A failed call that a retry then fixed still counts as error.

Suggested alerts. The thresholds are starting points, set from the full runs:

Alert Condition Why
The agents stay paused ap.agents.paused is 1 for more than an hour A pause that someone forgot stops every case that needs judgment.
The rules fail ap.rules.escalated{why="failed"} or {why="unread"} rises The ERP or the desk is failing. Cases are going to the agents for the wrong reason.
The agent's share grows Escalations divided by proposals goes above about 50% (the full runs: about 35%) New kinds of exception, or a change in the ERP's data, are reaching the agents.
A real refusal ap.occlude.refusals with any reason except DECLINED A person tried to read mail they may not, or a derivation failed.
Budgets are spent ap.agents.held{reason="budget"} above zero An agent loops, or a model changed. Look at the case.
Approvals drift ap.approvals.drift above zero The workbench and Nessy disagree about what waits on a person. A person may decide a proposal that no call hears, or a call may wait with nobody to see it. Read the desk's WARN log for the ids.
Answers are cut off gen_ai.client.operation.duration with gen_ai.response.finish_reasons="length" rises A model runs into its output limit. When it is a case agent with nothing in motion, the case goes to a person, and the timeline says the answer was cut off.
Model calls fail gen_ai.client.operation.duration with gen_ai.response.finish_reasons="error" rises The provider or the network is failing. When a case agent's turn fails, the case goes to a person with the kind of failure on its timeline.
The agent parks more Agent-settled cases that end ON_HOLD rise compared with resolved ones The agent decides less, and people do more.

Usage for each case, by model, is at /api/cases/{id}/usage.

What is still missing

  • Retention. Stored agent history never expires, and Occlude's erasure cannot reach the reader's copy (Nessy finding F13).
  • The model provider. Vendor data goes to a hosted model. A deployment needs the provider's data-processing terms and a decision on retention.
  • The breadth of the attacks. The evaluation has six attacks written by hand. Current practice adds attacks that a model generates and adapts, attackers over several turns, and attachments, which the desk does not read yet.
  • The quality of human oversight. The evaluation approves what it is asked to approve. Nothing measures whether a person looks at the evidence before approving.
  • The evaluation as a release gate. The full evaluation needs a model and costs money, so CI does not run it. A deployment runs it before each release and keeps the report.