πŸŽ“ Claude Architect KB CCAR-F Β· CCAR-P study guide

Domain 5 Β· Context Management & Reliability (15%)

Don't let the 15% fool you β€” this domain hides inside every other scenario as the "…and how do you make it production-ready?" follow-up. Context windows, caching, degradation, retries: the unglamorous stuff that decides whether people trust your agent. If Domain 1 is where you design the system, this is where you become the responsible adult who runs it.

πŸ“– New here? The two invisible forces: the window and entropy

Force one β€” the window. Everything the model "knows" in a call must fit in its context window, and everything competes for it: your instructions, the conversation so far, tool results, documents, and even the space reserved for the answer. Long chats "forget" their beginnings not from amnesia but from economics β€” something had to go. Nothing falls out by itself, though: in the raw Messages API earlier turns stay until the harness or product actively compacts or drops them; skip that and the request simply exceeds the window and errors (Claude Code auto-compacts as a product behavior). Context management is deciding, deliberately, what earns those tokens: summarize the old, retrieve on demand, isolate heavy work in subagents, and cache what never changes (the single biggest cost lever β€” repeat calls reuse the unchanged prefix at ~10% price).

Force two β€” entropy. In the demo, nothing fails. In production, everything does, on schedule: rate limits at your traffic peak, a truncated response the moment JSON matters, a dependency down during the demo to your VP. Reliability here isn't heroics β€” it's a checklist of boring guarantees: check why generation stopped before trusting it, back off and retry transient errors, make side effects idempotent so retries are safe, degrade gracefully to honest failure, and instrument everything so the 2 AM debug is a query, not an archaeology dig.

So what for the exam: these questions hide inside every scenario as "…and how do you make it production-ready?" The answers are always the same five words deep down: budget, cache, retry, idempotent, instrument.

Context management

🧭 Your seat at the table: this domain is you as the responsible adult of the system β€” deciding what earns space in the context budget, what happens when things fail (they will), and how you'll know what happened at 2 AM. None of it is glamorous; all of it is what separates a demo from a system people trust.

🧭 Decode every β€œremembers / forgets” before answering: the model owns the physics β€” the window's capacity, and attention effects like lost in the middle and recency bias (those genuinely ARE model behavior). Everything else is librarianship, and it is never the model's: every β€œthe agent remembers X” = your harness re-sent X in messages; every β€œit forgot” = your code dropped/compacted it, or the window overflowed by your arithmetic; prompt caching and server-side compaction = the API acting on your array, under flags you set; the memory tool = the model writes a request for a file operation and deterministic code executes it β€” the tool-use handshake, yet again. One test for any exam sentence: if the verb is about capacity or attention, the model; if it is about contents, the harness.

Who runs compaction? β€” the three-tier answer

The question every Claude Code user asks on their way to production: "I run /compact in the terminal β€” do I do that in my agent too, or is it automatic?" Depends entirely on which tier your system is built on:

You built on Context management is… Your job
Claude Code (interactive or headless) automatic β€” the product compacts as the window fills; /compact is the manual override mostly nothing; keep CLAUDE.md lean
Agent SDK inherited β€” the same engine's context handling, configurable tune it; trim your own tool results
Raw Claude API yours, entirely β€” the API is stateless; it never summarizes, and an over-long messages array is rejected with an error, not trimmed count tokens per call, trigger summarization at a threshold (~80%), keep a structured state object that survives compaction

πŸͺ€ Trap: "the long-running support agent suddenly gets API errors after ~40 turns β€” what happened?" The array outgrew the window, and on the raw Claude API nobody was compacting β€” there is no automatic anything. The answer is harness-side compaction + trimmed tool results, never "the API should handle it."

The budget mindset

