TimoBy Amotion AI

Workflow enforcement and handoff: CCAR-F task statement 1.4

CCAR-F · Agentic Architecture & Orchestration (27% of the exam)

Task statement 1.4 sits in Agentic Architecture & Orchestration, 27% of the CCAR-F exam. It tests three things: making sure required steps happen in the right order, handling a request that contains several problems, and handing a case to a person with everything they need to act.

What the official guide covers

The Claude Certified Architect Foundations exam guide (version 1.0, effective July 2026) lists this under task statement 1.4, "Implement multi-step workflows with enforcement and handoff patterns":

Knowledge ofSkills in
Programmatic enforcement (hooks, prerequisite gates) compared with prompt guidance for the order of stepsBuilding prerequisites in code that block later tool calls until earlier steps are complete, such as no refund until a verified customer ID exists
When compliance must be deterministic, such as identity checks before financial actions, prompt instructions alone still fail some of the timeSplitting a request with several concerns into separate items, investigating each in parallel with shared context, then giving one combined resolution
Structured handoff protocols for escalation mid-process: customer details, root cause, recommended actionWriting structured handoff summaries (customer ID, root cause, refund amount, recommended action) for human agents who cannot see the transcript

Prompt guidance or code enforcement?

A system prompt can say "always verify the customer before touching their account". Claude follows that most of the time. The guide's point is that "most of the time" is not good enough when a skipped step moves money or exposes someone else's data. For those steps, put a gate in code that the agent cannot get past.

The requirementUseWhy
A step must always come before another (verify, then refund)Prerequisite gate in codeThe later call is blocked until the earlier one has succeeded
A single action must never exceed a limitPreToolUse hook on that toolChecked on every call (see 1.5 Agent SDK hooks)
A preferred order that is fine to varyPrompt guidanceFlexibility helps; an occasional miss costs little
The steps never change and need no judgementFixed workflow in your own codeNo agent decision is needed (see 1.1)

Who owns each step: Claude, code or a person

Before placing gates, split the workflow into steps and give each one an owner. Three questions decide it: can a wrong call be undone, what does a wrong call cost, and who has to answer for it?

  • Claude owns language work: reading a free-text complaint, investigating across tools, drafting the reply.
  • Code or an existing system owns rules that must give the same answer every time (thresholds, eligibility, identity checks) and lookups of live data.
  • A person owns decisions that are costly, hard to reverse, or need someone accountable.

A worked example shows why the split matters. A lender's agent routes loan applications, and any application above 250,000 must go to a senior underwriter. The team asks Claude to read the amount and route the case. It works on every test case. In production, some applicants write the amount in words or as a range ("roughly a quarter of a million"), and a few of those land in the standard queue. Nothing raises an error; an audit finds them months later. The better design keeps the parts apart: Claude extracts the amount into a structured field, code applies the threshold, and a missing or uncertain amount goes to a person.

Building a prerequisite gate

A prerequisite gate has two parts. One part records that the earlier step succeeded. The other part checks that record before the later tool runs. In the Claude Agent SDK you can build both with hooks: a PostToolUse hook on get_customer stores the verified ID, and a PreToolUse hook on the order and refund tools denies the call if no verified ID exists for this session.

from claude_agent_sdk import ClaudeAgentOptions, HookMatcher

verified_ids = {}   # session_id -> verified customer ID

def deny(reason):
    return {"hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "deny",
        "permissionDecisionReason": reason,
    }}

async def record_verification(input_data, tool_use_id, context):
    # your parser: returns the customer ID only if get_customer confirmed identity
    customer_id = parse_verified_id(input_data["tool_response"])
    if customer_id:
        verified_ids[input_data["session_id"]] = customer_id
    return {}

async def require_verified_customer(input_data, tool_use_id, context):
    verified = verified_ids.get(input_data["session_id"])
    if verified is None:
        return deny("Verify the customer with get_customer before order or refund actions.")
    if input_data["tool_input"].get("customer_id") != verified:
        return deny("This action must use the verified customer ID from get_customer.")
    return {}

options = ClaudeAgentOptions(hooks={
    "PostToolUse": [HookMatcher(matcher="mcp__support__get_customer",
                                hooks=[record_verification])],
    "PreToolUse": [HookMatcher(matcher="mcp__support__lookup_order|mcp__support__process_refund",
                               hooks=[require_verified_customer])],
})

Three details matter. The gate checks that verification succeeded, not just that get_customer was called. It also checks that the later call uses the same customer ID. And each denial gives Claude a clear reason, so it goes back and runs the missing step instead of retrying the blocked call. Hook syntax and options are covered on the 1.5 page; this page is about where the gates go.

Requests with several problems

Customers often raise more than one issue in a message: "My order arrived damaged, I was charged twice, and I can't log in." Treat it as three items, not one.

  1. Split. List each concern as its own item with what needs to be found out.
  2. Investigate in parallel. Look up each item. Independent lookups can go out as several tool calls in one response, and they share the same conversation, so a fact found for one item (the customer ID, the order) is available to the others.
  3. Resolve together. Write one reply that answers every item, says what was done for each and flags any item being escalated.

