CascadingDev/olddocs/patcher-pipeline.puml

150 lines
3.4 KiB
Plaintext

@startuml patcher-pipeline
!theme plain
title AI Patch Generation and Application Pipeline
start
:Receive source file + target file + instruction;
:Build prompt with:
- Source file diff (staged changes)
- Source file full content
- Target file current content
- Generation instructions from rules
- Model hint (fast/quality) if specified;
partition "Multi-Provider Fallback" {
:Try Provider 1: Claude CLI;
if (Claude returned output?) then (yes)
if (Output contains\n"API Error: Overloaded"?) then (yes)
:Raise PatchGenerationError\n"Claude API is overloaded";
stop
endif
if (Output contains diff markers?) then (yes)
:Success! Continue to extraction;
else (no - non-diff response)
:Log: "Claude non-diff output";
:Try Provider 2: Codex CLI;
if (Codex returned output?) then (yes)
:Parse JSON response\nextract agent_message;
if (Parsed text contains diff?) then (yes)
:Success! Continue to extraction;
else (no - exit code 1)
:Log: "Codex exited with 1";
:Try Provider 3: Gemini CLI;
if (Gemini returned output?) then (yes)
if (Gemini returned sentinel?) then (yes)
:Log: "No changes needed";
stop
else (has diff)
:Success! Continue to extraction;
endif
else (no)
:Raise "All providers failed";
stop
endif
endif
else (no)
:Raise "All providers failed";
stop
endif
endif
else (no - command failed)
:Raise "Provider 1 command failed";
stop
endif
}
:Save raw output to\n.git/ai-rules-debug/*.raw.out;
if (Output contains\n<<<AI_DIFF_START>>>?) then (yes)
:Extract content between\nSTART and END markers;
else (no)
if (Output contains\n"diff --git"?) then (yes)
:Extract from\n"diff --git" onward;
else (no)
:Raise "AI output did not contain a diff";
stop
endif
endif
:Save to *.clean.diff;
:Sanitize patch:
- Remove "index ..." lines
- Remove "similarity index" lines
- Keep only diff content;
:Save to *.sanitized.diff;
if (New file and missing\n"new file mode"?) then (yes)
:Add "new file mode 100644" header;
endif
:Save to *.final.diff;
if (Patch is empty?) then (yes)
:Raise "AI returned empty patch";
stop
endif
:Try git apply -p1 --index --check;
if (Check succeeded?) then (yes)
:git apply -p1 --index;
:Success!;
stop
endif
:Try git apply -p1 --index --3way\n--recount --whitespace=nowarn;
if (3-way succeeded?) then (yes)
:Applied with 3-way merge;
:Success!;
stop
endif
if (Is new file?) then (yes)
:Try git apply -p1 (without --index);
if (Succeeded?) then (yes)
:git add target file;
:Success!;
stop
endif
endif
:Raise "Failed to apply patch\n(strict and 3-way both failed)";
stop
note right
**AI Provider Configuration:**
config/ai.yml defines fallback chains:
- command_chain (default)
- command_chain_fast (model_hint: fast)
- command_chain_quality (model_hint: quality)
**Provider Details:**
1. Claude: claude -p (auto-selects subagent)
2. Codex: codex exec --model gpt-5 --json
3. Gemini: gemini --model gemini-2.5-flash
**Debug Artifacts Location:**
.git/ai-rules-debug/
Files saved:
- *.raw.out (full AI response)
- *.clean.diff (extracted patch)
- *.sanitized.diff (cleaned patch)
- *.final.diff (applied patch)
Filename format:
{output_path_with_underscores}-{pid}.{ext}
end note
@enduml