Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.aidonow.com/llms.txt

Use this file to discover all available pages before exploring further.

Executive Summary

This analysis documents a critical failure mode in AI-assisted development: the fix-in-session anti-pattern, in which an AI agent responds to cascading compilation errors through sequential, locally-optimal corrections rather than through root cause analysis and systematic remediation. A single breaking macro change produced 30 fix commits across 24 hours, during which the codebase remained in an intermediate broken state and the AI agent began producing hallucinated fixes as context window saturation degraded its reasoning quality. Human intervention resolved the same problem in three commits and 90 minutes. The failure mode is predictable, detectable, and preventable — provided that engineers monitor error reduction rates, recognize batch-fixable patterns, and establish pre-change migration protocols for breaking changes.

Key Findings

  • The fix-in-session anti-pattern produces diminishing returns that are measurable in real time: error counts per commit declined from 12 in the first five commits to fewer than 2 in commits 16–30, with net error increases appearing in the final phase.
  • AI agents performing reactive error correction lack a system-wide mental model, fixing each error in isolation without recognizing that multiple errors share a single upstream root cause requiring a single batch fix.
  • Context window saturation in long error-fixing sessions degrades AI reasoning quality to the point of hallucination: the AI produced a structurally incorrect error type conversion after 24 commits, inventing a tuple variant that did not exist in the actual error enum.
  • Human batch intervention using standard tooling (ripgrep, sed, cargo expand) resolved the same problem 16 times faster than AI sequential fixing, with zero errors introduced during the remediation.
  • Breaking macro changes require pre-change migration plans: the cascade was preventable through a two-commit atomic strategy that would have taken two hours rather than 24.

1. Introduction

1.1 Background

A derive macro responsible for generating DynamoDB repository structs was extended to auto-generate CRUD methods. The change was expected to save approximately 200 lines of boilerplate per entity. The breaking change introduced four categories of downstream incompatibility across multiple crates:
  • Method name changes (savedb_save, getdb_get)
  • Factory pattern change (field access self.client → method call self.client())
  • Error type change (RepositoryErrorEventStoreError)
  • New dependency requirements (aws-runtime, aws-sdk-dynamodb, serde_dynamo)
The initial commit introducing the change:
// BEFORE: Macro generated struct, but methods were manual
#[derive(DynamoDbRepository)]
#[aggregate = "Account"]
pub struct DynamoDbAccountRepository;

impl DynamoDbAccountRepository {
    // Manual implementation of save, get, query, delete
    pub async fn save(&self, account: Account) -> Result<()> { /* ... */ }
    pub async fn get(&self, id: AccountId) -> Result<Option<Account>> { /* ... */ }
}

// AFTER: Macro generates methods too
#[derive(DynamoDbRepository)]
#[aggregate = "Account"]
pub struct DynamoDbAccountRepository;

// Macro now generates db_save, db_get, db_query, db_delete automatically

1.2 Expected vs. Actual Impact

Expected: manual updates to four affected crates, estimated at two hours of work. Actual: 30 fix commits, 24 hours of elapsed time, codebase remaining in a broken state throughout, and an unresolved error count of 14 at the point of human intervention.

2. Cascade Progression Analysis

2.1 Phase 1: Initial Errors (Commits 1–5, Hour 1)

The first commits addressed straightforward symptoms: duplicate export conflicts introduced by newly generated code, and missing imports required by the generated methods. Error resolution rate during this phase was approximately 12 errors per commit. Commit cd7c3e1:
fix(crm): remove duplicate DynamoDbLegalEntityRepository export
Commit 1ef9150:
fix(crm): fix syntax errors and add missing imports
Status at end of Phase 1: 5 commits, 214 compilation errors remaining.

2.2 Phase 2: Pattern Emergence (Commits 6–13, Hours 2–3)

The macro’s generated methods used a different factory pattern than the manually implemented methods they replaced:
// Manual code expected:
let client = self.client.clone();  // self.client is a field

