Донести detector signals до repair prompt
This commit is contained in:
parent
92e075157f
commit
50d4daf64e
|
|
@ -171,7 +171,7 @@ The status payload also exposes `effective_stage_status`, `effective_stage_statu
|
|||
|
||||
Use `python scripts/stage_agent_loop.py continue --manifest docs/orchestration/<stage_loop>.json` as the safe one-command continuation layer. From a cold start it materializes `domain_pack_loop.command.txt` without launching the long live loop; after a GUI review it can prepare a repair iteration and materialize `run-repair --dry-run` automatically; it will not run the real coder pass unless `--execute-repair` is passed, and it waits for a `--run-id assistant-stage1-<id>` when the next required step is post-repair rerun/ingest validation.
|
||||
|
||||
It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets, detector result signals, and sample user-facing failures without forcing the coder to reread the entire GUI conversation first.
|
||||
It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets, detector result signals, and sample user-facing failures without forcing the coder to reread the entire GUI conversation first. `prepare-repair` preserves those detector signals in the repair iteration plan, prompt, and checklist so the coder sees the concrete detector, issue code, message, and evidence preview.
|
||||
|
||||
For live stage-pack failures, prefer `lead_coder_handoff.md` over immediately preparing a coder pass. The intent is: strong business audit first, Lead Codex code repair second, same replay/GUI validation third.
|
||||
|
||||
|
|
|
|||
|
|
@ -1899,6 +1899,9 @@ def build_stage_repair_iteration_plan(
|
|||
if isinstance(target, dict)
|
||||
]
|
||||
sample_findings = handoff.get("sample_findings") if isinstance(handoff.get("sample_findings"), list) else []
|
||||
detector_result_signals = (
|
||||
handoff.get("detector_result_signals") if isinstance(handoff.get("detector_result_signals"), list) else []
|
||||
)
|
||||
candidate_files = list(
|
||||
dict.fromkeys(
|
||||
path
|
||||
|
|
@ -1937,6 +1940,9 @@ def build_stage_repair_iteration_plan(
|
|||
"auto_propose_gate": (
|
||||
handoff.get("auto_propose_gate") if isinstance(handoff.get("auto_propose_gate"), dict) else {}
|
||||
),
|
||||
"detector_result_signals": [
|
||||
signal for signal in detector_result_signals if isinstance(signal, dict)
|
||||
][:8],
|
||||
"primary_repair_targets": enriched_targets,
|
||||
"candidate_files": candidate_files,
|
||||
"sample_findings": [finding for finding in sample_findings if isinstance(finding, dict)][:8],
|
||||
|
|
@ -2009,6 +2015,19 @@ def build_stage_repair_checklist(plan: dict[str, Any]) -> str:
|
|||
f"- `{target.get('severity')}` `{target.get('problem_layer')}` / `{target.get('issue_code')}`: "
|
||||
f"{target.get('occurrences')} occurrence(s)"
|
||||
)
|
||||
detector_signals = (
|
||||
plan.get("detector_result_signals") if isinstance(plan.get("detector_result_signals"), list) else []
|
||||
)
|
||||
if detector_signals:
|
||||
lines.extend(["", "## Detector Signals"])
|
||||
for signal in detector_signals:
|
||||
if not isinstance(signal, dict):
|
||||
continue
|
||||
issue_codes = ", ".join(dcl.normalize_string_list(signal.get("issue_codes"))) or "n/a"
|
||||
lines.append(
|
||||
f"- `{signal.get('status')}` `{signal.get('detector')}` `{issue_codes}`: "
|
||||
f"{str(signal.get('message') or '').strip()}"
|
||||
)
|
||||
lines.extend(["", "## Acceptance"])
|
||||
acceptance = plan.get("acceptance_rerun") if isinstance(plan.get("acceptance_rerun"), dict) else {}
|
||||
for item in acceptance.get("after_patch", []) if isinstance(acceptance.get("after_patch"), list) else []:
|
||||
|
|
|
|||
|
|
@ -900,6 +900,14 @@ class StageAgentLoopTests(unittest.TestCase):
|
|||
"issue_codes": ["business_direct_answer_missing"],
|
||||
"rerun_matrix": ["failed_scenario", "direct_answer_surface_pack", "accepted_smoke_pack"],
|
||||
"auto_propose_gate": {"allowed": True, "reason": "auto_coder_gate_passed"},
|
||||
"detector_result_signals": [
|
||||
{
|
||||
"detector": "business_direct_answer_missing_signal",
|
||||
"status": "fail",
|
||||
"issue_codes": ["business_direct_answer_missing"],
|
||||
"message": "Direct answer is missing on the first line.",
|
||||
}
|
||||
],
|
||||
"primary_repair_targets": [
|
||||
{
|
||||
"problem_layer": "answer_shape_mismatch",
|
||||
|
|
@ -937,6 +945,7 @@ class StageAgentLoopTests(unittest.TestCase):
|
|||
self.assertIn("business_direct_answer_missing", plan["issue_codes"])
|
||||
self.assertIn("direct_answer_surface_pack", plan["rerun_matrix"])
|
||||
self.assertTrue(plan["auto_propose_gate"]["allowed"])
|
||||
self.assertEqual(plan["detector_result_signals"][0]["detector"], "business_direct_answer_missing_signal")
|
||||
self.assertIn("ingest-gui-run", plan["acceptance_rerun"]["ingest_command_template"])
|
||||
|
||||
def test_handle_prepare_repair_materializes_prompt_and_checklist(self) -> None:
|
||||
|
|
@ -965,6 +974,14 @@ class StageAgentLoopTests(unittest.TestCase):
|
|||
"question_quality_score": 100,
|
||||
"review_markdown": "review.md",
|
||||
"repair_targets_json": "repair_targets.json",
|
||||
"detector_result_signals": [
|
||||
{
|
||||
"detector": "business_direct_answer_missing_signal",
|
||||
"status": "fail",
|
||||
"issue_codes": ["business_direct_answer_missing"],
|
||||
"message": "Direct answer is missing on the first line.",
|
||||
}
|
||||
],
|
||||
"primary_repair_targets": [
|
||||
{
|
||||
"problem_layer": "business_utility_gap",
|
||||
|
|
@ -988,12 +1005,13 @@ class StageAgentLoopTests(unittest.TestCase):
|
|||
iteration_dir = stage_dir / "repair_iterations" / "repair_001"
|
||||
plan_exists = (iteration_dir / "repair_iteration_plan.json").exists()
|
||||
prompt = (iteration_dir / "repair_prompt.md").read_text(encoding="utf-8")
|
||||
checklist_exists = (iteration_dir / "repair_checklist.md").exists()
|
||||
checklist = (iteration_dir / "repair_checklist.md").read_text(encoding="utf-8")
|
||||
|
||||
self.assertEqual(exit_code, 0)
|
||||
self.assertTrue(plan_exists)
|
||||
self.assertTrue(checklist_exists)
|
||||
self.assertIn("business_answer_too_verbose", prompt)
|
||||
self.assertIn("business_direct_answer_missing_signal", prompt)
|
||||
self.assertIn("Direct answer is missing", checklist)
|
||||
|
||||
def test_handle_run_repair_dry_run_materializes_coder_command(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
|
|
|
|||
Loading…
Reference in New Issue