* feat(eval): ProofWriter-OWA refusal-floor lane (B1) — independent oracle, measure-only Mastery-v2 Step-3 Brief 1. Proves the open-world soundness floor: determine() never asserts a query True when the open-world truth is Unknown or False. Hardens "unknown != false" before the transitive-chain (B2) and closed-world (B4) work can stress it. - evals/proofwriter_owa/oracle.py: a SEPARATE minimal OWA label oracle (its own parser + reasoner + inverse/symmetric tables), importing NONE of determine, comprehend/ MeaningGraph realization, or production predicate-entailment helpers (INV-25/27 — the gold producer is disjoint from the solver). Grammar: member/subset/is-a closure, explicit negation (No X is a Y -> disjointness, the source of gold-False), and #775 inverse/symmetric ONE-HOP relational rules. No transitive relational chains. - evals/proofwriter_owa/fixtures.jsonl: 19 hand-authored ProofWriter-OWA-style items (9 True / 7 Unknown / 3 False), SHA-pinned. Gold computed by the oracle; the fixture's hand-authored `expected` pins the oracle (so the oracle is itself verified). - evals/proofwriter_owa/score.py: runs the production path (comprehend/comprehend_relational -> realize -> determine) vs the oracle gold; wrong = determine asserted True on a non-True gold. - tests/test_proofwriter_owa_lane.py: SHA pin; oracle==expected; wrong==0; every serving_support gold-True determines True (no coverage gaps); no answer=False (INV-30). Result: 19 items -> 9 correct (all serving_support True), 10 refused (Unknown/False), 0 wrong. Measure-only: no engine code touched; deliberately NOT a capability-index domain (a refusal floor has low coverage and would drag coverage_geomean). INV-30 green; smoke 99/99. Note: no live ProofWriter dataset access in this environment, so items are hand-authored in OWA style (provenance.md cites ProofWriter V2020.12.3 / arXiv:2012.13048 for semantics, attribution only) — but the GOLD is oracle-computed and verified, not hand-asserted. * harden(eval): OWA lane CLI fails on coverage_gaps too (review #779) score.py::main() exited nonzero only on wrong>0; it now ALSO exits nonzero when coverage_gaps is non-empty (serving-supported gold-True items that refused), matching the acceptance rule the tests already enforce and the module docstring. Both failure modes print to stderr; exit is 1 if either fires. Verified non-vacuously (injected gap -> exit 1). Lane test 5/5 green.
117 lines
4.1 KiB
Python
117 lines
4.1 KiB
Python
"""Score the ProofWriter-OWA refusal floor: `determine()` vs the independent oracle.
|
|
|
|
For each fixture item: compute the OWA gold with the disjoint `oracle.label(...)`, then run
|
|
the production path (`comprehend`/`comprehend_relational` -> `realize` -> `determine`) and
|
|
compare. The invariant is **wrong=0**: `determine()` may assert True only on a gold-`True`
|
|
item; asserting True on a gold `Unknown` or `False` is a soundness breach (it would mean
|
|
the engine claimed entailment where the open world does not entail it).
|
|
|
|
Measure-only — imports no `generate.derivation` / `core.reliability_gate`; NOT a
|
|
capability-index domain. A refusal on a gold-`True` item is a coverage miss (recorded),
|
|
never a wrong — UNLESS the item is marked `serving_support` (within the engine's claimed
|
|
support), in which case it must determine True.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from chat.runtime import ChatRuntime
|
|
from evals.proofwriter_owa.oracle import label as owa_label
|
|
from generate.determine import Determined, determine
|
|
from generate.meaning_graph.reader import Refusal, comprehend
|
|
from generate.meaning_graph.relational import (
|
|
comprehend_relational,
|
|
load_relational_pack_lemmas,
|
|
)
|
|
from generate.realize import realize_comprehension
|
|
from session.context import SessionContext
|
|
|
|
_FIXTURES = Path(__file__).resolve().parent / "fixtures.jsonl"
|
|
_HIGH = 10**9
|
|
|
|
|
|
def _load(path: Path = _FIXTURES) -> list[dict[str, Any]]:
|
|
return [
|
|
json.loads(line)
|
|
for line in path.read_text(encoding="utf-8").splitlines()
|
|
if line.strip()
|
|
]
|
|
|
|
|
|
def _comprehend_any(text: str, pack):
|
|
"""Relational reader first (specific), else the general comprehension reader."""
|
|
c = comprehend_relational(text, pack)
|
|
if isinstance(c, Refusal):
|
|
return comprehend(text)
|
|
return c
|
|
|
|
|
|
def run(path: Path = _FIXTURES) -> dict[str, Any]:
|
|
items = _load(path)
|
|
pack = load_relational_pack_lemmas()
|
|
rt = ChatRuntime(no_load_state=True)
|
|
vocab, persona = rt._context.vocab, rt._context.persona
|
|
|
|
correct = refused = wrong = 0
|
|
wrongs: list[dict[str, Any]] = []
|
|
coverage_gaps: list[dict[str, Any]] = [] # serving_support gold-True that refused
|
|
|
|
for it in items:
|
|
gold = owa_label(it["facts"], it["query"])
|
|
ctx = SessionContext(
|
|
vocab=vocab, persona=persona, vault_reproject_interval=_HIGH
|
|
)
|
|
for fact in it["facts"]:
|
|
realize_comprehension(_comprehend_any(fact, pack), ctx)
|
|
res = determine(_comprehend_any(it["query"], pack), ctx)
|
|
asserted_true = isinstance(res, Determined) and res.answer is True
|
|
|
|
if asserted_true and gold == "True":
|
|
correct += 1
|
|
elif asserted_true: # gold Unknown/False but engine asserted True -> BREACH
|
|
wrong += 1
|
|
wrongs.append({"id": it["id"], "gold": gold, "query": it["query"]})
|
|
else:
|
|
refused += 1
|
|
if it.get("serving_support") and gold == "True":
|
|
coverage_gaps.append({"id": it["id"], "query": it["query"]})
|
|
|
|
return {
|
|
"domain": "proofwriter_owa",
|
|
"total": len(items),
|
|
"correct": correct,
|
|
"refused": refused,
|
|
"wrong": wrong,
|
|
"wrongs": wrongs,
|
|
"coverage_gaps": coverage_gaps,
|
|
"counts": {"correct": correct, "wrong": wrong, "refused": refused},
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
r = run()
|
|
print(json.dumps({k: v for k, v in r.items() if k != "wrongs"}, indent=2, sort_keys=True))
|
|
failed = False
|
|
if r["wrong"]:
|
|
print(
|
|
"WRONG > 0 — determine asserted True on a non-True OWA gold (soundness breach):",
|
|
file=sys.stderr,
|
|
)
|
|
print(json.dumps(r["wrongs"], indent=2), file=sys.stderr)
|
|
failed = True
|
|
if r["coverage_gaps"]:
|
|
print(
|
|
"COVERAGE GAPS — serving-supported gold-True items refused (acceptance breach):",
|
|
file=sys.stderr,
|
|
)
|
|
print(json.dumps(r["coverage_gaps"], indent=2), file=sys.stderr)
|
|
failed = True
|
|
return 1 if failed else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|