Domain 5 is worth 15% — roughly 9 questions out of 60. It's the smallest, and the most cross-cutting: its questions revisit situations from the four other domains (subagents, tools, sessions, extraction) under a single angle — what happens when it doesn't fit, when it fails, when it contradicts itself? A candidate who has worked Domains 1 to 4 well already has 70% of this domain; the rest is a small number of reliability reflexes the exam expects by name: structured summary rather than truncation, partial result with explicit gaps rather than nothing, enriched error rather than swallowed or raw, source attached to every claim, normalization at ingestion.
This lesson follows the 6 task statements of the official exam guide v1.0 (July 2026). The exam scenarios that lean on this domain are the Multi-Agent Research System (scenario 3), the Document Processing Pipeline (scenario 6) and Developer Productivity (scenario 4).
The domain map
Three questions structure the domain: how much fits (5.1 budget, 5.2 compaction), what survives (5.3 memory), and what happens when it breaks (5.4 degradation, 5.5 propagation, 5.6 attribution and formats).
5.1 — The context budget
The context window isn't "large" or "small": it's a budget shared by four line items. The exam tests whether you know what consumes it and what must stay in it.
What you need to know
Four line items. The system prompt and tool definitions (fixed, paid every turn), the conversation history (grows), tool results (the item that explodes: files read, pages fetched, logs). An agent that reads 30 files in full has consumed its window before it started reasoning.
Quality degrades before the limit. It's not a wall: it's a slope. Attention dilution (Domain 1, 1.6), early instructions less respected, contradictory results depending on position in context. A "model with more context" pushes the wall back, not the slope.
Offload the verbose. A subagent (Explore in Claude Code, Task in the SDK) does the reading in its own isolated context and only returns a summary (Domain 3, 3.4). It's the expected answer whenever the prompt mentions "read dozens of files", "walk the codebase", "go through documents".
Summarize before injecting. A bulky tool result is reduced to its useful facts before entering the window: PostToolUse hook (Domain 1, 1.5) or tool-side preprocessing.
Restrict the fixed. Tools per role (Domain 2, 2.3), glob rules loaded conditionally (Domain 3, 3.3): every irrelevant fixed token is paid every turn.
5.2 — Compaction: the structured summary
When the window approaches the limit mid-task, you must make room. The question is how: what you keep, what you summarize, what you discard.
What you need to know
The structured summary. When compacting, you replace history with a summary that keeps: the original goal and constraints, decisions made and why, verified facts (with their source), gaps and uncertainties, what was attempted and failed, next steps. You discard raw tool results and reasoning back-and-forth.
Why not truncation. Cutting the beginning removes the goal and constraints: the agent keeps working, but on a task whose rules it no longer knows. The sliding window (keeping the last N turns) has the same flaw, with bounded cost; acceptable for a short stateless conversation, not for a multi-phase task.
When to start over. If compaction leaves a context that's mostly stale (code changed, results no longer reflect reality), you start a fresh session with the structured summary as initial context (Domain 1, 1.7). The summary is the exchange format between sessions.
Summarize per phase. On a long task, you compact at each phase change (end of exploration → summary → implementation), not only when the limit approaches. Compaction becomes a rhythm, not an emergency.
COMPACTION_SCHEMA = {
"name": "compact_context",
"description": "Produces the structured summary that replaces history. Keeps NO raw tool output.",
"input_schema": {"type": "object", "properties": {
"goal": {"type": "string", "description": "Original goal, constraints included"},
"decisions": {"type": "array", "items": {"type": "object",
"properties": {"what": {"type": "string"}, "why": {"type": "string"}}, "required": ["what", "why"]}},
"verified_facts": {"type": "array", "items": {"type": "object",
"properties": {"fact": {"type": "string"}, "source": {"type": "string"}}, "required": ["fact", "source"]}},
"open_gaps": {"type": "array", "items": {"type": "string"}},
"failed_attempts": {"type": "array", "items": {"type": "string"}},
"next_steps": {"type": "array", "items": {"type": "string"}},
"touched_files": {"type": "array", "items": {"type": "string"}},
}, "required": ["goal", "decisions", "verified_facts", "open_gaps", "next_steps"]},
}
def compact(messages):
resp = client.messages.create(model=M, max_tokens=2048, tools=[COMPACTION_SCHEMA],
tool_choice={"type": "tool", "name": "compact_context"},
messages=messages + [{"role": "user", "content": "Compact the history."}])
summary = next(b for b in resp.content if b.type == "tool_use").input
# New context: system + structured summary + the last 2 raw turns
return [{"role": "user", "content": f"<context_summary>{json.dumps(summary, ensure_ascii=False)}</context_summary>"}] + messages[-4:]5.3 — Persistent memory across sessions
A session ends. What must survive depends on its nature — and the exam tests precisely this placement choice.
Which memory mechanism for which information?
| Information | Expected location | |
|---|---|---|
| Conventions, standards, stable architecture | "Always true", shared by the team | Project CLAUDE.md (version-controlled) — Domain 3 |
| State of work in progress | Decisions, gaps, next steps of a multi-day task | Memory file / structured summary injected at start |
| Large history, search | Thousands of tickets, past decisions, documents | External store (SQL, vectors) queried by a tool |
| Personal preferences | A developer's style, language, favorite tools | ~/.claude/CLAUDE.md (never shared) |
| Raw tool results, logs | Files read, pages fetched, test outputs | Do NOT persist — regenerate, go stale |
| Named investigation sessions | Resume a still-valid analysis | --resume <name> (+ flag modified files) |
What you need to know
Choose by nature, not convenience. A convention goes in CLAUDE.md because it's stable and shared. The state of work in progress goes in a memory file or structured summary because it's temporary and task-specific. A large history goes in an external store because it doesn't fit in a file and you search it rather than read it.
What you don't persist. Raw tool results: they regenerate in one call and go stale fast. Persisting a file read yesterday means reasoning tomorrow on a false version. You persist the conclusions drawn, with their source, not the raw material.
The structured summary as exchange format. The same schema as in 5.2 serves as cross-session memory: written at session end, injected at the start of the next. It's dated and lists touched files, which tells you what may have changed.
Memory ≠ context. An external store doesn't load everything into the window: a tool queries it and returns only relevant entries. That's what allows months of memory without blowing the 5.1 budget.
CLAUDE.md": that file is loaded every session, it grows, and a task's temporary state pollutes permanent conventions. "Persist the full conversation history": verbose, stale, and must be reread in full. "A vector store for team conventions": oversized for twenty stable lines that must be read every time, not searched.5.4 — Graceful degradation
A tool doesn't respond, a source is unavailable, a process exceeds its deadline. The exam has a clear stance: an honest partial result beats nothing, and infinitely beats a lying success.
What you need to know
Bounded timeouts. Every external call has a maximum delay. Without it, a tool that doesn't respond blocks the agent, then the coordinator, then the pipeline.
Fallback. When the main call fails: alternative source (second search engine, yesterday's cache), retry with backoff for the transient (Domain 2, 2.2), or degraded functionality (report without the patents section rather than no report).
The partial result with explicit gaps. The output carries its completeness state: what's covered, what's missing, why, whether it's retryable. A report on four sources out of five, with the fifth flagged as missing, is a deliverable. A "complete" report that hides the absence of the fifth is a data error.
Never a lying success. Turning a failure into an empty result marked success is the gravest anti-pattern of the domain (already met in 2.2 and 5.5). Uncertainty is expressed: confidence, status, missing[].
5.5 — Error propagation between agents
Question 8 of the official guide. The web search subagent fails on timeout; depending on the version, the coordinator receives a raw error that kills the workflow, or nothing at all and produces a report without knowing a source is missing. What do you do?
What you need to know
Local recovery first. The subagent handles what it can itself: retry with backoff on transients, alternative source if within its scope. It only escalates what it couldn't resolve.
Enrich what escalates. The error passed to the coordinator contains: the category (transient / validation / business / permission), what was attempted (and how many times), the partial results obtained, the possible alternatives. That's what lets the coordinator choose: re-delegate, continue with a flagged gap, retry later, escalate.
The coordinator decides. Not the subagent: it only sees its task, the coordinator sees the whole (the four other sources, the deadline, the relative importance of the missing source). Consistent with Domain 1's hub-and-spoke.
Neither suppression nor raw. The two distractors of question 8: "catch the error and return an empty result as success" (the coordinator produces a report with a hole without knowing) and "local retry then generic failure status" (the retry is good, the generic prevents the decision).
# Subagent: local recovery, then ENRICHED error to the coordinator
def web_search_subagent(queries: list[str]) -> dict:
results, failed = [], []
for q in queries:
try:
results += search_with_retry(q, attempts=2, backoff=1.5, timeout=30) # local recovery
except TransientError as e:
failed.append({"query": q, "category": "transient", "attempts": 2, "last_error": str(e)})
if not failed:
return {"status": "ok", "results": results}
return { # neither silent [] nor raw raise
"status": "partial" if results else "failed",
"results": results, # partials preserved
"failed": failed,
"retryable": True,
"alternatives": ["cache_yesterday", "engine_b"],
"coverage": f"{len(queries) - len(failed)}/{len(queries)} queries",
}
# Coordinator: it DECIDES with the information received
out = web_search_subagent(queries)
if out["status"] == "partial":
alt = delegate("web_search", failed_queries(out), source="engine_b") # re-delegate via the alternative
report = synthesize(out["results"] + alt["results"], gaps=still_failed(alt)) # gap flagged if it persists[] as success, never a raw raise.5.6 — Source attribution and heterogeneous formats
Two topics linked by the same idea: the reliability of what comes out depends on discipline at the input. Anchored on scenarios 3 (research) and 6 (documents).
What you need to know
Content and metadata separated, from ingestion. The text of a finding on one side; the URL, document, page, date, source identifier on the other. In prose, attribution is lost at the first synthesis (Domain 1, 1.3).
The source follows the claim end to end. Every agent that transforms the data keeps the source_ids. The final report can trace any sentence back to its source.
Constrain by the schema. "Cite your sources" in the prompt produces plausible but invented references. The synthesis schema has a source_ids field whose values are restricted to the enum of sources actually provided: a citation outside the set is rejected at validation (Domain 4, 4.2).
Normalize at ingestion. Dates (Unix, ISO, "12/03/2026"), units (k€, M$), encodings, coded statuses: you convert once, at input (PostToolUse hook, preprocessing), and all downstream agents see a single format (Domain 1, 1.5). Asking the model to juggle formats is an error source at every step.
Contradictions flagged, not merged. Two sources give two figures for the same quantity: you don't average, you don't pick at random. A conflicts[] field carries both values, their sources and dates; the reader (or an explicit rule: "the most recent source wins") decides.
# Structured finding between agents: content | metadata, never prose
finding = {"id": "F42", "claim": "The market reached €4.2bn in 2025",
"source_id": "S3", "url": "https://…", "doc": "report-2026.pdf", "page": 14,
"published": "2026-02-11", "value": {"amount": 4.2e9, "currency": "EUR", "year": 2025}}
# Synthesis schema: source_ids constrained to the provided sources
def synthesis_tool(source_ids: list[str]) -> dict:
return {"name": "write_synthesis",
"input_schema": {"type": "object", "properties": {
"claims": {"type": "array", "items": {"type": "object", "properties": {
"text": {"type": "string"},
"source_ids": {"type": "array", "minItems": 1,
"items": {"type": "string", "enum": source_ids}}, # ← no invention possible
"confidence": {"type": "string", "enum": ["high", "medium", "low"]}},
"required": ["text", "source_ids", "confidence"]}},
"conflicts": {"type": "array", "items": {"type": "object", "properties": {
"topic": {"type": "string"},
"values": {"type": "array", "items": {"type": "object", "properties": {
"value": {"type": "string"}, "source_id": {"type": "string", "enum": source_ids},
"published": {"type": "string"}}, "required": ["value", "source_id"]}}},
"required": ["topic", "values"]}}, # ← contradiction exposed
"gaps": {"type": "array", "items": {"type": "string"}}},
"required": ["claims", "conflicts", "gaps"]}}source_id carried end to end and constrained by the schema.Cross-cutting traps of Domain 5
- Result honesty comes first. Partial with gaps, exposed contradiction, declared uncertainty: any option that "smooths" for a clean look is a distractor.
- Structure preserves, prose loses. Structured summary, structured finding, structured error: whenever information crosses a boundary (turn, session, agent), it travels as structure.
- You process at input, not at every step. Normalization, content/metadata separation, summarizing the verbose: once, at ingestion.
- The level that sees the whole decides. The coordinator, not the subagent; the schema, not the model; the explicit rule, not chance.
Night-before checklist
Task) or summary before injection; fixed → tools per role, glob rules.
- Limit near → structured summary (goal, decisions + why, sourced facts, gaps, failures, next, touched files), never truncation or sliding window on a multi-phase task.
- Stale context → fresh session + summary; long task → compact at each phase.
- Memory by nature: conventions → CLAUDE.md; work in progress → memory file / dated summary; volume → external store queried by tool; personal → ~/.claude/CLAUDE.md.
- Never persist raw tool results.
- Partial failure → bounded timeout + fallback + partial with explicit gaps (status, missing[], confidence).
- Never a lying success, never all-or-nothing.
- Between agents: local retry, then enriched error (category, attempts, partials, alternatives); the coordinator decides.
- Neither [] as success, nor raw exception.
- Content | metadata separated at ingestion; source_id carried end to end.
- source_ids constrained by the schema to the enum of provided sources → invented citation impossible.
- Heterogeneous formats normalized once at input (PostToolUse / preprocessing).
- Contradictions → conflicts[] with values, sources, dates; never silently merged.Five original scenario questions, corrected
Questions written by nAIvigate in the spirit of the exam, reproducing no real items.
Question 1 — Productivity scenario. A migration agent reads 60 files in full at the start of the task, then loses the constraints given in the first message and produces inconsistent changes. Fix?
A. Model with a larger window. B. Delegate the mapping to an Explore subagent that returns a structured summary, and compact at the end of the exploration phase before implementation. C. Repeat the constraints in every message. D. Truncate read results to the first 200 lines per file.
📚Answer Q1
B. Offload the verbose + structured summary per phase. A pushes the wall back without addressing dilution. C is a costly workaround. D loses information arbitrarily.
Question 2 — Research scenario. Out of five sources, the patents one times out. The current pipeline abandons the whole report. The PO wants "something deliverable". Approach?
A. Raise the timeout to 10 minutes. B. Deliver the report on four sources with status: "partial", missing: [{source: "patents", reason: "timeout", retryable: true}], and offer a re-run. C. Deliver the report on four sources without mentioning the fifth. D. Retry in a loop until success.
📚Answer Q2
B. Honest partial with explicit, retryable gap. A doesn't fix unavailability. C is a lying success. D has no bound.
Question 3 — Research scenario. The final report cites URLs that don't exist. The synthesis prompt says "always cite your sources with the URL". Fix?
A. Strengthen the instruction. B. Pass findings in a structured format with source_id, and constrain source_ids in the synthesis schema to the enum of actually collected identifiers. C. Check every URL afterwards and remove invalid ones. D. Ask the model for a confidence score per citation.
📚Answer Q3
B. The schema makes invention impossible; the instruction (A) stays probabilistic. C removes citations but leaves orphan claims and doesn't address the cause. D constrains nothing.
Question 4 — Document scenario. Three MCP servers return dates as Unix, ISO and "DD/MM/YYYY". The synthesis agent regularly gets the chronology wrong. Fix?
A. Add a table of formats to the synthesis prompt. B. Normalize to ISO 8601 at ingestion via a PostToolUse hook, so all downstream agents see a single format. C. Ask each MCP server to change its format. D. Have a dedicated subagent sort the dates.
📚Answer Q4
B. Normalization once at input. A makes the model carry the conversion at every step. C depends on third parties. D adds an agent for a data problem.
Question 5 — Research scenario. Two reliable sources give €3.8bn and €4.2bn for the same market in the same year. The current report shows "about €4bn". What do you do?
A. Keep the average, it's reasonable. B. Expose both values in a conflicts[] field with their sources and dates, and apply an explicit rule if one must win (e.g. the most recent). C. Take the best-known source without saying so. D. Remove the figure from the report.
📚Answer Q5
B. The contradiction is information; you flag it with its provenance. A destroys information. C hides a choice. D loses a useful fact.
Validation quiz
Which context window line item grows fastest in an agent that reads files?
📚Domain 5 glossary (expand)
Context budget — Split of the window between system prompt, tool definitions, history and tool results; planned, not endured.
Attention dilution — Quality degradation when too much content is processed at once, well before the hard limit.
Offloading — Having a subagent (Explore, Task) read the verbose and return only a summary.
Compaction — Replacing history with a structured summary when the window approaches its limit.
Structured summary — Goal, decisions and rationale, sourced facts, gaps, failures, next steps, touched files; exchange format between turns, phases and sessions.
Truncation — Anti-pattern: cutting old messages, losing goal and constraints.
Sliding window — Keeping the last N turns; bounded cost, same loss of the beginning; reserved for short stateless exchanges.
Persistent memory — What survives the session: chosen by nature (conventions, work in progress, volume, preferences).
Memory file — Dated structured summary written at session end and injected at the start of the next.
External store — SQL or vectors, queried by a tool; for volume and search, without loading the window.
Graceful degradation — Delivering a useful partial result rather than nothing, with explicit gaps.
Bounded timeout — Maximum delay on every external call; never an infinite wait.
Fallback — Alternative source, cache, retry with backoff, or degraded functionality when the main call fails.
Explicit partial result — Output carrying status, covered, missing[] (reason, attempts, retryable), confidence.
Lying success — Anti-pattern: failure turned into an empty or incomplete result shown as complete.
All-or-nothing — Anti-pattern: abandoning the whole process for a partial failure.
Local recovery — Subagent handling of what it can resolve (transient retry, alternative within its scope).
Enriched error — Category, attempts, partial results, alternatives; what escalates to the coordinator.
Silent suppression / raw propagation — The two anti-patterns of question 8: masking the error, or letting it kill the workflow.
Attribution (provenance) — Linking every claim to its source, kept end to end.
Content | metadata — Separation, from ingestion, of a finding's text and its source identifier, URL, document, page, date.
Constrained source_ids — Synthesis schema field restricted to the enum of provided sources; prevents invented citations.
Normalization at ingestion — Single conversion of heterogeneous formats (dates, units, encodings, statuses) at input, via PostToolUse or preprocessing.
conflicts[] — Field exposing contradictory values with their sources and dates, instead of merging them.
Going further
This was the last lesson of the series. The complete CCA-F guide gathers the five domains, the exam format and the revision plan; to see memory and drift handled in production, our article on persistent memory and personalization and the one on AI agent drift extend this domain.
If you want to certify a whole team — or make an existing multi-agent system reliable (context budget, compaction, error propagation, source attribution) before it fails in production — that's what nAIvigate Studio does in a Sprint.