// Macro generated:
let client = self.client();  // self.client() is a method
Every repository in the affected crate exhibited the same discrepancy. The AI agent addressed these individually rather than recognizing the cross-file pattern and applying a batch fix:
  • 9e0815f: replace self.client with client
  • 11fe195: add client creation to save_calendar method
  • b1a1ff0: batch fix organization_dynamodb.rs methods
  • eb5e215: fix pipeline_dynamodb client calls
  • a7fbb9b: fix remaining client() method calls
Status at end of Phase 2: 13 commits, 147 errors remaining.

2.3 Phase 3: Type System Errors (Commits 14–24, Hours 4–6)

The macro changed the primary key method signature:
  • Previous: pk_for_id(tenant_id, capsule_id, id)
  • Current: pk_for_id(id) — tenant and capsule context inferred from entity type
This affected 47 call sites across 12 files. The AI addressed each file sequentially, with each commit introducing new errors as partially updated files interacted with files that had not yet been updated:
  • 9249626: fix pk_for_id and gsi method signatures
  • 7503f9f: add GSI methods and fix syntax errors
  • 47fd4ae: fix CrmError variants, field access errors
  • 3afc5a0: move contact methods to ContactRepository impl block
  • 3862c3e: fix E0425 errors (missing values) and self.client() calls
Status at end of Phase 3: 24 commits, 68 errors remaining. Error reduction rate had declined to fewer than 2 errors per commit.

3. The Hallucination Event

After 24 commits and approximately 24 hours, the AI produced the following fix for a type mismatch error: The error:
error[E0308]: mismatched types
  --> crm/src/repositories/organization_dynamodb.rs:123:9
   |
   | expected enum `CrmError`
   | found enum `EventStoreError`
AI’s fix (commit c62ed84):
// AI added a conversion that does not match the actual type definition:
impl From<EventStoreError> for CrmError {
    fn from(e: EventStoreError) -> Self {
        CrmError::Repository("Event store error".to_string())  // ❌ WRONG
    }
}
The actual CrmError::Repository variant is a struct variant, not a tuple variant:
impl From<EventStoreError> for CrmError {
    fn from(e: EventStoreError) -> Self {
        CrmError::Repository {
            source: RepositoryError::EventStore(e),
            entity: "unknown".to_string(),
        }
    }
}
The AI hallucinated a type structure that did not exist in the codebase. By commit 24, the context window contained an accumulation of partial fixes and error messages that degraded the AI’s ability to reason accurately about actual code structure. At this point, the AI was generating plausible-looking code based on pattern matching rather than accurate code based on the actual type definitions. This state is not recoverable through continued AI iteration — it requires human intervention and, ideally, a fresh session.

4. Root Cause Analysis: The Fix-in-Session Anti-Pattern

4.1 Mechanism Description

The fix-in-session anti-pattern operates through the following cycle:
  1. A breaking change is introduced
  2. Compilation errors appear across multiple files
  3. The AI is instructed to fix all compilation errors
  4. The AI reads the first error, identifies the immediate cause, and applies a local fix
  5. Compilation reveals new errors in adjacent files
  6. The AI repeats from step 4
This cycle is locally optimal at each step — each individual fix addresses a real error — but globally suboptimal because it produces intermediate broken states, misses batch-fixable patterns, and exhausts context window capacity on accumulated error messages rather than on understanding the root cause.

4.2 Comparison with Effective Error Resolution

The error cascade that generated 30 commits was mechanically identical to the following pattern, repeated across each error category:
error[E0599]: no method named `save` found for type `DynamoDbAccountRepository`
  --> crm/src/services/account_service.rs:45:28
   |
45 |         self.repo.save(account).await?;
   |                   ^^^^ method not found

AI Fix: Rename save → db_save in account_service.rs

New Error:
error[E0599]: no method named `save` found for type `DynamoDbContactRepository`
  --> crm/src/services/contact_service.rs:67:28
   |
67 |         self.repo.save(contact).await?;
   |                   ^^^^ method not found

AI Fix: Rename save → db_save in contact_service.rs

