mail-address-semantics/mas_conformance/runner.py
tegwick c4719a238d MAS-WP-0008: v0.2 wording pass, statute-aware conformance corpus in the bundle
conformance/statute-aware.json (vendored as mas_conformance/statute_aware.json)
covers the 6.3 stand-in table, resource_id_case equivalence and the 12.1
destination results and refusals; mas test runs it. Misread refusals now
name the field that would change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5787@bnt-lap001
Assistant-Session: 5db26b82-138b-40cc-9856-4d5eb0f752fd
2026-10-19 09:31:30 +02:00

92 lines
3.4 KiB
Python

"""Run the conformance corpus against mas_core. Used by `mas test` and pytest."""
from __future__ import annotations
from dataclasses import dataclass, field
from mas_core.parser import MasSyntaxError, parse_for_profile
from . import address_fixtures, property_fixtures, statute_aware_fixtures
@dataclass
class Report:
passed: int = 0
failures: list = field(default_factory=list)
@property
def ok(self) -> bool:
return not self.failures
def check_address_fixture(f: dict):
"""Return None on pass, else a failure description."""
try:
got = parse_for_profile(f["local_part"], f["profile"])
except MasSyntaxError as e:
if f["valid"]:
return f"unexpected invalid ({e.code}: {e})"
if "error" in f and f["error"] != e.code and f["id"].startswith("prop-"):
return f"wrong error code: expected {f['error']}, got {e.code}"
return None
if not f["valid"]:
return f"expected invalid, parsed as {got.to_fixture_dict()}"
if got.to_fixture_dict() != f["parsed"]:
return f"parse mismatch: got {got.to_fixture_dict()}, expected {f['parsed']}"
for key in ("required_profile", "generator_allowed", "base"):
if key in f and got.to_dict()[key] != f[key]:
return f"{key} mismatch: got {got.to_dict()[key]!r}, expected {f[key]!r}"
return None
def run_parser_corpus() -> Report:
report = Report()
for f in address_fixtures() + property_fixtures():
problem = check_address_fixture(f)
if problem:
report.failures.append((f["id"], f["local_part"], problem))
else:
report.passed += 1
return report
def run_statute_aware_corpus() -> Report:
"""v0.2 stand-ins, resource_id_case equivalence and destination transforms."""
from mas_core.generator import CannotExpress, for_destination
from mas_core.parser import parse_address
from mas_core.policy import resolve
from mas_core.statute import build_statute
fx = statute_aware_fixtures()
statutes = {k: build_statute(doc, doc["namespace"]) for k, doc in fx["statutes"].items()}
def sem(st, lp):
return resolve(parse_address(f"{lp}@{st.namespace}"), st)
report = Report()
def record(f, subject, problem):
if problem:
report.failures.append((f["id"], subject, problem))
else:
report.passed += 1
for f in fx["interpretation"]:
d = sem(statutes[f["statute"]], f["local_part"]).to_dict()
got = (d["canonical_local_part"], d["stand_ins"])
record(f, f["local_part"], None if got == (f["canonical"], f["stand_ins"])
else f"got {got}, expected {(f['canonical'], f['stand_ins'])}")
for f in fx["equivalence"]:
st = statutes[f["statute"]]
same = sem(st, f["a"]).equivalence_key == sem(st, f["b"]).equivalence_key
record(f, f"{f['a']} ~ {f['b']}", None if same == f["equivalent"]
else f"equivalent={same}, expected {f['equivalent']}")
for f in fx["destination"]:
try:
got = for_destination(f["local_part"], statutes[f["statute"]], f["needs"],
allow_lossy=f.get("allow_lossy", False)).local_part
except CannotExpress as e:
got, why = None, e.code
record(f, f["local_part"], None if got == f["expect"]
else f"got {got!r}" + (f" ({why})" if got is None else "") + f", expected {f['expect']!r}")
return report