tenseleyflow/loader / ff9cfce

Browse files

Seed concrete HTML write scaffolds

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
ff9cfce0263804809d695b54bbfffde662b8e1a1
Parents
99fb65a
Tree
24003e6

2 changed files

StatusFile+-
M src/loader/runtime/repair.py 70 3
M tests/test_repair.py 18 6
src/loader/runtime/repair.pymodified
@@ -442,10 +442,17 @@ class ResponseRepairer:
442442
         )
443443
         if reference_cues_line:
444444
             lines.append(reference_cues_line)
445
+        html_scaffold_line = self._known_existing_html_scaffold_line(
446
+            concrete_target,
447
+            require_first_substantive_output=True,
448
+        )
449
+        if html_scaffold_line:
450
+            lines.append(html_scaffold_line)
445451
         html_starter_line = self._known_html_starter_shape_line(
446452
             concrete_target,
447453
             require_first_substantive_output=True,
448454
             retry_number=retry_number,
455
+            outline_label=outline_label,
449456
         )
450457
         if html_starter_line:
451458
             lines.append(html_starter_line)
@@ -931,6 +938,15 @@ class ResponseRepairer:
931938
             )
932939
             if reference_cues_line:
933940
                 lines.append(reference_cues_line)
941
+            html_scaffold_line = self._known_existing_html_scaffold_line(
942
+                concrete_target,
943
+                require_first_substantive_output=(
944
+                    has_confirmed_output_file_progress
945
+                    and not has_confirmed_substantive_output_file_progress
946
+                ),
947
+            )
948
+            if html_scaffold_line:
949
+                lines.append(html_scaffold_line)
934950
             html_starter_line = self._known_html_starter_shape_line(
935951
                 concrete_target,
936952
                 require_first_substantive_output=(
@@ -938,6 +954,7 @@ class ResponseRepairer:
938954
                     and not has_confirmed_substantive_output_file_progress
939955
                 ),
940956
                 retry_number=retry_number,
957
+                outline_label=outline_label,
941958
             )
942959
             if html_starter_line:
943960
                 lines.append(html_starter_line)
@@ -1025,6 +1042,15 @@ class ResponseRepairer:
10251042
             )
10261043
             if reference_cues_line:
10271044
                 lines.append(reference_cues_line)
1045
+            html_scaffold_line = self._known_existing_html_scaffold_line(
1046
+                inferred_pending_target,
1047
+                require_first_substantive_output=(
1048
+                    has_confirmed_output_file_progress
1049
+                    and not has_confirmed_substantive_output_file_progress
1050
+                ),
1051
+            )
1052
+            if html_scaffold_line:
1053
+                lines.append(html_scaffold_line)
10281054
             html_starter_line = self._known_html_starter_shape_line(
10291055
                 inferred_pending_target,
10301056
                 require_first_substantive_output=(
@@ -1032,6 +1058,7 @@ class ResponseRepairer:
10321058
                     and not has_confirmed_substantive_output_file_progress
10331059
                 ),
10341060
                 retry_number=retry_number,
1061
+                outline_label=outline_label,
10351062
             )
10361063
             if html_starter_line:
10371064
                 lines.append(html_starter_line)
@@ -1154,6 +1181,15 @@ class ResponseRepairer:
11541181
                     )
11551182
                     if reference_cues_line:
11561183
                         lines.append(reference_cues_line)
1184
+                    html_scaffold_line = self._known_existing_html_scaffold_line(
1185
+                        next_output_file,
1186
+                        require_first_substantive_output=(
1187
+                            has_confirmed_output_file_progress
1188
+                            and not has_confirmed_substantive_output_file_progress
1189
+                        ),
1190
+                    )
1191
+                    if html_scaffold_line:
1192
+                        lines.append(html_scaffold_line)
11571193
                     html_starter_line = self._known_html_starter_shape_line(
11581194
                         next_output_file,
11591195
                         require_first_substantive_output=(
@@ -1161,6 +1197,7 @@ class ResponseRepairer:
11611197
                             and not has_confirmed_substantive_output_file_progress
11621198
                         ),
11631199
                         retry_number=retry_number,
1200
+                        outline_label=outline_label,
11641201
                     )
11651202
                     if html_starter_line:
11661203
                         lines.append(html_starter_line)
@@ -1479,23 +1516,53 @@ class ResponseRepairer:
14791516
             return None
14801517
         return f"Reference cues from `{display_runtime_path(reference)}`: {cues}"
14811518
 
