core/evals/domain_contract_validation/runner.py
Shay 7784c39f9f feat(capability): implement ADR-0093 — Domain Pack Contract v1 wired in
Promotes ADR-0091 from proposed-but-unenforced to enforced. The CLI
command core capability domain-contract now runs the nine ADR-0091
predicates plus eval-lane artifact resolution; legacy structural-only
output remains available via --structural-only.

- new core/capability/domain_contract_predicates.py:
  evaluate_domain_contract(pack_id, *, data_root, chain_inventory,
  reviewer_registry) → DomainContractPredicateReport
- predicates wired:
  P1 manifest/checksum valid (via language_packs.compiler.load_pack)
  P2 gloss checksum (gloss-bearing packs only; otherwise vacuously pass)
  P3 domain_id ∈ DOMAIN_PACKS
  P4 teaching_chains entries ∈ TEACHING_CORPORA ∪ DOMAIN_CAPABILITY_CORPORA
  P5 ≥ 8 reviewed chains per claimed operator family from chain_report
  P6 ≥ 3 populated intent shapes per domain
  P7 every eval_lanes entry covers dev/public/holdout
  P8 reviewers resolve via ADR-0092 registry (consults can_review with
     scope='pack' and domain_id from contract)
  P9 known_gaps reference docs/gaps.md entries marked closed [x]
- _parse_gap_states reads docs/gaps.md format (- [x] / - [ ]) → {gap_id: closed?}
- _resolve_eval_lane_artifacts walks declared eval_lanes and surfaces
  per-split report path + SHA-256 (ADR-0093 item 4)
- CLI: cmd_capability_domain_contract now exits non-zero on any
  predicate failure; --structural-only preserves legacy behavior
- core.capability package re-exports new symbols (PredicateResult,
  DomainContractPredicateReport, evaluate_domain_contract)
- 24 unit tests covering contract presence/absence, each predicate
  positive + negative, gap parser, eval lane artifact surfacing,
  CLI default + structural-only paths, and determinism
- new evals/domain_contract_validation/ lane: 9 cases (positive +
  one negative per semantic predicate P3-P9 + determinism) passing
  9/9 byte-identical across runs (sha256 f9c06cde…)
- smoke 67/67, teaching 17/17, cognition 120/121 (pre-existing skip),
  ADR-0092..0095 tests 101/101; cognition eval byte-identical
  100/100/100/100
2026-05-21 18:33:23 -07:00

349 lines
11 KiB
Python

