ОРРКЕСТРАЦИЯ - Оркестрация домена: запретить ложный accepted при живых repair targets

This commit is contained in:
2026-04-14 23:27:48 +03:00
parent 82a020e302
commit 5934f5f3fc
2 changed files with 521 additions and 20 deletions
+111
View File
@@ -7,10 +7,12 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from scripts.domain_case_loop import (
build_deterministic_repair_targets,
build_scenario_acceptance_matrix,
carry_forward_analysis_context,
derive_pack_final_status,
evaluate_analyst_gate,
evaluate_deterministic_loop_gate,
load_scenario_pack,
merge_scenario_date_scope,
validate_step_contract,
@@ -499,3 +501,112 @@ def test_validate_step_contract_rejects_top_level_noise_as_direct_answer() -> No
assert validated["acceptance_status"] == "rejected"
assert "direct_answer_missing" in validated["violated_invariants"]
assert "top_level_noise_present" in validated["violated_invariants"]
def test_build_deterministic_repair_targets_marks_followup_router_gap_as_p0() -> None:
repair_targets = build_deterministic_repair_targets(
{"pack_id": "demo_pack", "domain": "inventory_stock", "final_status": "partial"},
[
{
"scenario_id": "inventory_selected_item_provenance",
"title": "Selected item provenance",
"artifact_dir": "artifacts/domain_runs/demo/scenarios/inventory_selected_item_provenance",
"scenario_state": {
"step_outputs": {
"step_02_supplier": {
"step_id": "step_02_supplier",
"question_resolved": 'По выбранному объекту "Столешница": кто поставил',
"execution_status": "exact",
"acceptance_status": "rejected",
"reply_type": "factual",
"selected_recipe": "address_inventory_on_hand_as_of_date_v1",
"capability_id": "confirmed_inventory_on_hand_as_of_date",
"violated_invariants": [
"wrong_followup_action",
"focus_object_missing",
"forbidden_capability_selected",
],
"warnings": [],
"hard_fail": True,
}
}
},
}
],
)
assert repair_targets["target_count"] == 1
target = repair_targets["targets"][0]
assert target["severity"] == "P0"
assert target["problem_type"] == "followup_action_resolution_gap"
assert "followup_action_resolution_gap" in target["root_cause_layers"]
assert "object_memory_gap" in target["root_cause_layers"]
assert "addressIntentResolver.ts" in " ".join(target["candidate_files"])
def test_build_deterministic_repair_targets_marks_anchor_gap_as_p1() -> None:
repair_targets = build_deterministic_repair_targets(
{"pack_id": "demo_pack", "domain": "inventory_stock", "final_status": "partial"},
[
{
"scenario_id": "inventory_sale_trace",
"title": "Sale trace",
"artifact_dir": "artifacts/domain_runs/demo/scenarios/inventory_sale_trace",
"scenario_state": {
"step_outputs": {
"step_02_selected_item_buyer_ui": {
"step_id": "step_02_selected_item_buyer_ui",
"question_resolved": 'По выбранному объекту "Шкаф": кому был продан товар',
"execution_status": "partial",
"acceptance_status": "rejected",
"reply_type": "partial_coverage",
"fallback_type": "partial",
"mcp_call_status": "materialized_but_not_anchor_matched",
"selected_recipe": "address_inventory_sale_trace_for_item_v1",
"capability_id": "inventory_inventory_sale_trace_for_item",
"violated_invariants": [],
"warnings": [],
"hard_fail": False,
}
}
},
}
],
)
assert repair_targets["target_count"] == 1
target = repair_targets["targets"][0]
assert target["severity"] == "P1"
assert target["problem_type"] == "domain_anchor_gap"
assert target["root_cause_layers"] == ["domain_anchor_gap"]
assert "addressQueryService.ts" in " ".join(target["candidate_files"])
def test_evaluate_deterministic_loop_gate_rejects_partial_pack_even_without_targets() -> None:
gate_ok, reason = evaluate_deterministic_loop_gate(
{"final_status": "partial"},
{"severity_counts": {"P0": 0, "P1": 0}},
)
assert gate_ok is False
assert reason == "pack_final_status=partial"
def test_evaluate_deterministic_loop_gate_rejects_remaining_p1_targets() -> None:
gate_ok, reason = evaluate_deterministic_loop_gate(
{"final_status": "accepted"},
{"severity_counts": {"P0": 0, "P1": 2}},
)
assert gate_ok is False
assert reason == "repair_targets_remaining=P0:0,P1:2"
def test_evaluate_deterministic_loop_gate_accepts_clean_pack_without_remaining_p0_p1() -> None:
gate_ok, reason = evaluate_deterministic_loop_gate(
{"final_status": "accepted"},
{"severity_counts": {"P0": 0, "P1": 0, "warning": 1}},
)
assert gate_ok is True
assert reason == "deterministic_gate_passed"