1519
+    def _known_existing_html_scaffold_line(
1520
+        self,
1521
+        target: Path,
1522
+        *,
1523
+        require_first_substantive_output: bool,
1524
+    ) -> str | None:
1525
+        if not require_first_substantive_output:
1526
+            return None
1527
+        if target.suffix.lower() not in {".html", ".htm"}:
1528
+            return None
1529
+        scaffold = self._best_known_root_html_scaffold(target)
1530
+        if scaffold is None:
1531
+            return None
1532
+        return (
1533
+            f"Reuse the existing `{display_runtime_path(scaffold)}` head/style/container "
1534
+            "pattern for this chapter so the guide stays visually consistent; only adapt "
1535
+            "the title, heading, and chapter body content."
1536
+        )
1537
+
14821538
     def _known_html_starter_shape_line(
14831539
         self,
14841540
         target: Path,
14851541
         *,
14861542
         require_first_substantive_output: bool,
14871543
         retry_number: int,
1544
+        outline_label: str | None,
14881545
     ) -> str | None:
14891546
         if not require_first_substantive_output or retry_number < 1:
14901547
             return None
14911548
         if target.suffix.lower() not in {".html", ".htm"}:
14921549
             return None
1550
+        label = outline_label.strip() if outline_label and outline_label.strip() else "this chapter"
14931551
         return (
1494
-            "For this first HTML content file, a minimal acceptable starter is: "
1495
-            "matching `<title>` and `<h1>`, one introductory paragraph, a few section "
1496
-            "blocks, and a back link to `../index.html`."
1552
+            f"If you get stuck, start with `<title>{label}</title>`, "
1553
+            f"`<h1>{label}</h1>`, one introductory paragraph, a couple of `<h2>` "
1554
+            "sections with short body text, and a back link to `../index.html`."
14971555
         )
14981556
 
1557
+    def _best_known_root_html_scaffold(self, target: Path) -> Path | None:
1558
+        normalized_target = target.expanduser().resolve(strict=False)
1559
+        if normalized_target.suffix.lower() not in {".html", ".htm"}:
1560
+            return None
1561
+        candidate = normalized_target.parent.parent / "index.html"
1562
+        if candidate == normalized_target or not candidate.exists():
1563
+            return None
1564
+        return candidate
1565
+
14991566
     def _best_known_reference_path(self, target: Path) -> Path | None:
15001567
         normalized_target = target.expanduser().resolve(strict=False)
15011568
         target_tokens = {
tests/test_repair.pymodified
@@ -1254,9 +1254,15 @@ def test_empty_response_retry_reuses_known_reference_structure_for_first_substan
12541254
         in decision.retry_message
12551255
     )
12561256
     assert (
1257
-        "For this first HTML content file, a minimal acceptable starter is: "
1258
-        "matching `<title>` and `<h1>`, one introductory paragraph, a few section "
1259
-        "blocks, and a back link to `../index.html`."
1257
+        f"Reuse the existing `{display_runtime_path(index_path)}` head/style/container pattern "
1258
+        "for this chapter so the guide stays visually consistent; only adapt the title, heading, "
1259
+        "and chapter body content."
1260
+        in decision.retry_message
1261
+    )
1262
+    assert (
1263
+        "If you get stuck, start with `<title>Chapter 1: Introduction to Nginx</title>`, "
1264
+        "`<h1>Chapter 1: Introduction to Nginx</h1>`, one introductory paragraph, a couple "
1265
+        "of `<h2>` sections with short body text, and a back link to `../index.html`."
12601266
         in decision.retry_message
12611267
     )
12621268
 
@@ -1343,9 +1349,15 @@ def test_compact_first_substantive_retry_reuses_known_reference_structure(
13431349
         in decision.retry_message
13441350
     )
13451351
     assert (
1346
-        "For this first HTML content file, a minimal acceptable starter is: "
1347
-        "matching `<title>` and `<h1>`, one introductory paragraph, a few section "
1348
-        "blocks, and a back link to `../index.html`."
1352
+        f"Reuse the existing `{display_runtime_path(index_path)}` head/style/container pattern "
1353
+        "for this chapter so the guide stays visually consistent; only adapt the title, heading, "
1354
+        "and chapter body content."
1355
+        in decision.retry_message
1356
+    )
1357
+    assert (
1358
+        "If you get stuck, start with `<title>Chapter 1: Introduction to Nginx</title>`, "
1359
+        "`<h1>Chapter 1: Introduction to Nginx</h1>`, one introductory paragraph, a couple "
1360
+        "of `<h2>` sections with short body text, and a back link to `../index.html`."
13491361
         in decision.retry_message
13501362
     )
13511363