« Phase 09 · Lab 01 · Track Overview
Warmup — The Control Plane, from Zero to Principal
Table of Contents
- 0. Where this sits
- 1. From first principles: what is a control plane?
- 2. Know Your Agent
- 3. The agent registry
- 4. Policy as code
- 5. The two combining rules
- 6. ABAC, and the shape of a decision input
- 7. PDP and PEP
- 8. The bundle: versioned, signed, atomically activated
- 9. Fail static — the third posture
- 10. Posture checks, and why they are graduated
- 11. Discovery is an authorization decision
- 12. Continuous authorization
- 13. Revocation latency, honestly
- 14. Evaluation as an authorization input
- 15. Tracing and lineage
- 16. The decision record
- 17. Numbers worth carrying
- 18. Interview questions, answered
- 19. References
0. Where this sits
Phase 08 answered who is asking — a credential derived, narrowed, chained and short-lived. This phase answers the next question: may they?
Those are genuinely different questions and they are answered by different machinery. Authentication is a cryptographic fact about a token. Authorization is a policy decision about a request, and unlike a signature it depends on things that change while the task runs: the agent's evaluation status, the user's entitlements, a risk score, whether an incident is open.
Phase 10 then takes the allow and makes the action safe to perform — idempotency, compensation, audit. So the three phases form a spine: who, may they, and what actually happened.
1. From first principles: what is a control plane?
Borrow the term from networking, where it is precise. A router has a data plane that forwards packets — per packet, in hardware, in nanoseconds — and a control plane that decides how to forward them, running routing protocols, converging over seconds, in software.
The split exists because the two have irreconcilable requirements:
| Control plane | Data plane | |
|---|---|---|
| Frequency | rarely — policy changes, agent onboarding | every request |
| Latency budget | seconds | microseconds to milliseconds |
| Correctness bar | must be right; a wrong route poisons everything | must be fast; a wrong packet is one packet |
| Consistency | strongly consistent, single source of truth | eventually consistent, cached locally |
| Availability coupling | should not be on the request path | is the request path |
Now map it. An AI platform's data plane is the agent runtime, the LLM gateway, the tool calls — everything that happens per request. Its control plane is the agent registry, the tool registry, the policy bundles, the evaluation pipeline: the slowly-changing truth about what exists and what is permitted.
The single most important consequence, and the one people get wrong: the control plane must not be a synchronous dependency of the data plane. If every request blocks on a call to the policy service, the policy service's availability multiplies into the platform's. Two nines of control plane makes four nines of data plane impossible, no matter how good the data plane is (Phase 00).
The fix is the same one routers use: push the decision material down, decide locally. Bundles are distributed to the enforcement points; the enforcement points evaluate in-process. The control plane is on the distribution path, not the request path.
2. Know Your Agent
KYA is the JD's own coinage, by analogy to KYC — and the analogy holds further than a slogan.
Know Your Customer exists because a bank that cannot say who its customers are cannot be held accountable for what they do with its money. KYA exists because a bank that cannot say what its agents are cannot be held accountable for what they do with its systems.
The six questions, at runtime:
- Who owns it? A named human, linked to the HR feed. Not a team alias, not a distribution list. When that person leaves, something must happen.
- What may it do? Tools, scopes, data classifications, action value limits, tenants.
- What model, at what version? Pinned. An agent whose model floats has been evaluated against a model it is no longer running.
- What has it been evaluated against, and when? Golden sets, safety suites, the score, the date.
- What is its posture right now? Anomaly signals, recent denials, an open incident, a failing canary.
- What is its lifecycle state? Draft, approved, active, suspended, retired — and who authorized the last transition.
The word doing the work in all six is runtime. An onboarding checklist describes the agent that was approved. The agent that is running may have a different model version, a stale evaluation, and an owner who left in March. A control plane that answers these from a wiki page is not answering them.
3. The agent registry
The registry is the database behind KYA, and its lifecycle is where the control lives:
draft ──approve──> approved ──activate──> active
│ │ │
│ │ suspend
│ │ ↓
│ │ suspended ──reactivate──> active
↓ ↓ ↓
retired <──────────────┴─────────────────────┘
Four properties are worth defending in review:
Draft cannot jump to active. The approval step is where a human accepts accountability. If the state machine permits the jump, someone will write the automation that uses it.
Retired is terminal. A retired agent that can be reactivated is a retired agent that will be reactivated by a rollback, with permissions nobody re-reviewed.
Suspend is reversible; retire is not. These are different operations for different reasons — incident response versus decommissioning — and merging them means incident response is destructive.
Every transition is recorded with an actor. "When did this become active, and who approved it?" is an examiner question with a one-line answer or a two-week investigation.
4. Policy as code
The claim: a rule in a wiki is a suggestion; a rule in a versioned, signed bundle is a control.
That is not a style preference. It is about what an auditor can reconcile. Given a decision record
that says "denied by rule deny-cross-tenant, policy version 2026-02-11.3", an auditor can pull
that version, read that rule, and confirm the decision followed it. Given a decision record that
says "denied", they can confirm nothing.
Policy-as-code means, concretely:
| Property | Because |
|---|---|
| Versioned | a decision references the version that produced it |
| In source control | reviewed, diffed, blamed, reverted |
| Tested | a rule with no test is a rule someone will change without knowing what it did |
| Signed | the enforcement point can prove the bundle came from the pipeline, not from a pod someone exec'd into |
| Deployed as an artifact | atomically, with the same rollback story as code |
The two production languages:
OPA / Rego — a Datalog-descended declarative language, general-purpose, deployed as a sidecar or library, with bundles served over HTTP and optionally signed. Very expressive; the expressiveness is also the complaint, because a sufficiently clever Rego policy is unreviewable.
AWS Cedar — deliberately less expressive, in exchange for being analyzable: Cedar's design
supports automated reasoning about policy sets ("can any principal ever reach this resource?"), and
its permit/forbid model with forbid-overrides is exactly the shape a bank wants. If you can
express your policy in Cedar, prefer it.
The lab uses Python callables for conditions, which buys the evaluation semantics without a parser. The honest cost appears immediately: you cannot sign a callable. A bundle digest over Python functions covers their presence, not their content. That limitation is precisely why production policy is text — text is what you sign, review and attest.
5. The two combining rules
Everything about evaluation reduces to two decisions, and a bank has no latitude on either.
Default-deny
No matching rule means DENY.
The alternative — an implicit allow for anything unmatched — is not merely riskier, it has a different failure character. Under default-deny, a forgotten case fails visibly: someone's agent stops working and files a ticket. Under default-allow, a forgotten case fails invisibly: an action nobody intended to permit succeeds, and you find out during an audit or an incident.
Security controls should fail in the direction that generates a ticket.
Deny-overrides
Any matching DENY beats every matching ALLOW, and evaluation does not stop at the first allow.
The second half matters as much as the first. If evaluation short-circuits on the first allow, the result depends on rule order, and a rule set whose meaning depends on order cannot be reviewed rule-by-rule — you must simulate the whole thing in your head. With deny-overrides and full evaluation, each rule means the same thing wherever it sits, and "does this rule set permit X?" is answerable by reading.
There is a real cost: you evaluate every rule on every request. With a few hundred rules and cheap conditions that is microseconds, and it is worth it. Past a few thousand you need indexing — which is what OPA's partial evaluation and Cedar's slicing do.
And a third thing to record
The decision should carry every rule that matched, not just the winner. In a policy incident the first question is never "which rule denied it" — that is in the message. It is "what else fired, and did the author of rule 12 know rule 3 existed?"
6. ABAC, and the shape of a decision input
Role-based access control asks what role does the caller have? Attribute-based access control asks what are the attributes of the subject, the action, the resource and the environment? — and it is the only one of the two that can express the rules a bank actually has.
"A payments agent may release a payment under 100,000 AED, in its own tenant, during business hours, when two humans have approved, when its evaluation is fresh, and when the anomaly score is low" is one ABAC rule and about forty RBAC roles.
The four-part input:
Subject — and here is the part specific to agentic systems: the subject is blended. An agent acting for a user is constrained by both. The agent's registration bounds what it may ever do; the user's entitlements bound what it may do now, for this person. Model them as one subject carrying both identities, plus the delegation chain from Phase 08, and write rules against either half.
A subject with an agent and no user is a workload acting on its own behalf — a genuinely different,
narrower thing, and your policy must be able to tell. deny-irreversible-without-user is a
three-line rule that exists only because the model distinguishes them.
Action — a verb, namespaced. Wildcards on the namespace (payments.*) keep rule sets small, and
the classic bug is a prefix check against the wrong string, so pay.* matches payments.release.
Resource — type, id, tenant, classification, and any barrier marking. In a bank, tenant and
classification carry most of the weight, and they are the two attributes most often left off the
first design.
Environment — everything about now: time, channel, approvals collected, step index, and the posture signals. The environment is what makes authorization continuous rather than static. If your decision input has no environment, you have not built continuous authorization; you have built a permission check with extra steps.
7. PDP and PEP
Two acronyms from XACML, worth knowing because everyone uses them:
- PDP — Policy Decision Point. Evaluates policy, returns a decision. Knows the rules.
- PEP — Policy Enforcement Point. Sits in the request path, asks the PDP, enforces the answer. Knows nothing about the rules.
The separation is what lets one policy govern many enforcement points: the action gateway, the retrieval layer, the MCP server, the model gateway. Each is a PEP; there is one policy.
The deployment question is where the PDP runs:
| Shape | Latency | Availability | Consistency |
|---|---|---|---|
| Remote PDP service | a network hop per decision | its availability multiplies into yours | immediate |
| Sidecar (OPA next to each PEP) | ~sub-ms, loopback | fails with the pod, which is correct | bundle-refresh lag |
| Embedded library | in-process | none added | bundle-refresh lag |
For a per-step authorization on an agent's critical path, take the sidecar or the library. The remote PDP is the shape that produces the incident where policy latency became platform latency.
And note what you buy the availability with: staleness. That is the trade, and the next two sections are about managing it honestly.
8. The bundle: versioned, signed, atomically activated
A bundle is the deployable unit of policy: a version, a rule set, a signature.
Three properties, each earning its complexity:
Versioned — so the decision record can name it, and so you can answer "what did policy say last Tuesday?" without a git spelunk.
Signed — so the enforcement point can verify the bundle came from the build pipeline. Without it, anything that can write to the bundle store can rewrite the bank's authorization rules, and the decision record will faithfully log the fabricated version.
Atomically activated — the swap is a pointer move. There is never a moment when half the old rules and half the new ones are live, which would produce a policy state that never existed in source control and cannot be reproduced.
Then the three things a distributor must refuse, and why the refusal is the feature:
- Unsigned or badly signed — obviously.
- Structurally invalid — duplicate rule names, or an ALLOW rule with every facet empty. That
last one is an unconditional allow-everything, it is never intended, it is silent, and it is a
forgotten
actions=away. - Older than the active bundle — a replayed old bundle is a policy rollback attack. An attacker who can replay yesterday's bundle can undo this morning's emergency restriction without forging anything.
In all three cases the previous bundle stays live. Which brings us to the important idea.
9. Fail static — the third posture
What does the enforcement point do when it cannot reach the control plane?
Everyone knows two answers. Fail open — allow — is a security hole with a friendly name; it is also, empirically, what systems do when nobody decided. Fail shut — deny — sounds correct and is usually wrong, because it makes the control plane's availability a hard multiplier on the data plane's. The mode where "the policy service had a bad deploy so the bank's agents stopped" is a fail-shut design working exactly as specified.
The third answer is fail static: keep enforcing the last known-good bundle, alarm on staleness, and hard-stop eventually.
It is right because of an asymmetry: policy changes slowly. A bundle that is five minutes old is almost certainly still correct. A bundle that is five hours old might be missing this morning's emergency restriction. So:
| Threshold | Typical | What it means |
|---|---|---|
| Refresh interval | 30 s | how often we try |
| Staleness alarm | 5 min | somebody is told; the platform keeps running |
| Hard stop | 30 min | we refuse to serve — a bundle this old in a bank is worse than an outage |
The hard stop is what makes fail-static defensible rather than a euphemism for "we stopped checking". It is fail-shut, deliberately, at a threshold you chose and can state.
Two implementation details that are easy to get wrong and matter:
A rejected push must not reset the staleness clock. Measure age from the last successful activation. If a rejected bundle counts as a refresh, a source that returns garbage forever looks perfectly healthy, and staleness never fires — which is the exact scenario staleness exists for.
Failure must be loud even while it is being tolerated. Fail-static without an alarm is indistinguishable from working, right up until the hard stop takes production down with no warning.
10. Posture checks, and why they are graduated
Posture is what makes KYA continuous. The checks:
| Check | Signal |
|---|---|
| Lifecycle state | not ACTIVE |
| Ownership | no owner, or an owner who left |
| Model pinning | no pinned version |
| Evaluation freshness | last evaluation older than the threshold |
| Anomaly | behaviour deviating from the agent's own baseline |
The subtlety is that these do not all bite equally hard, and treating them uniformly fails in both directions:
- Categorical — a suspended agent should do nothing at all. An ownerless one has no accountable human. These stop reads too.
- Graduated — an agent whose evaluation went stale this morning is not dangerous to read with, but has no business releasing a payment.
Treat everything as categorical and a late eval job takes the fleet offline — after which operators raise the thresholds until the control never fires, and you have a control in name only. Treat everything as graduated and a suspended agent keeps reading customer data.
The same split applies to discovery: under a graduated failure, show the read capabilities only. That is more honest than showing everything and refusing at call time, and it keeps the model from planning around a tool it cannot use.
On anomaly scores: they are the softest input here, and the one most likely to be waved at in a design review. If you put one in your design, be ready to say what feeds it (deviation from the agent's own historical tool-call distribution is the usual honest answer), what the false-positive rate is, and what an operator does when it fires. An anomaly score nobody can explain is a number that gets ignored.
11. Discovery is an authorization decision
The rule: a capability the principal cannot use must not be visible.
The reasoning is specific to agentic systems and worth being able to state:
- A tool's name and description are information.
treasury.execute_trade — Execute a trade against the wholesale booktells an attacker what exists. - A model that can see a tool will eventually try to call it. Not maliciously — because it is pattern-matching on a plausible plan. Every such attempt is a denial to investigate.
- Worse, an injected instruction in retrieved content can name a tool the model would not have chosen. If the tool was never in the list, the injection has nothing to reference (Phase 11).
So tools/list is filtered per principal, per request, by the same policy that would decide
tools/call. Not by a static per-agent allowlist — by the policy, so that a tenant restriction or a
posture failure changes the visible surface, not just the callable one.
This is the same filter-before-you-list rule as MCP discovery in Phase 02 and agent-card discovery in Phase 03, now at platform scope. It shows up three times because it is a general principle: in an agentic system, visibility is capability.
12. Continuous authorization
The static model: authenticate at session start, cache the permissions, run.
Why it breaks for agents, in one sentence: an agent task can run for an hour, and the conditions that admitted it at minute zero may not hold at minute fifty. The user's entitlements changed. The agent's evaluation expired. An incident opened. The agent was suspended.
Continuous authorization re-evaluates at each consequential step. The implementation problem is immediate: if every step is a full evaluation, you are back to the PDP on the critical path.
The answer is a lease — a cached decision with a TTL — plus explicit invalidation:
reuse the lease ⟺ it exists
∧ now - issued_at < ttl
∧ the action is not high-impact
∧ the agent is not revoked
∧ lease.policy_version == active bundle version
Each conjunct is load-bearing:
- The TTL bounds how stale a decision can be. It is your revocation SLA.
- High-impact is never leased. Reads are frequent and cheap to re-decide wrongly; payment releases are rare and expensive. The actions worth caching are exactly the ones not worth caching.
- Revocation is the kill switch, below.
- The policy version is the one people forget. Without it, a new bundle takes effect one TTL after activation — so your carefully atomic activation is followed by a minute of the old policy, and the decision records during that window name a version that is no longer active.
And a rule that looks like an optimization and is a correctness property: cache allows, never denies. A cached deny delays reinstatement by a TTL. Fixing the problem and still being denied for sixty seconds is how operators learn to distrust the system.
Note what the lease fingerprint must exclude: the volatile environment. If the tick and the anomaly score are part of the key, every request is a miss and the lease is decorative. Excluding them is what makes leases work — and is precisely why the TTL and the explicit invalidations have to carry the weight.
13. Revocation latency, honestly
You will be asked: "you've suspended an agent — how long until it stops acting?"
The honest answer has three terms:
worst case = lease TTL + bundle refresh interval + in-flight action duration
With a 60-second lease and a 30-second refresh, an agent that just started a two-minute tool call can still be acting three and a half minutes after you clicked suspend.
For a read agent that is fine. For one that can move money it is not, and the fix is a kill switch: a separate, low-latency channel that pushes revocation to enforcement points directly rather than waiting for the next poll.
A kill switch has two halves, and both are necessary:
- Drop the live leases — this is what makes it fast.
- Mark the agent revoked — this is what keeps it fast, because a request arriving one millisecond later would otherwise mint a fresh lease from a control plane that has not yet caught up. Without this, the kill switch has a race with the very traffic it is trying to stop.
The cost is honest and should be stated: the kill switch is a push channel, so it is a new availability dependency and a new attack surface. A forged revocation is a denial of service against your own platform, so it must be authenticated as carefully as the bundle.
And the anti-signal to avoid: claiming revocation is instant. It is not. Say the number.
14. Evaluation as an authorization input
Most platforms run evaluations. Golden sets, safety suites, regression gates — a pipeline, a dashboard, a Slack alert when the score drops.
The idea that makes it a control is one wire: evaluation status is an input to the authorization decision. An agent whose safety suite has not run in a week, or whose last run failed, cannot act on anything consequential.
That single link changes what the eval pipeline is. A dashboard is a thing people look at when they remember. An authorization input is a thing that stops the agent. Nobody has to remember.
Two design points:
A safety failure is disqualifying regardless of score. An agent that passes 98 of 100 cases, where the two failures are "leaked another customer's balance" and "followed an injected instruction", has a 0.98 and must not ship. An aggregate that can average away a safety failure is a gate that does not gate. Count them separately; gate on the count, not the mean.
Regression against the baseline is its own gate. 0.92 is a fine score and a serious problem if last week was 0.97. Absolute thresholds miss drift; comparative ones catch it.
15. Tracing and lineage
The JD asks for "tracing and lineage at agent and tool granularity", which is a precise requirement: one span per agent step and per tool call, not one per HTTP request.
Each span carries, beyond the usual:
| Field | Why |
|---|---|
agent_id | which agent |
user_id | on whose behalf |
tenant | which book of business |
policy_version | which rules decided |
decision | what they decided |
model_version | which model produced the reasoning |
Because every span carries these, the examiner's question — "what produced this outcome?" — becomes a query over one trace, returning the agents, the users, the tools, the models and the policy versions involved. That is lineage: not a log you grep, but a structure you query.
Two mechanical points that are unglamorous and cause real incidents:
Use one clock. A span whose started_at comes from a different source than its ended_at
produces negative durations, which look like a bug in your dashboards and are a bug in your
instrumentation.
Derive span ids. A counter or a hash, not uuid4(), if you want a test that can assert on a
trace. In production you want real ids — but the discipline of "could I reproduce this trace
exactly?" is what makes traces testable.
OpenTelemetry's GenAI semantic conventions give you the attribute names for the model half
(gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens). Use them
(Phase 14); a proprietary attribute scheme is a
migration you will do later under pressure.
16. The decision record
The output of the control plane is not a boolean. It is a record:
| Field | Why it is there |
|---|---|
effect | the answer |
reason | human-readable, for the operator and the log |
rule_name | which rule decided |
policy_version | the field that makes this evidence |
matched_rules | everything that fired, for incident review |
obligations | things the PEP must do — mask a field, log to the audit stream, require a second approver |
evaluated_at | when |
| trace id | ties it to §15 |
The one to defend in review is policy_version. Without it, a decision record is an assertion.
With it, an auditor can pull the version, read the rule, and confirm the decision followed the
policy that was live at the time. That is the difference between a log and evidence.
And note the case people forget: a posture denial never consulted policy, so there is no matching rule — but it must still carry the policy version. It is exactly the record an examiner will ask about, because "the system refused" is more interesting than "the system allowed".
17. Numbers worth carrying
| Quantity | Value | Where it comes from |
|---|---|---|
| Bundle refresh interval | 30 s | fast enough that policy pushes feel immediate |
| Staleness alarm | 5 min | ~10 missed refreshes: a real problem, not a blip |
| Hard stop | 30 min | a bank's tolerance for policy that might be missing an emergency rule |
| Decision lease TTL | 60 s | the revocation SLA you are prepared to state |
| Kill-switch propagation | < 1 s | the point of having one |
| Worst-case revocation | TTL + refresh + in-flight ≈ 3.5 min | be able to derive this on a whiteboard |
| Sidecar PDP latency | < 1 ms | loopback, in-process evaluation |
| Remote PDP latency | 5–20 ms | plus its availability multiplying into yours |
| Rules before you need indexing | ~1,000 | below that, evaluate them all |
| Evaluation freshness threshold | 24 h – 7 d | by autonomy band; tighter for anything irreversible |
| Safety failures tolerated | 0 | not a threshold, a floor |
18. Interview questions, answered
Q1. "What is a control plane, and what belongs in it?"
The control plane is the slowly-changing truth about what exists and what is permitted: the agent registry, the tool registry, policy bundles, the evaluation pipeline. The data plane is everything that runs per request: the agent runtime, the gateway, the tool calls.
The reason to be careful about the split is availability. If the data plane calls the control plane synchronously on every request, the control plane's availability multiplies into the platform's — two nines of policy service makes four nines of platform impossible. So the control plane sits on the distribution path, not the request path: bundles are pushed down, decisions are made locally, in-process.
That buys availability with staleness, and managing that staleness honestly — a refresh interval, a staleness alarm, a hard stop — is most of the design.
Q2. "Walk me through what happens when an agent asks to call a tool."
Six steps.
One, identity. The request carries a credential derived from the user's assertion, narrowed to this task, with the delegation chain — so we know it is agent A acting for user U via orchestrator O.
Two, KYA posture. Is the agent active, owned, on a pinned model, recently evaluated, behaving normally? These are runtime facts, and they short-circuit before we spend anything on policy. They are also graduated: a stale evaluation blocks a payment release and not a read.
Three, policy. Build the four-part input — the blended subject, the action, the resource with its tenant and classification, the environment with the posture signals and any approvals collected — and evaluate default-deny, deny-overrides. Every rule is evaluated, not just until the first allow.
Four, the decision record. Effect, reason, the rule that decided, every rule that matched, the policy version, and any obligations.
Five, enforcement. The PEP applies the obligations — mask a field, require a second approver — and performs the action through the action gateway, which owns idempotency and compensation.
Six, the trace. A span per step, carrying agent, user, tenant, policy version, decision and model version, so the whole thing is reconstructable.
And the step that only exists in a continuous model: before step three, check for a live lease — and drop it if the bundle version changed, if the agent was revoked, or if the action is high-impact.
Q3. "The control plane is down. What happens?"
Not fail-open — that is a hole. Not fail-shut — that makes control-plane availability a hard multiplier on the data plane, and it is the design that produces "the policy service had a bad deploy so the bank's agents stopped."
Fail static. Keep enforcing the last known-good bundle, because policy changes slowly and a five-minute-old bundle is almost certainly still right. Alarm on staleness at five minutes so somebody is working on it while the platform keeps running. Hard-stop at thirty, because a bundle that old might be missing this morning's emergency restriction, and at that point refusing is safer than guessing.
Two details I would check in a review. Staleness is measured from the last successful activation, so a source returning garbage does not look healthy. And the alarm has to be loud while the failure is being tolerated — fail-static without an alarm is indistinguishable from working, right up until the hard stop takes production down with no warning.
Q4. "Why is capability discovery an authorization decision?"
Because in an agentic system, visibility is capability.
A tool's name and description are information — treasury.execute_trade tells an attacker what
exists. And a model that can see a tool will eventually try to call it, not maliciously but because
it is pattern-matching on a plausible plan; every such attempt is a denial someone investigates.
The sharpest version: an injected instruction in retrieved content can name a tool. If the tool was never in the list, the injection has nothing to reference.
So tools/list is filtered per principal, per request, by the same policy that would decide
tools/call — not by a static allowlist, so that a tenant restriction or a posture failure changes
the visible surface too. And under a graduated posture failure I show the read tools only, rather
than showing everything and refusing at call time.
Q5. "How long after I suspend an agent does it stop acting?"
Worst case is the lease TTL plus the bundle refresh interval plus the in-flight action duration. With a 60-second lease and a 30-second refresh, an agent that just started a two-minute tool call can still be acting three and a half minutes later.
For a read-only agent that is acceptable. For one that can move money it is not, so there is a kill switch: a separate low-latency channel that pushes revocation directly.
It has two halves. Dropping the live leases makes it fast. Marking the agent revoked keeps it fast — otherwise a request arriving a millisecond later mints a fresh lease from a control plane that has not caught up, and the kill switch races the traffic it is trying to stop.
The cost is honest: the push channel is a new availability dependency and a new attack surface, so a revocation message has to be authenticated as carefully as a bundle. What I would not say is that revocation is instant. It is not, and the number is the answer.
Q6. "Why should evaluation status affect authorization?"
Because otherwise the evaluation pipeline is a dashboard, and dashboards are things people look at when they remember.
One wire changes it: evaluation freshness and outcome become inputs to the policy decision. An agent whose safety suite has not run in a week cannot release a payment. Nobody has to notice; the control enforces itself.
Two design points I would defend. A safety failure is disqualifying regardless of score — an agent that passes 98 of 100 where the two failures are "leaked another customer's balance" and "followed an injected instruction" has a 0.98 and must not ship. And regression against a baseline is its own gate, because 0.92 is a fine number and a serious problem if last week was 0.97.
I would also make the freshness threshold depend on the autonomy band: a read-only agent can go a week, an agent that moves money gets twenty-four hours.
Q7. "Default-deny and deny-overrides — why both, and what do they cost?"
Default-deny means no matching rule denies. The point is not that it is stricter, it is that it fails in the direction that generates a ticket: a forgotten case means someone's agent stops and files a bug, rather than an unintended action succeeding quietly until an audit finds it.
Deny-overrides means any matching deny beats every allow, and — the half people drop — evaluation does not stop at the first allow. That is what makes the rule set order-independent, and order-independence is what makes it reviewable: each rule means the same thing wherever it sits, so "does this permit X?" is answerable by reading rather than by simulating.
The cost is that you evaluate every rule on every request. At a few hundred rules with cheap conditions that is microseconds and worth it; past a few thousand you need indexing, which is what OPA's partial evaluation and Cedar's slicing exist for.
I would also record every rule that matched, not just the winner — in a policy incident the first question is what else fired.
19. References
Specifications and standards
- NIST SP 800-207 — Zero Trust Architecture
- NIST SP 800-162 — Attribute Based Access Control
- XACML 3.0 — where PDP/PEP and the combining algorithms come from
- OpenTelemetry — GenAI semantic conventions
Policy engines
- Open Policy Agent · Rego · bundles · bundle signing
- AWS Cedar · Cedar: A New Language for Expressive, Fast, Safe, and Analyzable Authorization
- Google Zanzibar — relationship-based authorization at scale
- OpenFGA — an open Zanzibar implementation
Continuous authorization
- Microsoft Entra — Continuous Access Evaluation
- Microsoft Entra — Conditional Access
- Shared Signals Framework (OpenID)
Agent governance and evaluation
- OWASP Top 10 for LLM Applications
- NIST AI Risk Management Framework
- Azure AI Foundry — evaluation
- Promptfoo · RAGAS · LangSmith evaluation
Background
- Google SRE Book — Chapter 22, Addressing Cascading Failures
- Release It!, Nygard — stability patterns, including the static-fallback shape