The context window (200K tokens standard on current Claude models; larger tiers exist) is a budget, not a dumpster. Everything competes: system prompt, tool definitions, conversation history, tool results, retrieved documents, thinking tokens (the model's internal reasoning budget β€” see extended thinking), and the output allowance (max_tokens reserves from the same window).

flowchart LR
  subgraph Window[Context window]
    SP[System + tool defs β€” static prefix]
    H[History]
    TR[Tool results]
    D[Retrieved docs]
    OUT[Reserved output]
  end
  style SP fill:#e3f2ec
Technique What it does
Prompt caching cache the static prefix (system prompt, tool defs, big docs) so repeat calls skip reprocessing β€” order matters: stable content first, volatile last; cache_control breakpoints mark the cached prefix; cache lifetime β€” TTL (time-to-live) ~5 min, extendable β€” and cache reads cost ~10% of input price
Compaction / summarization replace old turns with a summary when nearing limits (Claude Code's /compact)
Context isolation via subagents heavy work in a worker's own window; return summaries
Just-in-time retrieval fetch data by tool call when needed instead of pre-loading everything
Structured note-taking agent persists state to files/scratchpads outside the window, re-reads on demand
Long-doc placement documents at top, instructions after; quote-then-answer for grounding

🎯 Caching questions test order sensitivity: a cache breakpoint only hits if everything before it is byte-identical. Put timestamps, user ids, and dynamic content AFTER the cached prefix β€” one changing byte upstream invalidates the cache.

πŸ” See it run β€” turn 42 of a support conversation: the budget arithmetic, with numbers

Entry point: a support agent is 42 turns into a messy billing dispute. Naively, the window now holds:

Block (diagram box) Naive After management
[System + tool defs β€” static prefix] 5,500 5,500 β€” but cached: byte-identical every call, so reads bill at ~10%
[History] 148,000 9,200 β€” turns 1–35 compacted into a summary + a structured state object
[Tool results] 22,000 3,100 β€” the harness trims each result to the fields the model needs (ids + amounts, not raw API dumps)
[Retrieved docs] 12,000 2,400 β€” the billing policy is fetched just-in-time by tool call at turn 41, not pre-loaded at turn 1
[Reserved output] 4,000 4,000 β€” max_tokens reserves from the same window
Total ~191K β€” one bad turn from the ceiling ~24K β€” and the model reasons better, in a cleaner context

The state object that survives compaction is the load-bearing trick:

JSON
{"customer": "c_2214", "issue": "double-charge on 2026-07-30", "amount_cents": 4998,
 "actions_taken": ["verified charge", "opened dispute D-102"], "promised": "resolution by Friday"}

Turns 1–35 can be summarized away because everything operational lives here β€” and the escalation packet, if needed, is built from this object, not from re-reading 42 raw turns.

The caching fine print the exam tests: the prefix only hits cache if everything before the breakpoint is byte-identical. Put a timestamp at the top of the system prompt and you invalidate the cache on every single call β€” the most expensive one-line mistake in agent economics.

Long-conversation strategy (support-agent scenario)

Rolling summarization + a structured state object (customer, issue, actions taken) that survives even when raw turns are compacted; tool results trimmed to the fields the model needs; escalation packets built from the state object, not the raw transcript.

Reliability engineering

Error taxonomy β€” the harness branches on these

The first three are HTTP status codes the Claude API's endpoint returns instead of a normal response; the rest are conditions your harness detects after a response arrives.

Signal Meaning Correct handling
429 rate limit throughput exceeded exponential backoff + jitter; respect retry-after; queue/shed load
529 overloaded upstream saturation backoff + retry; consider fallback model
500 API error transient fault bounded retries
stop_reason: max_tokens truncated output raise limit / continue / fail loudly β€” never parse as complete
Timeouts slow generation client timeouts + streaming to detect stalls early
Tool failure dependency down is_error tool_result β†’ model adapts, or harness escalates after N attempts
Schema-invalid output model drift (a model update quietly changing the output's shape over time) validate β†’ 1 retry with the error fed back β†’ escalate
πŸ” See it run β€” one night of a 10,000-invoice batch job, four failures, zero data loss

Entry point: the nightly extraction job starts at 1:00 AM. The log tells the story β€” each incident maps to one taxonomy row:

02:14 β€” 429 rate limit (another team's backfill started). The client reads retry-after: 8, backs off 8s + jitter, resumes. Throughput drops; nothing fails. Without backoff, retry-storms would have hammered the Claude API and turned one 429 into thousands.

02:31 β€” stop_reason: max_tokens on invoice #6,201 (a 14-page monster). The harness checks stop_reason before parsing, sees the truncation, re-runs that one document with a higher limit. The naive version parses half a JSON object and either crashes or β€” worse β€” silently stores a truncated total.

03:07 β€” timeout mid-write. Invoice #7,455's request dies after the extraction was recorded but before the client got the response. The retry fires with idempotency key inv-7455 β€” the effects ledger says "already recorded" β†’ skip. This is why idempotency is a taxonomy answer and not a nicety: retry + side effect without it = duplicate rows at 3 AM.

03:40 β€” 529 overloaded, persisting. After 3 bounded retries, the degradation ladder engages: remaining invoices route to the fallback model tier; 112 low-confidence extractions get flagged for human review instead of being guessed at. Honest failure beats silent failure β€” nobody discovers a hole in the data three weeks later.

07:00 β€” the report: 10,000 processed, 9,888 clean, 112 flagged, 0 lost, 0 duplicated. Cost within budget because the static prefix (instructions + schema) was cached across all 10K calls.

The exam version of this walkthrough is any question ending "…what should the harness have done?" β€” the answer is always the boring row in the taxonomy table, never heroics.

Resilience patterns

Observability β€” every action explainable, auditable, replayable

Log per step: prompt version + model + parameters, tool calls with args/results, stop reasons, token usage + cost, gate verdicts, and terminal status β€” with correlation ids per run (a shared id stamped on every log line of one run, so you can filter to just that run). Traces make agent debugging possible; aggregate metrics (success rate, escalation rate, cost/run, p95 latency β€” the slowest 5% of runs) make it manageable; evals make change safe (golden sets + negative controls β€” attack/should-fail cases that must stay failing β€” run on every prompt/model change).

πŸͺ€ Trap: "the agent works in the demo but fails unpredictably in production β€” first step?" The tested answer is instrument it (tracing/logging of the full loop), not "improve the prompt" or "switch models." Diagnosis before treatment.

Model version pinning & change management

Pin exact model versions in production (claude-…-20260219-style ids, not aliases); upgrades go through the eval suite first; keep a rollback path. Alias tracking is for dev, pinning is for prod β€” a recurring one-liner question.

Drill-down: rate-limit architecture at scale

Token buckets per model (each model gets a refilling allowance of requests; when it's empty, callers wait); central client with concurrency caps; queue with priority classes (interactive > batch); shed or defer batch work under pressure; per-tenant quotas so one customer can't starve others; monitor input/output token rates, not just request counts.

Drill-down: cost engineering checklist
  1. Cache the static prefix (largest lever in agent loops).
  2. Tier models per role (cheap classify / frontier reason / a judge model from a different family, so it doesn't rubber-stamp its own kind's output).
  3. Trim tool results β€” return ids + summaries, not payload dumps.
  4. Batch API for offline work; streaming for interactive.
  5. Cap loops (max turns) and alert on cost-per-run outliers.
  6. Track tokens as a first-class metric per feature.

Context & reliability as real files β€” annotated, clickable

JSONC
// the MOVING BREAKPOINT β€” this turn WRITES the cache, the next turn READS it
{
  "system": [{ "type": "text", "text": "…8K of stable rules…",
               "cache_control": { "type": "ephemeral" } }],       // fixed breakpoint
  "messages": [ /* …history… */,
    { "role": "user", "content": [{ "type": "text", "text": "newest question",
        "cache_control": { "type": "ephemeral" } }] }             // moving breakpoint
  ]
}
JSONC
// a COMPACTION trace event β€” a routine, logged decision, never an outage
{ "type": "compaction", "before_tokens": 161240, "after_tokens": 42730,
  "kept_turns": 8, "facts_saved_to_state": ["migrated_files", "open_ids"] }
PYTHON
# PRE-FLIGHT fit check β€” measure, don't guess (count_tokens is exact, free, no generation)
n = client.messages.count_tokens(model=MODEL, system=system, tools=tools, messages=msgs).input_tokens
if n + MAX_OUT + MARGIN > WINDOW:
    msgs = compact(msgs)                 # BEFORE create β€” never learn "too long" from a 400

Specimens in the wild: cookbook:misc/prompt_caching.ipynb Β· cookbook:misc/session_memory_compaction.ipynb β€” client-side compaction + the moving breakpoint Β· cookbook:tool_use/automatic-context-compaction.ipynb β€” server-side, threshold-driven Β· cookbook:cost_optimization/cost_optimization.ipynb.

Named reliability patterns the exam tests

Lost in the middle β€” position effects

Models process the beginning and end of long inputs reliably and may drop findings from the middle. Two tested mitigations: place a key-findings summary at the top of aggregated input, and organize detail under explicit section headers so nothing important lives only mid-document. Related budget leak: verbose tool results (a 40-field order lookup when 5 fields matter) β€” trim to return-relevant fields before they accumulate, and extract transactional facts (amounts, dates, order numbers) into a persistent "case facts" block that rides outside the summarized history, where progressive summarization can't blur them into vagueness.

Scratchpads & crash-recovery manifests

Extended sessions degrade: the model starts answering from "typical patterns" instead of the specific classes it discovered an hour ago. Two structural fixes:

Confidence calibration & stratified sampling (human-review routing)

Provenance β€” claim-source mappings through synthesis

Summarization steps lose attribution unless the pipeline forces structure: subagents output claim β†’ source mappings (URL, document name, relevant excerpt) that synthesis agents must preserve and merge, never flatten. Three tested corollaries:

Practice this domain

🎯 Done with Domain 5? Prove it: Context & Reliability (Q27–Q30) β€” commit to an answer before revealing. Locally, your picks are captured with timestamps and scored per section, so weak spots surface on the practice page's comfort tiles.