arborist/tests/test_bench_batteries.py
russell@unturf.com 1f4c8b93c8
fan-out: code-py-ast graduation + 5R live + 5F fixture expansion + CI gate
Four-item fan-out per fox's 1/2/4/5 directive on the open menu.

(1) code-py-ast@v1 graduates from stub
    First non-text canonicalizer. Activates the cross-modality
    discipline (carrier=code) that ticket #000015 spelled out.
    Algorithm: ast.parse → walk node._fields in lexical order →
    emit deterministic S-expression. Source positions skipped
    naturally (not in _fields).
    Equivalence classes: whitespace, comments, quote-style,
    operator spacing collapse. Identifier names, operator types,
    argument order remain distinct.
    Projective (canonical = S-expression text, NOT Python).
    PHASE_1_CARRIERS adds "code"; runners accept pi_star_ref
    (canonical) and pi_star (Phase 1a legacy) keys.
    Tests: 11 new in test_pi_star.py.
    Bench fixtures: bench/fixtures/5s/{syntax,semantics}-code-v1.jsonl
    (10 + 12 = 22 code-carrier fixtures, all pass).
    Makefile: bench-5s-code target.

(2) CI gate via .gitlab-ci.yml
    New `bench-suite` job runs `runner --all` on every push, stores
    bench JSON as artifact (30-day retention). Fails the pipeline
    if any fixture fails.
    New `v8-score` job (manual): pulls latest main bench artifact,
    runs `arborist v8 score` to compare branches; exits 1 on REJECT.
    Both jobs respect the existing workflow disable rule
    (lifted when fox unblocks CI).

(4) 5R Phase 1b.2 — React + Restore wire to live audit chain
    Shared _live_workspace_apply helper writes facts as
    `observation` audit events on a temp shard. React live mode:
    snapshot_t1.facts written + audit bodies queried for
    expected_delta substrings. Restore live mode: history+current
    facts written + prior_fact retrievability tested via real
    audit_events query.
    12 react-live + 12 restore-live fixtures = 24 new live fixtures.
    Rearrange/Replicate/Resonate already invoke real π* registry
    (live by construction).

(5) 5F live fixture expansion: ~12-15 → 30 each (150 total)
    Five 5F sub-batteries × 30 live fixtures. Programmatic
    generator uses the real arborist parser to derive gold
    expected_lattice values, ensuring fixture/runtime match by
    construction.
    Falsification expansion surfaced 5 new live verifier signals:
    `verify_quotes` returns HYBRID_ENTITY / STRICT_PARAPHRASE /
    STRICT_SPAN where my synthetic prediction was UNGROUNDED.
    Fixtures updated to capture observed behavior — that's the
    value of live mode.

Surface delta:

- arborist/pi_star/code.py — full impl, replaces stub
- arborist/pi_star (no other changes; code.py is the action)
- bench/batteries/b_5s.py — pi_star_ref/pi_star backward-compat
- bench/batteries/b_5r.py — _live_workspace_apply helper +
  two-mode dispatch in run_react / run_restore
