Усилить reliability pack маржинальности
This commit is contained in:
@@ -9,16 +9,21 @@ from typing import Any
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
ORCHESTRATION_DIR = REPO_ROOT / "docs" / "orchestration"
|
||||
SCHEMA_DIR = REPO_ROOT / "docs" / "orchestration" / "schemas"
|
||||
ISSUE_CATALOG_PATH = REPO_ROOT / "docs" / "orchestration" / "issue_catalog.json"
|
||||
DETECTOR_REGISTRY_PATH = REPO_ROOT / "docs" / "orchestration" / "detector_registry.json"
|
||||
CONTRACTS_DIR = REPO_ROOT / "docs" / "orchestration" / "contracts"
|
||||
BUSINESS_ANSWER_CONTRACT_SCHEMA_VERSION = "business_answer_contract_v1"
|
||||
DOMAIN_SCENARIO_PACK_SCHEMA_VERSION = "domain_scenario_pack_v1"
|
||||
EXPECTED_SCHEMA_FILES = {
|
||||
"agent_issue_catalog.schema.json": "Agent Issue Catalog",
|
||||
"agent_detector_registry.schema.json": "Agent Detector Registry",
|
||||
"agent_detector_results.schema.json": "Agent Detector Results",
|
||||
"auto_coder_gate.schema.json": "Auto-Coder Gate",
|
||||
"business_answer_contract.schema.json": "Business Answer Contract",
|
||||
"business_audit_contract.schema.json": "Business Audit Contract",
|
||||
"domain_scenario_pack.schema.json": "Domain Scenario Pack",
|
||||
"domain_loop_lead_coder_handoff.schema.json": "Domain Loop Lead Coder Handoff",
|
||||
}
|
||||
AUTO_CODER_ALLOWED_ISSUE_CODES = {
|
||||
@@ -109,6 +114,72 @@ def collect_contract_detector_refs(contracts_dir: Path) -> tuple[dict[str, list[
|
||||
return refs, warnings
|
||||
|
||||
|
||||
def check_answer_contracts(contracts_dir: Path) -> tuple[dict[str, Any], list[str], list[str], set[str]]:
|
||||
failures: list[str] = []
|
||||
warnings: list[str] = []
|
||||
contract_ids: set[str] = set()
|
||||
contract_paths: list[str] = []
|
||||
if not contracts_dir.exists():
|
||||
return {"path": display_path(contracts_dir), "exists": False}, ["missing_answer_contracts_dir"], warnings, contract_ids
|
||||
|
||||
for path in sorted(contracts_dir.glob("*.json")):
|
||||
display = display_path(path)
|
||||
contract_paths.append(display)
|
||||
try:
|
||||
payload = read_json(path)
|
||||
except json.JSONDecodeError as error:
|
||||
failures.append(f"invalid_answer_contract_json:{display}:{error.msg}")
|
||||
continue
|
||||
if not isinstance(payload, dict):
|
||||
failures.append(f"answer_contract_not_object:{display}")
|
||||
continue
|
||||
|
||||
schema_version = str(payload.get("schema_version") or "").strip()
|
||||
contract_id = str(payload.get("contract_id") or "").strip()
|
||||
if schema_version != BUSINESS_ANSWER_CONTRACT_SCHEMA_VERSION:
|
||||
failures.append(f"answer_contract_schema_version_mismatch:{display}:{schema_version or 'empty'}")
|
||||
if not contract_id:
|
||||
failures.append(f"answer_contract_missing_contract_id:{display}")
|
||||
else:
|
||||
if contract_id in contract_ids:
|
||||
failures.append(f"answer_contract_duplicate_contract_id:{contract_id}")
|
||||
contract_ids.add(contract_id)
|
||||
if path.stem != contract_id:
|
||||
warnings.append(f"answer_contract_filename_mismatch:{display}:{contract_id}")
|
||||
if not str(payload.get("domain") or "").strip():
|
||||
failures.append(f"answer_contract_missing_domain:{display}")
|
||||
|
||||
answer_surface = payload.get("answer_surface") if isinstance(payload.get("answer_surface"), dict) else {}
|
||||
if not answer_surface:
|
||||
failures.append(f"answer_contract_missing_answer_surface:{display}")
|
||||
continue
|
||||
required_fields = answer_surface.get("required_fields")
|
||||
if not isinstance(required_fields, list) or not required_fields:
|
||||
failures.append(f"answer_contract_missing_required_fields:{display}")
|
||||
else:
|
||||
for index, field in enumerate(required_fields):
|
||||
if not isinstance(field, dict):
|
||||
failures.append(f"answer_contract_required_field_not_object:{display}:{index}")
|
||||
continue
|
||||
if not str(field.get("field") or "").strip():
|
||||
failures.append(f"answer_contract_required_field_missing_name:{display}:{index}")
|
||||
if not str(field.get("meaning") or "").strip():
|
||||
failures.append(f"answer_contract_required_field_missing_meaning:{display}:{index}")
|
||||
if not normalize_string_list(payload.get("detectors")):
|
||||
failures.append(f"answer_contract_missing_detectors:{display}")
|
||||
|
||||
summary = {
|
||||
"path": display_path(contracts_dir),
|
||||
"exists": True,
|
||||
"contract_count": len(contract_ids),
|
||||
"contract_ids": sorted(contract_ids),
|
||||
"contract_paths": contract_paths,
|
||||
}
|
||||
if not contract_ids:
|
||||
failures.append("answer_contracts_empty")
|
||||
return summary, failures, warnings, contract_ids
|
||||
|
||||
|
||||
def is_broad_patch_target(value: str) -> bool:
|
||||
normalized = value.strip().replace("\\", "/").lower()
|
||||
broad_targets = {
|
||||
@@ -307,23 +378,161 @@ def check_detector_registry(
|
||||
return summary, failures, warnings
|
||||
|
||||
|
||||
def scenario_pack_paths(orchestration_dir: Path) -> tuple[list[tuple[Path, dict[str, Any]]], list[str]]:
|
||||
warnings: list[str] = []
|
||||
packs: list[tuple[Path, dict[str, Any]]] = []
|
||||
if not orchestration_dir.exists():
|
||||
return packs, ["domain_scenario_pack_dir_missing"]
|
||||
for path in sorted(orchestration_dir.glob("*.json")):
|
||||
try:
|
||||
payload = read_json(path)
|
||||
except json.JSONDecodeError as error:
|
||||
warnings.append(f"domain_scenario_pack_scan_invalid_json:{display_path(path)}:{error.msg}")
|
||||
continue
|
||||
if isinstance(payload, dict) and payload.get("schema_version") == DOMAIN_SCENARIO_PACK_SCHEMA_VERSION:
|
||||
packs.append((path, payload))
|
||||
return packs, warnings
|
||||
|
||||
|
||||
def check_domain_scenario_packs(
|
||||
orchestration_dir: Path,
|
||||
known_contract_ids: set[str],
|
||||
detector_registry: dict[str, Any] | None = None,
|
||||
) -> tuple[dict[str, Any], list[str], list[str]]:
|
||||
failures: list[str] = []
|
||||
warnings: list[str] = []
|
||||
packs, scan_warnings = scenario_pack_paths(orchestration_dir)
|
||||
warnings.extend(scan_warnings)
|
||||
known_detectors = set()
|
||||
if isinstance(detector_registry, dict):
|
||||
detectors = detector_registry.get("detectors") if isinstance(detector_registry.get("detectors"), dict) else {}
|
||||
known_detectors = set(str(name) for name in detectors)
|
||||
|
||||
pack_ids: list[str] = []
|
||||
contract_bound_pack_count = 0
|
||||
step_count = 0
|
||||
contract_bound_step_count = 0
|
||||
wrong_domain_trap_step_count = 0
|
||||
for path, pack in packs:
|
||||
display = display_path(path)
|
||||
pack_id = str(pack.get("pack_id") or "").strip()
|
||||
if not pack_id:
|
||||
failures.append(f"domain_scenario_pack_missing_pack_id:{display}")
|
||||
else:
|
||||
pack_ids.append(pack_id)
|
||||
if not str(pack.get("domain") or "").strip():
|
||||
failures.append(f"domain_scenario_pack_missing_domain:{display}")
|
||||
scenarios = pack.get("scenarios")
|
||||
if not isinstance(scenarios, list) or not scenarios:
|
||||
failures.append(f"domain_scenario_pack_missing_scenarios:{display}")
|
||||
continue
|
||||
|
||||
source_contract_id = str(pack.get("source_contract_id") or "").strip()
|
||||
if source_contract_id:
|
||||
contract_bound_pack_count += 1
|
||||
if source_contract_id not in known_contract_ids:
|
||||
failures.append(f"domain_scenario_pack_unknown_source_contract:{display}:{source_contract_id}")
|
||||
if not isinstance(pack.get("acceptance"), dict) or not pack.get("acceptance"):
|
||||
failures.append(f"domain_scenario_pack_missing_acceptance:{display}:{source_contract_id}")
|
||||
if not normalize_string_list(pack.get("detectors_under_test")):
|
||||
failures.append(f"domain_scenario_pack_missing_detectors_under_test:{display}:{source_contract_id}")
|
||||
|
||||
analysis_context = pack.get("analysis_context") if isinstance(pack.get("analysis_context"), dict) else {}
|
||||
expected_contract = str(analysis_context.get("expected_business_answer_contract") or "").strip()
|
||||
if expected_contract and expected_contract not in known_contract_ids:
|
||||
failures.append(f"domain_scenario_pack_unknown_analysis_contract:{display}:{expected_contract}")
|
||||
|
||||
for detector_name in normalize_string_list(pack.get("detectors_under_test")):
|
||||
if known_detectors and detector_name not in known_detectors:
|
||||
failures.append(f"domain_scenario_pack_unknown_detector:{display}:{detector_name}")
|
||||
|
||||
for scenario in scenarios:
|
||||
if not isinstance(scenario, dict):
|
||||
failures.append(f"domain_scenario_pack_scenario_not_object:{display}")
|
||||
continue
|
||||
scenario_id = str(scenario.get("scenario_id") or "").strip()
|
||||
if not scenario_id:
|
||||
failures.append(f"domain_scenario_pack_scenario_missing_id:{display}")
|
||||
steps = scenario.get("steps")
|
||||
if not isinstance(steps, list) or not steps:
|
||||
failures.append(f"domain_scenario_pack_scenario_missing_steps:{display}:{scenario_id or 'unknown'}")
|
||||
continue
|
||||
for step in steps:
|
||||
step_count += 1
|
||||
if not isinstance(step, dict):
|
||||
failures.append(f"domain_scenario_pack_step_not_object:{display}:{scenario_id or 'unknown'}")
|
||||
continue
|
||||
step_id = str(step.get("step_id") or "").strip()
|
||||
if not step_id:
|
||||
failures.append(f"domain_scenario_pack_step_missing_id:{display}:{scenario_id or 'unknown'}")
|
||||
if not str(step.get("question") or "").strip():
|
||||
failures.append(f"domain_scenario_pack_step_missing_question:{display}:{scenario_id or 'unknown'}:{step_id or 'unknown'}")
|
||||
|
||||
step_contract = str(
|
||||
step.get("expected_business_answer_contract") or step.get("required_answer_contract") or ""
|
||||
).strip()
|
||||
if source_contract_id:
|
||||
if not step_contract:
|
||||
failures.append(
|
||||
f"domain_scenario_pack_step_missing_expected_contract:{display}:{scenario_id or 'unknown'}:{step_id or 'unknown'}"
|
||||
)
|
||||
else:
|
||||
contract_bound_step_count += 1
|
||||
if step_contract and step_contract not in known_contract_ids:
|
||||
failures.append(
|
||||
f"domain_scenario_pack_step_unknown_contract:{display}:{scenario_id or 'unknown'}:{step_id or 'unknown'}:{step_contract}"
|
||||
)
|
||||
|
||||
tags = normalize_string_list(step.get("semantic_tags"))
|
||||
if "wrong_domain_trap" in tags:
|
||||
wrong_domain_trap_step_count += 1
|
||||
if not normalize_string_list(step.get("forbidden_answer_patterns")):
|
||||
failures.append(
|
||||
f"domain_scenario_pack_wrong_domain_trap_missing_forbidden_patterns:{display}:{scenario_id or 'unknown'}:{step_id or 'unknown'}"
|
||||
)
|
||||
|
||||
return (
|
||||
{
|
||||
"path": display_path(orchestration_dir),
|
||||
"exists": orchestration_dir.exists(),
|
||||
"pack_count": len(packs),
|
||||
"pack_ids": sorted(pack_ids),
|
||||
"contract_bound_pack_count": contract_bound_pack_count,
|
||||
"step_count": step_count,
|
||||
"contract_bound_step_count": contract_bound_step_count,
|
||||
"wrong_domain_trap_step_count": wrong_domain_trap_step_count,
|
||||
},
|
||||
failures,
|
||||
warnings,
|
||||
)
|
||||
|
||||
|
||||
def build_healthcheck() -> dict[str, Any]:
|
||||
schema_files, schema_failures = check_schema_files(SCHEMA_DIR)
|
||||
answer_contracts, contract_failures, contract_warnings, contract_ids = check_answer_contracts(CONTRACTS_DIR)
|
||||
issue_catalog, catalog_failures, catalog_warnings = check_issue_catalog(ISSUE_CATALOG_PATH)
|
||||
issue_catalog_payload = read_json_object_or_empty(ISSUE_CATALOG_PATH)
|
||||
detector_registry_payload = read_json_object_or_empty(DETECTOR_REGISTRY_PATH)
|
||||
detector_registry, detector_failures, detector_warnings = check_detector_registry(
|
||||
DETECTOR_REGISTRY_PATH,
|
||||
issue_catalog_payload,
|
||||
)
|
||||
failures = schema_failures + catalog_failures + detector_failures
|
||||
warnings = catalog_warnings + detector_warnings
|
||||
domain_packs, domain_pack_failures, domain_pack_warnings = check_domain_scenario_packs(
|
||||
ORCHESTRATION_DIR,
|
||||
contract_ids,
|
||||
detector_registry_payload,
|
||||
)
|
||||
failures = schema_failures + contract_failures + catalog_failures + detector_failures + domain_pack_failures
|
||||
warnings = contract_warnings + catalog_warnings + detector_warnings + domain_pack_warnings
|
||||
return {
|
||||
"schema_version": "agent_reliability_contract_health_v1",
|
||||
"status": "pass" if not failures else "fail",
|
||||
"checked_at": datetime.now(timezone.utc).replace(microsecond=0).isoformat(),
|
||||
"schema_files": schema_files,
|
||||
"answer_contracts": answer_contracts,
|
||||
"issue_catalog": issue_catalog,
|
||||
"detector_registry": detector_registry,
|
||||
"domain_scenario_packs": domain_packs,
|
||||
"failures": failures,
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
@@ -14,8 +14,19 @@ from typing import Any
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
import agent_runtime_manifest as runtime_manifest
|
||||
import agent_detector_runner
|
||||
try:
|
||||
import agent_runtime_manifest as runtime_manifest
|
||||
except ModuleNotFoundError as error:
|
||||
if error.name != "agent_runtime_manifest":
|
||||
raise
|
||||
from scripts import agent_runtime_manifest as runtime_manifest
|
||||
|
||||
try:
|
||||
import agent_detector_runner
|
||||
except ModuleNotFoundError as error:
|
||||
if error.name != "agent_detector_runner":
|
||||
raise
|
||||
from scripts import agent_detector_runner
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
DEFAULT_ARTIFACTS_ROOT = REPO_ROOT / "artifacts" / "domain_runs"
|
||||
@@ -651,6 +662,22 @@ def merge_scenario_date_scope(
|
||||
current = current_date_scope if isinstance(current_date_scope, dict) else None
|
||||
if not current:
|
||||
return previous or current_date_scope
|
||||
if previous and depends_on:
|
||||
previous_source = str(previous.get("source") or "").strip()
|
||||
current_source = str(current.get("source") or "").strip()
|
||||
weak_current_sources = {
|
||||
"current_analysis",
|
||||
"active_domain_contract_default",
|
||||
"domain_default",
|
||||
"scenario_manifest_default",
|
||||
}
|
||||
stale_previous_sources = {"scenario_state_carryover"}
|
||||
if current_source in weak_current_sources and previous_source not in stale_previous_sources:
|
||||
merged = dict(current)
|
||||
for key in ("as_of_date", "period_from", "period_to"):
|
||||
if previous.get(key):
|
||||
merged[key] = previous.get(key)
|
||||
return merged
|
||||
return current
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ class AgentReliabilityContractHealthcheckTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(result["status"], "pass")
|
||||
self.assertEqual(result["failures"], [])
|
||||
self.assertIn("margin_profitability_v1", result["answer_contracts"]["contract_ids"])
|
||||
self.assertIn(
|
||||
"agent_margin_profitability_reliability_20260524",
|
||||
result["domain_scenario_packs"]["pack_ids"],
|
||||
)
|
||||
|
||||
def test_issue_catalog_healthcheck_blocks_auto_coder_issue_without_contract(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
@@ -216,6 +221,128 @@ class AgentReliabilityContractHealthcheckTests(unittest.TestCase):
|
||||
failures,
|
||||
)
|
||||
|
||||
def test_answer_contract_healthcheck_blocks_missing_required_fields(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
contracts_dir = Path(tmp) / "contracts"
|
||||
contracts_dir.mkdir()
|
||||
(contracts_dir / "demo_contract.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": "business_answer_contract_v1",
|
||||
"contract_id": "demo_contract",
|
||||
"domain": "demo",
|
||||
"answer_surface": {"required_fields": []},
|
||||
"detectors": ["demo_detector"],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
_, failures, _, contract_ids = health.check_answer_contracts(contracts_dir)
|
||||
|
||||
self.assertEqual(contract_ids, {"demo_contract"})
|
||||
self.assertTrue(
|
||||
any(failure.endswith("contracts\\demo_contract.json") for failure in failures),
|
||||
failures,
|
||||
)
|
||||
|
||||
def test_domain_scenario_pack_blocks_unknown_source_contract(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
orchestration_dir = Path(tmp)
|
||||
(orchestration_dir / "demo_pack.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": "domain_scenario_pack_v1",
|
||||
"pack_id": "demo_pack",
|
||||
"domain": "demo",
|
||||
"source_contract_id": "missing_contract",
|
||||
"detectors_under_test": ["demo_detector"],
|
||||
"acceptance": {"min_score": 80},
|
||||
"scenarios": [
|
||||
{
|
||||
"scenario_id": "demo_scenario",
|
||||
"steps": [
|
||||
{
|
||||
"step_id": "step_01",
|
||||
"question": "Question?",
|
||||
"expected_business_answer_contract": "missing_contract",
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
_, failures, _ = health.check_domain_scenario_packs(
|
||||
orchestration_dir,
|
||||
{"known_contract"},
|
||||
{"detectors": {"demo_detector": {}}},
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
any(
|
||||
failure.startswith("domain_scenario_pack_unknown_source_contract:")
|
||||
and failure.endswith("demo_pack.json:missing_contract")
|
||||
for failure in failures
|
||||
),
|
||||
failures,
|
||||
)
|
||||
self.assertTrue(
|
||||
any(
|
||||
failure.startswith("domain_scenario_pack_step_unknown_contract:")
|
||||
and failure.endswith("demo_pack.json:demo_scenario:step_01:missing_contract")
|
||||
for failure in failures
|
||||
),
|
||||
failures,
|
||||
)
|
||||
|
||||
def test_domain_scenario_pack_blocks_wrong_domain_trap_without_forbidden_patterns(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
orchestration_dir = Path(tmp)
|
||||
(orchestration_dir / "demo_pack.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": "domain_scenario_pack_v1",
|
||||
"pack_id": "demo_pack",
|
||||
"domain": "demo",
|
||||
"source_contract_id": "demo_contract",
|
||||
"detectors_under_test": ["demo_detector"],
|
||||
"acceptance": {"min_score": 80},
|
||||
"scenarios": [
|
||||
{
|
||||
"scenario_id": "demo_scenario",
|
||||
"steps": [
|
||||
{
|
||||
"step_id": "step_01",
|
||||
"question": "Question?",
|
||||
"expected_business_answer_contract": "demo_contract",
|
||||
"semantic_tags": ["wrong_domain_trap"],
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
_, failures, _ = health.check_domain_scenario_packs(
|
||||
orchestration_dir,
|
||||
{"demo_contract"},
|
||||
{"detectors": {"demo_detector": {}}},
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
any(
|
||||
failure.startswith("domain_scenario_pack_wrong_domain_trap_missing_forbidden_patterns:")
|
||||
and failure.endswith("demo_pack.json:demo_scenario:step_01")
|
||||
for failure in failures
|
||||
),
|
||||
failures,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user