Study guides / CCAR-F / Domain 1

Agentic Architecture & Orchestration · Lesson 6 of 7

1.6 - Task Decomposition Strategies

Design task decomposition strategies using fixed sequential pipelines and dynamic adaptive decomposition, and solve the attention dilution problem.

Task decomposition is how you break complex work into pieces an agentic system can actually handle. The exam tests two patterns and expects you to pick the right one for the task in front of you. Pick wrong and the work suffers in predictable ways. It also tests one specific failure mode - attention dilution - that shows up when decomposition is too shallow.

Pattern 1: Fixed Sequential Pipelines (Prompt Chaining)

Fixed sequential pipelines break work into predetermined steps that execute in order. Each step takes the output of the previous step as input.

How it works: The workflow is defined in advance. Step 1 runs, its output feeds into Step 2, Step 2's output feeds into Step 3, and so on. The sequence does not change based on intermediate results.

Example - Code review pipeline:

  1. For each file, run a local analysis pass (style, bugs, complexity).
  2. After all local passes, run a cross-file integration pass (data flow, API consistency, import chains).
  3. Compile results into a unified review report.

Best for: Predictable, structured tasks where the steps are known in advance. Code reviews, document processing, data extraction pipelines, and compliance checks all fit this pattern.

Advantages: Consistent and reliable. The same input always follows the same path. Easy to debug - you know exactly which step produced which output. Easy to monitor - you can log the output of each step.

Limitations: Cannot adapt to unexpected findings. If Step 2 discovers something that should change the approach for Step 3, the pipeline can't adjust. The steps are fixed regardless of what turns up along the way.

Key Concept

Fixed sequential pipelines (prompt chaining) are best for predictable, structured tasks. They provide consistency and reliability but cannot adapt to unexpected findings during execution.

Pattern 2: Dynamic Adaptive Decomposition

Dynamic adaptive decomposition generates subtasks based on what is discovered at each step. The plan evolves as the agent learns more about the problem.

How it works: The agent starts with a high-level goal, performs initial investigation, and generates a plan based on what it finds. As it executes the plan, it discovers new information that may change the remaining steps. The agent adapts the plan accordingly.

Example - Adding tests to a legacy codebase:

  1. Map the codebase structure (directories, modules, dependencies).
  2. Identify high-impact areas (most-used modules, modules with the most bugs, untested critical paths).
  3. Create a prioritised test plan based on the mapping.
  4. Start writing tests. Discover that Module A depends on Module B, which has no tests.
  5. Reprioritise: test Module B first so Module A's tests can rely on it.
  6. Continue adapting as new dependencies and issues emerge.

Best for: Open-ended investigation tasks where the full scope is not known at the start. Legacy system exploration, security audits, research projects, and debugging unfamiliar codebases all benefit from this pattern.

Advantages: Adapts to the problem. Can discover and respond to unexpected complexity. Produces more thorough results for open-ended tasks because it does not force-fit a predetermined plan.

Limitations: Less predictable. Execution time varies depending on what is discovered. Harder to estimate completion time or resource usage. More difficult to debug when things go wrong.

Selecting the Right Pattern

The exam tests your ability to match the pattern to the task:

Task Characteristics Pattern Reasoning
Steps known in advance, structured input Fixed pipeline Consistency and reliability outweigh adaptability
Open-ended, unknown scope Dynamic decomposition Adaptability is essential when the problem is not fully defined
Multi-file code review Fixed pipeline Per-file analysis + cross-file integration is predictable
Legacy codebase exploration Dynamic decomposition Dependencies and issues emerge during investigation
Document extraction Fixed pipeline Fields and format are predetermined
Debugging an unfamiliar system Dynamic decomposition Root cause is unknown; investigation must adapt

Exam Trap

The exam may present a fixed pipeline as the solution for an open-ended investigation task, or dynamic decomposition for a structured processing task. Match the pattern to the task characteristics, not to what sounds more sophisticated.

The Attention Dilution Problem

Attention dilution is a specific failure mode that occurs when an agent processes too many items in a single pass. The result is inconsistent depth - the agent produces thorough analysis for some items and misses obvious issues in others.

The telltale symptoms:

Why it happens: The model allocates attention across all items in the context. When there are too many items, attention per item decreases. Early items get disproportionate attention; later items get skimmed.

The fix: Multi-pass architecture. Split the work into two layers:

  1. Per-item local analysis passes: analyse each file (or document, or module) individually in its own pass. Each pass has the full attention budget focused on a single item.
  2. Cross-item integration pass: after all local passes complete, run a separate pass that looks across all items for cross-cutting concerns (data flow issues, inconsistent pattern usage, cross-file dependencies).

The per-item passes catch local issues consistently because each item gets dedicated attention. The integration pass catches cross-item issues because it focuses specifically on relationships between items rather than trying to do everything at once.

Practical Example: The 14-File Code Review

A code review agent processes 14 files in a single pass. The results:

This is attention dilution. The fix is not a better model, a larger context window, or a more detailed prompt. The fix is structural: split into 14 per-file analysis passes (each focused on one file) plus a cross-file integration pass (checking for data flow issues and pattern consistency across all files).

The multi-pass approach catches the null pointer bugs in Files 10-14 (because each file gets its own dedicated pass) and identifies the inconsistent forEach evaluation (because the integration pass specifically checks for cross-file pattern consistency).

Exam traps

Practice question

A code review agent processes 14 files and produces detailed feedback for the first 5 files but misses obvious bugs in files 10-14. It also flags a forEach loop as inefficient in one file while approving identical code in another. What is the root cause and the most appropriate solution?

  • A The model context window is too small to hold all 14 files - upgrade to a model with a larger context window

    Context window size is not the issue. Attention dilution occurs because processing too many items in a single pass produces inconsistent depth, regardless of how much context the model can hold. A larger window does not fix uneven attention allocation.

  • B Split the review into per-file local analysis passes plus a separate cross-file integration pass to avoid attention dilution Correct

    Multi-pass architecture solves attention dilution. Per-file passes ensure each file receives dedicated, consistent analysis. The cross-file integration pass catches data flow issues and pattern inconsistencies. This addresses both symptoms: missed bugs in later files and contradictory pattern evaluation.

  • C Add a stronger system prompt emphasising the importance of reviewing all files with equal thoroughness

    Prompt improvements do not solve attention dilution. The fundamental issue is processing too many items in a single pass, which is an architectural problem requiring a structural solution, not a prompting solution.

  • D Reduce the number of files per review to 5 and process in sequential batches of 5 files each

    Batching is closer to the right idea and solves within-batch attention dilution, but it misses cross-batch issues. Without a separate cross-file integration pass, data flow issues between batches and pattern consistency across all 14 files are not addressed.

Build exercise: Build a Multi-Pass Code Review Pipeline

Advanced · 60 minutes