- bench/batteries/base.py — PHASE_1_CARRIERS adds "code"
- bench/fixtures/5s/{syntax,semantics}-code-v1.jsonl (new)
- bench/fixtures/5r/{react,restore}-live-v1.jsonl (new)
- bench/fixtures/5f/*-live-v1.jsonl (expanded to 30 each)
- .gitlab-ci.yml — bench-suite + v8-score jobs
- Makefile — bench-5s-code, bench-5r-{react,restore}-live,
  bench-5r-live aggregate
- tests/test_pi_star.py — 11 new (code-py-ast graduation)
- tests/test_bench_batteries.py — 5 new (5R live)

Full suite: 1226 passed, 36 skipped.

Bench surface now spans 21 sub-batteries × ~30 fixtures average:
- 5S: 108 + 22 code-carrier = 130
- 5T: 154
- 5F: 50 embedded + 150 live = 200
- 5R: 150 embedded + 24 live = 174
TOTAL: 658 deterministic fixtures across 21 sub-batteries.
2026-05-08 08:59:31 -04:00

855 lines
30 KiB
Python

"""5S/5T/5F battery harness tests.
Covers:
- Phase 1a (#000021) — fixture digest stability + smoke
- Phase 1b (#000023, #000024) — Syllogism/Synthesis/Semiotics +
Transfer-Learning/Triangulation/Truthtables/Transitivity/Time
- Phase 1a (#000025) — 5F: Function/Finetuning/Falsification/
Formulate/Feedback Loop
- Carrier-metadata schema: unsupported carriers fail cleanly
- Determinism: fixture_digest stable across reads
"""
from __future__ import annotations
import json
from dataclasses import asdict
from pathlib import Path
import pytest
from bench.batteries import b_5f, b_5s, b_5t
from bench.batteries.base import (
PHASE_1_CARRIERS,
BatteryResult,
fixture_digest,
fixture_meta,
iter_tasks,
validate_carrier,
)
REPO_ROOT = Path(__file__).resolve().parent.parent
F5S = REPO_ROOT / "bench" / "fixtures" / "5s"
F5T = REPO_ROOT / "bench" / "fixtures" / "5t"
F5F = REPO_ROOT / "bench" / "fixtures" / "5f"
# ---------------------------------------------------------------------
# Phase 1a digest stability (must NOT change after Phase 1b lands)
# ---------------------------------------------------------------------
def test_phase1a_5s_syntax_digest_stable():
a = fixture_digest(F5S / "syntax-v1.jsonl")
b = fixture_digest(F5S / "syntax-v1.jsonl")
assert a == b
assert len(a) == 64
def test_phase1a_5s_semantics_digest_stable():
a = fixture_digest(F5S / "semantics-v1.jsonl")
b = fixture_digest(F5S / "semantics-v1.jsonl")
assert a == b
def test_phase1a_5t_transfer_digest_stable():
"""Per #000024 hard constraint: legacy transfer-v1 digest stays pinned."""
a = fixture_digest(F5T / "transfer-v1.jsonl")
b = fixture_digest(F5T / "transfer-v1.jsonl")
assert a == b
# ---------------------------------------------------------------------
# Carrier metadata schema (#000023/#000024/#000025)
# ---------------------------------------------------------------------
def test_phase1_carriers_whitelist_present():
"""Whitelist includes the expected Phase-1 carriers."""
for c in ("text", "claim_lattice", "memory_snapshot",
"selfmodel_snapshot", "providence_record", "verifier_strategies",
"propositional_logic", "relation_graph"):
assert c in PHASE_1_CARRIERS
def test_validate_carrier_accepts_phase_1():
assert validate_carrier({"carrier": "text"}) is None
assert validate_carrier({"carrier": "claim_lattice"}) is None
assert validate_carrier({}) is None # missing → defaults to text
def test_validate_carrier_rejects_unsupported():
reason = validate_carrier({"carrier": "image"})
assert reason is not None
assert "unsupported_carrier" in reason
reason = validate_carrier({"carrier": "hidden_channel"})
assert reason is not None
# ---------------------------------------------------------------------
# 5S Phase 1b — Syllogism / Synthesis / Semiotics
# ---------------------------------------------------------------------
def test_5s_syllogism_runs_30_fixtures():
res = b_5s.run_syllogism(F5S / "syllogism-v1.jsonl")
assert res.battery == "5s"
assert res.sub_battery == "syllogism"
assert res.pass_count + res.fail_count == 30
assert res.pass_count == 30 # all designed to pass
assert res.metrics["step_validity_rate"] == 1.0
def test_5s_synthesis_runs_30_fixtures():
res = b_5s.run_synthesis(F5S / "synthesis-v1.jsonl")
assert res.pass_count + res.fail_count == 30
assert res.pass_count == 30
assert res.metrics["derivation_pass_rate"] == 1.0
def test_5s_semiotics_runs_30_fixtures():
res = b_5s.run_semiotics(F5S / "semiotics-v1.jsonl")
assert res.pass_count + res.fail_count == 30
assert res.pass_count == 30
assert res.metrics["invariance_under_swap"] == 1.0
def test_5s_syllogism_fixture_digest_stable():
a = fixture_digest(F5S / "syllogism-v1.jsonl")
b = fixture_digest(F5S / "syllogism-v1.jsonl")
assert a == b
def test_5s_synthesis_fixture_digest_stable():
a = fixture_digest(F5S / "synthesis-v1.jsonl")
b = fixture_digest(F5S / "synthesis-v1.jsonl")
assert a == b
def test_5s_semiotics_fixture_digest_stable():
a = fixture_digest(F5S / "semiotics-v1.jsonl")
b = fixture_digest(F5S / "semiotics-v1.jsonl")
assert a == b
# ---------------------------------------------------------------------
# 5T Phase 1b — Transfer Learning / Triangulation / Truthtables /
# Transitivity / Time
# ---------------------------------------------------------------------
def test_5t_transfer_learning_runs():
res = b_5t.run_transfer_learning(F5T / "transfer-learning-v2.jsonl")
assert res.battery == "5t"
assert res.sub_battery == "transfer-learning"
assert res.pass_count == 30
assert res.metrics["transfer_learning_success_rate"] == 1.0
def test_5t_triangulation_runs():
res = b_5t.run_triangulation(F5T / "triangulation-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["triangulation_agreement_rate"] == 1.0
def test_5t_truthtables_runs():
res = b_5t.run_truthtables(F5T / "truthtables-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["truth_table_coverage_rate"] == 1.0
def test_5t_truthtables_caps_at_n_4():
"""Per ticket #000024 §4.4: N > 4 must be rejected."""
import tempfile
bad = tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False)
bad.write(json.dumps({"_meta": {"battery": "5t", "sub_battery": "truthtables", "version": "v1"}}) + "\n")
bad.write(json.dumps({
"id": "5t-tt-toobig",
"carrier": "claim_lattice",
"domain": "propositional_logic",
"pi_star_ref": "pi_truth_table_v1",
"variables": ["A", "B", "C", "D", "E"],
"expression": "A AND B AND C AND D AND E",
"rows": [{"inputs": {v: False for v in "ABCDE"}, "expected": False}],
}) + "\n")
bad.close()
res = b_5t.run_truthtables(Path(bad.name))
assert res.pass_count == 0
assert res.fail_count == 1
assert "exceeds cap" in res.per_task[0].detail["reason"]
def test_5t_transitivity_runs():
res = b_5t.run_transitivity(F5T / "transitivity-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["full_chain_pass_rate"] == 1.0
def test_5t_transitivity_rejects_non_whitelisted_relation():
"""Non-whitelisted relations always fail by construction."""
import tempfile
bad = tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False)
bad.write(json.dumps({"_meta": {"battery": "5t", "sub_battery": "transitivity", "version": "v1"}}) + "\n")
bad.write(json.dumps({
"id": "test",
"carrier": "claim_lattice",
"domain": "relation_graph",
"pi_star_ref": "pi_relation_graph_v1",
"edges": [
{"from": "A", "to": "B", "relation": "related_to"},
{"from": "B", "to": "C", "relation": "related_to"},
],
"query": {"from": "A", "to": "C", "relation": "related_to"},
"expected": "pass", # but it can't possibly pass on a non-transitive relation
}) + "\n")
bad.close()
res = b_5t.run_transitivity(Path(bad.name))
# observed=fail because not in whitelist; expected=pass; mismatch.
assert res.fail_count == 1
def test_5t_time_runs_against_synthetic_snapshots():
res = b_5t.run_time(F5T / "time-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["temporal_context_preservation_rate"] == 1.0
# ---------------------------------------------------------------------
# 5F Phase 1a — Function / Finetuning / Falsification / Formulate /
# Feedback Loop
# ---------------------------------------------------------------------
def test_5f_function_runs():
res = b_5f.run_function(F5F / "function-v1.jsonl")
assert res.battery == "5f"
assert res.sub_battery == "function"
assert res.pass_count == 10
assert res.metrics["function_pass_rate"] == 1.0
def test_5f_finetuning_runs():
res = b_5f.run_finetuning(F5F / "finetuning-v1.jsonl")
assert res.pass_count == 10
assert res.metrics["adaptation_improvement_rate"] == 1.0
def test_5f_falsification_runs():
res = b_5f.run_falsification(F5F / "falsification-v1.jsonl")
assert res.pass_count == 10
assert res.metrics["error_detection_rate"] == 1.0
def test_5f_formulate_runs():
res = b_5f.run_formulate(F5F / "formulate-v1.jsonl")
assert res.pass_count == 10
assert res.metrics["structural_match_rate"] == 1.0
def test_5f_feedback_loop_runs():
res = b_5f.run_feedback_loop(F5F / "feedback-loop-v1.jsonl")
assert res.pass_count == 10
assert res.metrics["integration_coverage_rate"] == 1.0
# --- 5F efficiency-metric zero-cost guards (2026-05-08 review) ----
def test_efficiency_zero_cost_positive_gain_returns_infinite():
from bench.batteries.b_5f import EFFICIENCY_INFINITE, _efficiency
assert _efficiency(0.5, 0) == EFFICIENCY_INFINITE
def test_efficiency_zero_cost_zero_gain_returns_zero():
from bench.batteries.b_5f import EFFICIENCY_UNDEFINED, _efficiency
assert _efficiency(0, 0) == EFFICIENCY_UNDEFINED
assert _efficiency(0, 0) == 0.0
def test_efficiency_zero_cost_negative_gain_returns_neg_infinite():
from bench.batteries.b_5f import EFFICIENCY_INFINITE, _efficiency
assert _efficiency(-0.3, 0) == -EFFICIENCY_INFINITE
def test_efficiency_normal_ratio():
from bench.batteries.b_5f import _efficiency
assert _efficiency(1.0, 4.0) == 0.25
assert _efficiency(2.0, 1.0) == 2.0
def test_5f_finetuning_emits_efficiency_metrics():
res = b_5f.run_finetuning(F5F / "finetuning-v1.jsonl")
assert "adaptation_efficiency_mean_finite" in res.metrics
assert "adaptation_efficiency_infinite_count" in res.metrics
assert "adaptation_efficiency_neg_infinite_count" in res.metrics
# Per-task detail carries the per-task efficiency.
for t in res.per_task:
assert "adaptation_efficiency" in t.detail
assert "capital_cost_delta" in t.detail
def test_5f_feedback_loop_emits_efficiency_metrics():
res = b_5f.run_feedback_loop(F5F / "feedback-loop-v1.jsonl")
assert "feedback_efficiency_mean_finite" in res.metrics
assert "feedback_efficiency_infinite_count" in res.metrics
for t in res.per_task:
assert "feedback_efficiency" in t.detail
assert "chain_length" in t.detail
# --- low-level kernel edge cases ---------------------------------
def test_eval_propositional_parens_nesting():
from bench.batteries.b_5t import _eval_propositional
# ((A AND B) OR C) on (T,F,T) should be (T AND F) OR T = T.
assert _eval_propositional("(A AND B) OR C", {"A": True, "B": False, "C": True}) is True
assert _eval_propositional("A AND (B OR C)", {"A": True, "B": False, "C": True}) is True
assert _eval_propositional("NOT (A AND B)", {"A": True, "B": True}) is False
def test_eval_propositional_rejects_unknown_variable():
from bench.batteries.b_5t import _eval_propositional
with pytest.raises(ValueError):
_eval_propositional("X AND Y", {"X": True}) # Y missing
def test_eval_propositional_rejects_malformed():
from bench.batteries.b_5t import _eval_propositional
with pytest.raises(ValueError):
_eval_propositional("A AND", {"A": True}) # incomplete
with pytest.raises(ValueError):
_eval_propositional("(A OR B", {"A": True, "B": False}) # unbalanced
def test_eval_propositional_xor_iff_impl():
from bench.batteries.b_5t import _eval_propositional
# IMPL truth table: T→F is the only false case.
for a, b in [(True, True), (True, False), (False, True), (False, False)]:
expected_impl = (not a) or b
expected_iff = a == b
expected_xor = a != b
assert _eval_propositional("A IMPL B", {"A": a, "B": b}) == expected_impl
assert _eval_propositional("A IFF B", {"A": a, "B": b}) == expected_iff
assert _eval_propositional("A XOR B", {"A": a, "B": b}) == expected_xor
def test_walk_relation_path_handles_self_loop():
from bench.batteries.b_5t import _walk_relation_path
# A→A self-loop should resolve immediately.
assert _walk_relation_path([], "A", "A", "implies") is True
def test_walk_relation_path_handles_cycles_without_infinite_loop():
from bench.batteries.b_5t import _walk_relation_path
edges = [
{"from": "A", "to": "B", "relation": "implies"},
{"from": "B", "to": "C", "relation": "implies"},
{"from": "C", "to": "A", "relation": "implies"}, # back-edge
]
# Should still find C reachable from A; no infinite loop.
assert _walk_relation_path(edges, "A", "C", "implies") is True
# And handle unreachable target cleanly.
assert _walk_relation_path(edges, "A", "Z", "implies") is False
def test_walk_relation_path_rejects_non_whitelisted_relation():
from bench.batteries.b_5t import _walk_relation_path
edges = [
{"from": "A", "to": "B", "relation": "related_to"},
{"from": "B", "to": "C", "relation": "related_to"},
]
# related_to is NOT in the transitive whitelist → always False.
assert _walk_relation_path(edges, "A", "C", "related_to") is False
def test_content_tokens_strips_punctuation():
from bench.batteries.b_5s import _content_tokens
tokens = _content_tokens("Hello, world! This is a test.")
assert "hello" in tokens
assert "world" in tokens
assert "test" in tokens
# Stopwords removed.
assert "is" not in tokens
assert "a" not in tokens
assert "this" not in tokens
def test_content_tokens_handles_unicode():
from bench.batteries.b_5s import _content_tokens
tokens = _content_tokens("Bonjour, café Paris!")
assert "bonjour" in tokens
assert "café" in tokens
assert "paris" in tokens
def test_capital_cost_delta_handles_missing_budget():
"""Empty resource_budget → zero cost."""
from bench.batteries.b_5f import _capital_cost_delta
assert _capital_cost_delta({}) == 0.0
assert _capital_cost_delta({"resource_budget": {}}) == 0.0
assert _capital_cost_delta({
"resource_budget": {"max_compute_ms_delta": 1000}
}) == 1.0
assert _capital_cost_delta({
"resource_budget": {"max_storage_delta_bytes": 5_000_000}
}) == 5.0
# --- 5F Phase 1b.2 — Formulate live wire-up ---------------------
def test_5f_formulate_live_path_routes_through_parse_claims():
"""The new formulate-live-v1.jsonl fixtures use input_text only;
runner derives produced_lattice via parse_pointer_claims and
matches against expected_lattice."""
res = b_5f.run_formulate(F5F / "formulate-live-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["structural_match_rate"] == 1.0
# Every task ran through the live path.
for t in res.per_task:
assert t.detail["source"] == "live"
def test_5f_formulate_embedded_path_still_works():
"""Phase 1a fixtures (embedded produced_lattice) keep working
after the Phase 1b.2 wire-up. Backward compat invariant."""
res = b_5f.run_formulate(F5F / "formulate-v1.jsonl")
assert res.pass_count == 10
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5f_formulate_live_helper_uses_real_arborist_parser(tmp_path):
"""The live path actually calls
arborist.qa.parse_claims.parse_pointer_claims — not a stub."""
from bench.batteries.b_5f import _live_produced_lattice
out = _live_produced_lattice("- Hello world. [E1]\n- Second one. [E2]")
assert out["claims"][0]["claim_text"] == "Hello world."
assert out["claims"][0]["pointer_ids"] == ["E1"]
assert out["claims"][1]["claim_text"] == "Second one."
assert out["claims"][1]["pointer_ids"] == ["E2"]
def test_5f_formulate_rejects_fixture_with_neither_field(tmp_path):
"""Task without produced_lattice OR input_text → fails cleanly."""
p = tmp_path / "bad.jsonl"
p.write_text(
json.dumps({"_meta": {"battery": "5f", "sub_battery": "formulate", "version": "v1"}}) + "\n" +
json.dumps({
"id": "test",
"carrier": "text",
"domain": "claim_lattice",
"pi_star_ref": "claim-lattice@v1",
"expected_lattice": {"claim_count": 0, "claims": []},
}) + "\n",
encoding="utf-8",
)
res = b_5f.run_formulate(p)
assert res.fail_count == 1
assert "produced_lattice" in res.per_task[0].detail["reason"]
# --- 5F Phase 1b.2 — Feedback Loop live wire-up -----------------
def test_5f_feedback_loop_live_path_writes_real_audit_events():
"""live_chain ops applied to a fresh temp shard via append_audit
+ memory.snapshot; expected_delta predicates verified against
the resulting audit_events / memory_branch_summaries."""
res = b_5f.run_feedback_loop(F5F / "feedback-loop-live-v1.jsonl")
assert res.pass_count == 30
# Every passing task must report source=live.
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5f_feedback_loop_embedded_path_still_works():
res = b_5f.run_feedback_loop(F5F / "feedback-loop-v1.jsonl")
assert res.pass_count == 10
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5f_live_feedback_chain_helper_appends_audit_event(tmp_path):
"""The live helper actually writes an audit event to a real
arborist shard."""
from bench.batteries.b_5f import _live_feedback_chain
state = _live_feedback_chain([
{"op": "append_audit", "event_type": "test_event", "body": {"k": "v"}},
{"op": "memory_snapshot"},
])
assert "test_event" in state["audit_event_types"]
assert "memory_snapshot_landed" in state["audit_event_types"]
assert "audit-mode-distribution" in state["memory_branch_ids"]
def test_5f_live_feedback_rejects_unknown_op(tmp_path):
from bench.batteries.b_5f import _live_feedback_chain
with pytest.raises(ValueError, match="unknown live op"):
_live_feedback_chain([{"op": "fake_op"}])
def test_5f_live_feedback_chain_audit_chain_intact():
"""Live helper exercises the real audit chain; chain should
re-verify after the helper completes."""
import hashlib
import os
import tempfile
from arborist.store import append_audit, connect, transaction
tmp = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
tmp.close()
try:
conn = connect(tmp.name)
with transaction(conn):
append_audit(conn, event_type="x", subject_root=None, body={"a": 1})
append_audit(conn, event_type="y", subject_root=None, body={"b": 2})
rows = conn.execute(
"SELECT event_hash, prev_event_hash, body FROM audit_events ORDER BY seq"
).fetchall()
prev = None
for row in rows:
h = hashlib.sha256()
if prev is not None:
h.update(bytes.fromhex(prev))
h.update(row["body"].encode("utf-8", errors="surrogatepass"))
assert h.hexdigest() == row["event_hash"]
prev = row["event_hash"]
conn.close()
finally:
try:
os.unlink(tmp.name)
except OSError:
pass
# --- 5F Phase 1b.2 — Function / Finetuning / Falsification live -
def test_5f_function_live_path_routes_through_parse_claims():
res = b_5f.run_function(F5F / "function-live-v1.jsonl")
assert res.pass_count == 30
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5f_function_embedded_path_still_works():
res = b_5f.run_function(F5F / "function-v1.jsonl")
assert res.pass_count == 10
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5f_function_live_helper_uses_real_parser():
from bench.batteries.b_5f import _live_function_produced
out = _live_function_produced({"input_text": "- A claim. [E1]\n- B claim. [E2]"})
assert out["claims"][0]["claim_text"] == "A claim."
assert out["claims"][0]["pointer_ids"] == ["E1"]
assert out["claims"][1]["pointer_ids"] == ["E2"]
def test_5f_finetuning_live_path_round_trips_selfmodel():
res = b_5f.run_finetuning(F5F / "finetuning-live-v1.jsonl")
assert res.pass_count == 30
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5f_finetuning_embedded_path_still_works():
res = b_5f.run_finetuning(F5F / "finetuning-v1.jsonl")
assert res.pass_count == 10
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5f_finetuning_live_helper_persists_real_selfmodel():
"""The live helper writes to the SelfModel store and reads
measured values back from claims_for."""
from bench.batteries.b_5f import _live_finetuning_measure
out = _live_finetuning_measure({
"target_capability": "test_metric",
"parent_measured_value": 0.40,
"child_measured_value": 0.62,
"expected_improvement_min": 0.05,
"resource_budget": {"max_compute_ms_delta": 100, "max_storage_delta_bytes": 1000},
})
assert out["parent_measured"] == pytest.approx(0.40)
assert out["child_measured"] == pytest.approx(0.62)
assert len(out["parent_root"]) == 64
assert len(out["child_root"]) == 64
assert out["parent_root"] != out["child_root"]
def test_5f_falsification_live_path_routes_through_verify_quotes():
res = b_5f.run_falsification(F5F / "falsification-live-v1.jsonl")
assert res.pass_count == 30
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5f_falsification_embedded_path_still_works():
res = b_5f.run_falsification(F5F / "falsification-v1.jsonl")
assert res.pass_count == 10
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5f_falsification_live_helper_calls_real_verifier():
"""UNGROUNDED + STRICT_SPAN signals come straight from verify_quotes."""
from bench.batteries.b_5f import _live_falsification_violations
# Verbatim match → STRICT_SPAN.
out_strict = _live_falsification_violations({
"answer_text": "Hydrogen has atomic number 1.",
"context": "Hydrogen has atomic number 1 and is the lightest element.",
})
assert "STRICT_SPAN" in out_strict
# Unrelated → UNGROUNDED.
out_ungrounded = _live_falsification_violations({
"answer_text": "K2 is the tallest mountain.",
"context": "Mount Everest is the tallest mountain.",
})
assert "UNGROUNDED" in out_ungrounded
# --- 5R Phase 2 (#000021) ----------------------------------------
def test_5r_react_runs():
from bench.batteries import b_5r
res = b_5r.run_react(REPO_ROOT / "bench" / "fixtures" / "5r" / "react-v1.jsonl")
assert res.battery == "5r"
assert res.sub_battery == "react"
assert res.pass_count == 30
assert res.metrics["react_integration_rate"] == 1.0
def test_5r_rearrange_runs():
from bench.batteries import b_5r
res = b_5r.run_rearrange(REPO_ROOT / "bench" / "fixtures" / "5r" / "rearrange-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["rearrange_invariance_rate"] == 1.0
def test_5r_restore_runs():
from bench.batteries import b_5r
res = b_5r.run_restore(REPO_ROOT / "bench" / "fixtures" / "5r" / "restore-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["restore_retrievability_rate"] == 1.0
def test_5r_replicate_runs():
from bench.batteries import b_5r
res = b_5r.run_replicate(REPO_ROOT / "bench" / "fixtures" / "5r" / "replicate-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["replicate_determinism_rate"] == 1.0
def test_5r_resonate_runs():
"""Deterministic π* must yield distinct=1 across N runs."""
from bench.batteries import b_5r
res = b_5r.run_resonate(REPO_ROOT / "bench" / "fixtures" / "5r" / "resonate-v1.jsonl")
assert res.pass_count == 30
assert res.metrics["resonate_stability_rate"] == 1.0
assert res.metrics["mean_distinct_outputs"] == 1.0
def test_5r_react_rejects_unsupported_carrier(tmp_path):
from bench.batteries import b_5r
p = tmp_path / "bad.jsonl"
p.write_text(
json.dumps({"_meta": {"battery": "5r", "sub_battery": "react", "version": "v1"}}) + "\n" +
json.dumps({
"id": "test", "carrier": "image",
"snapshot_t0": {"facts": []}, "snapshot_t1": {"facts": []},
"expected_delta": {"added_facts": [], "removed_facts": []},
}) + "\n",
encoding="utf-8",
)
res = b_5r.run_react(p)
assert res.fail_count == 1
assert "unsupported_carrier" in res.per_task[0].detail["reason"]
# --- 5R Phase 1b.2 — React + Restore live ---------------------------
def test_5r_react_live_path_writes_real_audit_events():
from bench.batteries import b_5r
res = b_5r.run_react(REPO_ROOT / "bench" / "fixtures" / "5r" / "react-live-v1.jsonl")
assert res.pass_count == 12
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5r_react_embedded_path_still_works():
from bench.batteries import b_5r
res = b_5r.run_react(REPO_ROOT / "bench" / "fixtures" / "5r" / "react-v1.jsonl")
assert res.pass_count == 30
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5r_restore_live_path_routes_through_audit_chain():
from bench.batteries import b_5r
res = b_5r.run_restore(REPO_ROOT / "bench" / "fixtures" / "5r" / "restore-live-v1.jsonl")
assert res.pass_count == 12
for t in res.per_task:
if t.passed:
assert t.detail["source"] == "live"
def test_5r_restore_embedded_path_still_works():
from bench.batteries import b_5r
res = b_5r.run_restore(REPO_ROOT / "bench" / "fixtures" / "5r" / "restore-v1.jsonl")
assert res.pass_count == 30
for t in res.per_task:
assert t.detail["source"] == "embedded"
def test_5r_live_workspace_helper_writes_real_events():
"""The shared _live_workspace_apply helper actually writes
audit events to a real arborist shard."""
from bench.batteries.b_5r import _live_workspace_apply
bodies = _live_workspace_apply(["alpha", "beta", "gamma"])
assert len(bodies) == 3
text = "\n".join(bodies)
assert "alpha" in text
assert "beta" in text
assert "gamma" in text
def test_finetuning_zero_cost_fixture_emits_inf(tmp_path):
"""Synthesize a fixture with zero resource_budget; assert inf emitted."""
p = tmp_path / "ft-zero.jsonl"
p.write_text(
json.dumps({"_meta": {"battery": "5f", "sub_battery": "finetuning", "version": "v1"}}) + "\n" +
json.dumps({
"id": "5f-ft-zero",
"carrier": "selfmodel_snapshot",
"domain": "capability_transition",
"pi_star_ref": "pi_selfmodel_v1",
"parent_selfmodel": "P", "child_selfmodel": "C",
"target_capability": "TEST",
"parent_measured_value": 0.40,
"child_measured_value": 0.60,
"expected_improvement_min": 0.05,
"resource_budget": {
"max_compute_ms_delta": 0,
"max_storage_delta_bytes": 0,
},
"expected": "pass",
}) + "\n",
encoding="utf-8",
)
res = b_5f.run_finetuning(p)
assert res.pass_count == 1
assert res.metrics["adaptation_efficiency_infinite_count"] == 1.0
# The single task's detail should record the +inf efficiency.
from bench.batteries.b_5f import EFFICIENCY_INFINITE
assert res.per_task[0].detail["adaptation_efficiency"] == EFFICIENCY_INFINITE
# ---------------------------------------------------------------------
# Carrier rejection tests — runners fail unsupported carriers cleanly
# ---------------------------------------------------------------------
def _write_unsupported_fixture(path: Path, sub: str, battery: str = "5s") -> None:
"""Write a fixture with an unsupported carrier."""
path.write_text(
json.dumps({"_meta": {"battery": battery, "sub_battery": sub, "version": "v1"}}) + "\n" +
json.dumps({
"id": "test",
"carrier": "image", # not in Phase-1 whitelist
"domain": "scene_graph",
"pi_star_ref": "image-base@v1",
# the rest doesn't matter — runner rejects on carrier check
"input": "x",
"premises": [], "candidate_step": {"claim": "x", "uses": []},
"rule": "categorical_transitivity",
"expected": "pass",
}) + "\n",
encoding="utf-8",
)
def test_5s_syllogism_rejects_unsupported_carrier(tmp_path):
p = tmp_path / "bad.jsonl"
_write_unsupported_fixture(p, "syllogism")
res = b_5s.run_syllogism(p)
assert res.fail_count == 1
assert "unsupported_carrier" in res.per_task[0].detail["reason"]
def test_5t_transfer_learning_rejects_unsupported_carrier(tmp_path):
p = tmp_path / "bad.jsonl"
_write_unsupported_fixture(p, "transfer-learning", battery="5t")
res = b_5t.run_transfer_learning(p)
assert res.fail_count == 1
assert "unsupported_carrier" in res.per_task[0].detail["reason"]
def test_5f_function_rejects_unsupported_carrier(tmp_path):
p = tmp_path / "bad.jsonl"
_write_unsupported_fixture(p, "function", battery="5f")
res = b_5f.run_function(p)
assert res.fail_count == 1
assert "unsupported_carrier" in res.per_task[0].detail["reason"]
# ---------------------------------------------------------------------
# Runner CLI (existing test from Phase 1a)
# ---------------------------------------------------------------------
def test_runner_main_smoke(capsys):
from bench.batteries.runner import main
rc = main([
"--battery", "5s", "--sub", "syntax",
"--fixtures", str(F5S / "syntax-v1.jsonl"),
])
out = capsys.readouterr().out
payload = json.loads(out)
assert payload["schema_version"] == "bench-result-v1"
assert payload["results"][0]["battery"] == "5s"
assert rc == 0
def test_runner_all_runs_full_suite():
"""--all runs every battery in _DEFAULT_FIXTURES; rc=0 since all pass."""
from bench.batteries.runner import main
rc = main(["--all"])
assert rc == 0