Keep quality repair worklists visible
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
2c722c3bb0c0301c8dff50d7e19eacc695adf94e- Parents
-
432985d - Tree
4eac6c6
2c722c3
2c722c3bb0c0301c8dff50d7e19eacc695adf94e432985d
4eac6c6| Status | File | + | - |
|---|---|---|---|
| M |
src/loader/runtime/finalization.py
|
23 | 5 |
| M |
tests/test_finalization.py
|
45 | 1 |
src/loader/runtime/finalization.pymodified@@ -55,6 +55,8 @@ WorkflowSetter = Callable[ | ||
| 55 | 55 | Awaitable[None], |
| 56 | 56 | ] |
| 57 | 57 | |
| 58 | +_MAX_HTML_QUALITY_REPAIR_TARGETS = 8 | |
| 59 | + | |
| 58 | 60 | |
| 59 | 61 | @dataclass |
| 60 | 62 | class CompletionGateResult: |
@@ -1308,16 +1310,30 @@ def _build_html_quality_repair_guidance( | ||
| 1308 | 1310 | targets: list[VerificationQualityRepairTarget], |
| 1309 | 1311 | ) -> str: |
| 1310 | 1312 | lines = ["Repair focus:"] |
| 1311 | - for target in targets[:4]: | |
| 1313 | + visible_targets = targets[:_MAX_HTML_QUALITY_REPAIR_TARGETS] | |
| 1314 | + for target in visible_targets: | |
| 1312 | 1315 | lines.append(f"- Improve `{target.artifact_path}`: {target.issue}.") |
| 1316 | + hidden_count = len(targets) - len(visible_targets) | |
| 1317 | + if hidden_count > 0: | |
| 1318 | + lines.append( | |
| 1319 | + f"- {hidden_count} additional generated artifact(s) also failed quality; " | |
| 1320 | + "repair the listed targets first, then rerun verification for the next batch." | |
| 1321 | + ) | |
| 1313 | 1322 | primary = targets[0] |
| 1314 | 1323 | lines.extend( |
| 1315 | 1324 | [ |
| 1316 | - f"- Immediate next step: edit `{primary.artifact_path}`.", | |
| 1325 | + f"- Immediate next step: edit `{primary.artifact_path}` with a substantial " | |
| 1326 | + "expansion or replacement that satisfies its listed quality issue.", | |
| 1327 | + "- If a target says thin content, add enough concrete prose to comfortably " | |
| 1328 | + "exceed the expected text-character floor; if it says insufficient " | |
| 1329 | + "structured content, add enough real sections, lists, code, tables, or " | |
| 1330 | + "other content blocks to exceed the block floor.", | |
| 1331 | + "- Repair every listed quality target in order before any final answer; " | |
| 1332 | + "do not stop after touching only the first file.", | |
| 1317 | 1333 | "- Update the listed generated artifacts directly; do not recreate the " |
| 1318 | 1334 | "artifact set or reread unrelated reference materials.", |
| 1319 | - "- After each content edit, continue with the next listed quality target " | |
| 1320 | - "or finish so Loader can re-run verification.", | |
| 1335 | + "- Once the listed target set has been substantially repaired, finish so " | |
| 1336 | + "Loader can rerun verification.", | |
| 1321 | 1337 | ] |
| 1322 | 1338 | ) |
| 1323 | 1339 | return "\n".join(lines) |
@@ -1398,7 +1414,9 @@ def _build_verification_failure_recovery_nudge( | ||
| 1398 | 1414 | "Do not restart discovery or keep auditing unrelated files. " |
| 1399 | 1415 | "Your next response should be one concrete `edit` or `write`-style tool " |
| 1400 | 1416 | f"call that expands `{primary_target.artifact_path}` to address: " |
| 1401 | - f"{primary_target.issue}.{remaining_hint}" | |
| 1417 | + f"{primary_target.issue}. Make a substantial change that clears the stated " | |
| 1418 | + "threshold, not a small incremental edit, and do not summarize completion " | |
| 1419 | + f"after only one target is touched.{remaining_hint}" | |
| 1402 | 1420 | ) |
| 1403 | 1421 | |
| 1404 | 1422 | fixes = _extract_verification_repairs(dod.evidence, repair_targets=repair_targets) |
tests/test_finalization.pymodified@@ -443,7 +443,8 @@ def test_verification_repair_guidance_replaces_stale_focus_for_html_quality_issu | ||
| 443 | 443 | ) |
| 444 | 444 | |
| 445 | 445 | assert guidance.startswith("Repair focus:") |
| 446 | - assert f"Immediate next step: edit `{first_chapter}`." in guidance | |
| 446 | + assert f"Immediate next step: edit `{first_chapter}` with a substantial" in guidance | |
| 447 | + assert "Repair every listed quality target in order before any final answer" in guidance | |
| 447 | 448 | assert "HTML guide content quality issues" not in guidance |
| 448 | 449 | assert repair is not None |
| 449 | 450 | assert repair.artifact_path == str(first_chapter.resolve(strict=False)) |
@@ -451,6 +452,49 @@ def test_verification_repair_guidance_replaces_stale_focus_for_html_quality_issu | ||
| 451 | 452 | assert str(third_chapter.resolve(strict=False)) in repair.allowed_paths |
| 452 | 453 | |
| 453 | 454 | |
| 455 | +def test_verification_repair_guidance_keeps_multi_file_quality_worklist( | |
| 456 | + temp_dir: Path, | |
| 457 | +) -> None: | |
| 458 | + chapters = temp_dir / "guides" / "nginx" / "chapters" | |
| 459 | + chapters.mkdir(parents=True) | |
| 460 | + chapter_paths = [ | |
| 461 | + chapters / f"{index:02d}-chapter-{index}.html" | |
| 462 | + for index in range(1, 9) | |
| 463 | + ] | |
| 464 | + for path in chapter_paths: | |
| 465 | + path.write_text(f"<h1>{path.stem}</h1>\n") | |
| 466 | + dod = create_definition_of_done("Create an equally thorough HTML guide.") | |
| 467 | + dod.evidence = [ | |
| 468 | + VerificationEvidence( | |
| 469 | + command="quality", | |
| 470 | + passed=False, | |
| 471 | + output=( | |
| 472 | + "HTML guide content quality issues:\n" | |
| 473 | + + "\n".join( | |
| 474 | + f"{path}: thin content (200 text chars, expected at least 1758)" | |
| 475 | + for path in chapter_paths | |
| 476 | + ) | |
| 477 | + ), | |
| 478 | + ) | |
| 479 | + ] | |
| 480 | + | |
| 481 | + guidance = _build_verification_repair_guidance( | |
| 482 | + dod, | |
| 483 | + project_root=temp_dir, | |
| 484 | + ) | |
| 485 | + repair = extract_active_repair_context( | |
| 486 | + [Message(role=Role.USER, content=guidance)] | |
| 487 | + ) | |
| 488 | + | |
| 489 | + assert f"Improve `{chapter_paths[0]}`: thin content" in guidance | |
| 490 | + assert f"Improve `{chapter_paths[-1]}`: thin content" in guidance | |
| 491 | + assert "add enough concrete prose" in guidance | |
| 492 | + assert "do not stop after touching only the first file" in guidance | |
| 493 | + assert repair is not None | |
| 494 | + assert repair.artifact_path == str(chapter_paths[0].resolve(strict=False)) | |
| 495 | + assert str(chapter_paths[-1].resolve(strict=False)) in repair.allowed_paths | |
| 496 | + | |
| 497 | + | |
| 454 | 498 | @pytest.mark.asyncio |
| 455 | 499 | async def test_turn_finalizer_records_skipped_verification_observation( |
| 456 | 500 | temp_dir: Path, |