# Advanced Agents From First Principles 16: Where Should an Agent Spend Its Compute? Build a Dynamic Budget Scheduler # Book: Advanced Agents From First Principles # Chapter URL: https://programmer.ie/books/advanced-agents-from-first-principles/16-chapter/ # Prose fingerprint (sha256, normalized): 956a82d182758c07299416d61370ed8ef493839eb5e857ad851857f4781f4be2 # Snapshot generated at build time by Hugo. This is the complete rendered prose # of the chapter; it is not a transcript of the source file. Where Should an Agent Spend Its Compute? A production agent has a budget whether you designed one or not. Every model call costs something. Every search node costs something. Every tool invocation costs something. Every verifier costs something. Every retry adds latency. Every escalation to a stronger model spends money and time that could have been used somewhere else. The naive architecture gives every subsystem its own fixed limit: MAX_STEPS = 20 MAX_SEARCH_NODES = 32 MAX_CRITIC_CALLS = 3 MAX_RETRIES = 4 MAX_VERIFIER_CALLS = 2 That looks safe. It is also usually wasteful. An easy task may consume far more computation than it needs. A hard task may spend its entire budget on generation and reach verification with nothing left. A search agent may keep expanding branches even after one branch is already strongly verified. A router may escalate to a frontier model because a threshold fired even though one cheap diagnostic tool call would have resolved the uncertainty. The deeper problem is this: Fixed limits control maximum spend. They do not decide where computation has the highest expected value. That is what this post is about. We are going to turn the agent budget into a first-class scheduling problem. The agent will no longer ask only: What should I do next? It will also ask: Where should the next unit of computation go? The Control Problem By this point in the series, an advanced agent may contain: a router, one or more generators, search, critics, memory, specialist models, tool execution, escalation, and external verification. Each of those mechanisms competes for the same resources. A simplified runtime might look like this: task | scheduler ___________|____________ / / | \ \ generate search tools critic verify \ \ | / / \______\_____|_____/____/ | outcome The scheduler does not produce the answer. It decides how much computation each part of the system receives. That distinction matters. In Step 15 we separated the execution plane from the control plane. The budget scheduler belongs in the control plane. Its job is to allocate resources while preserving hard constraints such as: safety, authorization, maximum monetary spend, maximum wall-clock latency, required verification, and external service limits. Start With a Shared Budget Do not let every subsystem pretend it owns an independent budget. Start with one shared resource envelope. For example: from dataclasses import dataclass @dataclass class Budget: max_model_calls: int max_tool_calls: int max_search_nodes: int max_verifier_calls: int max_cost_usd: float max_latency_ms: int used_model_calls: int = 0 used_tool_calls: int = 0 used_search_nodes: int = 0 used_verifier_calls: int = 0 used_cost_usd: float = 0.0 used_latency_ms: int = 0 That gives us accounting. It does not yet give us scheduling. The scheduler still needs to choose between competing actions. A Budget Is Multi-Dimensional One of the easiest mistakes is to reduce everything to dollars. Cost matters. But a production runtime often has several simultaneous constraints: money latency model calls tool calls search nodes context tokens rate limits verification capacity A cheap action can be slow. A fast action can be expensive. A tool call can cost almost nothing in model tokens while being operationally risky. A verifier may be expensive but mandatory. A local model may cost little money but consume scarce GPU capacity. So instead of one scalar budget, think in terms of a resource vector. @dataclass(frozen=True) class ResourceCost: model_calls: int = 0 tool_calls: int = 0 search_nodes: int = 0 verifier_calls: int = 0 dollars: float = 0.0 latency_ms: int = 0 The scheduler asks whether an action fits inside the remaining envelope. Some Budget Must Never Be Spent Elsewhere Suppose the system has a total budget of ten model calls. A naive search policy may spend all ten generating and scoring branches. Then the runtime reaches its best candidate and says: Great. Now verify it. But there is no budget left. That architecture is broken. Verification is not optional cleanup. If a verified outcome is required, the scheduler should reserve enough capacity for verification before speculative work begins. total budget | +-- mandatory reserve | | | +-- verification | +-- safety checks | +-- required persistence | +-- adaptive budget | +-- generation +-- search +-- tools +-- critique +-- escalation This gives us a critical rule: Never let speculative reasoning consume resources required for mandatory acceptance checks. A simple implementation might expose: @dataclass class BudgetReserve: verifier_calls: int = 1 dollars: float = 0.02 latency_ms: int = 500 The scheduler allocates from the adaptive portion while protecting the reserve. The Wrong Question: How Many Steps Should the Agent Get? A fixed-step architecture asks: max_steps = 20 A better architecture asks: Is the expected value of another step greater than its cost? That is a very different control problem. Suppose the agent has already: generated two strong candidates, run the relevant tests, obtained a high-confidence external verifier PASS, and found no unresolved required criteria. Why spend another ten steps because max_steps=20? The maximum should be a ceiling, not a target. Similarly, suppose the agent is at step 19 and has strong evidence that one more diagnostic action is likely to resolve the task. A rigid fixed-step scheduler may stop exactly when spending one more cheap action has high expected value. This is why production scheduling needs both: hard ceilings, and adaptive allocation below those ceilings. Expected Value of Computation A useful way to reason about the scheduler is expected value of computation. For a candidate action a, estimate: expected gain from action ------------------------- expected resource cost We do not need perfect economics. We need something better than blind fixed allocation. A conceptual score might be: def value_score( expected_success_gain: float, expected_information_gain: float, dollars: float, latency_ms: int, risk_penalty: float, ) -> float: denominator = 1.0 + dollars * 100 + latency_ms / 1000 return ( expected_success_gain + 0.3 * expected_information_gain - risk_penalty ) / denominator The exact formula is not the point. The point is that the scheduler should distinguish actions that are likely to change the decision from actions that merely consume compute. Information Can Be More Valuable Than Generation Advanced agents often overspend on generation. The task looks uncertain, so the system produces more answers. But uncertainty does not always mean we need another candidate. Sometimes we need information. For example, a coding agent is unsure whether a bug comes from: parsing, database state, configuration, or business logic. It could generate four patches. Or it could run one cheap diagnostic test that reveals the failing subsystem. The diagnostic action may have much higher expected value. uncertainty | +-- generate another candidate | +-- inspect state | +-- run diagnostic | +-- retrieve evidence | +-- verify assumption This leads to another important rule: Allocate compute to uncertainty reduction, not just answer production. Search Budget Is Not Beam Width A fixed beam search might use: beam_width = 4 max_depth = 6 That implies a roughly fixed search shape. But the useful shape of search is task-dependent. One task may benefit from wide exploration near the root: root / / | \ \ A B C D E | C1 | C2 Another may have one obvious root decision but require deep exploration later: root | A | A1 | A2 /|\ ... alternatives appear here So the scheduler should allocate nodes, not blindly enforce a geometric pattern. It can ask: Is branch uncertainty high? Are current branches meaningfully different? Is the verifier separating them? Has the best score plateaued? Are new nodes duplicates? Is search regret historically high at this state type? Then choose whether to: expand breadth, deepen one branch, stop search, or spend the next unit elsewhere. A Simple Dynamic Search Scheduler Here is a deliberately small example: @dataclass class SearchState: best_score: float second_best_score: float unique_branch_ratio: float no_improvement_rounds: int remaining_nodes: int def choose_search_action(state: SearchState) -> str: if state.remaining_nodes <= 0: return "stop" margin = state.best_score - state.second_best_score if state.no_improvement_rounds >= 2: return "stop" if state.unique_branch_ratio < 0.5: return "stop" if margin < 0.05: return "expand_breadth" if margin < 0.15: return "deepen_best" return "verify_best" This is not sophisticated. That is intentional. A small policy with measurable features is much easier to calibrate than a vague instruction like: Decide intelligently how much search is needed. Critics Also Need a Budget Critique can improve output. Critique can also become a ritual. Consider this loop: draft ↓ critic ↓ revision ↓ critic ↓ revision ↓ critic If the critic keeps producing minor stylistic objections while external verification is already passing, the scheduler should stop paying for criticism. Useful features include: historical net correction rate, severity of unresolved issues, verifier failures attributable to the critic’s domain, disagreement between scorer and verifier, and whether previous critic passes changed the output meaningfully. A critic that often converts wrong → correct deserves budget. A critic that mostly converts correct → correct while consuming tokens may not. A critic that sometimes converts correct → wrong needs stronger gating. Escalation Is a Budget Decision Suppose you have: a cheap local model, a medium model, and an expensive frontier model. The naive policy is: try cheap if uncertain → medium if still uncertain → frontier But uncertainty alone is not enough. The scheduler should ask: Is the task currently unresolved? Is another cheap diagnostic likely to help first? Is the stronger model historically better for this failure mode? Does enough budget remain for verification after escalation? Is the expected rescue value larger than the added cost? One useful metric from Step 15 is cost per rescue. incremental escalation cost --------------------------- number of failures rescued If frontier escalation costs $50 across a benchmark and rescues one additional task, that may be acceptable in one domain and absurd in another. The scheduler needs the application’s actual constraints. Verification Should Receive More Budget When Stakes Rise Not all tasks deserve the same verification spend. For a low-consequence summarization task, one lightweight check may be enough. For a deployment agent modifying production infrastructure, the scheduler should spend far more on verification. We can model a crude risk score: @dataclass(frozen=True) class RiskProfile: reversibility: float blast_radius: float financial_impact: float external_side_effects: float Higher risk can reserve more verification budget. low-risk task generation ███████ search ███ verify ██ high-risk task generation ████ search ███ verify ███████ That is often more rational than giving every request the same verifier pipeline. Budget Scheduling Is Constrained Optimization The scheduler should not simply maximize success probability. A production objective might be: minimize expected cost and minimize latency subject to: verified success >= target false success <= limit safety violations = 0 budget ceilings respected That is a much healthier formulation than: maximize reward It keeps hard boundaries hard. For example: @dataclass(frozen=True) class SchedulerConstraints: min_verified_success: float max_false_success: float max_cost_usd: float max_latency_ms: int The scheduler can optimize below those constraints. It cannot decide that skipping mandatory verification is worthwhile because it saves money. Hard Limits Still Matter Adaptive scheduling does not mean removing ceilings. You still want hard bounds such as: maximum spend maximum wall time maximum external side effects maximum retry count maximum search nodes Adaptive scheduling operates inside those bounds. hard safety envelope ┌─────────────────────────────────┐ │ │ │ adaptive budget scheduler │ │ │ │ generation / search / tools │ │ critics / escalation / verify │ │ │ └─────────────────────────────────┘ The envelope protects the system from pathological behavior. The scheduler tries to use the allowed resources intelligently. Stop When the Marginal Value Goes Negative One of the strongest scheduler decisions is simply: Stop spending. Suppose successive search rounds produce: Round Verified success estimate Added cost 1 0.72 $0.01 2 0.83 $0.01 3 0.87 $0.02 4 0.875 $0.03 5 0.876 $0.04 The first few rounds are valuable. The last two barely move the outcome. The runtime should not treat the remaining budget as an invitation to spend it. This gives us a practical metric: marginal verified gain per additional dollar or: marginal verified gain per additional second When that value collapses, stop. But Do Not Stop Before Required Verification There is an important asymmetry here. The scheduler may stop speculative computation early. It may not skip required acceptance criteria merely because more work looks expensive. That means the runtime often has two stopping concepts: stop exploration stop task They are not the same. exploration no longer valuable ↓ stop search/generation ↓ run mandatory verification ↓ PASS / FAIL / UNKNOWN That distinction prevents a common failure where an agent treats “I have a good candidate” as equivalent to “the task is complete.” A Minimal Scheduler Interface A clean runtime can represent scheduler decisions explicitly. from dataclasses import dataclass from typing import Literal ActionKind = Literal[ "generate", "search", "tool", "critic", "escalate", "verify", "stop_exploration", "stop_task", ] @dataclass(frozen=True) class SchedulerDecision: action: ActionKind reason: str expected_value: float expected_cost: ResourceCost policy_version: str This connects naturally to the trajectory observability from Step 13. Every allocation decision becomes traceable. state_id budget_remaining actions_considered selected_action expected_value expected_cost actual_cost actual_outcome policy_version Now the budget scheduler itself can be benchmarked and improved. Use Uncertainty Carefully A scheduler will often use uncertainty as a feature. That is useful. It is also dangerous. Model confidence is not automatically calibrated. A model can be confidently wrong. A critic can be confidently wrong. A router can produce a very sharp probability distribution and still route incorrectly. So scheduling features should include external signals where possible: test results, tool outcomes, score margins, branch disagreement, verifier disagreement, retrieval coverage, historical failure rates, task type, and state changes. Internal confidence is one signal, not truth. Budget Features Should Be Small and Observable Do not feed the entire trajectory into another giant LLM and call it a scheduler. Start with compact features such as: @dataclass(frozen=True) class SchedulerFeatures: task_risk: float best_score: float score_margin: float branch_diversity: float verifier_status: str no_progress_steps: int recent_tool_failures: int estimated_task_difficulty: float remaining_cost_fraction: float remaining_latency_fraction: float Then test whether those features actually predict useful allocation decisions. If a deterministic threshold table works, use it. If not, try a small calibrated model. Only add a complex controller if the evidence shows it is necessary. Scheduler Policy as Data A production scheduler should be versionable. For example: version: scheduler-2026-08-09-a reserves: verifier_calls: 1 cost_fraction: 0.20 rules: - when: verifier_status: PASS unresolved_required_criteria: 0 action: stop_task - when: no_progress_steps_gte: 2 score_margin_gte: 0.15 action: verify - when: branch_diversity_lt: 0.40 action: stop_exploration - when: task_risk_gte: 0.8 verifier_budget_multiplier: 2.0 Now policy changes can be reviewed like code. You can diff: scheduler-2026-08-09-a vs scheduler-2026-08-20-b and ask exactly what changed. Do Not Hide Budget Behind Agent Roles Multi-agent systems sometimes hide cost by treating each role as conceptually separate. planner researcher critic reviewer judge verifier But the user pays for all of them. The scheduler should flatten role boundaries into resource accounting. planner call -> 2,400 tokens researcher call -> 3,100 tokens critic call -> 1,700 tokens judge call -> 2,200 tokens verifier tool -> 800 ms Then ask: Which of these calls actually changed the verified outcome? If the planner rarely changes the route, reduce its budget. If the critic mostly confirms already-correct answers, gate it. If the judge performs no better than a deterministic score, remove it. Budget scheduling is another way to expose unnecessary architecture. Coding Agent Example Consider a coding agent handling a failing test. A rigid architecture might do this: plan ↓ retrieve ↓ generate 4 patches ↓ critic each patch ↓ rank ↓ run tests ↓ frontier-model review ↓ verify The scheduler may instead discover: 1. run failing test 2. inspect stack trace 3. inspect exact function 4. generate one patch 5. run targeted test 6. run regression subset 7. stop The dynamic path is cheaper because early diagnostics reduce uncertainty. If the targeted test still fails, the scheduler can spend more: failure persists ↓ branch into alternatives ↓ critic / search / stronger model The architecture escalates only when the evidence justifies it. Research Agent Example A research agent may initially spend heavily on generation: search summarize search summarize search summarize But the scheduler should track claim coverage. Suppose the report has ten required claims. After the first few searches: 8/10 claims externally supported 2/10 unresolved The remaining budget should focus on those two unresolved claims, not continue broad retrieval. A useful scheduler feature is: expected new verified claim coverage per search When another broad search returns sources for claims already covered, its marginal value is low. Browser Agent Example A browser agent attempting a checkout or form workflow may encounter ambiguity. It can: re-read the page with a model, inspect the DOM, take another screenshot, retry the action, navigate back, or escalate to a stronger visual model. The cheapest useful action depends on the state. If the DOM clearly exposes an error message, another visual model call is wasteful. If the DOM is inaccessible but the page changed visually, screenshot interpretation may be valuable. The scheduler should allocate to the cheapest signal that can reduce uncertainty. DevOps Agent Example For a production remediation agent, budget scheduling is not just about cost. It is also about risk. Suppose the agent believes restarting a service will fix an incident. Before spending its side-effect budget, the scheduler might allocate to: read-only metrics logs health checks dependency state current deployment version Only after enough evidence supports the hypothesis does it permit the irreversible or disruptive action. Then it allocates heavily to post-action verification. observe ↓ diagnose ↓ precondition verify ↓ action ↓ postcondition verify ↓ regression checks For consequential systems, verification budget should often dominate generation budget. Mixture-of-Agents Example A mixture-of-agents runtime may expose several specialists: local code model frontier code model retrieval specialist planner critic verifier The scheduler is different from the router. The router asks: Which expert is appropriate? The scheduler asks: How much resource should this task receive, and when should we spend it on that expert? These can interact. router: code-local probability = 0.72 scheduler: cheap local model has high expected value ↓ use local model first ↓ verification fails ↓ remaining budget sufficient ↓ frontier escalation now has high rescue value That is better than always running both models. Fixed Budgets Are Still the Baseline Do not assume dynamic scheduling is better. Benchmark it. A fair experiment might compare: Policy A — Fixed cheap 1 generation 1 verifier Policy B — Fixed medium 4 generations 2 critics 1 verifier Policy C — Fixed large 8 search nodes 3 critics strong-model escalation 2 verifiers Policy D — Dynamic scheduler same maximum resource envelope allocation depends on observed state Measure: verified success, false success, UNKNOWN rate, average cost, p50/p95 latency, model calls, tool calls, verifier calls, search nodes, cost per verified success, rescue rate, and marginal gain per additional unit of compute. The dynamic scheduler should beat at least one fixed allocation frontier. If it does not, keep the simpler policy. Compare at the Same Maximum Envelope A common experimental mistake is to give the adaptive system more total compute. Then the result tells you nothing about scheduling quality. Use the same maximum envelope. Policy A max = $0.20 / 20 calls / 10 sec Policy B max = $0.20 / 20 calls / 10 sec Then compare what each policy does inside that limit. Also compare average spend. An adaptive scheduler may achieve equal verified success while using much less compute on easy tasks. That is a genuine win. Stratify by Task Difficulty Average numbers can hide the scheduler’s actual behavior. Break tasks into buckets: easy medium hard unresolvable high-risk A useful scheduler might show: Difficulty Avg calls Verified success Easy 2.1 98% Medium 5.4 91% Hard 11.8 74% Unresolvable 4.0 UNKNOWN That is healthier than giving every task twelve calls. Especially notice the unresolvable bucket. A good scheduler should learn to stop wasting compute when evidence suggests the task cannot currently be verified. UNKNOWN Can Be a Budget-Saving Outcome Suppose the system cannot access the external service needed to verify completion. It has two options. Bad runtime: retry retry retry stronger model critic retry Good runtime: required evidence unavailable ↓ UNKNOWN ↓ stop UNKNOWN is not failure to be intelligent. It is often the correct resource decision. Budget Failures Need Their Own Taxonomy Step 13 introduced failure-stage classification. Budget scheduling adds another useful set of labels: OVERSPEND UNDERSPEND VERIFY_STARVATION PREMATURE_ESCALATION LATE_ESCALATION SEARCH_OVEREXPANSION SEARCH_UNDEREXPANSION CRITIC_OVERUSE TOOL_OVERUSE PREMATURE_STOP These are not model-quality failures. They are control-policy failures. That distinction is essential when improving the system. Log Expected and Actual Value For every scheduler decision, capture both the estimate and the result. { "event": "budget_allocation", "action": "frontier_escalation", "expected_success_gain": 0.18, "expected_cost_usd": 0.04, "actual_cost_usd": 0.05, "outcome_before": "FAIL", "outcome_after": "PASS", "policy_version": "scheduler-2026-08-09-a" } Over many runs, you can ask: Which actions are overvalued? Which are undervalued? Where does predicted rescue probability disagree with observed rescue rate? Which task classes consume budget without improving outcomes? Now scheduler calibration becomes possible. Calibration Matters Suppose the scheduler predicts: frontier escalation rescue probability = 0.8 But among 100 comparable cases, escalation rescues only 35. The policy is badly calibrated. That will cause overspending. Similarly, if it predicts only 0.2 but rescues 70% of those cases, it may under-escalate. This is the same calibration discipline from Step 15, now applied directly to resource allocation. Useful measurements include: reliability curves, Brier score, expected calibration error, predicted vs observed rescue rate, and predicted vs observed marginal gain. Offline Replay Before Production Trajectory logs from Step 13 let us test scheduler policies offline. For each historical decision point: state available actions remaining budget recorded decision recorded outcome A candidate scheduler can propose a different allocation. Some counterfactuals will be unknowable. That is fine. Do not fabricate outcomes. Classify them as unavailable for exact offline evaluation. Use: replay where outcomes are known, controlled benchmarks for uncertain cases, shadow mode in production, and then canary deployment. Shadow the Scheduler Before allowing a new scheduler to control production, run it in shadow mode. production scheduler → actual action candidate scheduler → logged hypothetical action Compare: route differences, escalation differences, search-budget differences, predicted cost, expected verifier reserve, and stop decisions. This catches pathological policies before they spend real resources or change real environments. Canary and Rollback The deployment path should be boring: offline benchmark ↓ shadow ↓ small canary ↓ compare metrics ↓ promote / rollback Rollback should mean restoring a known scheduler version. Not asking another model to “behave more conservatively.” scheduler-2026-08-09-a scheduler-2026-08-14-b scheduler-2026-08-27-c Version the control policy. Pricing Changes Can Change the Optimal Architecture This is an underappreciated point. Suppose the frontier model price falls by 80%. A routing policy that previously preferred local-model search may no longer be optimal. Or suppose a local GPU becomes saturated and latency triples. The scheduler may need to route more requests externally even if token price is higher. Agent architecture is therefore partly economic. The optimal policy depends on: model quality model price latency capacity verification cost tool cost task distribution risk tolerance Those quantities change. That is why the budget scheduler should be policy-driven and observable rather than buried inside prompts. Use Pareto Frontiers, Not One Magic Score A single reward number can hide important tradeoffs. Instead, compare policies on a frontier: verified success ↑ false success ↓ cost ↓ latency ↓ Policy A may be cheapest. Policy B may be fastest. Policy C may provide the highest verified success. The right deployment depends on product requirements. There may be no universally best scheduler. Different Tenants May Need Different Budgets A low-cost interactive product and a high-value engineering workflow should not necessarily use the same scheduler. For example: interactive chat max latency: 3 sec max cost: $0.02 moderate verification code migration max latency: 10 min max cost: $2.00 strong verification production deployment max latency: 20 min max cost: $5.00 very strong verification The scheduler can share the same mechanism while operating under different envelopes. Do Not Let the Scheduler Rewrite Safety The budget scheduler may decide: whether to search more, whether to escalate, whether to invoke a critic, how many candidates to generate, which verifier tier to use when several are allowed. It should not decide: whether authorization is required, whether secrets may be accessed, whether a sandbox can be bypassed, whether a prohibited tool may be called, whether mandatory verification can be skipped. Those remain outside the optimization layer. This boundary is worth repeating because “dynamic allocation” can otherwise turn into “the agent can choose which safeguards to spend on.” No. Dynamic Scheduling Can Simplify the Runtime This may sound like another layer of complexity. It can actually remove complexity. Suppose your current architecture has: always plan always Best-of-N always critic always search always frontier review always verify twice A scheduler may discover that most tasks only need: cheap model ↓ cheap tool evidence ↓ verification while a small fraction deserve the expensive path. That means the sophisticated architecture still exists. But it is sparse in use. Only difficult tasks pay for difficult machinery. This is one of the most important production patterns in advanced agents. The Architecture Becomes Conditional Instead of: request ↓ planner ↓ search ↓ critic ↓ frontier ↓ verifier we get: request ↓ cheap path ↓ verify ├── PASS → stop | └── unresolved ↓ scheduler / | \ diagnostic search escalate \ | / \___|____/ ↓ verify The architecture is no longer one fixed pipeline. It is a set of mechanisms activated by evidence. Metrics for a Production Budget Scheduler At minimum, track: Outcome metrics verified success false success FAIL rate UNKNOWN rate Resource metrics cost per task cost per verified success model calls tool calls search nodes verifier calls p50/p95 latency Allocation metrics frontier escalation rate critic invocation rate search activation rate average search nodes when activated verifier budget fraction reserved budget consumed Decision-quality metrics escalation rescue rate cost per rescue premature stop rate unnecessary escalation rate search regret verification starvation rate Calibration metrics predicted vs observed rescue predicted vs observed success gain predicted vs actual action cost Without these, “adaptive budget” is just another opaque behavior. A Complete Control Loop The scheduler now connects the last several posts into one system: production task ↓ execution state ↓ control policy ↓ budget scheduler ↓ allocate next computation ↓ trajectory observability ↓ external verification ↓ verified outcome ↓ offline benchmark ↓ policy calibration ↓ shadow / canary ↓ new scheduler version That is no longer a prompt trick. It is a runtime optimization loop. The Final Rule The goal is not to consume the budget efficiently. The goal is to achieve the required verified outcome with the smallest justified expenditure of resources. That gives us the central rule for this stage: Spend the next unit of computation where it has the highest expected value, reserve enough resources to prove success, and stop spending when additional work no longer earns its cost. A sophisticated agent should not merely know how to think longer. It should know when not to. And if a cheap deterministic action can resolve the uncertainty better than another thousand tokens of reasoning, the scheduler should choose the cheap action. That is what advanced control should look like.