Wave 3, closes the LexicalClaim slice of ADR-0167. After this PR the math reader's refusal taxonomy is evidence, not terminus: lexical refusals flow through audit row → typed evidence → dedup signature → HITL ratification (W2-D) → pack write → next-audit-pass-resolves. Deliverables ------------ - tests/test_math_evidence_e2e.py (new, 7 tests): * test_full_pipeline_from_audit_to_evidence * test_e2e_replay_equivalence * test_lexical_ratification_advances_unknown_word_row (case 0040 'sees') * test_e2e_determinism_across_processes * test_cognition_teaching_corridor_unaffected * test_evidence_dedup_via_claim_signature * test_audit_artifact_round_trip_with_signatures - evals/gsm8k_math/train_sample/v1/audit_brief_11.md: Post-W2 baseline table + cognition regression line + case 0050 hazard status + pointer to the new e2e regression module. - tests/test_candidate_domain_partition.py: minimal allowlist patch to test_existing_cognition_tests_untouched so that future ADR-0167 PRs can add their own evidence test files without tripping a structurally brittle hard-coded whitelist (W2-C partition risk; recorded in PR body). Hard constraints held --------------------- - wrong == 0: case 0050 hazard still refuses at sentence_index 0 after the tmpdir-pack 'sees' ratification; no admission introduced. - Cognition regression: zero modifications to cognition test bodies; only the W2-C whitelist assertion was loosened. - Determinism: in-process and cross-process evidence_hash byte-identical. - No real-pack mutation: a per-test digest fixture asserts language_packs/data/en_core_math_v1/ is byte-identical before and after each test. Out of scope ------------ - Frame/Composition/Reference/Slot ratification handlers (follow-up ADRs). - Workbench v1 wiring of math candidates (ADR-0167 §Q4). - Auto-ratification — HITL only, forever. - The two partition risks Gemini flagged in W2-C (cognition pack indexing, replay-gate default) remain follow-up. With this PR merged the engine can ratify math-domain lexical claims from its own refusal evidence through the existing HITL teaching corridor — the thesis claim of ADR-0167 becomes a concrete green test.
97 lines
3.1 KiB
Python
97 lines
3.1 KiB
Python
"""Tests for W2-C — candidate domain partition."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from core.protocol import canonical_bytes
|
|
from teaching.discovery import DiscoveryCandidate
|
|
|
|
|
|
def _candidate(*, domain: str | None = None) -> DiscoveryCandidate:
|
|
kwargs: dict[str, Any] = {
|
|
"candidate_id": "cand_1",
|
|
"proposed_chain": {
|
|
"subject": "wisdom",
|
|
"intent": "cause",
|
|
"connective": None,
|
|
"object": None,
|
|
},
|
|
"trigger": "would_have_grounded",
|
|
"source_turn_trace": "t1",
|
|
"pack_consistent": True,
|
|
"boundary_clean": True,
|
|
}
|
|
if domain is not None:
|
|
kwargs["domain"] = domain
|
|
return DiscoveryCandidate(**kwargs)
|
|
|
|
|
|
def test_default_domain_is_cognition():
|
|
"""Bare DiscoveryCandidate has domain == 'cognition'."""
|
|
cand = _candidate()
|
|
assert cand.domain == "cognition"
|
|
|
|
|
|
def test_math_domain_can_be_set():
|
|
"""Explicit domain='math' constructs successfully."""
|
|
cand = _candidate(domain="math")
|
|
assert cand.domain == "math"
|
|
|
|
|
|
def test_round_trip_preserves_domain():
|
|
"""Serialization/deserialization preserves the domain field."""
|
|
# Cognition domain
|
|
cand_cog = _candidate(domain="cognition")
|
|
dict_cog = cand_cog.as_dict()
|
|
assert "domain" not in dict_cog # Omitted to preserve legacy keys
|
|
roundtrip_cog = DiscoveryCandidate.from_dict(dict_cog)
|
|
assert roundtrip_cog.domain == "cognition"
|
|
|
|
# Math domain
|
|
cand_math = _candidate(domain="math")
|
|
dict_math = cand_math.as_dict()
|
|
assert dict_math["domain"] == "math" # Included for math
|
|
roundtrip_math = DiscoveryCandidate.from_dict(dict_math)
|
|
assert roundtrip_math.domain == "math"
|
|
|
|
|
|
def test_canonical_bytes_includes_domain_deterministically():
|
|
"""Same domain value -> same canonical bytes contribution."""
|
|
cand_math_1 = _candidate(domain="math")
|
|
cand_math_2 = _candidate(domain="math")
|
|
bytes_1 = canonical_bytes(cand_math_1)
|
|
bytes_2 = canonical_bytes(cand_math_2)
|
|
assert bytes_1 == bytes_2
|
|
|
|
cand_cog = _candidate(domain="cognition")
|
|
bytes_cog = canonical_bytes(cand_cog)
|
|
assert bytes_cog != bytes_1
|
|
assert b'"domain":"math"' in bytes_1
|
|
assert b'"domain":"cognition"' in bytes_cog
|
|
|
|
|
|
def test_existing_cognition_tests_untouched():
|
|
"""Assert zero modifications to pre-existing cognition test files."""
|
|
# Find modified or untracked test files in git status
|
|
result = subprocess.run(
|
|
["git", "status", "--porcelain", "tests/"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]
|
|
# Allowlist of new/modified test files contributed by ADR-0167 PRs.
|
|
# Future ADR-0167 PRs append their own file here so this regression net
|
|
# stays meaningful as the wave progresses.
|
|
allowed = {
|
|
"test_candidate_domain_partition.py", # W2-C
|
|
"test_math_evidence_e2e.py", # W3-A
|
|
}
|
|
for line in lines:
|
|
path = line.split()[-1]
|
|
assert Path(path).name in allowed, (
|
|
f"unexpected new/modified test file: {path}"
|
|
)
|