Chapter 04 — Enforcement, Hooks, and Decomposition Strategy
Domain 1: Agentic Architecture & Orchestration (27%) — task statements 1.4, 1.5, 1.6
If you learn one thing from Domain 1, learn this chapter's central claim: hooks are deterministic, prompts are probabilistic. It is the answer to more items than any other single idea on this exam.
1. Programmatic enforcement vs prompt guidance
🎯 The core principle
Prompt instructions have a non-zero failure rate. That's the guide's own language, and it's the whole argument. A system prompt that says "always call get_customer before process_refund" will be followed most of the time. "Most of the time" is fine for formatting conventions. It is not fine for issuing refunds.
| Mechanism | Guarantee | Appropriate for |
|---|---|---|
| System prompt instruction | Probabilistic — usually followed | Style, tone, preferences, soft conventions |
| Few-shot examples | Probabilistic — improves consistency | Ambiguous judgement calls, output shape |
| Hook / prerequisite gate / programmatic check | Deterministic — cannot be bypassed | Ordering, authorization, limits, anything irreversible |
The decision rule
Ask: what happens the one time in fifty that the model doesn't comply?
- Output is slightly off-style → prompt is fine.
- A refund is issued to an unverified customer → you need a gate.
- A compliance record is written without a required field → you need a gate.
If the answer involves money, policy violation, data loss, or anything you can't undo, the correct answer is deterministic enforcement. ⚠️ Options offering "add a stronger instruction to the system prompt," "provide few-shot examples of the correct order," or "clarify the tool descriptions" are all plausible and all lose to a gate in these items.
The canonical example
Scenario 1's requirement: process_refund must never execute before get_customer has returned a verified customer ID.
# Deterministic gate: the tool cannot run until its prerequisite is satisfied.
def pre_tool_use(tool_name, tool_input, session_state):
if tool_name == "process_refund":
verified_id = session_state.get("verified_customer_id")
if not verified_id:
return {
"block": True,
"reason": (
"process_refund requires a verified customer ID. "
"Call get_customer first and confirm the returned "
"verification status before attempting a refund."
),
}
return {"block": False}
Two things to notice, because both are examinable:
- The gate blocks the action, so no prompt-following failure can produce a refund.
- The block returns an actionable reason to the model, so the agent recovers rather than dead-ends. A gate that returns a bare "denied" leaves the agent stuck — this is the same principle as structured errors (Chapter 06 §3).
2. Agent SDK hooks
Task statement 1.5. Hooks intercept the agentic loop at defined points, in your code, deterministically.
📎 PostToolUse — normalizing heterogeneous tool output
The guide's exact use case: an agent talks to several backend systems that return the same logical field in different shapes — Unix timestamps from one, ISO 8601 from another, numeric status codes from a third. The model can usually cope, but "usually" produces intermittent misreadings that are extremely hard to debug.
The fix is a PostToolUse hook that normalizes every tool result before it enters the conversation:
def post_tool_use(tool_name, tool_result):
"""Normalize before the model ever sees it. Deterministic, not probabilistic."""
if "created_at" in tool_result:
tool_result["created_at"] = to_iso8601(tool_result["created_at"])
if "status" in tool_result:
tool_result["status"] = STATUS_CODE_MAP.get(
tool_result["status"], tool_result["status"]
)
return tool_result
🎯 The item shape: "different backend systems return timestamps in different formats and the agent occasionally misinterprets dates — what should the architect do?" The answer is a PostToolUse hook. The distractors: tell the model about the formats in the system prompt (probabilistic), add few-shot examples of each format (probabilistic), or modify each backend (out of scope, high effort, often impossible).
⚠️ Note what this hook is not for: it isn't a place to reduce verbosity for cost reasons only — though trimming there is legitimate (Chapter 11). Its examinable purpose is making heterogeneous data uniform before the model reasons over it.
📎 Tool-call interception — blocking and redirecting
Hooks can inspect a pending tool call and block or redirect it. The guide's example: refunds above $500 must not be processed automatically; they must be redirected to human escalation.
def pre_tool_use(tool_name, tool_input, session_state):
if tool_name == "process_refund" and tool_input.get("amount", 0) > 500:
return {
"block": True,
"reason": (
"Refunds over $500 require human approval. "
"Call escalate_to_human with the customer ID, order ID, "
"requested amount, and the reason for the refund."
),
}
return {"block": False}
Again: block and redirect. The hook doesn't just refuse; it names the correct next action. A hook that blocks without direction converts a policy violation into a stuck conversation.
Where hooks sit relative to everything else
user turn
│
▼
┌───────────────┐
│ model turn │ ← system prompt, tools, few-shot (PROBABILISTIC)
└───────────────┘
│ requests tool
▼
┌───────────────┐
│ PreToolUse │ ← gate: block / allow / redirect (DETERMINISTIC)
└───────────────┘
│ executes
▼
┌───────────────┐
│ PostToolUse │ ← normalize / trim / annotate (DETERMINISTIC)
└───────────────┘
│ result appended
▼
loop continues
🧠 Read the diagram as a policy statement: everything above the first hook is advice to the model; everything at or below is enforcement. Put a requirement in the layer that matches its consequence.
3. Structured handoffs
Task statement 1.4, second half. When an agent escalates or hands off, what it passes is examinable.
A handoff to a human agent should carry a structured summary, not the raw conversation. The guide's named fields for Scenario 1:
| Field | Why |
|---|---|
| Customer ID | The human shouldn't re-identify the customer |
| Root cause | What the agent determined, not the transcript |
| Refund amount (or the relevant quantity) | The specific number in dispute |
| Recommended action | The agent's proposal, so the human reviews rather than restarts |
⚠️ The distractor is "pass the full conversation transcript." It sounds thorough and is worse: it forces the human to re-derive conclusions the agent already reached, and it buries the numbers. The same logic applies between agents — upstream agents should return structured data, not verbose reasoning (Chapter 11 §3).
📎 Note the parallel structure across three different boundaries. All three want the same shape:
| Boundary | Carries |
|---|---|
| Agent → human (escalation) | customer ID, root cause, amount, recommended action |
| Subagent → coordinator (error) | failure type, retryability, what was attempted, partial results, alternatives |
| Session → session (fresh start) | structured summary of durable facts, not stale tool results |
One reflex covers all three: cross a boundary with conclusions and identifiers, never with raw history.
4. Task decomposition strategy
Task statement 1.6. Two named strategies, and a rule for choosing.
Prompt chaining vs dynamic adaptive decomposition
| Prompt chaining | Dynamic adaptive decomposition | |
|---|---|---|
| Structure | A fixed sequence of prompts; each stage's output feeds the next | The agent decides what to investigate next based on findings |
| Fits | Predictable, multi-aspect work where the aspects are known in advance | Open-ended investigation where the path depends on what you find |
| Example | Code review covering security, then performance, then style — every time | "Find out why this service started timing out last Tuesday" |
| Predictability | High: same stages, same cost, auditable | Low: variable depth and cost |
🎯 The exam's discriminator is one word in the stem: is the work predictable or open-ended? A review that always covers the same five dimensions is a chain. A root-cause investigation is dynamic. Don't overthink it.
🎯🎯 Attention dilution and the split-pass pattern
This is one of the most reliably tested ideas on the whole exam, and it's the direct application of Reflex 7.
The problem: a code review agent given 15 changed files in one prompt misses issues it would catch in any single file. Not because the content doesn't fit — because attention spreads thin across a large prompt. This is attention dilution.
The fix: per-file passes, plus a cross-file integration pass.
Pass 1..N → one focused review per changed file (catches local issues)
Pass N+1 → integration review across all files (catches interface and
contract mismatches)
Both halves matter. Per-file passes alone miss the bugs that only exist between files — a changed function signature and its unchanged callers. The integration pass exists specifically to catch those.
⚠️ The distractor is always "use a model with a larger context window." It appears in the published sample questions and it is wrong: the content already fit. Capacity was never the constraint; attention was. Memorize this: larger context does not fix attention dilution.
Other options in this family that also lose: "increase max_tokens," "enable extended thinking," "summarize the files before reviewing." The last one is actively harmful — you'd be reviewing a summary instead of the code.
5. Worked examples
Example 1 — enforcement layer
In a customer support agent,
process_refundhas occasionally been called before the customer's identity was verified viaget_customer, resulting in refunds to unverified accounts. The system prompt already instructs the agent to verify first. What is the most effective way to guarantee correct ordering?A. Implement a programmatic prerequisite check that blocks
process_refunduntilget_customerhas returned a verified ID. B. Add few-shot examples to the system prompt demonstrating the correct call order. C. Rewrite theprocess_refundtool description to emphasize that verification is required first. D. Combine the two tools into a singleverify_and_refundtool.
Answer and reasoning
A.
The stem contains the decisive detail: the system prompt already instructs it. Prompt guidance has been tried and has a non-zero failure rate; the consequence is financial. Only a deterministic gate provides a guarantee.
- B — Few-shot improves the rate. It does not eliminate the failure. The requirement here is "guarantee."
- C — Same class of fix as B: still an instruction the model may not follow, and the prompt already carries the instruction.
- D — Genuinely tempting, and note why it's inferior: it removes the agent's ability to verify identity without refunding (a legitimate standalone need), couples two distinct operations, and still doesn't gate the refund path if the combined tool is called with incomplete data. It's a redesign where a check suffices — over-engineering (Reflex 2).
Reflex applied: #1. Financial consequence + prompt already tried → deterministic mechanism.
Example 2 — attention dilution
A CI code review agent reviews pull requests that typically touch 12–20 files. Reviewers observe that the agent catches far fewer issues per file than it does when asked to review a single file in isolation. The full diff fits comfortably within the model's context window. What is the most effective approach?
A. Run a separate focused review pass for each changed file, followed by one integration pass across all files. B. Switch to a model with a larger context window. C. Increase
max_tokensso the agent can produce a longer review. D. Summarize each file before submitting the diff for review.
Answer and reasoning
A.
"The full diff fits comfortably within the context window" is the stem telling you capacity is not the problem. The symptom — good per-file performance in isolation, poor performance in bulk — is the definition of attention dilution. Split the passes. The integration pass is not optional: it's what catches cross-file contract breaks that per-file passes structurally cannot see.
- B — The named distractor. Larger context adds capacity, and capacity was already sufficient. Attention dilution is unaffected.
- C — Bounds output length. The problem is input attention, not output room.
- D — Actively harmful: you'd be reviewing summaries rather than code, discarding exactly the detail a review depends on.
Reflex applied: #7. Split passes, don't enlarge context.
6. Decision reflexes (reproduce from memory)
- Hooks are deterministic; prompts are probabilistic. Match the mechanism to the consequence.
- Prompt instructions have a non-zero failure rate → never rely on them for money, policy, or irreversible actions.
- "The system prompt already says so" in a stem = prompt guidance has been tried = the answer is a gate.
PreToolUsegates: block and redirect with an actionable reason (e.g. refunds > $500 →escalate_to_human).PostToolUsehooks: normalize heterogeneous tool output (Unix vs ISO 8601 timestamps, numeric status codes) before the model sees it.- Cross any boundary with conclusions and identifiers, never raw history: escalations carry customer ID, root cause, amount, recommended action.
- Prompt chaining for predictable multi-aspect work; dynamic decomposition for open-ended investigation.
- Attention dilution → per-file passes + cross-file integration pass. Larger context windows do not fix it.