Apply Iterative Refinement Techniques for Progressive Improvement
This module is about getting better results from Claude Code by giving it concrete feedback loops, not vague corrections.
The exam will test whether you know how to improve Claude’s output progressively using:
Concrete input/output examples
Tests and failure output
Interview-first clarification
Specific edge cases
Batching interacting issues
Sequentially fixing independent issues
Claude Code’s own docs describe its working loop as: gather context, take action, verify results, and repeat based on what it learns from tool outputs. For coding tasks, Claude may run tests, read failures, edit files, and rerun tests until the task is complete. (Claude)
1. Core mental model
This is about replacing vague guidance with observable signals.
Weak:
Better:
Here are three failing cases. Update the migration so these inputs produce the expected outputs, then run the test suite and iterate until it passes.
The exam shortcut:
Ambiguous transformation → give examples.
Unreliable implementation → give tests.
Unfamiliar domain → use interview pattern.
Edge-case bug → give exact input + expected output.
Interacting issues → provide together.
Independent issues → fix sequentially.
Claude Code best practices explicitly recommend giving Claude a check it can run, such as tests, a build, a linter, fixture comparison, or screenshot comparison, because that lets Claude read the result and iterate until the check passes. (Claude)
2. Concrete input/output examples
The official guide says concrete input/output examples are the most effective way to communicate expected transformations when prose is interpreted inconsistently.
This is especially important for:
Data migrations
String normalization
Formatting transformations
Code generation patterns
API response shaping
Schema conversions
Validation behavior
UI copy transformations
Anthropic’s prompting docs also say examples are one of the most reliable ways to steer output format, tone, and structure, and recommend making examples relevant, diverse, and structured. (Claude)
2.1 Weak prose-only instruction
Problems:
What does “normalize” mean?
Should null become empty string, unknown, or remain null?
Should whitespace be trimmed?
Should casing change?
What about non-Latin names?
2.2 Better: 2–3 concrete examples
Update normalizeCustomerName(input) so it follows these examples:
Example 1:
Input:
{ "firstName": " ashish ", "lastName": " dubey " }
Expected output:
"Ashish Dubey"
Example 2:
Input:
{ "firstName": "ASHISH", "lastName": null }
Expected output:
"Ashish"
Example 3:
Input:
{ "firstName": null, "lastName": null }
Expected output:
null
Preserve non-empty name parts, trim whitespace, title-case ASCII names, and return null only when both name parts are missing.
This gives Claude enough information to infer the transformation.
Exam rule
When natural language requirements are being interpreted inconsistently, the best fix is usually:
Not:
3. Example-driven correction
Concrete examples are also the best way to correct a wrong implementation.
Suppose Claude wrote a migration script that converts legacy records:
into:
But your desired behavior is:
Weak correction:
Better correction:
Fix null handling in the migration. These cases must pass:
Input:
{ "legacyStatus": null }
Expected:
{ "status": "UNKNOWN" }
Input:
{ "legacyStatus": "enabled" }
Expected:
{ "status": "ACTIVE" }
Input:
{ "legacyStatus": "disabled" }
Expected:
{ "status": "INACTIVE" }
Do not default null to ACTIVE.
This is exactly the kind of edge-case correction the exam is likely to test.
4. Test-driven iteration
The official statement emphasizes writing tests first, then iterating by sharing test failures.
This pattern is:
1. Define expected behavior.
2. Write tests for normal cases, edge cases, and performance requirements.
3. Ask Claude to implement.
4. Run tests.
5. Share failing output.
6. Claude fixes based on concrete failure signal.
7. Repeat until tests pass.
Claude Code docs recommend giving Claude verification criteria and show the same general pattern: provide a check, have Claude run it, read the result, and iterate. (Claude)
4.1 Weak prompt
This is underspecified.
4.2 Better test-driven prompt
First write tests for validateEmail covering:
Valid:
- user@example.com
- first.last+tag@example.co.uk
Invalid:
- invalid
- user@.com
- @example.com
- user@example
- null
- empty string
Then implement validateEmail so the tests pass.
Run the targeted test file and iterate until it passes.
This aligns with Claude Code’s recommended practice of providing test cases and asking Claude to run verification after implementation. (Claude)
5. Sharing test failures effectively
When tests fail, do not just say:
Give Claude the failure signal.
Better:
The following test is failing:
Test:
validateEmail(null) should return false
Failure:
TypeError: Cannot read properties of null (reading 'includes')
at validateEmail src/validation/email.ts:14
Expected:
false
Actual:
exception thrown
Fix the null handling without changing the passing cases.
Why this works:
It identifies the failing input.
It gives expected vs actual behavior.
It includes the stack trace.
It constrains the fix not to regress passing cases.
Claude Code’s agent loop documentation gives a similar example where Claude runs a test suite, reads failures, reads relevant files, edits code, reruns tests, and stops when tests pass. (Claude)
6. What tests should cover
For D3.5, tests are not just “unit tests exist.” The exam statement explicitly mentions:
Test suite design checklist
1. Happy path
2. Common invalid inputs
3. Null / undefined / empty values
4. Boundary values
5. Existing behavior that must not regress
6. Error handling
7. Performance constraints if relevant
8. Idempotency if relevant
9. Backward compatibility if relevant
Example: migration script tests
Expected behavior:
- enabled → ACTIVE
- disabled → INACTIVE
Edge cases:
- null → UNKNOWN
- empty string → UNKNOWN
- unrecognized string → UNKNOWN
- already migrated record remains unchanged
Performance:
- migrates 100,000 records within acceptable time
- does not load entire table into memory if streaming is required
Example prompt
Before implementing the migration, add tests for:
1. enabled/disabled status mapping
2. null legacyStatus
3. empty string legacyStatus
4. unknown legacyStatus
5. already-migrated rows
6. a large batch case to verify we process in chunks
Then implement the migration and iterate on failures.
7. The interview pattern
The interview pattern means asking Claude to ask you questions before implementation.
Use it when:
The domain is unfamiliar.
There are hidden tradeoffs.
Multiple design choices exist.
Requirements are incomplete.
Operational failure modes matter.
You suspect you have not considered important cases.
Claude Code’s Agent SDK docs describe an AskUserQuestion mechanism for clarifying questions; they give examples such as Claude asking about tech stack choices before proceeding when multiple valid directions exist. (Claude)
7.1 Interview pattern prompt
Before implementing, interview me.
Ask up to 7 questions that would affect the design. Focus on:
- cache invalidation
- failure modes
- data consistency
- rollback strategy
- performance constraints
- security implications
- backward compatibility
After I answer, summarize the design constraints and propose an implementation plan.
Do not edit files until then.
Good use case: cache design
Weak:
Better:
Before implementing caching for the pricing service, interview me about:
- acceptable staleness
- invalidation triggers
- cache key structure
- per-tenant isolation
- failure behavior when cache is unavailable
- metrics and observability
Why?
Caching has hidden design decisions.
Wrong assumptions can create stale data, tenant leaks, or hard-to-debug behavior.
Good use case: unfamiliar migration
Before writing the migration, ask me questions about:
- whether legacy null values have semantic meaning
- whether the migration must be reversible
- whether historical records should be backfilled
- whether the script must be idempotent
- batch size and performance constraints
8. When not to use the interview pattern
Do not overuse interviews for trivial changes.
Bad:
Better:
Use the interview pattern when developer input can materially change the design.
9. All issues at once vs sequential refinement
This is one of the trickiest exam concepts in D3.5.
The question is:
9.1 Provide all issues in one message when they interact
Use a single detailed message when fixes affect each other.
Examples:
API schema change + validation behavior + error response format
Migration null handling + idempotency + performance batching
Cache key design + invalidation + tenant isolation
UI state model + loading behavior + error rendering
Auth middleware order + permission checks + audit logging
Why?
Fixing one in isolation may create rework.
The correct design depends on seeing all constraints together.
Claude needs the full constraint set before editing.
Example: interacting issues
The current migration has three interacting problems:
1. Null legacyStatus must map to UNKNOWN, not ACTIVE.
2. The migration must be idempotent because it may be rerun after partial failure.
3. It must process records in batches of 1,000 because production has 5M rows.
Please update the tests first to cover all three requirements, then revise the migration. Do not fix these independently because the batching logic and idempotency checks interact.
This is better than giving one issue, waiting for Claude to implement, then revealing the next issue that invalidates the prior design.
9.2 Fix sequentially when issues are independent
Use sequential iteration when problems do not affect one another.
Examples:
Typo in error message
Missing import
One failing unit test
Formatting issue
One accessibility label
One isolated validation condition
Why?
Sequential fixes keep each change small.
It is easier to verify each step.
There is less chance of over-editing.
Example: independent issues
First fix the missing aria-label on the submit button and run the component test.
After that passes, we’ll address the unrelated copy change.
Exam rule
10. Iterative refinement patterns
Pattern A: Examples first
Use when Claude’s transformation is inconsistent.
Here are 3 examples of the exact transformation I expect.
Update the implementation to match them.
Add these examples as tests.
Run the tests and iterate.
Pattern B: Tests first
Use when behavior must be verified.
Write tests covering the expected behavior and edge cases before implementation.
Then implement.
Then run the tests and fix failures.
Pattern C: Failure-driven correction
Use when tests already fail.
Here is the failing test output.
Expected: ...
Actual: ...
Stack trace: ...
Fix only the root cause and rerun the targeted test.
Pattern D: Interview first
Use when requirements are incomplete or domain assumptions matter.
Before implementing, ask me the design questions that would affect the solution.
After I answer, summarize constraints and propose the implementation.
Pattern E: Batch interacting issues
Use when constraints affect one another.
Pattern F: Sequential independent fixes
Use when issues are unrelated.
11. Worked example: bad vs good refinement
Initial request
Likely poor outcome: Claude guesses what “improve” means.
Better iterative prompt
Before implementing, ask me up to 5 questions about CSV import behavior, especially null handling, duplicate rows, invalid dates, partial failure handling, and performance constraints.
After I answer, write tests first for:
1. valid row import
2. missing optional fields
3. missing required fields
4. invalid date format
5. duplicate external_id
6. 100k-row streaming import
Then implement and iterate until tests pass.
After first implementation fails
The duplicate external_id test is failing:
Input CSV:
external_id,email
123,a@example.com
123,b@example.com
Expected:
- First row imported
- Second row rejected with error code DUPLICATE_EXTERNAL_ID
- Import continues
Actual:
- Both rows imported
Fix duplicate detection within the same file and preserve the passing invalid-date behavior.
This is strong because it gives exact input, expected output, actual output, and regression constraint.
12. Prompt templates
Template 1: Concrete examples
The prose requirement is being interpreted inconsistently. Use these examples as the source of truth:
Example 1:
Input:
...
Expected output:
...
Example 2:
Input:
...
Expected output:
...
Example 3:
Input:
...
Expected output:
...
Update the implementation and add tests for these examples.
Template 2: Test-driven iteration
Write tests before implementation.
The tests must cover:
- happy path
- null/empty inputs
- invalid inputs
- boundary values
- regression behavior
- performance requirement: [specific requirement]
After writing tests, implement the change and run the targeted test command. Iterate until the tests pass.
Template 3: Failure feedback
The following test failed:
Test name:
...
Input:
...
Expected:
...
Actual:
...
Failure output:
...
Fix the root cause. Preserve these passing behaviors:
...
Rerun the targeted test and report the result.
Template 4: Interview pattern
Before implementing, interview me.
Ask up to [N] questions that could materially affect the design. Focus on:
- failure modes
- data consistency
- security
- performance
- backward compatibility
- rollout/rollback
- observability
After I answer, summarize the constraints and propose the implementation plan.
Template 5: Interacting issues
These issues interact and should be solved together:
1. ...
2. ...
3. ...
Do not fix them independently. First explain how the combined solution handles all constraints, then update tests and implementation.
Template 6: Sequential independent fixes
These issues are independent. Fix them one at a time.
First fix:
...
Run the targeted verification. Stop and report before moving to the next issue.
13. Scenario-based practice questions
Question 1
Claude repeatedly misinterprets a string transformation rule described as “normalize customer names.” What is the most effective next step?
A) Repeat the instruction in all caps.
B) Provide 2–3 concrete input/output examples showing exactly how names should transform.
C) Ask Claude to use a different model.
D) Move the requirement to .mcp.json.
Answer
B. Concrete examples are the best way to clarify transformations when prose is interpreted inconsistently. They define the desired behavior more precisely than abstract wording.
Question 2
You need Claude to implement a migration script with tricky null handling and idempotency requirements.
What is the strongest approach?
A) Ask Claude to implement first and test later.
B) Write tests for expected behavior, null handling, idempotency, and edge cases first, then have Claude implement and iterate from failures.
C) Tell Claude to “be careful.”
D) Skip tests because migrations are one-time scripts.
Answer
B. Test-driven iteration gives Claude an executable feedback loop. Null handling and idempotency are exactly the kind of edge cases that should be captured in tests before implementation.
Question 3
A test fails with:
The failing input is:
Expected output is:
What should you send Claude?
A) “Still wrong.”
B) “Fix nulls.”
C) The failing input, expected output, actual failure, and instruction to preserve passing cases.
D) A request to rewrite the whole system.
Answer
C. Specific test failure feedback is actionable. It tells Claude exactly what failed and what behavior to preserve.
Question 4
You are asking Claude to add caching to a pricing service, but you are unsure about invalidation, staleness, tenant isolation, and failure behavior.
What should you do before implementation?
A) Use the interview pattern and ask Claude to surface design questions.
B) Ask Claude to implement the simplest cache immediately.
C) Add a formatting rule.
D) Use Glob.
Answer
A. Caching has hidden design decisions. The interview pattern helps surface considerations the developer may not have anticipated.
Question 5
A migration has three related requirements: null handling, idempotency, and batch processing. The implementation strategy depends on all three.
How should you give feedback?
A) Provide all three issues in one detailed message.
B) Reveal one issue at a time after each implementation.
C) Ask Claude to ignore batch processing.
D) Use a slash command.
Answer
A. These requirements interact. Claude needs to consider them together to avoid rework and design conflicts.
Question 6
You have three unrelated UI issues: a typo, a missing aria-label, and an incorrect icon size.
What is the best refinement strategy?
A) Force Claude to redesign the whole component.
B) Fix them sequentially, verifying each small change.
C) Use the interview pattern.
D) Write a database migration.
Answer
B. Independent issues are best handled sequentially. This keeps changes small and easier to verify.
Question 7
Claude implements a parser that passes happy-path tests but fails on empty strings, nulls, and malformed input.
What should you do?
A) Add specific test cases for empty strings, nulls, and malformed input, then share failures to guide iteration.
B) Ask Claude to “make it robust.”
C) Remove the tests.
D) Switch to plan mode only.
Answer
A. Edge-case failures should be converted into explicit tests with expected output.
Question 8
A developer says: “Before implementing this unfamiliar data retention policy, help me figure out what questions I should answer.”
Which technique is this?
A) Path-specific rule loading
B) Interview pattern
C) Glob search
D) Forced tool selection
Answer
B. The interview pattern asks Claude to surface design considerations before implementation.
Question 9
Claude’s generated API response format is inconsistent across attempts. What should you provide?
A) A single vague statement: “Use our API style.”
B) Several exact request/response examples, including edge cases.
C) Only the file path.
D) A larger context window.
Answer
B. Input/output examples anchor the expected transformation and format.
Question 10
A test suite is already written. Claude’s implementation fails three tests. What should the developer provide?
A) Only the names of the failing tests.
B) Full failure output, expected vs actual behavior, and any relevant input fixtures.
C) No feedback; ask Claude to guess.
D) A new CLAUDE.md file.
Answer
B. Claude can iterate effectively when given concrete failure signals.
14. Final D3.5 checklist
Memorize this:
1. Use concrete input/output examples when prose is ambiguous.
2. Provide 2–3 examples for transformations; more if edge cases vary.
3. Tests are executable specifications.
4. Write tests before implementation when behavior matters.
5. Cover happy path, edge cases, invalid inputs, and performance requirements.
6. Share test failures, not vague complaints.
7. Include input, expected output, actual output, and stack trace when available.
8. Use the interview pattern when requirements are incomplete or the domain is unfamiliar.
9. Interview first for cache invalidation, failure modes, consistency, security, rollout, and performance tradeoffs.
10. Do not use the interview pattern for trivial fixes.
11. Give interacting issues together in one detailed message.
12. Fix independent issues sequentially.
13. Convert edge-case bugs into explicit test cases.
14. Ask Claude to preserve passing behavior when fixing failures.
15. Iterate until the verification signal passes.
D3.5 mental model
Examples clarify intent.
Tests define success.
Failures guide correction.
Interviews surface hidden requirements.
Batch interacting constraints.
Sequence independent fixes.
The most exam-relevant takeaway:
Progressive improvement works best when Claude has concrete signals: examples, tests, failure output, and design answers—not vague prose.