Applied Intelligence
Module 5: Output Validation and Iteration

Effective Feedback Patterns

From detection to correction

The previous sections covered recognizing problems. Now comes the harder part: fixing them without making things worse.

The difference between developers who iterate successfully and those who restart constantly often comes down to how they phrase corrections. Microsoft's Developer Tools group found that prompts with explicit specifications reduced back-and-forth refinements by 68%. The same principle applies to corrections: specificity compounds while vagueness confuses.

The verification loop principle

Boris Cherny, creator of Claude Code, points to verification as the single most impactful practice for quality output: give the agent a way to verify its work, and quality improves 2-3x.

This isn't metaphorical. The 2025 State of AI Code Quality report found that teams using AI code review saw quality improvements at 81%, compared to 55% for teams without. Verification transforms generation from a single-shot gamble into an iterative refinement process.

How verification works depends on what you're building.

For backend code, tests provide verification. Before requesting a feature, ensure tests exist or ask the agent to write them first. Then generate the implementation. The test suite becomes the verification mechanism. Failures give the agent concrete feedback about what went wrong.

For frontend code, visual verification matters. The Claude Code team uses browser-based testing: the agent generates UI code, opens a browser, examines the result, and iterates. Screenshot feedback tells the agent what a test suite cannot: whether the result looks right.

For infrastructure code, execution verification works. The agent writes a Terraform configuration, applies it in a test environment, and the apply output becomes feedback. Success or failure is unambiguous.

The common thread: verification output becomes input for the next iteration. Error messages, test failures, visual mismatches, and execution results all serve as structured feedback that guides correction.

Specific versus vague corrections

How specific a correction is determines whether the next iteration improves or wanders.

Vague correctionSpecific correction
"This doesn't work""The validateToken function returns undefined when the token is expired instead of throwing an ExpiredTokenError"
"Fix the bug""Line 47 checks user.id but the user object uses user.userId, align the property name"
"Make it faster""The database query on line 23 runs N+1 times, batch the lookups using WHERE id IN (...)"
"The tests are failing""The testUserLogin case fails because the mock doesn't include the refreshToken field that the function expects"

Vague corrections force the agent to diagnose before fixing. That diagnostic phase consumes context and may lead down wrong paths. Specific corrections skip diagnosis and go straight to repair.

Research quantifies this: technical debt to correct AI errors ranges from 5.6 to 9.1 minutes per instance. Vague feedback pushes toward the high end. Specific feedback pushes toward the low end, or eliminates iterations entirely.

Constraints over explanations

When providing context for corrections, constraints outperform explanations.

Consider the difference. Explanation-heavy feedback: "The reason this approach fails is that our authentication system uses short-lived tokens that expire after 15 minutes, so the caching strategy you implemented will return stale tokens, causing downstream services to reject requests."

Constraint-based feedback: "Do not cache tokens. Fetch fresh tokens for each request. The getToken function must call the auth service every time."

Both convey the same information. But constraint-based feedback translates directly into code changes. Explanation-heavy feedback requires the agent to extract actionable requirements from narrative.

Research on prompting techniques supports this pattern. Instructing models on what not to do proves safer than providing elaborate positive examples, which can cause narrow pattern-matching that degrades on novel cases.

The most effective correction format combines constraint and context minimally:

Do not cache tokens - they expire in 15 minutes.
Fetch fresh on each request.

Two sentences. One constraint, one reason. Everything the agent needs.

The CLAUDE.md mistake memory

Corrections that work once should work permanently. The CLAUDE.md file provides persistent memory for patterns that repeatedly cause problems.

When an agent makes a mistake, a developer notices, adds the pattern to CLAUDE.md, commits to version control, and the agent reads it in subsequent sessions. The correction becomes institutional knowledge.

Structure mistake memory as anti-patterns with concrete examples:

## Common mistakes to avoid

### Token handling
NEVER cache authentication tokens. Our tokens expire in 15 minutes
and caching causes silent auth failures in downstream services.

WRONG:
```typescript
const tokenCache = new Map();
function getToken(userId) {
  if (tokenCache.has(userId)) return tokenCache.get(userId);
  // ...
}

RIGHT:

async function getToken(userId) {
  return await authService.fetchToken(userId);
}

Database connections

NEVER create database connections inside loop iterations. Use connection pooling. See src/database/config.ts for the standard pattern.


The mistake memory compounds.
A team that documents ten common agent errors has essentially trained the agent to avoid those ten errors in every future session.
Over months, the CLAUDE.md file becomes a curated guide to the codebase's specific pitfalls.

Note the difference from general instructions.
"Write clean code" is useless.
"Do not use `any` types in TypeScript, use proper generics or explicit union types" is actionable.
The specificity that makes corrections effective in conversations makes them effective in persistent configuration.

## Showing versus telling

When corrections require demonstrating a pattern, examples outperform descriptions.

Telling: "Use our standard error handling pattern with proper logging and error categorization."

Showing:
```typescript
// Use this error handling pattern:
try {
  await operation();
} catch (error) {
  logger.error('operation_failed', {
    errorCode: error.code,
    context: operationContext,
    stack: error.stack
  });
  throw new OperationError(error.code, error.message);
}

Research on few-shot prompting confirms this: providing 2-8 input-output examples improves accuracy 15-40% compared to zero-shot descriptions. The agent pattern-matches from examples more reliably than it infers patterns from descriptions.

For corrections, the "show don't tell" principle applies directly. If the agent generates code that doesn't match project conventions, paste an example of code that does. If the agent structures data incorrectly, provide correct structure alongside the incorrect one.

The combination of wrong and right proves particularly effective:

Your output:
{ user_name: "Alice", login_count: 5 }

Expected format:
{ userName: "Alice", loginCount: 5 }

Use camelCase for all object properties.

Three lines of example communicate more than a paragraph of explanation about naming conventions.

Feedback that closes loops

The best feedback leaves nothing ambiguous. The agent knows what was wrong, what to do instead, and how to verify success.

Incomplete feedback: "The login function has a bug."

Complete feedback: "The login function at auth/login.ts:47 fails when the user has no lastLoginDate because line 52 calls .toISOString() on a potentially undefined value. Add a null check before the conversion. The existing test case testFirstTimeLogin should pass after the fix."

Complete feedback includes the location (file and line), the problem (null access on undefined), the correction (add null check), and the verification (specific test should pass). The agent can execute the fix and confirm success in a single iteration.

This structure works for complex corrections too:

Problem: The batch processor processes records sequentially when it should parallelize.

Location: src/processing/batch.ts, lines 23-45

Current behavior: forEach loop with await processes one record at a time

Expected behavior: Process up to 10 records concurrently using Promise.all

Verification: The integration test `testBatchPerformance` should complete
in under 5 seconds (currently takes 30+ seconds)

Constraint: Do not exceed 10 concurrent operations - the downstream
API rate limits at 15 requests per second

Every element the agent needs is present. No diagnosis required. The correction is a specification.

The feedback escalation ladder

When initial corrections don't resolve an issue, escalate systematically rather than repeating the same feedback with increasing frustration.

Start with more specificity. If "fix the null pointer" doesn't work, try "add a null check for user.profile at line 34 before accessing user.profile.avatar."

If specificity doesn't work, provide examples. Paste working code that handles the same case correctly.

If examples don't work, decompose the problem. "First, add a function hasProfile(user) that returns true if the user has a profile. Then use that function as a guard at line 34."

If decomposition doesn't work, switch to diagnostic mode. Stop asking for fixes entirely. "Don't change any code. Explain why user.profile might be undefined at line 34 given the control flow in this function."

Each level reduces ambiguity and increases guidance. The escalation ladder prevents the common pattern of repeating identical feedback while expecting different results.

Timing feedback delivery

When to interrupt versus when to let the agent complete affects correction efficiency.

Interrupt immediately when the agent's plan reveals a fundamental misunderstanding. Letting it execute a flawed plan wastes context on code that will be discarded. The Escape key preserves context while stopping execution.

Wait for completion when the agent's approach is reasonable but might have minor issues. Seeing the complete output often reveals the actual problem more clearly than stopping mid-generation.

Batch corrections when multiple independent issues exist. Rather than fixing one issue, waiting for regeneration, then fixing the next, list all issues together: "Three changes needed: (1) rename userData to userProfile per our conventions, (2) add error handling for the API call at line 15, (3) move the validation logic before the database write."

Batching reduces round trips. The agent addresses all issues in one generation pass rather than three.

The feedback variable

The patterns here are learnable. During early ASD sessions, it helps to pause before typing corrections: Is this specific or vague? Does it include location, problem, correction, and verification? Would an example communicate faster than an explanation?

That pause pays off quickly. A well-constructed correction saves the multiple iterations that a vague correction would require.

Developers who internalize these patterns often report that the agent feels more capable. The same underlying model performs better because the feedback it receives is better. The developer's skill in giving feedback multiplies the agent's effectiveness.

This is what casual users miss about ASD. The agent is a constant. The feedback is a variable. Improving the variable improves everything downstream.

On this page