๐ŸŽ“ Claude Architect KB CCAR-F ยท CCAR-P study guide

Domain 1 โ€“ Facts

Agentic Architecture ยท the things to remember, in plain words

Each item is one rule that decides exam questions. Read the short headline, say the rule to yourself, then read the line to check. Open why if the reason is not clear, and follow the question link to see the rule in action. Collected from the lesson, the practice questions and two full third-party mock exams. They help you remember; they do not guarantee a score.

Back to Domain 1 lesson ยท Domain 1 โ€“ Questions ยท Domain Q&A

Workflow vs agent โ€” choosing the pattern

  1. Agent or workflow? Ask one thing: who decides the next step? If your code already knows the steps, it's a workflow, even with many LLM calls. If the model looks at the situation and picks the next step and tool, it's an agent. Watch for answers that swap the two. Practice Q&A ยท Q38 ยท โŒ wrong choice to avoid: an answer that swaps the two: a workflow that steers itself, an agent that follows fixed code
    why

    This is the dividing line in Anthropic's Building Effective Agents. Both can call tools, loop, and run things in parallel, so those features don't tell them apart. Choose by how well you know the path: known path, workflow; path found along the way, agent. The wrong answer just swaps the two definitions, which looks right if you read fast.

  2. Steps already known? If you know the steps before any input arrives (summarize โ†’ extract โ†’ format; classify โ†’ extract โ†’ validate), use prompt chaining: your code calls step A, feeds its output to step B, and checks the result in code between steps. Not orchestrator-workers, not one agent with three tools. Practice Q&A ยท Q2 ยท Practice Q&A ยท Q33 ยท โŒ wrong choice to avoid: orchestrator-workers, or one agent given three tools
    why

    When the order is fixed, your code can just write it down as a chain, and a code check between steps catches bad output early. An orchestrator adds a model call to decide a split you already know. One agent with three tools makes the model rediscover the same order every run, and it may skip or reorder steps. For big volume, run the same chain in many parallel workers, not a planner.

  3. The five patterns Anthropic names five patterns: prompt chaining, routing, parallelization, orchestrator-workers, and evaluator-optimizer. Parallelization has two flavors (sectioning and voting), but they count as one pattern.
    why

    Chaining is a fixed sequence. Routing sorts the input into a category and sends it to a specialised prompt or model. Parallelization either splits independent subtasks (sectioning) or runs the same task N times and combines the answers (voting). Orchestrator-workers lets a model split the work at runtime and then combine results; evaluator-optimizer loops a writer with a critic. A table may show six rows, but it is still five patterns. Each one answers a question: is the order known, does input fall into categories, are subtasks independent, can you predict them up front, is there a clear rubric to iterate against?

  4. When orchestrator-workers? Use orchestrator-workers only if a model must decide the split while running, because the subtasks depend on the input ("find out why checkout dropped"). If the job is fixed and would just be faster in parallel, that's not a reason. โŒ wrong choice to avoid: choosing an orchestrator just because a fixed job would be faster in parallel
    why

    The orchestrator's extra model call pays off only when nobody can list the subtasks in advance: it reads the situation, decides what to look into, hands out work, then combines the results. "Why did checkout conversion drop?" is like that, because the next questions depend on what the first look finds. "This fixed job would be faster in parallel" is a parallelization problem; the harness (your code that runs the model) solves it with a worker pool. A planner there just re-creates a split you already wrote.

  5. Big volume, same steps? Here's the thing: 100,000 identical invoices still use the SAME fixed chain. The harness runs it many times side by side (queue, worker pool, Batch API for overnight work). An orchestrator would spend a model call deciding what a for-loop already knows. โŒ wrong choice to avoid: an orchestrator-workers design picked to handle scale
    why

    Volume is a throughput problem, and throughput is your code's job: put documents on a durable queue, run a limited number of workers that each run classify โ†’ extract โ†’ validate, and use the Batch API for work that can finish overnight. A model orchestrator would pay a call per invoice for a split that never changes. Later stages still need earlier results, so a batch design sends the classification jobs, saves the results, then sends the extraction jobs that qualify and validates them in code.

  6. Plan as you go? Use dynamic adaptive decomposition (build and change the plan while working) if the useful subtasks only show up from what you find midway, OR the task is open-ended, like writing tests for an unmapped legacy codebase. Either signal is enough. If the step order is stable, use a fixed pipeline. โŒ wrong choice to avoid: seeing only the "subtasks come from findings" signal and missing that open-ended work also counts
    why

    Adaptive means: first map the area, then make a prioritised plan that changes as you learn about dependencies and findings. Two things each point to it on their own: subtasks that only appear after early results, and a task with no existing map (full tests for an old codebase nobody has charted). If every run checks the same predictable things, or each step feeds the next in a stable order, a fixed pipeline fits and the adaptive setup is wasted.

  7. Small question, full pipeline? If a coordinator runs all five subagents even for a simple factual question, add a step that classifies the request first and then calls only the subagents it needs. Not two separate systems, not caching, not smaller budgets per subagent. โŒ wrong choice to avoid: a second lightweight system, a cache, or smaller per-subagent budgets
    why

    Calling every specialist on every request means even a one-line answer pays the full time and token cost. A classification step at the start lets cheap questions take the cheap path. Two separate systems duplicate logic, a cache helps only when the exact same request repeats, and cutting each subagent's budget makes every answer worse while the unneeded work still runs.

  8. Critic loop or code check? Evaluator-optimizer means: write a draft, a critic checks it against clear criteria, then revise, until the critic accepts or you hit a revision limit. Use it when "good" is a judgement call. If the check is arithmetic, your code does it, not a critic loop. Practice Q&A ยท Q33 ยท โŒ wrong choice to avoid: a critic loop that reviews extractions until the totals add up
    why

    A critic model scores the draft against an explicit rubric and sends it back for changes. This pays off for translation, writing, and research, where quality is a judgement. Checking that invoice totals add up is math your code can check exactly and for free; a model critic looping until the numbers match swaps a sure check for a slow, maybe-correct one.

  9. Is one agent enough? If the task fits in one context window and one tool set, use a single agent loop. Answers like "when subagents are unavailable", "when latency doesn't matter", or "never at scale" are wrong reasons. Practice Q&A ยท Q7 ยท โŒ wrong choice to avoid: "when subagents are unavailable", "when latency doesn't matter", or "never at scale"
    why

    A single agent loop is one model, one conversation, one set of tools, looping on tool_use until end_turn. It stays right as long as the instructions, tool results, and reasoning all fit in one context window with one coherent tool set. More agents add coordination code, handoff bugs, and cost; add them only when work is independent enough to run in parallel, or the raw material would overflow one context. Whether subagents exist, whether speed matters, or how big the deployment is does not decide it.

The agent loop, messages array & stop reasons

  1. What does stop_reason say? Always check stop_reason first. tool_use โ†’ run the tool, append a tool_result, call again. end_turn โ†’ deliver the answer. max_tokens โ†’ output is cut off, never treat it as complete. stop_sequence โ†’ your own rule decides. refusal โ†’ don't retry automatically.
    why

    stop_reason is the API telling your code why the model stopped, so your harness must branch on it before using the content. max_tokens means the output hit the cap you set for this call, so the text is incomplete. stop_sequence means one of your custom stop strings matched, and your own protocol decides what that means. refusal means the model said no; retrying automatically is the wrong reflex.

  2. When does the loop stop? Keep looping while you get "tool_use"; stop on "end_turn". Looking for "refactoring complete" in the text, scanning for XML tags, or using max_turns: 8 as the main stop are anti-patterns. Keep a turn cap only as a safety net. โŒ wrong choice to avoid: parsing the reply for a "done" phrase, or relying on a fixed max_turns cap
    why

    The API's own signal is the real exit: keep going on tool_use, stop on end_turn. Searching the reply for a phrase or tag ties the stop to wording the model can change. A hard max_turns as the main stop can cut off work that needed one more step, or let a stuck loop waste eight turns before anyone notices. Keep the cap only to stop runaway cost; the structured stop reason is what controls the loop.

  3. Random JSON parse failures? If JSON parsing fails now and then and the logs show stop_reason: max_tokens, the output was cut off but treated as complete. It's not hallucination, not a too-strict schema, not temperature, not checkpoint corruption. Practice Q&A ยท Q4 ยท Practice Q&A ยท Q40 ยท โŒ wrong choice to avoid: model hallucination, a too-strict schema, or temperature
    why

    When output hits max_tokens the model stops mid-sentence; JSON cut at the right spot can even parse, just with fields missing. The clue is in the logs: every failed response has stop_reason: max_tokens, and a harness that never checks this field accepts it silently. Hallucination wouldn't line up with the stop reason, a strict schema rejects instead of cutting, temperature changes wording not length, and checkpoints don't touch the response. Fix: branch on stop_reason, then raise the budget or make the task smaller.

  4. What max_tokens means max_tokens limits the output of one call, nothing else. If the input is bigger than the context window, the API rejects the request with an error before generating anything. If your custom stop string matches, you get stop_sequence. Practice Q&A ยท Q37 ยท โŒ wrong choice to avoid: reading max_tokens as "the input outgrew the context window"
    why

    max_tokens says nothing about how big the messages array is. An input that's too large gets an error up front, not a response with a stop reason. So max_tokens as a stop reason means exactly one thing: generation reached the ceiling you set, and the text is incomplete.

  5. What goes in before call 2? Before the next call, append two things at the END: the assistant response exactly as returned (including the tool_use block), then a user-role message with the tool_result. If a tool_result has no matching tool_use in the history, the API rejects it. Practice Q&A ยท Q35 ยท โŒ wrong choice to avoid: appending only the tool_result, or putting it before the assistant turn
    why

    The API is stateless (it remembers nothing between calls), so call 2 must tell the whole story in order: the assistant turn with its tool_use block and id, then the user message carrying the tool_result. Both go at the end because the array is in time order. Sending only the tool_result, or putting it before the assistant turn, leaves a result with nothing to pair with, and the API rejects it; putting things at the start scrambles the conversation.

  6. Who makes the tool id? The Claude API creates the id: "toolu_โ€ฆ" on every tool_use block. Your tool_result copies it back as tool_use_id. Tool definitions have no id, and even a single tool call needs this pairing. Practice Q&A ยท Q32 ยท โŒ wrong choice to avoid: your harness or the tool definition creating the id, or ids mattering only with several calls
    why

    Each tool_use block gets a fresh id like toolu_01A, made by the Claude API, not by your code and not written in the tool definition (which only has name, description, and input_schema). Your harness copies that id into the tool_result's tool_use_id so the API can match result to request. This is required even when there is only one tool call in the response.

  7. Does the API remember? No. The API is stateless: you resend the whole messages array every call. system and tools are separate request fields (the stable part that caching can reuse). Tool results go in as user; there is no tool role. โŒ wrong choice to avoid: a "tool" role, or the API remembering earlier turns
    why

    The Claude API keeps no conversation between calls, so a 40-turn conversation is a 40-turn array sent every time. system and tools travel next to it as separate fields, so they stay byte-identical and prompt caching can reuse them while messages grows. For the model, tool results are news from the outside world, and the outside world always speaks as user.

  8. Who runs the tool? Your code does. The model only asks for an action by writing tool_use data. Your harness checks it against input_schema, checks permission, runs it, and checks the result. The Claude API never runs your client tool. Practice Q&A ยท Q31 ยท โŒ wrong choice to avoid: the model or the Claude API checking and running the tool
    why

    A tool_use block is a request, not an action: the model writes the tool name and arguments as data and stops. Everything after that is your harness: validate the arguments against input_schema, check this agent may do this action with these values, run the tool, and look at the result before appending it. Strict tool inputs can shape the argument structure, but they never approve a shipment or prove a business value is right.

  9. Does tool order matter? No. The tools array is a menu, not a run order. Where a tool sits in the list creates no dependency, and strict: true only shapes the arguments. If one step must come before another, your code enforces it. โŒ wrong choice to avoid: expecting tool order or strict schemas to force a call sequence
    why

    The tools list only tells the model what it may call. strict: true controls the shape of the arguments, but it doesn't pick the right business task, check permission, or force one call before another. If step B must never run before step A, put that rule in your harness: check the state before running the tool.

