core/packs/common/validator.py
Shay d52bff56e7
chore(phase2): close W-006/W-010/W-014 — cleanup + doc amendments (#264)
W-006 (operator decision: delete):
- Remove dormant packs/en/el/grc/he/readback_rules.py (4 files, 0 live
  production callers). generate/realizer.py superseded the per-language
  readback path; per [[feedback-cleanup-as-you-find]], superseded code
  is removed rather than preserved.
- Remove _gate_readback from packs/common/validator.py and drop it from
  the validate_pack_dir gate sequence. Add language to the report dict
  so the param remains non-vacuous.

W-010 (operator decision: intentional token-level):
- Amend ADR-0143 with "Vocabulary isolation is intentional" section.
  Token-level anti-unification derives its own structural vocabulary;
  importing VocabManifold adds no information at that level. Confirmed
  intentional by operator review 2026-05-25.

W-014 (operator decision: evals-only):
- Add deployment-scope note to core/cognition/provenance.py docstring:
  evals-only infrastructure, no live runtime caller. Confirmed
  evals-only by operator review 2026-05-25.
2026-05-25 06:05:17 -07:00

122 lines
4.8 KiB
Python

"""Executable validation gates for local language packs."""
from __future__ import annotations
import importlib.util
import json
from pathlib import Path
from types import ModuleType
from packs.common.runtime_rules import read_jsonl
def _load_module(path: Path, name: str) -> ModuleType:
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise ImportError(f"cannot load {path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _gate_schema(pack_dir: Path) -> tuple[bool, str]:
required = ("lemmas.jsonl", "senses.jsonl", "morphology.jsonl", "probes/basic.jsonl")
for rel in required:
path = pack_dir / rel
if not path.exists():
return False, f"missing {rel}"
try:
read_jsonl(path)
except json.JSONDecodeError as exc:
return False, f"{rel}: invalid JSONL: {exc}"
return True, "ok"
def _gate_lexical(pack_dir: Path) -> tuple[bool, str]:
seen = set()
for record in read_jsonl(pack_dir / "lemmas.jsonl"):
lid = record["lemma_id"]
if lid in seen:
return False, f"duplicate lemma_id: {lid}"
seen.add(lid)
if not record.get("field_hooks"):
return False, f"lemma has no field_hooks: {lid}"
return True, "ok"
def _gate_morphology(pack_dir: Path) -> tuple[bool, str]:
known = {record["lemma_id"] for record in read_jsonl(pack_dir / "lemmas.jsonl")}
for record in read_jsonl(pack_dir / "morphology.jsonl"):
if record["lemma_id"] not in known:
return False, f"unknown lemma_id in morphology: {record['lemma_id']}"
return True, "ok"
def _gate_lift(pack_dir: Path) -> tuple[bool, str]:
lift_rules = _load_module(pack_dir / "lift_rules.py", f"{pack_dir.name}_lift_rules")
for probe in read_jsonl(pack_dir / "probes" / "basic.jsonl"):
if probe.get("kind") != "lift":
continue
packet = lift_rules.lift(probe["input"])[0]
payload = json.loads(packet.payload_json)
expected = probe["expected"]
for key in ("field_target", "pressure_kind"):
if key in expected and payload.get(key) != expected[key]:
return False, f"{probe['probe_id']}: {key} {payload.get(key)!r} != {expected[key]!r}"
return True, "ok"
def _gate_determinism(pack_dir: Path) -> tuple[bool, str]:
lift_rules = _load_module(pack_dir / "lift_rules.py", f"{pack_dir.name}_lift_rules_det")
for probe in read_jsonl(pack_dir / "probes" / "basic.jsonl"):
if probe.get("kind") == "lift":
left = lift_rules.lift(probe["input"])[0].payload_json
right = lift_rules.lift(probe["input"])[0].payload_json
if left != right:
return False, f"{probe['probe_id']}: lift is nondeterministic"
return True, "ok"
def _gate_alignment(pack_dir: Path) -> tuple[bool, str]:
lemmas = {record["lemma_id"] for record in read_jsonl(pack_dir / "lemmas.jsonl")}
senses = {record["sense_id"] for record in read_jsonl(pack_dir / "senses.jsonl")}
for probe in read_jsonl(pack_dir / "probes" / "basic.jsonl"):
if probe.get("kind") != "alignment":
continue
expected = probe["expected"]
if expected.get("lemma_id") not in lemmas:
return False, f"{probe['probe_id']}: unknown lemma anchor"
if expected.get("sense_id") not in senses:
return False, f"{probe['probe_id']}: unknown sense anchor"
return True, "ok"
def _gate_coverage(pack_dir: Path) -> tuple[bool, str]:
covered = {probe["kind"] for probe in read_jsonl(pack_dir / "probes" / "basic.jsonl")}
required = {"normalize", "lift", "alignment"}
missing = required - covered
if missing:
return False, f"missing probe kind(s): {', '.join(sorted(missing))}"
return True, "ok"
def validate_pack_dir(pack_dir: Path, *, pack_id: str, language: str) -> dict:
gates = (
("schema", lambda: _gate_schema(pack_dir)),
("lexical", lambda: _gate_lexical(pack_dir)),
("morphology", lambda: _gate_morphology(pack_dir)),
("lift", lambda: _gate_lift(pack_dir)),
("determinism", lambda: _gate_determinism(pack_dir)),
("alignment", lambda: _gate_alignment(pack_dir)),
("coverage", lambda: _gate_coverage(pack_dir)),
)
report = {"pack_id": pack_id, "language": language, "active": False, "gates": {}}
for index, (name, gate_fn) in enumerate(gates):
passed, reason = gate_fn()
report["gates"][name] = {"passed": passed, "reason": reason}
if not passed:
for remaining_name, _ in gates[index + 1:]:
report["gates"][remaining_name] = {"passed": False, "reason": "blocked by prior gate failure"}
return report
report["active"] = True
return report