"""Runner for evals/domain_contract_validation/ (ADR-0093).
Builds synthetic pack fixtures in a temp directory, runs the nine
ADR-0091 predicates via
:func:`core.capability.domain_contract_predicates.evaluate_domain_contract`,
and asserts each case's actual outcome matches its declared expectation.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import shutil
import sys
import tempfile
from pathlib import Path
from typing import Any, Callable
from core.capability.domain_contract_predicates import (
DomainContractPredicateReport,
evaluate_domain_contract,
)
from core.capability.reviewers import Reviewer, ReviewerRegistry, SCHEMA_VERSION
PACK_ID = "synthetic_math_pack_v1"
def _registry() -> ReviewerRegistry:
return ReviewerRegistry(
schema_version=SCHEMA_VERSION,
reviewers=(
Reviewer(
reviewer_id="shay-j",
display_name="Joshua Shay",
role="primary",
domains=("*",),
review_scope=("pack", "proposal", "chain", "eval"),
provenance="adr-0092:lane:test",
),
Reviewer(
reviewer_id="physics-only",
display_name="Physics Reviewer",
role="domain",
domains=("physics",),
review_scope=("pack",),
provenance="adr-0092:lane:test",
),
),
)
def _full_inventory() -> dict[str, Any]:
return {
"by_domain_operator_family": {
"mathematics_logic": {
"transitive": 10,
"proof_chain": 9,
"contradiction": 8,
},
},
"by_domain_intent_shape": {
"mathematics_logic": {
"cause": 4,
"verification": 3,
"comparison": 5,
},
},
}
def _sparse_inventory() -> dict[str, Any]:
return {
"by_domain_operator_family": {
"mathematics_logic": {
"transitive": 2,
"proof_chain": 9,
"contradiction": 8,
},
},
"by_domain_intent_shape": {
"mathematics_logic": {
"cause": 4,
"verification": 3,
"comparison": 5,
},
},
}
def _thin_intent_inventory() -> dict[str, Any]:
return {
"by_domain_operator_family": {
"mathematics_logic": {
"transitive": 10,
"proof_chain": 9,
"contradiction": 8,
},
},
"by_domain_intent_shape": {
"mathematics_logic": {"cause": 4, "verification": 0, "comparison": 0},
},
}
def _write_pack(
data_root: Path,
*,
domain_id: str = "mathematics_logic",
teaching_chains: tuple[str, ...] = ("mathematics_logic_chains_v1",),
reviewers: tuple[str, ...] = ("shay-j",),
eval_lanes: tuple[dict[str, Any], ...] = (
{
"lane": "elementary_mathematics_ood",
"version": "v1",
"splits": ["dev", "public", "holdout"],
},
),
known_gaps: tuple[str, ...] = (),
) -> None:
pack_dir = data_root / PACK_ID
pack_dir.mkdir(parents=True, exist_ok=True)
manifest: dict[str, Any] = {
"pack_id": PACK_ID,
"name": "synthetic pack",
"domain_contract_version": 1,
"domain_id": domain_id,
"axioms": None,
"rules": None,
"teaching_chains": list(teaching_chains),
"eval_lanes": [dict(lane) for lane in eval_lanes],
"reviewers": list(reviewers),
"known_gaps": list(known_gaps),
"provenance": "lane:fixture:v1",
}
(pack_dir / "manifest.json").write_text(
json.dumps(manifest, sort_keys=True), encoding="utf-8"
)
def _evaluate(
data_root: Path,
*,
inventory: dict[str, Any] | None = None,
registry: ReviewerRegistry | None = None,
) -> DomainContractPredicateReport:
return evaluate_domain_contract(
PACK_ID,
data_root=data_root,
chain_inventory=inventory or _full_inventory(),
reviewer_registry=registry or _registry(),
)
# ---------------------------------------------------------------------------
# Cases
# ---------------------------------------------------------------------------
def _case_positive(tmp_root: Path) -> dict[str, Any]:
"""Synthetic fixtures cannot satisfy P1/P2 (require a compiled pack).
The lane asserts the *semantic* predicates P3-P9 pass on a
well-formed contract; P1/P2 are exercised against in-tree packs
elsewhere (and by tests/test_domain_contract_predicates.py).
"""
data_root = tmp_root / "positive"
_write_pack(data_root)
report = _evaluate(data_root)
semantic = [p for p in report.predicates if p.predicate_id not in {"P1", "P2"}]
failing = [p.predicate_id for p in semantic if not p.passed]
if failing:
return _fail(
"positive_all_predicates_pass",
f"P3-P9 expected pass; failing={failing}",
)
return _pass(
"positive_all_predicates_pass",
{
"semantic_predicates_passed": len(semantic),
"p1_p2_under_synthetic_fixture_excluded": True,
},
)
def _case_p3(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p3"
_write_pack(data_root, domain_id="alien_domain")
report = _evaluate(data_root)
if report.contract_valid:
return _fail("p3_unknown_domain", "contract should be parse-rejected")
if not any("domain_id:unknown" in e for e in report.contract_errors):
return _fail("p3_unknown_domain", f"missing domain_id:unknown error; errors={report.contract_errors}")
return _pass("p3_unknown_domain", {"contract_errors": list(report.contract_errors)})
def _case_p4(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p4"
_write_pack(data_root, teaching_chains=("ghost_chains_v999",))
report = _evaluate(data_root)
p4 = _find(report, "P4")
if p4.passed:
return _fail("p4_unregistered_chain", "P4 should fail on unregistered corpus")
return _pass("p4_unregistered_chain", {"notes": p4.notes})
def _case_p5(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p5"
_write_pack(data_root)
report = _evaluate(data_root, inventory=_sparse_inventory())
p5 = _find(report, "P5")
if p5.passed:
return _fail("p5_chain_shortfall", "P5 should fail with transitive=2")
return _pass("p5_chain_shortfall", {"notes": p5.notes})
def _case_p6(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p6"
_write_pack(data_root)
report = _evaluate(data_root, inventory=_thin_intent_inventory())
p6 = _find(report, "P6")
if p6.passed:
return _fail("p6_too_few_intents", "P6 should fail with 1 intent shape")
return _pass("p6_too_few_intents", {"notes": p6.notes})
def _case_p7(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p7"
_write_pack(
data_root,
eval_lanes=(
{
"lane": "elementary_mathematics_ood",
"version": "v1",
"splits": ["dev", "public"],
},
),
)
report = _evaluate(data_root)
p7 = _find(report, "P7")
if p7.passed:
return _fail("p7_incomplete_splits", "P7 should fail without holdout")
return _pass("p7_incomplete_splits", {"notes": p7.notes})
def _case_p8(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p8"
_write_pack(data_root, reviewers=("ghost-reviewer",))
report = _evaluate(data_root)
p8 = _find(report, "P8")
if p8.passed:
return _fail("p8_unknown_reviewer", "P8 should fail on unknown reviewer")
return _pass("p8_unknown_reviewer", {"notes": p8.notes})
def _case_p9(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "p9"
_write_pack(data_root, known_gaps=("gap:absolutely_imaginary_blocker",))
report = _evaluate(data_root)
p9 = _find(report, "P9")
if p9.passed:
return _fail("p9_open_gap", "P9 should fail on unknown gap")
return _pass("p9_open_gap", {"notes": p9.notes})
def _case_determinism(tmp_root: Path) -> dict[str, Any]:
data_root = tmp_root / "determinism"
_write_pack(data_root)
a = _evaluate(data_root).as_dict()
b = _evaluate(data_root).as_dict()
if a != b:
return _fail("determinism", "two evaluations produced different reports")
return _pass("determinism", {"all_passed": a["all_passed"]})
CASES: tuple[tuple[str, Callable[[Path], dict[str, Any]]], ...] = (
("positive_all_predicates_pass", _case_positive),
("p3_unknown_domain", _case_p3),
("p4_unregistered_chain", _case_p4),
("p5_chain_shortfall", _case_p5),
("p6_too_few_intents", _case_p6),
("p7_incomplete_splits", _case_p7),
("p8_unknown_reviewer", _case_p8),
("p9_open_gap", _case_p9),
("determinism", _case_determinism),
)
def _find(report: DomainContractPredicateReport, predicate_id: str) -> Any:
for p in report.predicates:
if p.predicate_id == predicate_id:
return p
raise RuntimeError(f"predicate {predicate_id} missing from report")
def _pass(case_id: str, details: dict[str, Any]) -> dict[str, Any]:
return {"case_id": case_id, "passed": True, "details": details, "divergence": None}
def _fail(case_id: str, divergence: str) -> dict[str, Any]:
return {"case_id": case_id, "passed": False, "details": {}, "divergence": divergence}
def run() -> dict[str, Any]:
tmp_root = Path(tempfile.mkdtemp(prefix="domain_contract_lane_"))
try:
case_results = [fn(tmp_root) for _, fn in CASES]
finally:
shutil.rmtree(tmp_root, ignore_errors=True)
return {
"lane": "domain_contract_validation",
"lane_version": "v1",
"split": "dev",
"adr": "ADR-0093",
"invariant": "domain_contract_v1_predicates_enforced",
"total_cases": len(case_results),
"passed_cases": sum(1 for r in case_results if r["passed"]),
"failed_cases": sum(1 for r in case_results if not r["passed"]),
"all_passed": all(r["passed"] for r in case_results),
"cases": case_results,
}
def _canonical_json(payload: dict[str, Any]) -> bytes:
return json.dumps(payload, sort_keys=True, indent=2).encode("utf-8") + b"\n"
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="domain_contract_validation lane runner")
parser.add_argument("--report", type=Path, default=None)
args = parser.parse_args(argv)
summary = run()
lane_dir = Path(__file__).resolve().parent
report_path = args.report or (lane_dir / "results" / "v1_dev.json")
report_path.parent.mkdir(parents=True, exist_ok=True)
payload_bytes = _canonical_json(summary)
report_path.write_bytes(payload_bytes)
print(f"report: {report_path}")
print(f"sha256: {hashlib.sha256(payload_bytes).hexdigest()}")
print(f"passed: {summary['passed_cases']}/{summary['total_cases']}")
return 0 if summary["all_passed"] else 1
if __name__ == "__main__":
sys.exit(main())