AnthropicClaude Certified Architect – Foundations2026-103.5 Apply iterative refinement techniques for progressive improvement
Define passing behavior before implementing code
Completed by the knowledge check
Learning objective
Write tests for normal behavior, edge cases, and relevant performance requirements before implementation, then iterate on observed failures.
Core idea
Give Claude Code an executable definition of success before asking it to implement a feature. A test suite turns the next correction from “this looks wrong” into an observed difference between required and actual behavior. Anthropic’s Claude Code best practices recommend checks Claude can run and results it can read: tests, build exit codes, linters, and scripts that compare output with fixtures.
Both the exam guide and Anthropic’s Claude Code best practices describe writing tests before code. The best-practices page recommends having one Claude write tests, then another implement code to pass them; fresh context reduces bias toward code Claude just wrote. The architect’s job is to ensure those checks represent the intended contract. Tests derived uncritically from generated implementation can certify an interpretation the owner never approved.
This Bite owns the overall test-first loop. See 3.5.1 for clarifying the contract with examples and 3.5.3 for the smaller correction packet used when one additional edge case fails.
How it works
Cover three kinds of acceptance evidence
Before implementation, define what an ordinary request does, what boundary inputs require, and which performance requirements matter to the feature. The following acceptance matrix is an illustrative project contract for a customer migration; its quantities are not Anthropic limits.
| Coverage class | Required behavior | Check prepared before implementation |
|---|---|---|
| Normal behavior | Every valid populated contact becomes the approved destination shape | Compare the complete converted record with an owner-approved fixture |
| Edge cases | Empty and null optional values retain their agreed absence semantics; malformed required IDs are rejected | Separate assertions for each input category and expected outcome |
| Relevant performance | Convert a fixed fixture of 100,000 valid records in under 10 seconds on the designated runner | Measure the converter over that fixture and record elapsed time and output count |
A performance requirement needs its workload and measurement conditions. “Make it fast” cannot determine whether a change passed. In this scenario, the owner specifies the runner and fixture before implementation, so a timing result has a meaning. A smaller input, skipped records, or a different machine cannot silently substitute for the agreed measurement.
Normal behavior also needs complete outputs. Checking only that the result has a phone field can miss a dropped customer ID or an extra unwanted field. Edge cases should express separate policy choices: a missing optional phone and an invalid required identifier need not produce the same outcome.
Review the tests before they become the target
Claude Code’s common-workflows page says it can generate tests matching existing project styles, frameworks, and assertion patterns. Ask it to inspect the relevant test files and propose checks for the stated behavior. Review the fixtures, expected outputs, and performance conditions before asking for implementation. Write and review the suite in one session, then start a separate implementation session with the reviewed requirements and tests. You can also use /clear to reset context before supplying those artifacts. This separates test authorship from implementation while keeping the approved expectations available.
Run the checks before implementing. Inspect why they fail. A failure because the implementation is absent is different from a broken fixture loader or an unavailable test dependency. The useful starting signal is that the checks exercise the intended interface and would reject the missing or incorrect behavior. An environment error tells you to repair the test setup, not the converter.
Do not require every test to fail. Existing code may already satisfy part of the contract. The important ordering is that the required behavior exists independently of the proposed solution and that at least the targeted deficiency is observable.
Let observed failures drive the next change
Specify the project’s actual command to run the checks and identify the test files. Ask Claude to implement the approved behavior, run the command, read its output, and repair the observed failures.
A useful result includes the command, the failing test name, the expected and actual values or exception, and the relevant stack trace. Anthropic’s debugging workflow explicitly recommends providing the reproduction command and stack trace. If you run the checks outside Claude Code, paste that evidence into the conversation. If Claude runs them, ask it to show the evidence rather than assert that the suite passes.
Use the failure to locate the violated requirement. If null handling fails, repair that behavior and retain the populated-record checks. If the performance check fails after all outputs match, investigate the measured conversion path rather than weakening the functional assertions. Each round should preserve already satisfied requirements while addressing the observed deficiency.
Preserve general behavior when checks pass
Anthropic’s prompting best-practices page warns that coding can overfocus on passing tests. Its recommended instruction asks for a general-purpose solution for all valid inputs, without hard-coded test values, and states that tests verify correctness rather than define the solution.
Carry that instruction into the implementation request. Ask Claude to report an incorrect or infeasible test instead of working around it. A test expecting the wrong field value should trigger a requirement review, not special-case code for its fixture. Changes to expected outputs need the same owner review as the original suite.
The final evidence should include all three coverage classes that matter here. A passing focused functional check is an intermediate result; it does not establish that the agreed performance workload passed. Conversely, a fast converter that silently drops failing records has not met the functional contract.
Each round runs the checks, repairs the observed failures, and ends only when every coverage class that matters has passed.
Key distinctions and trade-offs
Tests first versus tests after: Prewritten tests express the intended behavior before a generated implementation influences the expected answers. Tests added afterward can still be valuable, but require particular care to avoid copying the implementation’s mistakes.
Observed failure versus a success claim: “The tests pass” describes an outcome without exposing how it was obtained. A command and its returned output let you assess which checks ran and whether they covered the requirement.
Correctness versus performance: Correct outputs and acceptable execution time are different acceptance conditions. Neither substitutes for the other. Include a performance gate when the feature has a relevant requirement, rather than inventing an arbitrary benchmark for every small change.
Writing the checks first costs effort before the visible implementation appears. That effort buys a stable correction target and reduces repeated manual interpretation. It is particularly useful for transformations whose many small branches otherwise require line-by-line review after every generated change.
Architecture / decision scenario
A developer productivity team asks Claude Code to implement a migration converter. The team prepares normal-record fixtures, independent empty/null cases, rejection cases for malformed required IDs, and the 100,000-record timing check with its designated runner. It reviews those expectations in the test-authoring session, then provides the approved suite and requirements to a separate implementation session.
The initial run exposes the missing converter. Claude implements it and runs the supplied command. Normal behavior passes, but explicit null raises an exception and the timing check exceeds 10 seconds. The developer supplies both observed failures and asks Claude to explain whether the fixes interact; correction grouping is covered in 3.5.5.
The following run must show correct outputs for ordinary and boundary inputs plus the agreed workload within its threshold. The developer rejects a proposal to skip null records or shrink the timing fixture. If the threshold proves infeasible under the approved contract, Claude reports that constraint for a decision rather than changing the test to manufacture success.
Common exam traps
- Implementing first and accepting tests that reproduce whatever the implementation does.
- Covering ordinary values while omitting boundary cases or relevant performance requirements.
- Treating missing dependencies as evidence of incorrect business logic.
- Sharing “still broken” instead of the command and actual failure output.
- Allowing hard-coded fixtures, suppressed assertions, or skipped records to produce a green result.
- Treating one passing check as evidence that every acceptance condition passed.
What to remember
Prepare and review the acceptance suite before implementation. Include normal behavior, distinct edge cases, and measurable performance conditions when they matter. Iterate on actual failure evidence, preserve the contract across rounds, and require a general solution rather than a test-specific workaround.
Knowledge check
A team knows exactly how a customer-migration converter must behave, including empty and null optional values and a throughput requirement on a fixed fixture. It wants each Claude Code iteration to be a measurable step rather than another manual read of the function. What is the most effective approach?
Before implementation, Claude runs the newly approved suite. Every test fails with ModuleNotFoundError: No module named 'fixture_loader' raised while the tests are collected. What does this result tell the team?
The functional tests pass, but converting the agreed 100,000-record fixture takes 14 seconds on the designated runner against a 10-second requirement. Claude proposes measuring a 10,000-record subset instead. What should the developer do?
A team has written and reviewed its acceptance suite in the Claude Code session that drafted it. How should implementation begin?
References
- Anthropic, Best practices for Claude Code
- Anthropic, Common workflows
- Anthropic, Prompting best practices
- Anthropic, Claude Certified Architect – Foundations Exam Guide