tenseleyflow/loader / d950aff

Browse files

Refresh quality repair focus

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
d950aff823a6924066a5617ad3f5b9a2646661d3
Parents
a3cc97b
Tree
9a0407f

3 changed files

StatusFile+-
M src/loader/runtime/tool_batches.py 25 1
M tests/test_repair_focus.py 34 0
M tests/test_tool_batches.py 7 3
src/loader/runtime/tool_batches.pymodified
@@ -2,6 +2,7 @@
22
 
33
 from __future__ import annotations
44
 
5
+import re
56
 import shlex
67
 from collections.abc import Awaitable, Callable
78
 from dataclasses import dataclass, field
@@ -1009,6 +1010,12 @@ class ToolBatchRunner:
10091010
                 changed_path=changed_path,
10101011
             )
10111012
             if next_target:
1013
+                repair_issue = _quality_repair_issue_for_target(repair, next_target)
1014
+                issue_line = (
1015
+                    f"- {repair_issue}\n"
1016
+                    if repair_issue
1017
+                    else f"- Improve `{next_target}` until it satisfies the active content-quality verifier.\n"
1018
+                )
10121019
                 self.context.queue_steering_message(
10131020
                     "The active HTML content-quality repair target was updated. "
10141021
                     "If the current file now comfortably clears its stated threshold, "
@@ -1016,7 +1023,12 @@ class ToolBatchRunner:
10161023
                     "using one substantial write/edit/patch anchored to current content. "
10171024
                     "If it still looks thin, expand this same file further now. "
10181025
                     "Do not rerun verification, reopen unrelated references, or summarize "
1019
-                    "completion after only one quality target."
1026
+                    "completion after only one quality target.\n\n"
1027
+                    "Repair focus:\n"
1028
+                    f"{issue_line}"
1029
+                    f"- Immediate next step: edit `{next_target}`.\n"
1030
+                    "- Continue with one concrete `edit`, `patch`, or `write` call that "
1031
+                    "actually changes the current generated file."
10201032
                 )
10211033
                 return
10221034
 
@@ -1808,6 +1820,9 @@ class ToolBatchRunner:
18081820
             return
18091821
         if not all_planned_artifact_outputs_exist(dod, project_root=self.context.project_root):
18101822
             return
1823
+        repair = extract_active_repair_context(self.context.session.messages)
1824
+        if repair is not None and _repair_context_is_html_quality(repair):
1825
+            return
18111826
 
18121827
         next_pending = preferred_pending_todo_item(
18131828
             dod,
@@ -3458,6 +3473,15 @@ def _quality_repair_issue_for_target(repair: Any, target: str) -> str:
34583473
             return clean_line
34593474
         if normalized_target and normalized_target in clean_line:
34603475
             return clean_line
3476
+        for candidate in re.findall(r"`([^`]+)`", clean_line):
3477
+            try:
3478
+                normalized_candidate = str(
3479
+                    Path(candidate).expanduser().resolve(strict=False)
3480
+                )
3481
+            except (OSError, RuntimeError, ValueError):
3482
+                normalized_candidate = str(Path(candidate).expanduser())
3483
+            if normalized_target and normalized_candidate == normalized_target:
3484
+                return clean_line
34613485
 
34623486
     return first_quality_line
34633487
 
tests/test_repair_focus.pymodified
@@ -53,3 +53,37 @@ def test_extract_active_repair_context_keeps_immediate_target_first(
5353
     assert context.artifact_path == str(index_path.resolve(strict=False))
5454
     assert context.allowed_paths[0] == str(index_path.resolve(strict=False))
5555
     assert str(chapter_path.resolve(strict=False)) in context.allowed_paths
56
+
57
+
58
+def test_extract_active_repair_context_uses_latest_quality_handoff(
59
+    tmp_path: Path,
60
+) -> None:
61
+    first = tmp_path / "guide" / "chapters" / "01-introduction.html"
62
+    second = tmp_path / "guide" / "chapters" / "02-installation.html"
63
+
64
+    context = extract_active_repair_context(
65
+        [
66
+            Message(
67
+                role=Role.USER,
68
+                content=(
69
+                    "Repair focus:\n"
70
+                    f"- Improve `{first}`: thin content (400 text chars, expected at least 1758).\n"
71
+                    f"- Immediate next step: edit `{first}`.\n"
72
+                ),
73
+            ),
74
+            Message(
75
+                role=Role.USER,
76
+                content=(
77
+                    "The active HTML content-quality repair target was updated.\n\n"
78
+                    "Repair focus:\n"
79
+                    f"- Improve `{second}`: insufficient structured content (6 blocks, expected at least 18).\n"
80
+                    f"- Immediate next step: edit `{second}`.\n"
81
+                    "- Continue with one concrete edit, patch, or write call.\n"
82
+                ),
83
+            ),
84
+        ]
85
+    )
86
+
87
+    assert context is not None
88
+    assert context.artifact_path == str(second.resolve(strict=False))
89
+    assert context.allowed_paths[0] == str(second.resolve(strict=False))
tests/test_tool_batches.pymodified
@@ -7309,9 +7309,13 @@ async def test_tool_batch_runner_quality_repair_success_hands_to_next_target(
73097309
     )
73107310
 
73117311
     assert queued
7312
-    assert any("next listed quality target" in message for message in queued)
7313
-    assert any(str(second.resolve(strict=False)) in message for message in queued)
7314
-    assert any("Do not rerun verification" in message for message in queued)
7312
+    handoff = next(message for message in queued if "next listed quality target" in message)
7313
+    assert str(second.resolve(strict=False)) in handoff
7314
+    assert "Do not rerun verification" in handoff
7315
+    assert "Repair focus:" in handoff
7316
+    assert "insufficient structured content" in handoff
7317
+    assert f"Immediate next step: edit `{second.resolve(strict=False)}`" in handoff
7318
+    assert all("All explicitly planned artifacts now exist" not in message for message in queued)
73157319
 
73167320
 
73177321
 @pytest.mark.asyncio