Engineering with AI Coding Agents: Practices, Evidence, and Lessons Learned - Part 2: Debugging, Testing, and Independent Review
This is Part 2 of Engineering with AI Coding Agents: Practices, Evidence, and Lessons Learned, a three-part guide based on my development experience and further research. In Part 1, we looked at getting the agent to understand requirements and helping it design architecture and interfaces before implementing them. We also covered practical boundaries that keep implementation focused on the approved design.
This article begins where implementation becomes uncertain: a bug is hard to locate, generated tests offer misleading reassurance, or a reviewer reports a problem that may not be real. The techniques in Part 2 deal with debugging, testing, and independent review. Part 3 then moves to maintaining project knowledge, configuring safer access, and choosing how much reasoning effort a task deserves.
IN THIS ARTICLE
5. Debugging and Troubleshooting · SDLC: Debugging
6. Testing and Verification · SDLC: Testing
7. Code Review and Independent Audits · SDLC: Review
5. Debugging and Troubleshooting
The most expensive debugging mistake is acting confidently on a cause that has not been established. These techniques move the agent from plausible explanations toward observations and tests.
5.1. Separate observations, hypotheses, and conclusions
THE PROBLEM
During debugging, a reasonable explanation may quietly become an assumed fact, especially after it has appeared repeatedly in the conversation. Later patches can then depend on a claim that nobody verified.
THE TECHNIQUE
Make the agent label the status of its claims before it proposes a fix. During debugging, a statement such as “the cache invalidation is broken” can shift from a tentative guess to an accepted premise without any supporting test. Ask for verified observations first, reasonable explanations second, and the next action that would tell them apart. This is not a request for a lengthy analysis report. It is a simple way to prevent the agent from taking action on an assumption whose status has become unclear.
PRACTICAL EXAMPLE
PROMPT Before proposing a patch, separate your analysis into: (1) verified observations with file locations or test output, (2) unverified hypotheses, and (3) the smallest useful check that could confirm or reject each hypothesis. Do not present hypotheses as established facts.
WHY IT WORKS
A visible distinction between facts and possible explanations lets the developer check what supports a diagnosis before a patch depends on it. Merely labeling an idea as a hypothesis does not establish whether it is correct.
EVIDENCE AND LIMITATIONS
The 2026 preprint From Faulty Claims to Incorrect Patches examined 400 agent trajectories and used claim-corrected replays to trace some defective patches to false premises about the task or code. This supports checking consequential claims before acting on them, but it did not evaluate this observation-hypothesis-conclusion template. Simply labeling a hypothesis does not verify it, and faulty claims also appeared in successful trajectories.
SOURCES From Faulty Claims to Incorrect Patches (2026)
5.2. Ground repository claims in the current source
THE PROBLEM
Agents sometimes describe repository behavior from an earlier read or a mistaken inference. When code has changed during the session, a once-reasonable description may no longer be accurate.
THE TECHNIQUE
If the agent says a helper is unused, an endpoint does not exist, or a permission is enforced in a particular layer, ask it to point to the current implementation. For an important claim, a path and line range should be accompanied by an explanation of what the code proves. Where static reading is insufficient, require execution evidence. This is particularly useful in fast-changing repositories or after several rounds of edits, when an agent's earlier description may no longer match the files on disk.
PRACTICAL EXAMPLE
PROMPT For every claim that determines the fix, show the current source location and explain what it establishes. If the behavior depends on runtime state, identify the command or test that verifies it. Do not rely on a remembered description of the repository.
WHY IT WORKS
Checking the current source or running a targeted test can reveal when the agent relies on an old assumption. A file path alone is not proof; the code at that location must support the claim.
EVIDENCE AND LIMITATIONS
The 2026 preprint From Faulty Claims to Incorrect Patches links some incorrect patches to unsupported claims about the task and existing implementation. That makes checking key assertions against current source and executable evidence sensible. It does not show that requesting line references alone improves results; citations can be irrelevant or stale, and runtime claims may require direct tests or logs.
SOURCE From Faulty Claims to Incorrect Patches (2026)
5.3. After an unsuccessful patch, revisit the underlying assumption
THE PROBLEM
After several unsuccessful patches, the agent may keep changing details of a solution built on the same incorrect diagnosis. More editing then increases the diff without resolving the original uncertainty.
THE TECHNIQUE
After repeated unsuccessful fixes, stop asking for another slightly different patch. Request an account of what the previous attempts assumed, which observations contradicted those assumptions, and whether the original diagnosis needs to change. The next useful step may be a trace, a new reproduction, or a fresh read-only investigation rather than another edit. You can also restart in a new conversation with the original request, current diff, and verified failures, leaving behind the prior agent's unsupported explanations.
PRACTICAL EXAMPLE
PROMPT Stop editing. List the assumptions behind the last attempts, the evidence for and against each, and what we learned from the failures. Identify the next diagnostic action before proposing another patch.
WHY IT WORKS
A failed patch provides information about the assumptions behind it. Revisiting those assumptions can change the direction of the investigation instead of producing another variation of the same fix.
EVIDENCE AND LIMITATIONS
The controlled replay portion of From Faulty Claims to Incorrect Patches showed that correcting a causally important false claim often fixed its associated defect. The result came from a particular experimental setup and should not be turned into a universal success percentage. The defensible takeaway is that an incorrect premise can survive multiple local code changes. Revising the premise is sometimes more useful than refining the code built around it.
SOURCES From Faulty Claims to Incorrect Patches (2026)
5.4. Establish a baseline before modifying anything
THE PROBLEM
When a test fails after a change, the agent may blame the patch even though the test was already broken. Performance comparisons are equally misleading if there is no reliable starting measurement.
THE TECHNIQUE
Before an implementation, have the agent record the initial build and test state, relevant versions, and known failures. For a performance change, capture a benchmark with the intended input and environment. After implementation, repeat the same checks so that new failures can be distinguished from old ones. This is especially important for repositories with unreliable tests, shared environments, or previously broken builds. A final “tests failed” report is much less informative without knowing whether they already failed beforehand.
PRACTICAL EXAMPLE
WORKFLOW Run and save the relevant commands before editing, including tool versions and failing test names. Run the same commands after the patch, and compare changes rather than presenting only the final status.
WHY IT WORKS
A before-and-after baseline makes the difference attributable to the change more interpretable. The comparison is meaningful only when inputs, environment, and relevant conditions are sufficiently similar.
EVIDENCE AND LIMITATIONS
A peer-reviewed IEEE Transactions on Software Engineering study of real CI pipelines documents flaky failures that appear deterministic and finds substantial variation across test environments. It illustrates why a failure seen after a patch cannot automatically be attributed to that patch. The before-and-after baseline is a controlled-comparison principle, not a coding-agent prompting intervention tested by the paper; inputs and environments must be comparable.
5.5. Use instrumentation when reasoning alone is insufficient
THE PROBLEM
Static inspection can leave several explanations consistent with the same symptoms. Another speculative edit does not resolve the uncertainty if it produces no new evidence.
THE TECHNIQUE
If reading code produces several reasonable causes but no way to choose among them, instruct the agent to collect new evidence before patching. Logging, tracing, controlled requests, and targeted tests can reveal execution order, data flow, or state changes that are invisible in static code. The useful question is not “what else could be wrong?” but “which observation would settle the uncertainty?” Temporary instrumentation should be removed or justified before the task is complete.
PRACTICAL EXAMPLE
PROMPT Stop proposing patches. Identify the missing evidence that separates the leading hypotheses, then add the smallest safe log, trace, or controlled test needed to collect it. Explain how each possible result changes the diagnosis.
WHY IT WORKS
Instrumentation or a controlled test adds an observation that may distinguish competing causes. The new signal needs to be chosen carefully because logging and tracing can sometimes alter timing-sensitive behavior.
EVIDENCE AND LIMITATIONS
This practice follows causal debugging: if two hypotheses fit the same observations, those observations cannot distinguish them. No cited controlled study establishes that this precise prompt improves coding-agent success rates, so it should be presented as a sound diagnostic method, not a proven prompting breakthrough. Instrumentation itself can disturb timing-sensitive behavior, which is particularly relevant for concurrency bugs.
SOURCES From Faulty Claims to Incorrect Patches (2026)
6. Testing and Verification
Generated tests can repeat the mistakes of generated code. This section focuses on building independent checks and making the result harder to pass by accident.
6.1. Generate acceptance tests from the specification when possible
THE PROBLEM
When a model sees an incorrect implementation before writing tests, its expected results may reflect the same mistake. The resulting tests can pass without challenging the faulty behavior.
THE TECHNIQUE
For substantial changes, consider asking for acceptance tests from the requirements before the test-writing agent sees the implementation. Give it the expected behavior, public contracts, and important edge cases, then preserve those expectations while a separate workflow produces the code. This is particularly helpful when the same coding agent would otherwise implement a feature and write tests by reading back its own implementation. The goal is not to hide the whole repository, but to prevent the implementation's mistakes from becoming the test's definition of success.
PRACTICAL EXAMPLE
PROMPT Using the specification and public contracts, write behavioral acceptance tests without inferring expected results from the implementation. State which requirement each assertion verifies. Do not change these expectations merely because the implementation fails.
WHY IT WORKS
Generating acceptance criteria from the independent specification reduces one route by which implementation assumptions leak into tests. This does not make the specification infallible, but it keeps the expected behavior from being inferred solely from the code under test.
EVIDENCE AND LIMITATIONS
The 2026 preprint On the Risk of Coding Before Testing found lower fault detection when generated tests were exposed to faulty code first than when tests were generated independently (14% versus 25% in its evaluated conditions). This supports concern about implementation errors contaminating test expectations. It does not prove that a separate session or different model is always necessary, and an incorrect specification can still produce incorrect tests.
SOURCES On the Risk of Coding Before Testing (2026)
6.2. Derive tests from explicit behavioral contracts
THE PROBLEM
Requests such as “write tests for this feature” do not say which behavior must be protected. Tests may then emphasize convenient code paths rather than important rules.
THE TECHNIQUE
Before asking for tests, have the agent convert a requirement into the conditions that must hold before an operation, the outcome that must follow, and any rule that must always remain true. For a booking service, that might include not creating two reservations for one idempotency key, rejecting unavailable slots, and preserving existing reservations when a payment fails. Ask the agent to connect each test to one of those contracts, so the assertions express intended behavior rather than copying current code.
PRACTICAL EXAMPLE
PROMPT Extract the preconditions, postconditions, invariants, and boundary cases from this feature requirement. Use those contracts to propose tests, and explain which contract each test checks. Ask about undefined behavior rather than inventing a requirement.
WHY IT WORKS
Explicit preconditions, outcomes, and invariants turn vague requirements into observable pass and fail conditions. A test can then check a behavioral contract rather than merely repeat the current implementation.
EVIDENCE AND LIMITATIONS
Google Research's work on contract-grounded, specification-driven test generation offers empirical support for this general approach. The mechanism is understandable: explicit expected behavior provides a more independent target for test assertions. The important limit is specification quality. When a product rule is missing or ambiguous, the agent should surface the gap instead of silently choosing its own contract.
SOURCES Grounding AI Agents in Contracts (Google Research, 2026)
6.3. Do not let the implementation redefine its own acceptance criteria
THE PROBLEM
An agent trying to make the suite green may alter assertions or expected values instead of correcting the implementation. That can remove the very evidence intended to detect the defect.
THE TECHNIQUE
When a patch fails an acceptance test, instruct the agent to investigate the mismatch before editing the test. If the test is genuinely wrong, the agent should show how the original requirement justifies a changed assertion and request approval. This is especially important when an agent owns both implementation and tests, because it can make a broken implementation appear successful by weakening expectations or deleting difficult cases. Treat edits to acceptance criteria as separate decisions, not routine bug fixes.
PRACTICAL EXAMPLE
PROMPT Do not modify acceptance-test assertions to make your patch pass. If you believe an expectation is wrong, cite the requirement it contradicts, propose a separate test change, and leave it unapplied until reviewed.
WHY IT WORKS
Keeping acceptance criteria independent prevents the system under test from silently changing its own standard of success. A test can still be corrected when wrong, but that change needs justification against the original requirement.
EVIDENCE AND LIMITATIONS
On the Risk of Coding Before Testing found that model-generated tests can reproduce assumptions from faulty implementations, reducing their effectiveness as independent oracles. This supports holding acceptance expectations against the specification instead of silently relaxing them to match a patch. The paper did not evaluate this precise approval workflow, and acceptance tests can themselves be wrong; justified test corrections should remain possible under review.
SOURCE On the Risk of Coding Before Testing (2026)
6.4. Measure assertion quality, not only coverage
THE PROBLEM
High coverage and many passing tests can create confidence even when assertions fail to detect meaningful defects. Executing a path is not the same as checking whether it behaves correctly.
THE TECHNIQUE
Ask the agent to explain what meaningful failure would make an important test fail, rather than accepting a large test count or high line coverage as proof of quality. A test that enters the correct function but never checks the resulting state may execute code without detecting a broken outcome. For critical workflows, consider a small mutation exercise: introduce a safe, reversible fault in a test environment and confirm that the test catches it. This makes the conversation about defects detected, not merely lines executed.
PRACTICAL EXAMPLE
PROMPT For each important new test, identify the behavioral defect it is meant to catch and the assertion that would fail. Flag tests that execute code without checking an observable outcome.
WHY IT WORKS
Asking what defect would fail a test forces attention onto the test oracle, the rule that distinguishes a correct outcome from an incorrect one. Meaningful assertions matter more than test count alone.
EVIDENCE AND LIMITATIONS
Research on traditional test criteria for LLM-generated code has highlighted gaps between coverage-style metrics and actual fault detection. The broader test-oracle problem is established in software testing: execution alone cannot tell correct results from incorrect ones. This does not mean every test must use a simple assertion. Property-based tests and snapshots can have valid oracles when their expected properties are properly defined.
SOURCES How Effective Are Traditional Test Criteria on LLM Code? (2026)
6.5. Give security-sensitive changes independent verification
THE PROBLEM
An endpoint can return the correct response for authorized requests while still leaking data or accepting forbidden operations. Functional tests do not necessarily check security properties.
THE TECHNIQUE
When a change touches authentication, authorization, input validation, secrets, or user data, add a security-specific review instead of relying on successful functional tests. Ask the reviewer to identify relevant trust boundaries and attempt appropriate negative cases, such as an unauthorized role accessing an endpoint or sensitive values appearing in logs. Keep tests in isolated environments and use approved scanning or specialist review when the risk warrants it. The same code can work correctly for an authorized user and remain insecure for another user.
PRACTICAL EXAMPLE
PROMPT Perform a security-focused review of this change. Check authorization boundaries, input validation, handling of secrets, and relevant negative scenarios. Cite code or test evidence. Do not assume passing functional tests establishes security.
WHY IT WORKS
A separate security-focused review examines the conditions an attacker or unauthorized user might exploit. This extends verification beyond the happy path without assuming that a general code review has covered the threat model.
EVIDENCE AND LIMITATIONS
NIST's Secure Software Development Framework calls for integrating security practices throughout development. It is an established engineering standard rather than evidence that this exact AI prompt improves vulnerability detection. Agent-assisted security review can find useful issues, but it cannot substitute for enforceable access controls, specialized tools, or qualified human assessment on high-risk systems.
SOURCES NIST Secure Software Development Framework
7. Code Review and Independent Audits
A second look can catch what implementation missed, but review itself can also be wrong. Give reviewers independent standards and require evidence before acting on findings.
7.1. Experiment with independent review sessions
THE PROBLEM
An agent reviewing its own implementation may carry forward the assumptions and explanations that shaped the patch. A long review conversation can then repeat those assumptions instead of challenging them.
THE TECHNIQUE
For large or consequential changes, test a review workflow in which a fresh agent session reads the requirements, final code, and Git diff without inheriting the implementation conversation. Keep the reviewer read-only initially, and ask for evidence-backed findings rather than edits. A new session can avoid some conversational assumptions, but it does not remove a model's general tendencies or guarantee better criticism. Compare this method against a single same-session review on your own tasks before making it mandatory.
PRACTICAL EXAMPLE
PROMPT Audit these changes in read-only mode against the original requirements. Use the diff and current repository as primary evidence. Identify defects, possible regressions, and unverified assumptions. Do not trust the implementation author's conclusions without checking them.
WHY IT WORKS
A fresh review can reduce carryover from the implementation conversation, but the reviewer still shares possible model weaknesses and may reach the same mistaken conclusion. Independent acceptance criteria matter as much as session separation.
EVIDENCE AND LIMITATIONS
Cross-Context Review (revised version 2) tested 30 artifacts with injected errors and found fresh-session reviewing better than a repeated same-session review, but not significantly better than one same-session review across runs (p = 0.26). A NeurIPS 2024 study separately documents self-preference in LLM evaluations. Neither study establishes that a fresh session reliably outperforms a single review of production code, so this should be treated as a workflow to benchmark, not a universal rule.
SOURCES Cross-Context Review, version 2 (2026) | LLM Evaluators Recognize and Favor Their Own Generations (NeurIPS 2024)
7.2. Transfer verifiable facts, not the author's confidence
THE PROBLEM
An independent reviewer may inherit the author's untested assumptions when given the full development chat. A concise evidence-first brief helps separate facts from confidence. Resuming implementation is a different continuity problem (Part 3, Section 8.4).
THE TECHNIQUE
For an independent review, supply the original requirements, final diff, current code, executed checks and their results, and unresolved risks. Ask the reviewer to assess these artifacts before reading the author's interpretations. They should verify the current Git state and request missing context as needed. Use the fuller progress records described in Part 3 to resume unfinished implementation.
PRACTICAL EXAMPLE
PROMPT Review the current diff independently against the original requirements and recorded test results. Check important claims in the code, identify gaps or regressions, and distinguish verified findings from hypotheses. Do not treat the author's confidence as evidence.
WHY IT WORKS
A reviewer brief prioritizes primary evidence over the author's narrative. It does not guarantee accuracy: the reviewer must still check code, test scope, and uncertainties.
EVIDENCE AND LIMITATIONS
Anthropic's practitioner account describes progress records and Git history for checking transferred state. The EMNLP 2026 study reports misalignment in real coding-agent sessions, including unreliable progress accounts. Neither tests this independent-review brief. Its aim is to prioritize primary evidence over the author's narrative; Part 3, Section 8.4 addresses ongoing implementation instead.
SOURCES Anthropic: Effective Harnesses for Long-Running Agents | How Coding Agents Fail Their Users (EMNLP 2026)
7.3. Require evidence for review findings
THE PROBLEM
Agent reviews can contain reasonable but incorrect bug reports. Automatically treating every reported concern as a real defect may introduce regressions and waste developer time.
THE TECHNIQUE
Ask reviewers to make each important finding actionable: identify affected code, describe the conditions under which it fails, and provide a reproducer, failing test, or a clear reasoning chain. This is more useful than a long list of statements beginning “this might be a bug.” If the issue is a maintainability concern rather than a reproducible failure, the reviewer should describe the concrete future cost and its assumptions. The format makes it easier for a developer to decide whether a proposed change is justified.
PRACTICAL EXAMPLE
PROMPT For each finding, include the file and location, the expected and actual behavior, the evidence, and a verification method where possible. Mark unverified concerns as hypotheses rather than confirmed defects.
WHY IT WORKS
Asking for a concrete failure condition, affected code, and supporting evidence makes a finding easier to verify. Evidence requirements cannot eliminate false positives, but they improve the basis for triage.
EVIDENCE AND LIMITATIONS
A peer-reviewed 2026 Automated Software Engineering study found that LLM-based reviewers could wrongly reject correct code in its evaluated setting. Separately, a 2025 IJCNLP/AACL paper examined model-generated code review comments and reported hallucinations in approximately half of the comments under its tested conditions. Together these studies justify verifying important review findings against source code and behavior, rather than treating a plausible comment as proof. Neither tested this particular evidence-reporting template, and the reported rates should not be generalized to every model, repository, or review workflow.
SOURCES Are LLMs Reliable Code Reviewers? (Automated Software Engineering, 2026) | Hallucinations in Code Change to Natural Language Generation (IJCNLP/AACL 2025)
7.4. Avoid unlimited review loops
THE PROBLEM
Repeating review and fix cycles can produce an expanding stream of speculative findings and changes. More review rounds do not guarantee that the remaining issues are real or important.
THE TECHNIQUE
Reviewing a patch, fixing the findings, and asking for another review can be useful, but repeating the cycle indefinitely creates opportunities for speculative issues and unnecessary changes. Set a criterion for an additional round, such as unresolved confirmed defects or new behavior introduced by the fixes. Keep optional suggestions separate from defects. If a new round produces only low-confidence style concerns, consider stopping and recording those ideas rather than changing tested code again.
PRACTICAL EXAMPLE
WORKFLOW Run one substantial review; triage its findings; fix confirmed important defects; rerun targeted checks. Start another full review only when the changes or unresolved risks justify it, and stop when acceptance criteria are satisfied.
WHY IT WORKS
A stopping rule ties additional review to newly verified problems rather than the mere availability of another agent. This limits changes whose expected value is lower than the regression risk and review cost.
EVIDENCE AND LIMITATIONS
The revised Cross-Context Review experiment finds that additional review in the same context does not necessarily improve detection, while a 2026 peer-reviewed code-review study documents false rejections of correct implementations. These results motivate scrutiny of repeated review-and-fix cycles, but neither paper measures an optimal number of rounds. Continue when new evidence or risk warrants it, not merely because another review is possible.
SOURCES Cross-Context Review, version 2 (2026) | Are LLMs Reliable Code Reviewers? (Automated Software Engineering, 2026)
7.5. Triage findings before applying changes
THE PROBLEM
A report may mix confirmed bugs with uncertain risks and optional style preferences. Passing that entire report directly to an implementation agent treats very different claims as equally actionable.
THE TECHNIQUE
Do not pass a reviewer report directly to an implementation agent with “fix everything.” First classify findings as verified defects, reasonable concerns needing investigation, or optional improvements. Authorize fixes for the first group, request evidence for the second, and decide whether the third belongs in the current task. This is especially useful when reviewers produce many findings or when the codebase has complex trade-offs that an isolated reviewer may not understand.
PRACTICAL EXAMPLE
PROMPT Do not implement the audit findings yet. Classify each as confirmed, needs verification, or optional. Explain the evidence and impact. Propose fixes only for confirmed issues that are within scope.
WHY IT WORKS
Triage separates identifying a concern from authorizing a modification. Fixes can then be prioritized by evidence and impact, while lower-confidence issues are investigated or left as documented suggestions.
EVIDENCE AND LIMITATIONS
The 2026 peer-reviewed Automated Software Engineering study shows that LLM reviewers can misclassify correct code as defective and that their explanations are not sufficient grounds for automatic correction. This supports triaging findings against requirements and tests before authorizing edits. The study does not directly test the proposed three-way triage labels; architectural and maintainability concerns may still need human judgment even when a failing test is unavailable.
SOURCE Are LLMs Reliable Code Reviewers? (Automated Software Engineering, 2026)
What comes next
The techniques in this article share one idea: an agent’s explanation and its successful-looking output need independent checks. Reproduction, behavioral contracts, and review findings grounded in evidence can limit mistakes, but none is a universal guarantee. Part 3 completes the series by covering the information the agent carries between sessions, the permissions it operates under, and how to choose the amount of reasoning effort for a task.
Leave a Reply
Your e-mail address will not be published. Required fields are marked *