New Error:
error[E0308]: mismatched types - expected `CrmError`, found `EventStoreError`
  --> crm/src/services/account_service.rs:45:9

AI Fix: Add error conversion in account_service.rs

New Error: ...
The effective approach would have been:
  1. Recognize the pattern: all save() calls require renaming to db_save()
  2. Fix all instances in a single commit
  3. Recognize the pattern: all error type references require a unified conversion
  4. Add the conversion once
  5. Compile once to verify

4.3 Why AI Agents Do Not Self-Correct This Pattern

Three structural limitations prevent AI agents from escaping the fix-in-session pattern without human intervention: Absence of system-wide mental model: AI agents see errors as they appear in compiler output. They do not maintain a forward-looking model of which files will be affected by a given upstream change. Human developers with knowledge of the codebase can predict the full impact of a macro change before making it. Local optimization over global optimization: Each fix is evaluated against the criterion of resolving the current compiler error, not against the criterion of minimizing total work or preserving codebase coherence. A fix that adds a new method to seven structs instead of updating seven call sites is locally valid but globally wasteful. No self-assessment of diminishing returns: After 15 commits with declining error reduction rates, the AI does not re-evaluate its strategy. It continues applying the same approach until either the errors are resolved or context window saturation degrades output quality to the point of hallucination.

5. Human Intervention and Recovery

5.1 Intervention Method

Upon recognizing the pattern — after examining commit messages and noting diminishing error reduction rates — the AI session was terminated. Recovery proceeded as follows: Step 1: Root cause analysis (30 minutes) The original macro change commit was read in full. All categories of breaking change were enumerated:
  • save()db_save()
  • get()db_get()
  • client field → client() method
  • RepositoryErrorEventStoreError
  • New dependency requirements
Step 2: Batch remediation (45 minutes, 3 commits)
rg "\.save\(" -t rust | cut -d: -f1 | sort -u | xargs sd '\.save\(' '.db_save('
rg "\.get\(" -t rust | cut -d: -f1 | sort -u | xargs sd '\.get\(' '.db_get('
git commit -m "refactor: update to new CRUD method names"

git commit -m "refactor: update to client() method pattern"

git commit -m "fix: add error type conversions for macro changes"
Step 3: Verification (15 minutes)
cargo check --workspace  # All clean
cargo test --workspace   # 142 tests passing

5.2 Comparative Metrics

ApproachCommitsElapsed TimeFinal Error CountErrors Introduced During Fix
AI fix-in-session3124 hours14 remaining~40 new errors
Human batch intervention390 minutes00

6. Detection and Prevention

6.1 Early Warning Indicators

The following indicators signal that fix-in-session has become ineffective and manual intervention is required: Indicator 1: Declining error reduction rate. Track errors fixed per commit:
Commit RangeError Reduction RateAction
Commits 1–510–15 errors per commitContinue AI-assisted fixing
Commits 6–154–9 errors per commitMonitor closely
Commits 16–300–3 errors per commitIntervene manually
Any commitNet error increaseIntervene immediately
Indicator 2: Repeated fix patterns across commits. Commit messages referencing the same pattern type across multiple commits (“fix client() calls” appearing in seven commits; “fix pk_for_id signature” appearing in five) indicate that the AI has identified a batch-fixable pattern but is addressing it incrementally. Indicator 3: Partial fix language in commit messages. Commit messages containing “partial fix,” “fix remaining,” or “batch fix [specific file]” indicate that the AI does not have a complete solution and is iterating toward one without a defined endpoint.

6.2 Pre-Change Protocol for Breaking Macro Changes

The cascade was preventable through the following pre-change discipline:
1

Impact analysis

Run cargo tree to identify all crates consuming the macro. Use cargo expand on one representative entity to inspect generated code before and after the change. Grep for all usage sites across the workspace.
2

Breaking change enumeration

List all method signature changes, type changes, factory pattern changes, and new dependency requirements introduced by the macro modification.
3

Migration plan

