@@ -322,9 +322,23 @@ def _run_figure_phase(self):
322322 self .log_step (f"No figure script at { script_path } , skipping generation" , "info" )
323323
324324 # Step 2.5: Generate AI concept figures (Nano Banana)
325+ # Track which files are AI-generated so the figure fixer won't touch them
326+ ai_generated_files = set ()
325327 if self .config .get ("figure_generation" ) == "nano_banana" :
326328 self .log_step ("Generating AI concept figures (Nano Banana)..." , "progress" )
329+ # Snapshot existing files before generation
330+ existing_before = {f .name for f in self .figures_dir .glob ("*" )}
327331 self ._generate_nano_banana_figures ()
332+ # Any new files are AI-generated concept figures
333+ existing_after = {f .name for f in self .figures_dir .glob ("*" )}
334+ ai_generated_files = existing_after - existing_before
335+ # Also include files that were already generated in earlier phases
336+ for f in self .figures_dir .glob ("*.png" ):
337+ if f .name .startswith ("fig_" ) and f .name not in ai_generated_files :
338+ # Check if this was generated by PaperBanana (large, not from matplotlib)
339+ # PaperBanana PNGs are typically >100KB; matplotlib PNGs are smaller
340+ if f .stat ().st_size > 150_000 :
341+ ai_generated_files .add (f .name )
328342
329343 for loop in range (MAX_FIGURE_LOOPS ):
330344 # Step 3: Compile and convert to images
@@ -365,6 +379,18 @@ def _run_figure_phase(self):
365379 except Exception :
366380 pass
367381
382+ # Build protected files section
383+ protected_section = ""
384+ if ai_generated_files :
385+ protected_list = "\n " .join (f"- { f } " for f in sorted (ai_generated_files ))
386+ protected_section = f"""
387+ ### ⚠️ PROTECTED AI-Generated Concept Figures (DO NOT MODIFY)
388+ The following figures were generated by PaperBanana/Gemini AI and must NOT be
389+ overwritten, regenerated, or replaced by matplotlib. Do NOT modify any Python
390+ script to output to these filenames. Only check their LaTeX placement/sizing.
391+ { protected_list }
392+ """
393+
368394 fixer_prompt = f"""## Figure Quality Check (Loop { loop + 1 } /{ MAX_FIGURE_LOOPS } )
369395
370396### Template Geometry Parameters
@@ -375,7 +401,7 @@ def _run_figure_phase(self):
375401
376402### Current Figure Files
377403{ figures_list }
378- { overlap_section }
404+ { protected_section } { overlap_section }
379405### PDF Page Images (use Read tool to view each page)
380406{ images_list }
381407
@@ -409,7 +435,19 @@ def _run_figure_phase(self):
409435 elif "FIGURES_NEED_FIX" in (result or "" ):
410436 self .log_step ("Figure fixer made changes, will re-check..." , "progress" )
411437 if full_script .exists ():
438+ # Back up AI-generated concept figures before re-running script
439+ backups = {}
440+ for fname in ai_generated_files :
441+ fpath = self .figures_dir / fname
442+ if fpath .exists ():
443+ backups [fname ] = fpath .read_bytes ()
412444 self .generate_figures ()
445+ # Restore any AI-generated files that were overwritten
446+ for fname , data in backups .items ():
447+ fpath = self .figures_dir / fname
448+ if not fpath .exists () or fpath .read_bytes () != data :
449+ fpath .write_bytes (data )
450+ self .log (f"Restored AI-generated figure: { fname } " , "INFO" )
413451 else :
414452 self .log_step ("Figure fixer verdict unclear, continuing..." , "warning" )
415453 break
0 commit comments