@@ -1038,6 +1038,15 @@ def test_empty_response_retry_adds_root_html_starter_shape_for_first_index_write |
| 1038 | 1038 | chapters.mkdir() |
| 1039 | 1039 | index_path = guide_root / "index.html" |
| 1040 | 1040 | chapter_one = chapters / "01-introduction.html" |
| 1041 | + index_path.write_text( |
| 1042 | + "\n".join( |
| 1043 | + [ |
| 1044 | + '<a href="chapters/01-introduction.html">Chapter 1: Introduction to Nginx</a>', |
| 1045 | + '<a href="chapters/02-installation.html">Chapter 2: Installation and Setup</a>', |
| 1046 | + "", |
| 1047 | + ] |
| 1048 | + ) |
| 1049 | + ) |
| 1041 | 1050 | |
| 1042 | 1051 | implementation_plan = temp_dir / "implementation.md" |
| 1043 | 1052 | implementation_plan.write_text( |
@@ -1600,6 +1609,67 @@ def test_repeated_first_substantive_retry_includes_minimal_payload_shape( |
| 1600 | 1609 | assert "../index.html" in decision.retry_message |
| 1601 | 1610 | |
| 1602 | 1611 | |
| 1612 | +def test_empty_response_retry_surfaces_minimal_child_html_payload_earlier_after_progress( |
| 1613 | + temp_dir: Path, |
| 1614 | +) -> None: |
| 1615 | + context = build_context( |
| 1616 | + temp_dir=temp_dir, |
| 1617 | + use_react=False, |
| 1618 | + ) |
| 1619 | + repairer = ResponseRepairer(context) |
| 1620 | + |
| 1621 | + guide_root = temp_dir / "guides" / "nginx" |
| 1622 | + chapters = guide_root / "chapters" |
| 1623 | + guide_root.mkdir(parents=True) |
| 1624 | + chapters.mkdir() |
| 1625 | + index_path = guide_root / "index.html" |
| 1626 | + chapter_one = chapters / "01-introduction.html" |
| 1627 | + index_path.write_text( |
| 1628 | + "\n".join( |
| 1629 | + [ |
| 1630 | + '<a href="chapters/01-introduction.html">Chapter 1: Introduction to Nginx</a>', |
| 1631 | + '<a href="chapters/02-installation.html">Chapter 2: Installation and Setup</a>', |
| 1632 | + "", |
| 1633 | + ] |
| 1634 | + ) |
| 1635 | + ) |
| 1636 | + |
| 1637 | + implementation_plan = temp_dir / "implementation.md" |
| 1638 | + implementation_plan.write_text( |
| 1639 | + "\n".join( |
| 1640 | + [ |
| 1641 | + "# Implementation Plan", |
| 1642 | + "", |
| 1643 | + "## File Changes", |
| 1644 | + f"- `{guide_root}/`", |
| 1645 | + f"- `{index_path}`", |
| 1646 | + f"- `{chapters}/`", |
| 1647 | + f"- `{chapter_one}`", |
| 1648 | + "", |
| 1649 | + ] |
| 1650 | + ) |
| 1651 | + ) |
| 1652 | + |
| 1653 | + dod = create_definition_of_done("Create a multi-file nginx guide.") |
| 1654 | + dod.implementation_plan = str(implementation_plan) |
| 1655 | + dod.touched_files.append(str(index_path)) |
| 1656 | + dod.completed_items.append("Develop the main index.html file with proper structure") |
| 1657 | + dod.pending_items.append("Create first chapter file (01-introduction.html)") |
| 1658 | + |
| 1659 | + decision = repairer.handle_empty_response( |
| 1660 | + task="Create a multi-file nginx guide.", |
| 1661 | + original_task=None, |
| 1662 | + empty_retry_count=3, |
| 1663 | + max_empty_retries=6, |
| 1664 | + dod=dod, |
| 1665 | + ) |
| 1666 | + |
| 1667 | + assert decision.should_continue is True |
| 1668 | + assert decision.retry_message is not None |
| 1669 | + assert "If blanking continues, use this minimal starter payload shape" in decision.retry_message |
| 1670 | + assert "<title>Chapter 1: Introduction to Nginx</title>" in decision.retry_message |
| 1671 | + |
| 1672 | + |
| 1603 | 1673 | def test_first_substantive_retry_activates_on_first_empty_turn( |
| 1604 | 1674 | temp_dir: Path, |
| 1605 | 1675 | ) -> None: |