The common failure is answering only the first concern, or answering each one in a separate reply that contradicts the others.

Where a human gate goes

Not every step needs a person. Ask what the worst outcome is if the step runs unchecked, and gate only where that outcome is costly or permanent.

Point in the workflowWhat triggers the gateExample
Before an action that cannot be undoneThe agent is about to pay, delete, send or change a live recordA refund above the agent's limit
After a plan, before it runsThe agent has proposed a multi-step changeClosing and reopening 40 customer accounts
On an unexpected resultAn empty result, an error flag, or a value out of the expected rangeOne email address matches two customers

Low-cost, reversible steps (looking up an order, drafting a reply that a person sends) need no gate. Gating them only slows the work.

Timing matters as much as placement. The gate sits on the specific call, at the moment the agent proposes it. One approval at the start of a session cannot cover an action nobody has seen yet, and a review after the write (in the next pull request, say) approves something that has already happened. In the Agent SDK, the canUseTool callback asks a person about a specific call; if they deny it, Claude receives your message and can tell the customer or take another route. The callback never fires for tools that a permission rule or mode already approves, so a check that must run on every call belongs in a PreToolUse hook. And a gate is only real if someone staffs it: a "Claude drafts, a person approves" step with no reviewer assigned is an automated step.

Handing off to a person

When the agent escalates, the person who picks up the case usually cannot see the conversation. The handoff must stand on its own. Send a structured summary, not "customer is unhappy, please help" and not the raw transcript.

{
  "customer_id": "C-48213",
  "verified": true,
  "issue": "Duplicate charge on order 99187",
  "root_cause": "Payment retried after a gateway timeout; both captures succeeded",
  "evidence": ["Two captures 40 seconds apart on the same card", "Only one shipment"],
  "actions_taken": ["Confirmed duplicate with lookup_order", "Refund blocked: above agent limit"],
  "refund_amount": 640.00,
  "recommended_action": "Approve refund of the second capture",
  "customer_told": "A specialist will confirm the refund within one business day"
}

Each field answers a question the human would otherwise have to ask: who is this, what went wrong, why, what has already been done, and what should happen next. The customer_told field stops the human from promising something different.

Rules that decide exam answers

  • Required order means code. If a step must always come first, choose the prerequisite gate or hook. More emphatic prompt wording or extra examples still leave a failure rate.
  • Gate on success, not on attempt, and say why. A gate that only checks whether the verification tool was called lets a failed verification through. A denial with a clear reason lets Claude run the missing step instead of retrying.
  • Approve before the action, not after. A human gate sits on the specific risky call before it executes. A single approval at session start, or a review after the write, is the wrong answer.
  • Split multi-issue requests. Decompose, investigate each item, then give one combined resolution. Options that handle only the first issue are wrong.
  • Handoffs must stand alone. The human cannot see the transcript. Choose the structured summary with customer ID, root cause, amount and recommended action.
  • Give the rule to code, not to Claude. When a fixed threshold must route cases every time, let Claude extract the value and let code apply the rule. An option that asks Claude to "apply the threshold carefully" still leaves a failure rate.

Where it appears in the exam

Domain 1 is a primary domain in three of the six exam scenarios: Customer Support Resolution Agent, Multi-Agent Research System and Developer Productivity with Claude. Prerequisite gates, multi-concern requests and handoffs fit the Customer Support Resolution Agent scenario, which uses get_customer, lookup_order, process_refund and escalate_to_human. The guide's preparation exercise "Build a Multi-Tool Agent with Escalation Logic" reinforces this domain.

Two sample questions

These are original Timo practice questions. They are not official exam questions.

Question 1

A billing agent may call issue_credit only after verify_identity has confirmed the caller. The team added a hook that blocks issue_credit unless verify_identity appears earlier in the session. An audit finds credits issued in sessions where verification returned "failed". What should the team change?

Answer: A. The gate checked that verification was attempted, not that it succeeded. Recording the result and gating on success closes the hole. B adds probabilistic guidance on top of a broken gate. C removes the code check altogether. D reduces the damage but still lets unverified callers receive credit.

Question 2

A support agent escalates complex cases through escalate_to_human. The human team says that many escalations arrive as "Customer needs help with a billing problem", and they spend the first ten minutes asking the customer to repeat everything. Human agents cannot open the agent's conversation. What should the architect do?

Answer: D. A structured handoff gives the person everything they need without the transcript, and every case arrives in the same shape. A changes how many cases escalate, not what arrives. B adds a slow round trip for facts that should have been sent. C may help, but free text varies from case to case and can still miss key fields.

Build exercise

  1. Build a support agent with get_customer, lookup_order and process_refund tools, and add the two hooks above.
  2. Ask for a refund without giving any details. Confirm the refund is denied with a reason and that Claude then calls get_customer.
  3. Make get_customer return a failed verification and confirm the gate still blocks the refund.
  4. Send a message with three separate problems. Check that the agent investigates all three and replies once. Then force an escalation and check the handoff contains every field in the JSON above.

Practise this topic

Sources