Orchestrator, subagents & context handoff

  1. Do subagents share context? No. A subagent never inherits the coordinator's context or another subagent's. Anything it needs (findings, file paths, generated code, artifact revision) your coordinator must put into its prompt explicitly. โŒ wrong choice to avoid: assuming the later agent inherits, or can look up, what an earlier agent produced
    why

    A subagent starts blank: it sees only what the coordinator writes into its prompt, not the coordinator's conversation and not what sibling agents found. So every input is carried by hand: the findings a synthesis step must cite, the paths and schema mappings a test agent needs, the code to test, the revision to read. If a later agent acts like an earlier result never existed, first check whether the prompt ever included it.

  2. Where did content go missing? Walk back to the earliest failure. Topic never assigned โ†’ fix the split/coverage plan. Assigned and done but not passed on โ†’ fix collection/handoff. Passed in but left out โ†’ look at synthesis. โŒ wrong choice to avoid: blaming synthesis or the workers when logs show the topic was never assigned or never passed on
    why

    Check the coordinator's logs stage by stage. If no worker was ever given the topic, the plan was too narrow; the workers did their jobs. If a worker finished it but the output never reached the next prompt, collecting results or the handoff is broken. Only if the content was passed in and still disappeared from the report is the synthesis step to blame.

  3. Only the first result used? All workers "returned successfully, no tool errors", but the report covers only auth? The coordinator sent only the first result to synthesis. A max_turns or rate-limit failure doesn't fit the question. โŒ wrong choice to avoid: blaming the workers: max_turns running out or silent rate-limit failures
    why

    Every worker finished cleanly, yet only the first module shows up: the coordinator took one result and moved on. Subagents return output to the coordinator, but the coordinator must collect all of them and pass them on together; nothing does this automatically. A max_turns or rate-limit failure would show up as an error or an incomplete result, which contradicts "all returned successfully, no tool errors".

  4. Tests use old schema names? If the tests use schema names that were already renamed, the coordinator didn't pass the migration result (the mapping and the revision) to the test agent. Just running them in order doesn't fix it, and a message bus breaks hub-and-spoke. โŒ wrong choice to avoid: running the migration and test agents one after the other instead of in parallel
    why

    In hub-and-spoke (all messages go through the coordinator), the coordinator is the only channel, so it must put the migration agent's output (the schema mapping and the revision) into the test agent's prompt. Running the two agents one after the other changes timing but still passes nothing. A shared message bus lets workers talk directly, which breaks the hub-and-spoke model and adds complexity. Letting the test agent dig through migration files works around a problem the coordinator owns.

  5. What's a good handoff? A handoff needs three things: the earlier step is ready, the result is spelled out (schema_mapping, changed_files, artifact_revision, checks, open_issues), and the next agent can read that exact revision. Just saying "done" is too vague. โŒ wrong choice to avoid: passing "done" as the handoff
    why

    A handoff can break in three places, and "done" covers none of them. Ready: the earlier change must really be complete enough to build on. Context: the next prompt must carry the concrete result and the acceptance criteria. Files: the next agent must be able to read that exact revision, which isn't automatic when agents work in separate worktrees, and old tool results don't refresh by themselves.

  6. What do workers send back? Workers send back a short structured summary (~150 tokens), never their full transcript. A 12K-token page stays inside the worker's own window. In hub-and-spoke, workers never talk to each other. Practice Q&A ยท Q3 ยท Practice Q&A ยท Q34 ยท โŒ wrong choice to avoid: one agent looping through every source with heavy compaction, or a chain going through them in one conversation
    why

    That's the point of a worker: it reads and digests the 12K-token page in its own context window and returns only a small summary with sources, so the coordinator's context stays small enough to combine many workers. Sending back the raw transcript would blow the coordinator's budget. All findings go up to the coordinator and, if needed, down in the next prompt. Summaries lose detail, so check they're complete; isolation doesn't guarantee quality.

  7. How to run subagents in parallel? Subagents run at the same time only if the coordinator puts several Task/Agent calls in ONE response. Raising max_tokens, shortening timeouts, or merging everything into one prompt doesn't make it parallel. โŒ wrong choice to avoid: raising max_tokens, shortening timeouts, or merging the jobs into one prompt
    why

    In the Agent SDK and Claude Code, the coordinator must emit several Task (now Agent) tool calls in a single response; calls spread over separate turns run one after another. max_tokens only changes output length, a shorter timeout just cuts research short, and merging jobs into one prompt brings back the single-agent bottleneck. For independent work, total time drops to about the slowest worker.

  8. Delegate or do it yourself? Send the 60-file rename to a subagent with focused context; the coordinator does the one-file health check itself. Size alone doesn't force a subagent, and doing both in the coordinator spreads its attention too thin. โŒ wrong choice to avoid: handling both tasks in the coordinator to avoid overhead
    why

    Delegating costs something: writing the context, starting the agent, collecting the result. It's worth it when the task is big or needs focus. A rename across 60 files would crowd the coordinator, so a subagent takes it; a one-file health-check endpoint is tiny, so the coordinator just does it. Delegating both wastes overhead on the small task, doing both pulls 60 files through the coordinator, and swapping them sends each task the wrong way.

  9. Agent uses the wrong tools? If a search agent keeps calling summarise/sentiment_analysis, remove those analysis tools from its list and give them to the analysis agent. A prompt reminder or a PreToolUse block still leaves the tools in view. โŒ wrong choice to avoid: system-prompt reminders to use only the fetching tools
    why

    The more tools an agent sees, the less reliably it picks the right one, and an agent that sees summarise and sentiment_analysis will call them sometime, even if its job is only fetching raw data. The sure fix is to cut its list to the four or five fetching tools. A prompt reminder is probabilistic (it may or may not work) and has already failed; a PreToolUse hook that blocks the calls is over-built and still shows tools the model shouldn't consider. Removing tools doesn't stop the model writing a summary in plain text, so still check the output to keep the handoff raw evidence.

  10. Report has gaps? If the final report has unsupported claims or thin subtopics, the coordinator sends focused follow-ups for just those gaps, then re-runs synthesis. Don't restart from scratch, don't let the model fill gaps from its own knowledge, don't accept it to save budget. โŒ wrong choice to avoid: restarting from scratch, filling gaps from the model's own knowledge, or accepting the thin report
    why

    The coordinator looks at what's missing, sends narrow follow-up searches and analysis for exactly those gaps, then combines again with the extra evidence. Starting over throws away good work and may repeat the same gaps. Filling holes from the model's own knowledge creates claims with no source. Accepting the report to save budget ships known problems.

  11. Fix loop never converges? If a fix-until-tests-pass loop writes brand-new code every round, the coordinator isn't passing the previous code + the specific failing tests into the next prompt. More rounds or a Read tool won't fix it. โŒ wrong choice to avoid: allowing more rounds, or adding a Read tool
    why

    The loop only gets closer to passing if each round starts from the last attempt, so the worker edits instead of starting over. Without that, each round writes fresh code that fails in new ways, so the number of rounds doesn't matter. A Read tool doesn't help either: the last attempt lives in a finished context, not in a file the worker can find.

