tenseleyflow/loader / 5f3c87e

Browse files

Extend first-file retry budget

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
5f3c87e0c0df21e514d32180ccaebd5a0ffd3ecb
Parents
78c5d51
Tree
ed17ee8

2 changed files

StatusFile+-
M src/loader/runtime/repair.py 21 1
M tests/test_repair.py 58 0
src/loader/runtime/repair.pymodified
@@ -659,11 +659,31 @@ class ResponseRepairer:
659659
             extra_retries = _LATE_STAGE_EMPTY_RETRY_EXTRA
660660
             if self._has_confirmed_substantive_output_file_progress(dod):
661661
                 extra_retries += _MULTI_FILE_OUTPUT_EMPTY_RETRY_EXTRA
662
-            elif completed_artifacts > 0:
662
+            elif completed_artifacts > 0 or self._has_existing_planned_directory_progress(
663
+                dod
664
+            ):
663665
                 extra_retries += _FIRST_FILE_EMPTY_RETRY_EXTRA
664666
             return base_max_empty_retries + extra_retries
665667
         return base_max_empty_retries
666668
 
669
+    def _has_existing_planned_directory_progress(
670
+        self,
671
+        dod: DefinitionOfDone,
672
+    ) -> bool:
673
+        for target, expect_directory in collect_planned_artifact_targets(
674
+            dod,
675
+            project_root=self.context.project_root,
676
+            max_paths=12,
677
+        ):
678
+            if not expect_directory:
679
+                continue
680
+            try:
681
+                if target.expanduser().is_dir():
682
+                    return True
683
+            except OSError:
684
+                continue
685
+        return False
686
+
667687
     def _should_compact_empty_retry_message(self, dod: DefinitionOfDone) -> bool:
668688
         completed_artifacts, missing_artifacts = self._planned_artifact_counts(dod)
669689
         if completed_artifacts >= 3:
tests/test_repair.pymodified
@@ -703,6 +703,64 @@ def test_empty_response_retry_budget_extends_when_concrete_next_output_is_known(
703703
     )
704704
 
705705
 
706
+def test_empty_response_retry_budget_extends_after_setup_directories_exist(
707
+    temp_dir: Path,
708
+) -> None:
709
+    context = build_context(
710
+        temp_dir=temp_dir,
711
+        use_react=False,
712
+    )
713
+    repairer = ResponseRepairer(context)
714
+
715
+    guide_root = temp_dir / "guides" / "nginx"
716
+    chapters = guide_root / "chapters"
717
+    chapters.mkdir(parents=True)
718
+    index_path = guide_root / "index.html"
719
+
720
+    implementation_plan = temp_dir / "implementation.md"
721
+    implementation_plan.write_text(
722
+        "\n".join(
723
+            [
724
+                "# Implementation Plan",
725
+                "",
726
+                "## File Changes",
727
+                f"- `{guide_root}/`",
728
+                f"- `{index_path}`",
729
+                f"- `{chapters}/`",
730
+                "",
731
+            ]
732
+        )
733
+    )
734
+
735
+    dod = create_definition_of_done("Create a multi-file nginx guide.")
736
+    dod.implementation_plan = str(implementation_plan)
737
+    dod.completed_items.extend(
738
+        [
739
+            "First, examine the existing Fortran guide structure to understand the format and depth",
740
+            "Create the new nginx guide directory structure",
741
+        ]
742
+    )
743
+    dod.pending_items.append("Develop the main index.html file for the nginx guide")
744
+
745
+    decision = repairer.handle_empty_response(
746
+        task="Create a multi-file nginx guide.",
747
+        original_task=None,
748
+        empty_retry_count=5,
749
+        max_empty_retries=2,
750
+        dod=dod,
751
+    )
752
+
753
+    assert decision.should_continue is True
754
+    assert decision.retry_message is not None
755
+    assert "retry 5/6" in decision.retry_message
756
+    assert "Next missing planned artifact: `index.html`" in decision.retry_message
757
+    assert (
758
+        "Resume with this exact next step: continue `Develop the main index.html file for the nginx guide` "
759
+        "by creating `index.html`."
760
+        in decision.retry_message
761
+    )
762
+
763
+
706764
 def test_empty_response_retry_budget_extends_further_after_first_output_file_exists(
707765
     temp_dir: Path,
708766
 ) -> None: