Skip to content

AI Fix Generator Validation - Critical Bug Fix

Problem Report

Date: 2025-01-12 Severity: CRITICAL - Data Loss Bug Test Case: Java Comprehensive Security & Quality Test Issue: AI fix generator destroying code outside error scope

Symptoms

User attempted to fix line 32 (XXE vulnerability) in Java test file: 1. Expected: 10-15 line fix for XXE vulnerability 2. Actual: 467-line diff that destroyed adjacent code 3. Result: All code between Error 1 (line 14) and Error 5 (line 32) disappeared 4. Impact: Deleted entire methods: findUser, parseXML, LDAP injection, deserialization

User Report

"Is the DIFF correct?... Looking to the Editor, seams that all the code between the Error 1 and Error 5 have gone missing…"

The AI replaced the findUser method with XXE fix code and deleted the parseXML method completely.

Root Cause Analysis

How Context Window Works

The AI fix generator uses a context window approach to avoid reformatting entire files:

  1. Extract 30-line window around the error (15 lines before + 15 lines after)
  2. Send ONLY this window to AI with relative line number
  3. AI fixes the issue within the window
  4. Splice the fixed window back into the original file

Example for line 32: - Window: lines 17-47 (30 lines total) - Relative line: 16 (the issue line within the window) - Expected AI response: 30 lines with line 16 fixed

The Bug

OLD CODE (lines 149-162 of /api/generate-fix/route.ts):

// Reconstruct full file by replacing the window with fixed version
const codeLines = code.split('\n');
const contextSize = 15;
const startLine = Math.max(0, issue.line - contextSize - 1);
const endLine = Math.min(codeLines.length, issue.line + contextSize);

const fixedWindowLines = cleanedFixedCode.split('\n');
const reconstructedLines = [
  ...codeLines.slice(0, startLine),      // Before window
  ...fixedWindowLines,                    // Fixed window
  ...codeLines.slice(endLine)            // After window
];

const fullFixedCode = reconstructedLines.join('\n');

Critical Issues:

  1. No line count validation - AI could return 5 lines or 500 lines, code would blindly splice it
  2. No safety checks - If AI returned entire file, would delete everything before/after window
  3. No boundary verification - Could splice at invalid indices
  4. No logging - Impossible to debug what went wrong
  5. Silent data loss - Failed silently, user discovered missing code manually

What Happened to User's Code

Scenario: - Original file: 300 lines - Error at line 32 (XXE vulnerability) - Window extracted: lines 17-47 (30 lines) - AI returned: ~60+ lines (reformatted entire file section) - Reconstruction: - Lines 1-16: Preserved ✓ - Lines 17-47: REPLACED with 60+ lines from AI ❌ - Lines 48-300: Spliced starting at line 77+ instead of 48 ❌ - Result: Lines 17-47 destroyed, lines 48+ shifted, entire structure broken

Solution Implemented

Fix 1: Enhanced System Prompt (lines 23-44)

Added explicit line count requirements:

const systemPrompt = `You are an expert code fixer. Fix ONLY the specific reported issue with SURGICAL PRECISION.

CRITICAL RULES:
1. Fix ONLY the reported issue on the specified line
2. DO NOT modify comments, formatting, or any unrelated code
3. Make the MINIMAL change needed to fix the issue
4. Preserve ALL indentation, whitespace, and style EXACTLY as provided
5. Keep ALL comments unchanged
6. Return ONLY the provided code window with the fix applied
7. DO NOT add or remove any lines outside the specific fix
8. DO NOT reformat, reindent, or reorganize code structure

IMPORTANT: You will receive a small code window (30 lines). Return the SAME window with ONLY the reported line fixed. Do NOT return the entire file.`;

Fix 2: Explicit Line Count in User Prompt (lines 68-89)

const userPrompt = `Fix this ${language} code issue:

Issue: ${issue.message}
Severity: ${issue.severity}
Type: ${issue.type}
Location: Line ${relativeLineNumber + 1} of the code window below

CODE WINDOW (lines ${startLine + 1}-${endLine} of full file):
\`\`\`${language}
${codeWindow}
\`\`\`

CRITICAL INSTRUCTIONS:
1. This window contains EXACTLY ${originalWindowLineCount} lines
2. The issue is on line ${relativeLineNumber + 1} of THIS WINDOW
3. Return EXACTLY ${originalWindowLineCount} lines - no more, no less
4. Fix ONLY the reported issue on line ${relativeLineNumber + 1}
5. Do NOT modify any other lines
6. Do NOT add or remove lines
7. Preserve exact formatting, indentation, and comments on all other lines

If you cannot fix the issue while maintaining the exact line count, return the window unchanged and note the limitation in caveats.`;

Fix 3: Comprehensive Logging (lines 60-66)

if (isDev) {
  console.log(`Extracting context window for line ${issue.line}:`);
  console.log(`  - Start line: ${startLine + 1} (0-indexed: ${startLine})`);
  console.log(`  - End line: ${endLine} (0-indexed: ${endLine})`);
  console.log(`  - Window size: ${originalWindowLineCount} lines`);
  console.log(`  - Relative line number: ${relativeLineNumber}`);
}

Fix 4: Critical Line Count Validation (lines 173-197)