Categorize required downstream changes by type. Prepare batch fix commands for each category. Document the workspace-wide verification command.
4

Atomic commit strategy

Commit the macro change and all downstream crate updates together, after verifying workspace compilation and test passage. Never commit the macro change ahead of downstream crate updates.
The two-commit target:
# Commit 1: The macro change (breaking, documented as such)
git commit -m "feat: add CRUD method generation (BREAKING)"

# Before Commit 2: fix all downstream changes atomically
# 1. Update method calls (save → db_save) across all files
# 2. Add required dependencies to Cargo.toml files
# 3. Update error handling for new error types
# 4. Verify compilation
# 5. Run tests

git commit -m "refactor: adapt to CRUD macro breaking changes"
Use cargo expand on a single entity to verify macro-generated code before migrating all entities. Thirty minutes of upfront verification eliminates the risk of discovering the generated code pattern is incompatible with existing call sites after the change is already propagated.

7. Post-Incident Analysis: AI as Prevention vs. Remediation

Following recovery from the cascade, a fresh AI session was used to analyze the incident. The result was instructive: the AI produced a comprehensive pre-change checklist for macro modifications that accurately described exactly the steps that would have prevented the cascade. This confirmed a structural observation about AI agent capability: AI agents are effective at planning ahead for known failure modes. They are poor at recognizing those same failure modes when experiencing them reactively. The distinction is between proactive pattern application (producing a checklist before a change) and reactive pattern recognition (recognizing mid-cascade that a batch fix is required). AI agents perform well on the former because it is a generation task applied to a well-defined input. They perform poorly on the latter because it requires a form of meta-cognition — recognizing that the current approach is failing and that a strategy change is required — that is not well-supported in current AI architectures.

8. Recommendations

  1. Establish and enforce a pre-change protocol for all breaking changes to shared components. Macros, traits, and interfaces with multiple downstream consumers require impact analysis, breaking change enumeration, and atomic commit planning before the change is made.
  2. Monitor error reduction rate per commit during AI-assisted error fixing. When the rate falls below three errors per commit for three consecutive commits, halt the AI session and perform manual intervention.
  3. Constrain AI error-fixing sessions with explicit limits. A prompt structure such as “fix compilation errors, maximum five commits, group related fixes, do not add new methods or types, report and stop if stuck after three commits” produces better outcomes than an unconstrained “fix all errors” instruction.
  4. Use fresh AI sessions for post-incident analysis. Context window saturation during long error-fixing sessions degrades AI reasoning quality. Post-incident analysis benefits from a session that begins with the root cause clearly stated rather than one carrying accumulated error message context.
  5. Apply batch tools for systematic renames across a codebase. Ripgrep, sed, and similar utilities complete in seconds what AI agents address over dozens of commits. The tooling required to perform the human intervention in this analysis:
# Find all usage sites
rg "\.save\(" --type rust

# Batch rename
sd '\.save\(' '.db_save(' crm/**/*.rs

# Verify
cargo check
  1. Treat AI quality degradation in long sessions as a system property, not an anomaly. Context window saturation producing hallucinated fixes is a predictable outcome of extended error-fixing sessions, not an exceptional failure. Session management — recognizing when to start fresh — is a required operational skill.

9. Conclusion

The fix-in-session anti-pattern is a predictable failure mode in AI-assisted development, not an edge case. It emerges whenever a breaking change propagates errors across multiple files and an AI agent is instructed to resolve them without a structured migration plan. The pattern is detectable through real-time monitoring of error reduction rates and recognizable through characteristic commit message patterns. It is preventable through pre-change impact analysis and atomic commit strategies. As AI-assisted development tools become more prevalent in software engineering workflows, the distinction between tasks where AI generates value through autonomous execution and tasks where AI requires human-defined structure before execution will become increasingly important to document and transmit. Breaking change management belongs firmly in the latter category.
All content represents personal learning from personal projects. Code examples are sanitized and generalized. No proprietary information is shared. Opinions are my own and do not reflect my employer’s views.