tenseleyflow/loader / 660dc4d

Browse files

Filter stale setup todos

Authored by espadonne
SHA
660dc4d64044ef67a796be6ab3950f492f57d995
Parents
fad3bf8
Tree
3434a9f

3 changed files

StatusFile+-
M src/loader/runtime/workflow.py 45 0
M tests/test_repair.py 64 0
M tests/test_workflow.py 43 0
src/loader/runtime/workflow.pymodified
@@ -817,6 +817,16 @@ def effective_pending_todo_items(
817817
     )
818818
     if not planned_targets:
819819
         return pending_items
820
+    pending_items = [
821
+        item
822
+        for item in pending_items
823
+        if not _todo_describes_completed_setup_step(
824
+            item,
825
+            dod=dod,
826
+            planned_targets=planned_targets,
827
+            project_root=project_root,
828
+        )
829
+    ]
820830
     if not all_planned_artifacts_exist(dod, project_root=project_root, max_paths=24):
821831
         return pending_items
822832
 
@@ -1463,6 +1473,41 @@ def _todo_describes_directory_content_creation(
14631473
     return False
14641474
 
14651475
 
1476
+def _todo_describes_completed_setup_step(
1477
+    item: str,
1478
+    *,
1479
+    dod,
1480
+    planned_targets: list[tuple[Path, bool]],
1481
+    project_root: Path,
1482
+) -> bool:
1483
+    text = item.strip().lower()
1484
+    if not text or item in _SPECIAL_TODO_ITEMS:
1485
+        return False
1486
+    if not _contains_any(text, _CREATION_STEP_HINTS):
1487
+        return False
1488
+    if not _contains_any(text, _BROAD_SETUP_HINTS):
1489
+        return False
1490
+
1491
+    planned_directories = [
1492
+        target
1493
+        for target, expect_directory in planned_targets
1494
+        if expect_directory
1495
+    ]
1496
+    if not planned_directories:
1497
+        return False
1498
+    if any(
1499
+        not planned_artifact_target_satisfied(
1500
+            dod=dod,
1501
+            target=directory,
1502
+            expect_directory=True,
1503
+            project_root=project_root,
1504
+        )
1505
+        for directory in planned_directories
1506
+    ):
1507
+        return False
1508
+    return True
1509
+
1510
+
14661511
 def _reopen_aggregate_completion_steps_for_missing_artifacts(
14671512
     dod,
14681513
     *,
tests/test_repair.pymodified
@@ -1111,6 +1111,70 @@ def test_empty_response_retry_uses_compact_prompt_after_early_progress_with_conc
11111111
     )
11121112
 
11131113
 
1114
+def test_empty_response_retry_ignores_stale_setup_todo_after_files_created(
1115
+    temp_dir: Path,
1116
+) -> None:
1117
+    context = build_context(
1118
+        temp_dir=temp_dir,
1119
+        use_react=False,
1120
+    )
1121
+    repairer = ResponseRepairer(context)
1122
+
1123
+    guide_root = temp_dir / "guides" / "nginx"
1124
+    chapters = guide_root / "chapters"
1125
+    chapters.mkdir(parents=True)
1126
+    index_path = guide_root / "index.html"
1127
+    chapter_one = chapters / "01-introduction.html"
1128
+    index_path.write_text("<html></html>\n")
1129
+    chapter_one.write_text("<html></html>\n")
1130
+
1131
+    implementation_plan = temp_dir / "implementation.md"
1132
+    implementation_plan.write_text(
1133
+        "\n".join(
1134
+            [
1135
+                "# Implementation Plan",
1136
+                "",
1137
+                "## File Changes",
1138
+                f"- `{guide_root}/`",
1139
+                f"- `{chapters}/`",
1140
+                f"- `{index_path}`",
1141
+                f"- `{chapter_one}`",
1142
+                f"- `{chapters / '02-installation.html'}`",
1143
+                "",
1144
+            ]
1145
+        )
1146
+    )
1147
+
1148
+    dod = create_definition_of_done("Create a multi-file nginx guide.")
1149
+    dod.implementation_plan = str(implementation_plan)
1150
+    dod.touched_files.extend([str(index_path), str(chapter_one)])
1151
+    dod.completed_items.extend(
1152
+        [
1153
+            "Develop the main index.html file for the nginx guide",
1154
+            "Create first chapter file (01-introduction.html)",
1155
+        ]
1156
+    )
1157
+    dod.pending_items.extend(
1158
+        [
1159
+            "Create the nginx directory structure",
1160
+            "Create second chapter file (02-installation.html)",
1161
+        ]
1162
+    )
1163
+
1164
+    decision = repairer.handle_empty_response(
1165
+        task="Create a multi-file nginx guide.",
1166
+        original_task=None,
1167
+        empty_retry_count=1,
1168
+        max_empty_retries=2,
1169
+        dod=dod,
1170
+    )
1171
+
1172
+    assert decision.should_continue is True
1173
+    assert decision.retry_message is not None
1174
+    assert "Create the nginx directory structure" not in decision.retry_message
1175
+    assert "02-installation.html" in decision.retry_message
1176
+
1177
+
11141178
 def test_empty_response_retry_fails_after_extended_late_stage_budget_is_exhausted(
11151179
     temp_dir: Path,
11161180
 ) -> None:
tests/test_workflow.pymodified
@@ -569,6 +569,49 @@ def test_effective_pending_todo_items_filters_stale_discovery_after_artifacts_ex
569569
     assert not any("Fortran guide structure" in item for item in pending)
570570
 
571571
 
572
+def test_effective_pending_todo_items_filters_completed_setup_before_build_finishes(
573
+    temp_dir: Path,
574
+) -> None:
575
+    guide_root = temp_dir / "guides" / "nginx"
576
+    chapters = guide_root / "chapters"
577
+    chapters.mkdir(parents=True)
578
+    index_path = guide_root / "index.html"
579
+    chapter_one = chapters / "01-introduction.html"
580
+    index_path.write_text("<html></html>\n")
581
+    chapter_one.write_text("<h1>One</h1>\n")
582
+
583
+    implementation_plan = temp_dir / "implementation.md"
584
+    implementation_plan.write_text(
585
+        "\n".join(
586
+            [
587
+                "# Implementation Plan",
588
+                "",
589
+                "## File Changes",
590
+                f"- `{guide_root}/`",
591
+                f"- `{chapters}/`",
592
+                f"- `{index_path}`",
593
+                f"- `{chapter_one}`",
594
+                f"- `{chapters / '02-installation.html'}`",
595
+                "",
596
+            ]
597
+        )
598
+    )
599
+
600
+    dod = create_definition_of_done("Create a multi-file nginx guide.")
601
+    dod.implementation_plan = str(implementation_plan)
602
+    dod.pending_items = [
603
+        "Create the nginx directory structure",
604
+        "Create each chapter file with appropriate content",
605
+        "Complete the requested work",
606
+    ]
607
+
608
+    pending = effective_pending_todo_items(dod, project_root=temp_dir)
609
+
610
+    assert "Create the nginx directory structure" not in pending
611
+    assert "Create each chapter file with appropriate content" in pending
612
+    assert "Complete the requested work" in pending
613
+
614
+
572615
 def test_effective_pending_todo_items_filters_stale_creation_steps_after_artifacts_exist(
573616
     temp_dir: Path,
574617
 ) -> None: