arborist/tests/test_bench_batteries.py
russell@unturf.com 9899a33b7b
#000048 step 2.1 — verify_quotes entity salient-token-disagreement gate
Closes the 4 HYBRID_ENTITY over-grounds #000046 left in
falsification-hard-v1.jsonl. The entity strategy grants HYBRID when a
multi-word proper noun matches the source — but "Insulin was
discovered by Alexander Fleming" against "Penicillin was discovered by
Alexander Fleming" matches on the shared "Alexander Fleming" while the
swapped subject "Insulin" (the falsehood) is ignored.

arborist/qa/verify.py: _entity_salient_disagrees(answer_text, norm_ctx)
flags a >4-char Capitalized content token (stopword-filtered) or a
digit-number in the answer absent from the source.
_is_single_sentence(text) — no internal '. '/'! '/'? ' break. Gated in
verify_quotes' entity branch (proximity policy) in the weakest-grounding
slot only: not cluster AND len(verified) <= 1 AND _is_single_sentence
AND _entity_salient_disagrees → UNGROUNDED. The narrow caller-gate is
what keeps a structured multi-claim summary untouched — the Matrix cast
list (many entities, a tight cluster) and the TMNT answer (a numbered
list with parenthetical nicknames the source omits): model-added
accurate detail in a real summary isn't a contradiction, only the
single-sentence-one-weak-match shape is. The Matrix/TMNT/hybrid
entity-path regression tests still pass, pinned untouched.

Effect: falsification-hard rate 6/12 → 10/12 = 0.833 (Insulin / Berlin
/ 1889 / Pacific now correctly UNGROUNDED). The 2 live-pack fixtures it
newly demotes — 5f-fal-live-003 (the exact gap #000046 built its hard
pack around) and 5f-fal-live-028 — had expected_reason updated
HYBRID_ENTITY → UNGROUNDED (the live pack records what verify_quotes
actually does). Remaining hard-pack headroom: 2 STRICT_PARAPHRASE
recombinations (Mercury, Einstein — step 2.2) + 8 Formulate
mis-segments (step 2.4).

Bench gate: make bench-qa (n=3 × 75 × 3 = 675 cells) after
(bench/qa_results/2026-05-11T17-12-41Z) vs the pre-step-2.1 baseline
(...T14-19-51Z = HEAD's verify.py). STRICT-rate quote 0.50→0.54,
pointer 0.25→0.22, lattice 0.45→0.43 — all within the 5-pp noise
floor. Per-row diff (675 common cells, 30 quote-mode rows changed
audit_mode): 0 quote-mode rows demoted to UNGROUNDED from the entity
path — the gate fired on 0 legitimate QA answers in the whole bench.
Every transition was LLM re-answer variance (verifier quote→quote with
the verdict flipping); pointer/lattice deltas are noise too (the gate
is in verify_quotes / quote mode, not the claim-lattice verifier). No
regression — the gate is provably narrow on real traffic. Summarized in
qa-modes-bench.md Addendum 6 + ticket-000048 §5 step 2.1.

Tests: 4 new in test_verify.py (_is_single_sentence helper,
_entity_salient_disagrees helper, swapped-subject → UNGROUNDED,
gate-narrow-on-multi-claim); test_5f_falsification_hard_pack_below_ceiling
re-pinned 6/12 → 10/12; test_fork_score_positive_gamma_5f_... updated
(positive γ·Δ5f on the real lift — possibly MARGINAL given the ÷5
dilution; ACCEPT via a degraded-parent sub-scenario).
make test 2343 passed, 28 skipped.

#000048 → step 2.1 landed; #000046 / #000012 §8 / TICKETS.md /
Makefile / fixture _meta + notes / baseline JSON updated.
2026-05-11 13:57:45 -04:00

1184 lines
44 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""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"
# Phase 1c (2026-05-09) — fixture catalog expanded 10 → 30.
assert res.pass_count == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 62 # Phase 1e: +12 fixtures covering uncovered motifs
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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 + Phase 1c expansion. Backward
compat invariant."""
res = b_5f.run_formulate(F5F / "formulate-v1.jsonl")
assert res.pass_count == 50 # Phase 1d — expanded 10 → 30
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 == 50 # Phase 1d
# 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 == 50 # Phase 1d
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 §10.13 — feedback latency / real-workload efficiency --------
def test_5f_persisted_cost_helper():
"""_persisted_cost = audit-row count + body bytes / 1e6 (the real
footprint a live chain wrote, not the count of requested ops)."""
from bench.batteries.b_5f import _persisted_cost
assert _persisted_cost({}) == 0.0
state = {
"audit_event_types": ["a", "b", "c"],
"audit_event_bodies": ['{"x":1}', '{"y":2}', ""], # 7 + 7 + 0 bytes
}
assert _persisted_cost(state) == pytest.approx(3.0 + 14 / 1e6)
def test_5f_feedback_loop_embedded_reports_no_latency():
res = b_5f.run_feedback_loop(F5F / "feedback-loop-v1.jsonl")
assert res.metrics["feedback_latency_mean_seconds"] == 0.0
assert res.metrics["feedback_live_task_count"] == 0.0
for t in res.per_task:
assert t.detail.get("feedback_latency_seconds") is None
# Embedded cost-proxy stays len(chain) → integer-ratio efficiency.
assert "persisted_cost" not in t.detail
def test_5f_feedback_loop_live_reports_latency_and_persisted_cost():
res = b_5f.run_feedback_loop(F5F / "feedback-loop-live-v1.jsonl")
assert res.metrics["feedback_live_task_count"] == 50.0 # Phase 1d
assert res.metrics["feedback_latency_mean_seconds"] > 0.0
for t in res.per_task:
if not t.passed:
continue
lat = t.detail["feedback_latency_seconds"]
assert isinstance(lat, float) and lat >= 0.0
# Real footprint: every live chain has >= 1 append_audit op.
assert t.detail["persisted_audit_rows"] >= 1
assert t.detail["persisted_cost"] >= 1.0
# feedback_efficiency now = downstream_effect / persisted_cost,
# not / len(chain). downstream_effect is 1.0 when the chain
# integrated, else 0.0 (an expected-"fail" task still passes).
if t.detail["integrated"]:
assert t.detail["feedback_efficiency"] == pytest.approx(
1.0 / t.detail["persisted_cost"]
)
else:
assert t.detail["feedback_efficiency"] == 0.0
# --- 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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 50 # Phase 1d
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 == 62 # Phase 1e: +12 fixtures covering uncovered motifs
for t in res.per_task:
assert t.detail["source"] == "embedded"
# --- #000046 Phase 2 — HARD live-path Formulate tier --------------
def test_5f_formulate_hard_pack_below_ceiling():
"""Below-ceiling baseline for the Formulate sub-battery: 12 inputs
that parse_pointer_claims should segment a particular way; the
line/bullet-based parser mis-segments 8 of 12 (merges multi-claim
lines, splits wrapped bullets) → rate 4/12. parse_pointer_claims
is deterministic, so this is stable; the pinned value fires if it
shifts."""
res = b_5f.run_formulate(F5F / "formulate-hard-v1.jsonl")
assert res.pass_count == 4
assert res.fail_count == 8
assert res.metrics["structural_match_rate"] == pytest.approx(4 / 12)
for t in res.per_task:
assert t.detail["source"] == "live"
# The 8 that fail do so on claim-count mismatch (the parser put
# multiple claims on one line, or split one across lines) — that's
# the mis-segmentation, not a noisy pointer/text near-miss.
for t in res.per_task:
if not t.passed:
assert t.detail["count_ok"] is False
# --- #000046 Phase 1 — HARD live-path Falsification tier ----------
def test_5f_falsification_hard_pack_below_ceiling():
"""The hard pack is a deliberate below-ceiling baseline: 12
near-misses whose correct verdict is UNGROUNDED. As of #000048
step 2.1 (2026-05-11): #000046's paraphrase numeric-agreement gate
catches the 2 magnitude/year over-grounds (50-vs-100,
300-vs-300,000) + #000048's entity salient-token gate catches the
4 HYBRID_ENTITY over-grounds (Insulin/Berlin/1889/Pacific) → 10/12
pass; the remaining 2 are recombination STRICT_PARAPHRASE (hard-003
Mercury, hard-005 Einstein — the false claim recombines source
tokens; lexical token-coverage can't tell recombination from
grounding), headroom for #000048 step 2.2. verify_quotes is
deterministic, so this is stable; if it shifts, the pinned value
here fires (loud signal — either the verifier got better/worse, or
the pack drifted)."""
res = b_5f.run_falsification(F5F / "falsification-hard-v1.jsonl")
assert res.pass_count == 10
assert res.fail_count == 2
assert res.metrics["error_detection_rate"] == pytest.approx(10 / 12)
# All tasks route the live verifier; every fixture asserts UNGROUNDED.
for t in res.per_task:
assert t.detail["source"] == "live"
assert t.detail["expected_reason"] == "UNGROUNDED"
# The 2 that fail do so by over-grounding (STRICT_/HYBRID_), never
# by the verifier saying UNGROUNDED — real over-ground misses, not
# "the verifier abstained".
for t in res.per_task:
if not t.passed:
obs = set(t.detail["observed_violations"])
assert "UNGROUNDED" not in obs
assert any(o.startswith(("STRICT_", "HYBRID_")) for o in obs)
def test_fork_score_positive_gamma_5f_on_hard_falsification_improvement():
"""Worked example for #000046/#000048 — the loop: a real verifier
improvement that lifts the falsification-hard rate produces a
*positive* γ·Δ5f term in fork_score. Whether it clears SIGNAL_FLOOR
(→ ACCEPT) or not (→ MARGINAL) depends on the magnitude and the
÷5 averaging dilution (#000047) — a small single-sub lift is
positive-but-MARGINAL by design; a big-enough one ACCEPTs. Both
shown here. The point: the bench Δ-rate carries signal it can't
carry while every pack is at ceiling."""
from arborist.substrate.fork_score import fork_score
hard_rate = b_5f.run_falsification(
F5F / "falsification-hard-v1.jsonl"
).metrics["error_detection_rate"]
assert hard_rate < 1.0
# (a) A real lift from the current hard-pack rate to 1.0 — positive,
# possibly MARGINAL (the ÷5 dilution of a single-sub gain).
parent_a = {"5s": {}, "5t": {}, "5f": {"falsification": {"error_detection_rate": hard_rate}}}
child_a = {"5s": {}, "5t": {}, "5f": {"falsification": {"error_detection_rate": 1.0}}}
sf_a = fork_score(parent_a, child_a)
assert sf_a.breakdown["gamma_x_delta_5f"] > 0.0
assert sf_a.breakdown["gamma_x_delta_5f"] == pytest.approx((1.0 - hard_rate) / 5)
assert sf_a.verdict in ("ACCEPT", "MARGINAL")
assert not any(f.startswith(("REGRESSION_", "NEG_INF_")) for f in sf_a.flags)
# (b) A bigger lift (degraded parent at 0.5 → child 1.0) clears the
# floor: Δ5f = 0.5/5 = 0.1 ≥ SIGNAL_FLOOR → ACCEPT.
parent_b = {"5s": {}, "5t": {}, "5f": {"falsification": {"error_detection_rate": 0.5}}}
child_b = {"5s": {}, "5t": {}, "5f": {"falsification": {"error_detection_rate": 1.0}}}
sf_b = fork_score(parent_b, child_b)
assert sf_b.breakdown["gamma_x_delta_5f"] == pytest.approx(0.5 / 5)
assert sf_b.verdict == "ACCEPT"
assert not any(f.startswith(("REGRESSION_", "NEG_INF_")) for f in sf_b.flags)
def test_5f_falsification_covers_every_documented_motif():
"""#000025 §10.12: Falsification fixtures must cover every documented
failure-motif tag. Pins motif-coverage of the falsification-v1.jsonl
fixture pack against the verifier's `violations.append` registry +
the soft-demote registry in arborist.cli."""
import json
fixture_path = F5F / "falsification-v1.jsonl"
covered: set[str] = set()
with fixture_path.open() as f:
for line in f:
d = json.loads(line)
if "expected_reason" in d:
covered.add(d["expected_reason"])
documented = {
# Hard violations emitted by arborist/qa/verify.py
"CITATION_MISMATCH",
"DEFLECTION_DETECTED",
"FORMAT_COLLAPSED",
"MANUAL_QUOTE_VIOLATION",
"NO_EVIDENCE_POINTER",
"POINTER_OVERFLOW_TRIMMED",
"SCHEMA_INVALID",
"SOURCE_ROLE_BLOCKED",
"SUBJECT_TOKENS_ABSENT",
"TITLE_MISMATCH",
"TOO_MANY_CLAIMS",
"TOO_MANY_EVIDENCE_IDS",
"UNKNOWN_EVIDENCE_ID",
"WARRANT_MISSING",
# Soft-demote violations registered in arborist/cli.py
"LAZY_ANCHOR_DEMOTED",
"BARE_NAME_CLAIM",
"BROAD_QUANTIFIER_RUNAWAY",
"BROAD_QUANTIFIER_CAP_APPLIED",
"BROAD_QUANTIFIER_SCOPE_UNBOUND",
"BROAD_QUANTIFIER_REJECTED",
}
missing = documented - covered
assert not missing, (
f"falsification-v1.jsonl missing {len(missing)} motif tag(s): "
f"{sorted(missing)}. Add a fixture with `expected_reason` set to "
"each, or remove from the documented registry if intentionally "
"retired."
)
def test_5f_falsification_harvested_pack_runs_clean():
"""#000037 Phase 1 → 5F loop: the harvested pack at
falsification-harvested-v1.jsonl was generated by
bench/scripts/harvest_falsification_proposals.py from real qa.db
high-divergence rows. Pin: pack runs at 100% pass-rate, all
fixtures route through the embedded runner path, every fixture
carries the harvest-attribution metadata."""
import json
fixture_path = F5F / "falsification-harvested-v1.jsonl"
res = b_5f.run_falsification(fixture_path)
assert res.fail_count == 0
assert res.metrics["error_detection_rate"] == 1.0
# Every fixture must carry the harvest metadata so future
# regenerations are traceable to the source providence_cache
# row.
with fixture_path.open() as f:
next(f) # _meta header
for line in f:
row = json.loads(line)
meta = row.get("_harvest_meta", {})
assert meta.get("source_ticket") == "#000037 §13 step 11"
# Two harvest sources now: providence_cache directly
# (Phase 1 buckets) and controller_events stream (live
# Phase 2 advisory writes).
assert meta.get("harvested_from") in (
"providence_cache",
"controller_events",
)
assert isinstance(meta.get("witness_divergence"), (int, float))
assert meta["witness_divergence"] >= 0.5
assert meta.get("audit_mode_at_harvest") in ("HYBRID", "UNGROUNDED")
def test_5f_falsification_harvested_pack_widens_motif_coverage():
"""The harvested pack introduces real-corpus motif tags that the
hand-curated falsification-v1.jsonl doesn't have. Pin: the
HYBRID_QUOTE + HYBRID_CLAIM_LATTICE pair appear in the harvested
pack — concrete evidence that the harvest is doing widening
work, not just duplicating the curated set."""
import json
fixture_path = F5F / "falsification-harvested-v1.jsonl"
motifs: set[str] = set()
with fixture_path.open() as f:
for line in f:
d = json.loads(line)
if "expected_reason" in d:
motifs.add(d["expected_reason"])
# Harvest contains HYBRID variants surfaced from corpus that the
# hand-curated set lacks. If the harvested DB drifts and these
# motifs disappear, the test loud-fails — by then the harvest
# rotation has lost signal and the pack should be regenerated.
assert "HYBRID_QUOTE" in motifs or "HYBRID_CLAIM_LATTICE" in motifs
assert "UNGROUNDED" in motifs
def test_harvest_includes_controller_events_bucket(tmp_path):
"""The harvester pulls a third bucket from the live
controller_events stream (event_kind =
controller_falsification_proposal) in addition to the two
providence_cache buckets. Builds a synthetic qa.db with both
sources and asserts the controller_events-derived fixture appears
with the right provenance."""
import sqlite3 as _sqlite3
from bench.scripts.harvest_falsification_proposals import harvest
qa_db = tmp_path / "qa.db"
conn = _sqlite3.connect(qa_db)
conn.row_factory = _sqlite3.Row
# Minimal providence_cache schema for the harvest path.
conn.executescript(
"CREATE TABLE providence_cache ("
" cache_key TEXT PRIMARY KEY, audit_mode TEXT, n_quotes INTEGER,"
" n_verified INTEGER, unverified_quotes TEXT, verifier_method TEXT,"
" falsification_state TEXT, answer_text TEXT);"
"CREATE TABLE controller_events ("
" event_id INTEGER PRIMARY KEY AUTOINCREMENT,"
" organism_root TEXT NOT NULL, branch_id TEXT, event_kind TEXT NOT NULL,"
" label TEXT, entropy REAL, difficulty REAL, allocation REAL,"
" body_blob TEXT NOT NULL, body_hash TEXT NOT NULL,"
" recorded_at INTEGER NOT NULL,"
" UNIQUE (event_kind, body_hash));"
)
# Providence row whose cache_key matches a future
# controller_events branch_id prefix. Divergence < 0.5 so the row
# is INVISIBLE to the providence buckets — it surfaces ONLY via the
# controller_events stream.
conn.execute(
"INSERT INTO providence_cache VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
(
"ce-only-cache-key-12345678abcdef",
"HYBRID",
10, 9,
json.dumps(["one quote"]), # 1/10 = 0.1 < threshold
"claim_lattice",
"live",
"Synthetic answer text from a controller-events row.",
),
)
# Matching controller_falsification_proposal row. Divergence here
# is the high signal that surfaced the proposal at controller-decide
# time (sweep mode would commonly push such rows).
conn.execute(
"INSERT INTO controller_events VALUES "
"(NULL, ?, ?, ?, ?, NULL, NULL, NULL, ?, ?, ?)",
(
"qa:ce-only-cache-key-12345678abcdef",
"qa:ce-only-cache-key", # 16-char prefix of the cache_key
"controller_falsification_proposal",
"WITNESS_DIVERGENCE_EXCEEDS_THRESHOLD",
json.dumps({
"kind": "controller_falsification_proposal",
"organism_root": "qa:ce-only-cache-key-12345678abcdef",
"branch_id": "qa:ce-only-cache-key",
"witness_divergence": 0.8,
"reason": "WITNESS_DIVERGENCE_EXCEEDS_THRESHOLD",
}),
"deadbeef" * 8, # placeholder body_hash for the test
1700000000,
),
)
conn.commit()
conn.close()
fixtures = harvest(qa_db, threshold=0.5, sample_per_bucket=20)
ce_fixtures = [
fx for fx in fixtures
if fx["_harvest_meta"]["harvested_from"] == "controller_events"
]
assert len(ce_fixtures) == 1
fx = ce_fixtures[0]
assert fx["_harvest_meta"]["controller_organism_root"].startswith("qa:")
assert fx["_harvest_meta"]["witness_divergence"] == 0.8
assert fx["id"] == "5f-fal-harvested-ce-only-cache-ke"
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