You'll practice:

  1. Create a code review agent that accepts a directory path containing at least 10 source files

    The 10+ file threshold is where attention dilution becomes observable. The exam uses a 14-file example where detailed feedback for early files degrades to superficial analysis for later files. Your setup must replicate this scale.

    You should see: A code review function that reads all files in a directory and prepares them for analysis. It should handle at least 10 TypeScript or JavaScript source files.

    Hints
    1. You need a directory with enough files to observe attention degradation. What kind of files would have reviewable code patterns?
    2. Create or use a directory with 10-15 source files that contain a mix of good code, bugs, and repeated patterns. Include at least one bug pattern that appears in multiple files.
    3. import fs from "fs";
      import path from "path";
      
      async function loadCodebase(dirPath: string): Promise<Map<string, string>> {
        const files = fs.readdirSync(dirPath)
          .filter(f => f.endsWith(".ts") || f.endsWith(".js"));
        const codebase = new Map<string, string>();
        for (const file of files) {
          codebase.set(file, fs.readFileSync(path.join(dirPath, file), "utf-8"));
        }
        console.log(`Loaded ${codebase.size} files for review`);
        return codebase;
      }
  2. Implement a single-pass review that processes all files at once and record the results

    The single-pass approach is the baseline that demonstrates attention dilution. The exam expects you to recognise the symptoms: thorough analysis for early files, shallow analysis for later files, and contradictory pattern evaluation.

    You should see: A review result where early files receive detailed feedback with specific line references and bug identification, while later files receive increasingly brief or missing feedback. This is the attention dilution pattern.

    Hints
    1. Pass all file contents to the model in a single prompt. How does the analysis quality vary from first file to last?
    2. Concatenate all file contents into a single prompt and ask for a code review. Record the number of issues found per file and the level of detail for each.
    3. async function singlePassReview(codebase: Map<string, string>): Promise<ReviewResult[]> {
        const allCode = Array.from(codebase.entries())
          .map(([name, content]) => `=== ${name} ===\n${content}`)
          .join("\n\n");
        const response = await client.messages.create({
          model: "claude-sonnet-5",
          max_tokens: 4096,
          messages: [{
            role: "user",
            content: `Review all files for bugs, style issues, and security vulnerabilities. Provide specific line references for each issue.\n\n${allCode}`
          }]
        });
        return parseReviewResults(response.content[0].text);
      }
  3. Implement per-file local analysis passes that produce structured feedback for each file individually (bug count, severity, specific line references)

    Per-file passes give each file the full attention budget. This is the first layer of multi-pass architecture. The exam contrasts this with single-pass to show that structural decomposition solves attention dilution, not better prompts or larger context windows.

    You should see: Consistent analysis depth across all files. The last file receives the same level of detail as the first. Each review includes bug count, severity ratings, and specific line references in a structured format.

    Hints
    1. How does reviewing one file at a time change the attention allocation? Each file gets the full context budget.
    2. Send each file individually to the model with the same review prompt. Collect structured output for each: file name, issues array with line numbers, severity, and description.
    3. interface FileReview {
        fileName: string;
        issues: { line: number; severity: string; description: string }[];
        bugCount: number;
      }
      
      async function perFileReview(codebase: Map<string, string>): Promise<FileReview[]> {
        const reviews: FileReview[] = [];
        for (const [name, content] of codebase) {
          const response = await client.messages.create({
            model: "claude-sonnet-5",
            max_tokens: 2048,
            messages: [{
              role: "user",
              content: `Review this file for bugs, style issues, and security vulnerabilities. Return JSON with issues array (line, severity, description).\n\n=== ${name} ===\n${content}`
            }]
          });
          reviews.push(JSON.parse(response.content[0].text));
        }
        return reviews;
      }
  4. Implement a cross-file integration pass that checks for data flow issues, API consistency, and pattern usage consistency across all files

    Per-file passes catch local issues but miss cross-cutting concerns. The exam tests whether you include a cross-file integration pass - batching without it still misses data flow issues and pattern inconsistencies across files.

    You should see: A separate analysis that takes the per-file summaries and checks for cross-file issues: inconsistent API usage, data flow problems between modules, and patterns used differently across files.

    Hints
    1. What can a cross-file pass catch that per-file passes cannot? Think about relationships between files.
    2. Feed the per-file review summaries plus file structure information into a dedicated cross-file prompt. Ask specifically about data flow, import chains, API consistency, and contradictory pattern usage.
    3. async function crossFilePass(codebase: Map<string, string>, perFileResults: FileReview[]): Promise<CrossFileIssue[]> {
        const summary = perFileResults.map(r =>
          `${r.fileName}: ${r.bugCount} issues - ${r.issues.map(i => i.description).join("; ")}`
        ).join("\n");
        const imports = extractImportGraph(codebase);
        const response = await client.messages.create({
          model: "claude-sonnet-5",
          max_tokens: 2048,
          messages: [{
            role: "user",
            content: `Cross-file integration review. Check for:\n1. Data flow issues between modules\n2. Inconsistent API usage across files\n3. Same pattern handled differently in different files\n\nPer-file summaries:\n${summary}\n\nImport graph:\n${JSON.stringify(imports)}`
          }]
        });
        return JSON.parse(response.content[0].text);
      }
  5. Compare results: document which issues the single-pass review caught versus the multi-pass approach, paying special attention to consistency of analysis depth across all files

    This comparison demonstrates the exam argument quantitatively. Attention dilution is not a model capability problem - it is an architectural problem. The same model produces better results with multi-pass architecture, proving the fix is structural.

    You should see: A comparison table showing: more total issues found by multi-pass, consistent issue counts across files (no drop-off for later files), and cross-file issues caught only by the integration pass.

    Hints
    1. Compare issue counts per file between single-pass and multi-pass. Is there a drop-off pattern in single-pass that disappears in multi-pass?
    2. For each file, compare the number of issues found in single-pass vs per-file pass. Calculate the standard deviation of issues per file for each approach - lower deviation means more consistent analysis.
    3. function compareResults(singlePass: ReviewResult[], multiPass: FileReview[]) {
        console.log("=== Consistency Comparison ===");
        for (let i = 0; i < multiPass.length; i++) {
          const sp = singlePass.find(r => r.fileName === multiPass[i].fileName);
          console.log(`${multiPass[i].fileName}: single-pass=${sp?.issues.length ?? 0}, multi-pass=${multiPass[i].bugCount}`);
        }
        const spCounts = singlePass.map(r => r.issues.length);
        const mpCounts = multiPass.map(r => r.bugCount);
        console.log(`Single-pass std dev: ${stdDev(spCounts).toFixed(2)}`);
        console.log(`Multi-pass std dev: ${stdDev(mpCounts).toFixed(2)}`);
      }
  6. Record any cases where the single-pass review flagged a pattern in one file but approved identical code in another - these are attention dilution artefacts

    Contradictory pattern evaluation is the clearest symptom of attention dilution. The exam uses the forEach example: flagged as inefficient in File 3, approved without comment in File 11. Documenting these artefacts proves the structural nature of the problem.

    You should see: At least one case where the single-pass review treated identical code patterns differently across files. The multi-pass review should treat the same pattern consistently.

    Hints
    1. Search for the same code pattern appearing in multiple files. Did the single-pass review evaluate it consistently?
    2. Compare the single-pass findings for files that contain the same patterns. Look for cases where a pattern was flagged in an early file but ignored in a later file.
    3. function findContradictions(results: ReviewResult[], codebase: Map<string, string>): string[] {
        const contradictions: string[] = [];
        const patternFiles = findDuplicatePatterns(codebase);
        for (const [pattern, files] of patternFiles) {
          const flagged = files.filter(f =>
            results.find(r => r.fileName === f)?.issues.some(i => i.description.includes(pattern))
          );
          const notFlagged = files.filter(f => !flagged.includes(f));
          if (flagged.length > 0 && notFlagged.length > 0) {
            contradictions.push(
              `Pattern "${pattern}" flagged in [${flagged.join(", ")}] but approved in [${notFlagged.join(", ")}]`
            );
          }
        }
        return contradictions;
      }

Sources