"""Write contract.md, runner.py, __init__.py, and gaps.md for each Phase 5.4–5.7 domain lane. The lane scaffolds delegate scoring to the grammatical_coverage runner (same pattern as english_fluency_ood) so the rubric stays consistent across lanes. Vocabulary is the only thing that changes. Run after `generate_phase5_domain_lanes.py`. """ from __future__ import annotations from pathlib import Path LANES: dict[str, dict[str, str]] = { "elementary_mathematics_ood": { "phase": "5.4", "title": "Elementary mathematics fluency OOD", "public_domains": "arithmetic, set, geometry", "holdout_domain": "probability", "claim": "the deterministic realizer produces grammatical English surfaces over elementary-mathematics vocabulary the seed pack does not contain", }, "foundational_physics_ood": { "phase": "5.5", "title": "Foundational physics fluency OOD", "public_domains": "mechanics, electricity, thermodynamics", "holdout_domain": "optics", "claim": "the deterministic realizer produces grammatical English surfaces over foundational-physics vocabulary the seed pack does not contain", }, "foundational_biology_ood": { "phase": "5.6", "title": "Foundational biology fluency OOD", "public_domains": "cell, organism, ecosystem", "holdout_domain": "genetics", "claim": "the deterministic realizer produces grammatical English surfaces over foundational-biology vocabulary the seed pack does not contain", }, "classical_literature_ood": { "phase": "5.7", "title": "Classical literature fluency OOD", "public_domains": "epic, tragedy, lyric", "holdout_domain": "comedy", "claim": "the deterministic realizer produces grammatical English surfaces over classical-literature vocabulary the seed pack does not contain", }, } def _contract(lane: str, spec: dict[str, str]) -> str: return f"""# {spec['title']} eval lane (Phase {spec['phase']}) ## What it measures Whether {spec['claim']}. The structural claim under test: fluency is mechanistic in the realizer (templates over typed graph nodes), not lexical (pack-bound). If the claim holds, this OOD vocabulary passes the same syntactic gates the seed vocabulary did at v1/v2 of `grammatical_coverage` — and the same 13 constructions covered by the Phase 5.1 `english_fluency_ood` lane. ## Inputs `public/v1/cases.jsonl` : 117 cases — 13 constructions × 3 public domains ({spec['public_domains']}) × 3 lexical items per domain. `holdouts/v1/cases.jsonl` : 39 cases — 13 constructions × 1 held-out domain ({spec['holdout_domain']}) × 3 items. `dev/cases.jsonl` : 13 cases — one of each construction from the first public domain. Each case is one PropositionGraph JSON with realised constraints, generated by `scripts/generate_phase5_domain_lanes.py`. ## Scoring rubric Delegated to `evals/grammatical_coverage/runner.py` so the rubric stays consistent across all fluency-OOD lanes: - surface satisfies `accept_surfaces` or `constraints` (must_contain, word_order, max_words) - surface is not in `reject_surfaces` ## Target 100% on public + holdouts. Any miss indicates a real realizer or inflection gap and is filed in `gaps.md`. ## Provenance Same harness as `evals/english_fluency_ood/` (Phase 5.1). Vocabulary is the only material change between lanes. """ _RUNNER = '''"""Phase {phase} domain fluency OOD eval lane runner. Verifies the deterministic realizer produces grammatical English surfaces across the 13 grammatical-coverage constructions when the (subject, predicate, object) vocabulary is **out of the en_core_cognition_v1 distribution** — drawn from the {public_domains} public domains and the held-out {holdout_domain} domain. Scoring is delegated to the grammatical_coverage runner so the rubric stays consistent across all fluency-OOD lanes. Conforms to the framework interface: run_lane(cases, config=None) -> report. """ from __future__ import annotations from typing import Any from evals.grammatical_coverage.runner import LaneReport, run_lane as _run def run_lane(cases: list[dict[str, Any]], *, config: Any = None) -> LaneReport: return _run(cases, config=config) ''' def _gaps(lane: str, spec: dict[str, str]) -> str: return f"""# {spec['title']} — gaps ## v1 (current) - Constructions covered: all 13 (C01–C13) via grammatical_coverage rubric. - Domains covered: public — {spec['public_domains']}; holdout — {spec['holdout_domain']}. - Predicates default to regular verbs to keep morphology gaps from confounding the structural fluency claim. ## Known gaps for v2 The Phase 5.1 English fluency OOD lane already names three realizer gaps that apply equally here: G1. Irregular past tense — past_tense() handles regular -ed but not irregular forms (e.g. "ran", "stood"). G2. Plural agreement — the realizer does not pluralise nouns or conjugate to plural subjects. G3. Punctuation strictness — the rubric pins comma-bounded relative clauses exactly; small punctuation differences still fail. These are not lane-specific. When 5.1 closes them, every domain lane gains the same coverage for free. ## Out of scope for this lane - Domain-specific semantic correctness (whether "ribosome assembles protein" is *true* biology). This lane measures fluency, not factual correctness. Truth checks live in the `epistemic_status` surface (ADR-0021) and future curriculum lanes. """ if __name__ == "__main__": root = Path(__file__).resolve().parent.parent for lane, spec in LANES.items(): lane_dir = root / "evals" / lane (lane_dir / "__init__.py").write_text("") (lane_dir / "contract.md").write_text(_contract(lane, spec)) (lane_dir / "runner.py").write_text(_RUNNER.format(**spec)) (lane_dir / "gaps.md").write_text(_gaps(lane, spec)) print(f"scaffolded: evals/{lane}/")