Gates, HITL & idempotency

  1. Approve before or after? Before. A $600 replacement with a $100 auto-approve line โ†’ the gate fires before anything runs: the run pauses, a human gets the handoff packet, nothing has executed yet. Run-then-sign-off, flag-for-audit-later, and "ask the customer" are all wrong. Practice Q&A ยท Q36 ยท โŒ wrong choice to avoid: running under an idempotency key and getting sign-off afterwards, or flagging the run for audit later
    why

    The check is simple math your harness does on the tool_use block's input before running it: $600 is over $100, so the run parks, and the pending block plus a handoff packet go to the approval queue for a human. Running first and getting sign-off later, or flagging for audit afterwards, both ship before permission exists; an idempotency key stops duplicates but is not permission. Asking the model to check with the customer gives the decision to the wrong person.

  2. Where does a hard rule go? A rule like "never credit above $50 without sign-off" goes in a code gate in your harness + a human approval queue. Not the system prompt, not a few-shot refusal, not CLAUDE.md. Prompts guide; your code enforces. Practice Q&A ยท Q1 ยท โŒ wrong choice to avoid: putting the rule in the system prompt, a few-shot refusal example, or CLAUDE.md
    why

    A prompt, an example refusal, or a CLAUDE.md line can describe the $50 rule, but the model can still propose a $75 credit; text guides behaviour, it doesn't control the payment system. The rule holds only if backend code checks the amount before issuing the credit and, above the limit, saves the request for an authorised human. Also, CLAUDE.md is a Claude Code memory file; a plain Messages API loop never loads it.

  3. Does waiting cost anything? No. Between one response and the next request nothing is running. Save the messages array up to the pending tool_use, its id, and the handoff packet. No tokens are spent while waiting, and the process can exit. โŒ wrong choice to avoid: keeping a model call or a process open while the human decides
    why

    An agent run is only alive during a model call or a tool run. So a parked approval is free: your harness saves the messages array through the assistant turn holding the pending tool_use, that block's id, and the handoff packet (who, what, why, amount) to a queue or store. Days later a worker loads the same run_id and continues. No request is open, so nothing times out on the API side.

  4. How to resume after approval? Resume by building the missing tool_result. Approved โ†’ run it NOW with an idempotency key and return the real outcome under the pending tool_use_id. Denied โ†’ a tool_result that says so. Don't ask the model to request it again; "approved" alone doesn't prove the money moved. โŒ wrong choice to avoid: a new model turn that asks for the action again, or treating approval as proof it ran
    why

    The pending tool_use is still waiting for its answer. If approved, your harness runs the tool now with an idempotency key (a unique id so a repeat does nothing twice) and reports the real result, like a replacement id or refund status. If denied, the tool_result says so and the model explains it to the customer next turn. A new model turn asking for the refund again wastes a turn and might produce a different action. "Approved" is permission, not proof the money moved.

  5. Refunded twice after retry? If a retry after a timeout refunds or ships twice, you're missing idempotency: a stable key per operation plus a record of effects, at the point where the real action happens. Not checkpointing, HITL threshold, turn budget, temperature, timeout, or a "never refund twice" prompt. Practice Q&A ยท Q6 ยท Practice Q&A ยท Q39 ยท โŒ wrong choice to avoid: missing checkpointing, lower temperature, a longer timeout, or a "never refund twice" prompt
    why

    After a timeout your code doesn't know if the action happened, and a simple retry does it again. The fix is where the action hits the outside system: give each operation a stable key, save its result in an effects ledger, and a retry with the same key returns the saved result instead of acting again. Checkpointing resumes progress but can't tell whether an uncertain external write happened. HITL thresholds, turn budgets, temperature, timeouts, and prompts all work on the model side and can't stop a duplicate backend call.

  6. Who approves? A human, using plain plumbing: a queue row, an approval screen, and a resume endpoint. An "approval agent" may advise but never decide. Approve-and-train turns past decisions into new code rules, offline. โŒ wrong choice to avoid: an "approval agent" that decides, or auto-approving similar cases next time
    why

    The approval path is normal code with a person deciding: queue row, notification, approval UI, and an endpoint that continues the same run_id. A second model judging the first model's action is like a student grading their own homework and defeats the gate; it may summarise or suggest, never decide. Approve-and-train keeps the gate as code but lets it improve: each decision is logged and later, offline and with review, turned into new gate rules.

  7. When to hand off to a human? Escalation is a planned ending, not a crash: open a ticket, attach the handoff packet, tell the user honestly. Trigger it when confidence is below the floor, the request is outside the agent's job, a needed tool is down, the user asks for a person, or a gate blocks. โŒ wrong choice to avoid: treating escalation as an error case instead of a planned outcome
    why

    Build escalation into the design from the start, not as an error handler added later. The triggers are concrete: confidence under the set floor, a request type outside the agent's charter, a dependency like the order-lookup tool being down, the user asking for a human, or a gate blocking the action. Each ends the same way: a ticket, a handoff packet (conversation summary, evidence, actions tried), and an honest message about what happens next.

