Filter stale setup todos
- SHA
660dc4d64044ef67a796be6ab3950f492f57d995- Parents
-
fad3bf8 - Tree
3434a9f
660dc4d
660dc4d64044ef67a796be6ab3950f492f57d995fad3bf8
3434a9f| Status | File | + | - |
|---|---|---|---|
| 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( | ||
| 817 | 817 | ) |
| 818 | 818 | if not planned_targets: |
| 819 | 819 | 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 | + ] | |
| 820 | 830 | if not all_planned_artifacts_exist(dod, project_root=project_root, max_paths=24): |
| 821 | 831 | return pending_items |
| 822 | 832 | |
@@ -1463,6 +1473,41 @@ def _todo_describes_directory_content_creation( | ||
| 1463 | 1473 | return False |
| 1464 | 1474 | |
| 1465 | 1475 | |
| 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 | + | |
| 1466 | 1511 | def _reopen_aggregate_completion_steps_for_missing_artifacts( |
| 1467 | 1512 | dod, |
| 1468 | 1513 | *, |
tests/test_repair.pymodified@@ -1111,6 +1111,70 @@ def test_empty_response_retry_uses_compact_prompt_after_early_progress_with_conc | ||
| 1111 | 1111 | ) |
| 1112 | 1112 | |
| 1113 | 1113 | |
| 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 | + | |
| 1114 | 1178 | def test_empty_response_retry_fails_after_extended_late_stage_budget_is_exhausted( |
| 1115 | 1179 | temp_dir: Path, |
| 1116 | 1180 | ) -> None: |
tests/test_workflow.pymodified@@ -569,6 +569,49 @@ def test_effective_pending_todo_items_filters_stale_discovery_after_artifacts_ex | ||
| 569 | 569 | assert not any("Fortran guide structure" in item for item in pending) |
| 570 | 570 | |
| 571 | 571 | |
| 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 | + | |
| 572 | 615 | def test_effective_pending_todo_items_filters_stale_creation_steps_after_artifacts_exist( |
| 573 | 616 | temp_dir: Path, |
| 574 | 617 | ) -> None: |