Bound the Parameters
Last reviewed · content updated
IntermediateWhat you'll learn
~18 min- Read a run-budget denial and explain why counting from the receipt chain, not an in-memory counter, makes a budget authorization-bearing
- Read a seven-row table of agent-permission surfaces and name where each one's enforcement actually sits, and as of when
- Recognize a budget that only binds a caller using the polite API, and name the fix
Before the detail — Decision: bound how much of the world one unattended action, and one unattended run, may move (its blast radius) — not just which actions are allowed. Outcome: a run that cannot be talked into fourteen crews when its envelope allows three, and cannot outrun its receipt-derived budget after a restart. Artifact: a run-budget denial receipted by name, and a seven-row table naming where the same idea is enforced, and where it is only a hint, across seven agent-permission surfaces today. Status of what follows: reusable guidance, dated where the practice memo dates it.
Prompt first: size the blast radius before the first run
Read-only: for one action-taking agent, list every parameter of everytool it can call, and answer three questions for each: - what is the largest single value this parameter could carry that would still look like a normal request? - how many times could this action run before someone notices, inside one hour? - is there a budget enforced anywhere that would stop it before that count is reached?
Where the third answer is "no", say so plainly rather thanestimating a number that has never been tested.A parameter bound answers “how much can one call move”; a run budget answers “how much can one run move before anyone looks” — they are different numbers, and a policy that only sets the first has answered half the question.
Blast radius is a number, and this run’s is enforced
MU-AI-011’s envelope declares both kinds of bound on the same action. pre_position_crew accepts crews between 1 and 3 — a single-call limit. max_actions_per_run: 10 counts prior agent-action receipt rows for the run; max_mutating_actions_per_run: 4 counts prior non-read-only outcomes that touched the target. The first caps attempted actions; the second caps changes — two different counts, not one ceiling read twice. On the training’s own storm night, the agent’s plan calls for fourteen crews in one move against a feeder carrying the night’s highest risk. The guard’s answer is immediate, and it never reaches a second step:
STEP - DENY 'crews'=14 exceeds the envelope maximum 3RESULT denied exit 3The committed nine-call anchor records this denial as 3:3 — call 3, exit 3.
The run budget is the sharper case, because it is not a static ceiling — it is counted live from the receipt chain the guard has already written for that run. A separate run against the same envelope drafts four work orders, each one a mutating action, and the fifth is refused before anything is planned:
STEP - DENY run RUN-BUDGET-01 has already changed the target 4 times; the budget max_mutating_actions_per_run=4 is spent, and 'draft_work_order' is class=reversibleRESULT denied-over-budget exit 3Counting from the chain rather than from a counter in memory is what makes the budget mean something under audit: an in-memory count resets the moment the process restarts, and a log the agent itself could edit would let the same agent edit its own ceiling. That is exactly why the receipt store is not a path this agent may write to — a fact Lesson 2.4 makes literal in the envelope’s own list of writable state paths.
Seven permission surfaces and their enforcement points
These surfaces do not all express a numeric budget. The table separates what each exposes from where enforcement sits, showing where a custom run budget would have to live:
| Surface | Policy is expressed as | Enforced at | As of |
|---|---|---|---|
| Claude Code | permissions.allow/ask/deny; three consecutive or twenty total blocks pause auto mode, not configurable | CLI harness, outside the prompt | 2026-08-29 |
| OpenAI Agents software development kit (SDK) | needsApproval / needs_approval; input, output, and tool guardrails | your own process — the SDK’s own guidance is to “add review and enforcement to your own harness” | undated |
| Copilot CLI | --allow-tool / --deny-tool / --allow-all; a trusted-directories list; ~/.copilot/permissions-config.json | CLI harness | 2026-08-29 |
| Azure SRE Agent | per-tool allow, ask, or deny across three scopes, up to 1,000 patterns per scope | the agent service, before the call is made | 2026-06-02 |
| AgentCore | Cedar — Amazon Web Services (AWS)‘s policy language — plus Dogwood, its session-temporal extension — approval granted before a transfer, action-count caps, a running total kept under a budget | the Gateway, outside the agent’s own code | 2026-08-29 |
| MCP | a tool’s own annotations — hints a client reads at its own discretion, never a bound | wherever the client chooses to enforce one; the protocol enforces nothing itself | 2025-06-18 |
| org policy | Azure Policy’s deny effect; an AWS service control policy that defines a guardrail but grants no permission | before the Azure Resource Provider; during AWS identity evaluation for member accounts | 2025-03-04 · 2026-08-29 |
Five rows are runtime or harness permission surfaces. Model Context Protocol (MCP) supplies hints but enforces no authorization bound; organization policy is an outer guardrail that can constrain requests regardless of runtime. This training’s own guard adds a behavior none of the seven reproduce: it recounts the receipt chain on every attempt rather than trusting a number a runtime remembered from earlier in the session.
A team choosing where to build its own budget is choosing how many products it has to re-verify when one of them changes its defaults — the fewer surfaces holding the number, the fewer places a contract renewal or a version bump can quietly move it.
The budget that binds only the polite caller
A budget enforced on one verb does nothing against a different verb that reaches the same effect. A PodDisruptionBudget — Kubernetes policy limiting simultaneous voluntary disruptions to a replicated workload — states its limit plainly in Kubernetes’ documentation: “involuntary disruptions cannot be prevented by PDBs; however they do count against the budget,” and the fix it recommends is to “use tools which respect PodDisruptionBudgets by calling the Eviction API instead of directly deleting pods.” An agent with kubectl delete pod in its toolset walks straight past a budget written for evict pod, not because the budget failed but because it was never asked the question.
The same shape of gap is what Lesson 2.1’s bypass transcript showed for this training’s own gateway: a budget counted on calls that reach the guard does nothing for a call that reaches the target directly. The fix in both cases is identical — deny the impolite verb outright rather than trust that every caller prefers the polite one, and close the direct path rather than assume nobody will use it. Lesson 5.3 reads a case where the tell was not any single call but the pace of an agent’s own requests — a budget on rate, not just on count, is the same idea one dimension further out.
No runtime in this table expires what it grants
One more gap is worth stating plainly, because it is easy to assume otherwise: as of 2026-08-29, none of the five runtimes in the table above expires a granted approval on its own. Copilot CLI’s closest equivalent is a saved approval that lasts “the remainder of the session” — a session boundary, not a clock. AgentCore’s Dogwood comes closest to the shape this training needs, expressing approval-before-transfer as a session-temporal condition rather than a permanent grant — Lesson 4.1 builds an approval token with an actual expiry on top of that same idea, because none of these five ships one.
Stop and escalate when a budget’s count comes from anywhere other than the log of record — an in-memory counter that resets on restart, a total the agent itself reports, a log the agent can trim. Whether that budget gets rebuilt on the receipt chain or the runtime gets replaced is a decision for whoever owns the receipt store’s access controls, not for whoever configured the runtime’s defaults.
An agent's toolset includes both evict_pod, which a PodDisruptionBudget can refuse, and delete_pod, which it cannot. A budget is set on evictions. What does actually bounding the blast radius require?
Key takeaway
Blast radius is a number twice over: how much one call may move, and how much one run may move before its own log is asked. MU-AI-011’s envelope enforces both, counted from the receipt chain rather than a counter that forgets on restart; seven agent-permission surfaces place that same idea at seven different points today — some enforced, one a hint by the protocol’s own admission — and none of them expiring what they grant; and a budget written for the polite verb does nothing against the impolite one that reaches the same effect. Lesson 2.3 turns this same envelope into decision tests, so a change to any of these bounds is caught before it reaches a storm night, not after.
LEADERSHIP DECISION fund one enforced run budget per action-taking agent, counted from its own receipt chain, not from a runtime's remembered totalPRACTITIONER ACTION name every verb that reaches the same effect as a bounded one, and deny the unbounded verb outright rather than trust a preference for itSUCCESS MEASURE zero standing tools that reach a bounded effect through an unbounded verb - an audit finding avoided