// CRITICAL VALIDATION: Check line count matches original window
const fixedWindowLines = cleanedFixedCode.split('\n');
const fixedWindowLineCount = fixedWindowLines.length;

if (isDev) {
  console.log(`\nValidating AI response:`);
  console.log(`  - Original window: ${originalWindowLineCount} lines`);
  console.log(`  - Fixed window: ${fixedWindowLineCount} lines`);
  console.log(`  - Line count match: ${originalWindowLineCount === fixedWindowLineCount ? 'YES' : 'NO - DANGER!'}`);
}

// SAFETY CHECK: Reject if line counts don't match
if (fixedWindowLineCount !== originalWindowLineCount) {
  const error = `AI returned ${fixedWindowLineCount} lines but expected ${originalWindowLineCount} lines. This would destroy adjacent code. Rejecting fix for safety.`;
  console.error(`CRITICAL ERROR: ${error}`);

  throw new Error(`Fix validation failed: ${error}\n\nThe AI may have:\n1. Added/removed lines outside the error scope\n2. Returned the entire file instead of just the window\n3. Reformatted code structure\n\nPlease try again or fix manually.`);
}

Fix 5: Boundary Validation (lines 199-202)

// SAFETY CHECK: Verify window boundaries are correct
if (startLine < 0 || endLine > codeLines.length) {
  throw new Error(`Invalid window boundaries: startLine=${startLine}, endLine=${endLine}, total lines=${codeLines.length}`);
}

Fix 6: Reconstruction Logging (lines 213-225)

if (isDev) {
  console.log(`\nReconstruction successful:`);
  console.log(`  - Lines before window: ${startLine}`);
  console.log(`  - Fixed window lines: ${fixedWindowLines.length}`);
  console.log(`  - Lines after window: ${codeLines.length - endLine}`);
  console.log(`  - Total reconstructed: ${reconstructedLines.length} lines (original: ${codeLines.length})`);

  // Final safety check
  const lineDiff = reconstructedLines.length - codeLines.length;
  if (lineDiff !== 0) {
    console.warn(`WARNING: Reconstructed file has ${lineDiff > 0 ? '+' : ''}${lineDiff} lines difference!`);
  }
}

Testing Instructions

Test Case 1: XXE Vulnerability (Previously Failed)

  1. Load: test-files/COMPREHENSIVE-java-security.java
  2. Analyze code (should detect XXE on line 32)
  3. Click "Generate Fix" for XXE vulnerability
  4. Expected behavior:
  5. ✅ Console shows: "Window size: 30 lines"
  6. ✅ Console shows: "Line count match: YES"
  7. ✅ Diff shows ~10-15 line change (not 467 lines)
  8. ✅ Only parseXML method modified
  9. ✅ All other methods (findUser, LDAP, etc.) preserved
  10. ✅ Error count decreases by 1
  11. If validation fails:
  12. ❌ Console shows: "NO - DANGER!"
  13. ❌ Error message: "Fix validation failed..."
  14. ❌ Code NOT applied (safe rejection)

Test Case 2: Multi-Error File

  1. Load any file with 5+ errors
  2. Generate fix for middle error (e.g., error 3 of 5)
  3. Verify:
  4. ✅ Errors before and after the fixed error still present
  5. ✅ Line numbers shifted correctly for later errors
  6. ✅ No code disappears
  7. ✅ Console logs show exact line counts

Test Case 3: Edge of File

  1. Load file with error on line 5 (near start)
  2. Generate fix
  3. Verify: Lines 1-4 unchanged
  4. Load file with error on last 5 lines (near end)
  5. Generate fix
  6. Verify: All previous lines unchanged

Prevention Guidelines

For Developers

  1. Always validate AI responses before applying to user code
  2. Never blindly splice without checking line counts
  3. Log extensively for debugging (especially in dev mode)
  4. Reject destructive changes with clear error messages
  5. Test with multi-method files to catch adjacency issues

For AI Prompt Engineering

  1. Explicit line counts in prompts ("Return EXACTLY N lines")
  2. Window markers to help AI understand boundaries
  3. Relative line numbers to avoid confusion with absolute positions
  4. Minimal change emphasis in system prompt
  5. Escape hatches ("If you cannot fix while maintaining line count, say so")

Impact Assessment

Before Fix

  • ❌ AI could destroy adjacent code
  • ❌ No validation or safety checks
  • ❌ Silent data loss
  • ❌ Users lose work when applying fixes
  • ❌ Feature unusable for production

After Fix

  • ✅ Line count validation prevents destruction
  • ✅ Clear error messages on validation failure
  • ✅ Extensive logging for debugging
  • ✅ Safe rejection instead of silent data loss
  • ✅ Feature safe for production use
  • src/app/api/generate-fix/route.ts - Main fix generation logic (lines 46-225)
  • src/app/api/fix-all/route.ts - Batch fix endpoint (may need similar fixes)
  • src/lib/utils/diff-generator.ts - Diff generation utilities

Status

FIXED - Critical validation added, destructive behavior prevented

Next Steps

  1. Test with the exact Java test case that failed (line 32 XXE)
  2. Monitor console logs during fix generation
  3. Verify no code disappears after applying fixes
  4. Consider applying similar validation to /api/fix-all endpoint