State, budgets, sessions & recovery

  1. Job crashed midway? If a 12-step job dies after step 7, you need a checkpoint after each step, so you resume at step 8 and don't redo anything with side effects. Retrying the whole run, a bigger model, or emailing an admin all fail. Practice Q&A ยท Q8 ยท โŒ wrong choice to avoid: retrying the whole run, a bigger model, or emailing an admin
    why

    Save the state after every finished step; then a crash after step 7 restarts at step 8 with earlier work kept. Don't blindly repeat a step with side effects: if step 7's result is unclear, check its status or rely on idempotency before repeating it. Rerunning everything repeats seven real actions, a bigger model doesn't stop crashes, and emailing an admin isn't recovery.

  2. Returned means finished? No. WAITING_FOR_APPROVAL and WAITING_FOR_RETRY end the function call, not the task; only COMPLETED is the end. To resume, load the saved run_id and continue from its phase, never from the top. โŒ wrong choice to avoid: treating a returned call as a finished task, or restarting the run from the top
    why

    A durable agent keeps the function call separate from the real task. On a pending approval the controller sets the phase to WAITING_FOR_APPROVAL, saves, and returns: the call is over, the task isn't. WAITING_FOR_RETRY works the same, with a next_retry_at. Only COMPLETED (or a failure end state) closes the task. On resume, load the run_id, check phase and pending work first, and continue; never start a new conversation or replay the first prompt.

  3. Do budgets reset on resume? No. Save both the limit and what's used (max_model_turns: 30, completed_model_turns: 10 โ†’ 20 left). Approval doesn't give new turns. Going over any budget is a final state (BUDGET_EXHAUSTED), not a reason to keep going quietly. โŒ wrong choice to avoid: resetting the turn count on resume, or logging a warning and continuing past the limit
    why

    You can only enforce a budget if the run saves both the ceiling and the usage, so 20 turns remain after resume however long the approval took. A human approval unblocks one pending tool; it doesn't reset the counter. When any budget (model turns, tool calls, cost) runs out, the run goes to an end state like BUDGET_EXHAUSTED for a person to review. A warning that lets the loop continue is not a budget.

  4. Retry which failures? It depends on the failure type. Temporary tool error โ†’ limited retry with backoff and jitter, or WAITING_FOR_RETRY + next_retry_at. Bad arguments โ†’ error tool_result, new model turn. Permission denied โ†’ never retry. Out of attempts โ†’ DEAD_LETTER. A tool retry is not a model turn. โŒ wrong choice to avoid: retrying every failure the same way, or retrying a permission denial
    why

    A timeout or 503 gets a limited retry with backoff and jitter (waiting longer each time, with some randomness), or the run parks; retrying the tool uses no model turn. Bad arguments are the model's mistake, so send an error tool_result and let it try again next turn. A permission denial won't change, so never retry it. When attempts run out, the run moves to DEAD_LETTER for human review instead of looping forever.

  5. Fork or fresh session? Want to try two strategies from the same good starting point? Use fork_session (an SDK option used with resume=). Old file reads are stale? Start a fresh session with a summary of checked findings and re-read the changed files. โŒ wrong choice to avoid: exporting the session findings to a file and pointing two new sessions at it
    why

    fork_session copies the live session so each strategy starts from the same baseline without affecting the other. Exporting findings to a markdown file and opening new sessions loses detail and is manual, and telling the model "forget strategy A" doesn't erase context. When early file reads are out of date because a colleague pushed changes, start fresh with a verified summary of findings and decisions, then re-read the changed files. A fork would copy the stale reads, and staying in the old session keeps conflicting content in context.

  6. What a fork can't do A fork copies the conversation, not your files, so use separate git worktrees for editing experiments. An export is a lossy document, not a session; compaction shrinks history but doesn't branch; and a fork copies stale reads too. โŒ wrong choice to avoid: using a fork to separate file edits, or to get rid of stale context
    why

    Two forks editing the same files would clash, so give each editing experiment its own git worktree. Exporting a session gives you a document that misses the real state's nuance. Compaction shortens history in place and makes no branch. Because a fork copies everything, it copies old tool results too, which is why recovering from stale context uses a fresh session.

  7. Faster but untested? The 97% invoice accuracy belongs to the OLD chain; the merged prompt's 1.8s is an unmeasured guess. So reject the merge, or test it first: "single-purpose chain steps outperform multi-task prompts". โŒ wrong choice to avoid: accepting the merge only for low-risk invoice types
    why

    The 1.8 seconds is a projection, and the merged prompt's accuracy was never measured. Putting classification, extraction, and validation into one prompt splits the model's attention three ways, and focused chain steps with checks between them do better than multi-task prompts. Using the merge only for low-risk types creates two inconsistent pipelines; the 68% contract accuracy is a separate problem, and adding more context per step doesn't fix a focus problem.

  8. Code check or model judge? If code can see the failure, code catches it: rate limits, tool timeouts, JSON-schema violations. Subtle factual drift in a summary needs a semantic evaluator (a model judge) calibrated against human labels. Practice Q&A ยท Q5 ยท โŒ wrong choice to avoid: spending a model judge on rate limits, timeouts, or schema errors that code already catches
    why

    Your harness catches rate limits, timeouts, and bad JSON exactly. A summary sentence that sounds fine but misstates the source is invisible to code, so you need an independent model judge whose scores are checked against human-labeled examples. You don't need a different model family, and a judge is no guarantee; the calibration is what makes the score mean something.

  9. Coordinator never delegates? No delegation and no errors? allowedTools is missing Task (now Agent). A prompt can't create a tool that isn't there. A custom Messages-API harness delegates by calling its own worker function; no special tool name needed. โŒ wrong choice to avoid: adding stronger "delegate this" wording to the prompt
    why

    In Claude Code and the Agent SDK, the coordinator starts a subagent by calling Task (now named Agent). Without it in allowedTools, the model can't delegate, so it quietly does everything itself and no error appears. A harness built directly on the Messages API has no such built-in tool; it delegates through its own worker function, or a delegation tool you design. Whether the tool exists and whether it's permitted are two separate checks.

Review sources

Domain 1 lesson and worked explanations ยท Official reference↗

Fact wording rewritten as concrete numbered facts on 25 September 2026. The mock providers' original keys are preserved on their review pages; these recall lines retain the engineering caveats.