Build evals/l10_continuity/, the empirical gate between the two L10 targets (T-resume: provable same-life resume; T-experience: continuous experiencing field-life). Drives the REAL turn loop (ChatRuntime + CognitiveTurnPipeline) over a deterministic in-vocab corpus, with reboot and orphan-crash legs, and evaluates falsifiable predicates over recorded evidence. Additive only; no existing file touched; read-only over the runtime; no serving-path import. Predicates (each with a *_holds real-soak test AND a *_bites mutation test, per the CLAUDE.md schema-as-proof discipline): - P1 closure: versor_condition < 1e-6 every turn (green guard). - P2a determinism: two independent runtimes -> byte-identical trace_hash. - P2b reboot transparency (the diagnostic): a reboot never alters pre-reboot turns (hard guard); post-reboot transparency is MEASURED and today FALSE -- the mechanical proof that Shape B (ADR-0146) discards the lived field/vault, i.e. "many lives sharing a checkpoint". A pinned test flips if persistence is ever added, forcing a doc update so the gap can't close silently. - P3 bounded resources: vault grows linear-bounded/monotonic (RSS recorded). - P4 crash recovery: two recoveries from one checkpoint converge (determinism) + commit-point/ARIES force boundary (recovered turn_count == committed) + atomic-write survives mid-os.replace kill (ADR-0156). - P5b anchor stability (T-experience crux): field anchors without COLLAPSE (dist_to_anchor not -> 0) or FREEZE (turn_movement not -> 0); the long-horizon test of the sanctioned _session_anchor_pull (alpha=0.05). Thresholds measured. - P5c coherence: surfaces stay non-empty and not collapsed to one output, over more than one corpus cycle. - P5a recall precision@k: recorded as not_covered (needs a held-out probe set). report.py assembles the panel into a structured report with a hardware-stable deterministic_digest (trace_hash sequence + verdicts; excludes RSS/wall-clock) as the freeze handle. Run: python -m evals.l10_continuity [n_turns] [reboot_turn]. 24 tests pass; adversarially reviewed across 4 lenses (bite-discipline, invariant/trust-boundary, honesty/determinism, correctness) before landing.
152 lines
5.3 KiB
Python
152 lines
5.3 KiB
Python
"""Assemble the L10 continuity panel into a structured, freeze-gateable report.
|
|
|
|
The panel runs the soaks the predicates need (an uninterrupted baseline, a
|
|
reboot leg, and two crash-recoveries), evaluates every predicate, and emits a
|
|
structured report with per-predicate PASS/FAIL, metrics, the explicitly
|
|
*not-covered* legs (no silent skips — CLAUDE.md), and a **deterministic digest**.
|
|
|
|
The digest is a SHA-256 over only the hardware-stable evidence: the canonical
|
|
``trace_hash`` sequence (``core.cognition.trace`` already rounds floats so the
|
|
hash is stable across hardware) and each predicate's ``(name, passed)`` verdict.
|
|
It deliberately EXCLUDES RSS, wall-clock, and raw float metrics, which are not
|
|
reproducible across machines. The digest is the freeze handle: pin it once the
|
|
lane is trusted and a regression flips it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from dataclasses import asdict, dataclass
|
|
from pathlib import Path
|
|
|
|
from core.config import RuntimeConfig
|
|
|
|
from evals.l10_continuity.predicates import (
|
|
PredicateOutcome,
|
|
evaluate_p1_closure,
|
|
evaluate_p2a_determinism,
|
|
evaluate_p2b_reboot_transparency,
|
|
evaluate_p3_bounded_resources,
|
|
evaluate_p4_commit_point,
|
|
evaluate_p4_recovery_determinism,
|
|
evaluate_p5b_anchor_stability,
|
|
evaluate_p5c_coherence,
|
|
)
|
|
from evals.l10_continuity.runner import (
|
|
SoakResult,
|
|
_inject_orphan_tmp,
|
|
read_recovered_turn_count,
|
|
run_soak,
|
|
)
|
|
|
|
# Legs the spec names but this lane does not yet cover, recorded explicitly so a
|
|
# PASS is never read as "everything was checked".
|
|
NOT_COVERED: tuple[tuple[str, str], ...] = (
|
|
(
|
|
"P5a_recall_stability",
|
|
"recall precision@k over a held-out probe set requires a probe set with "
|
|
"known-relevant entries and a metric grounded in the vault's scoring "
|
|
"semantics (the raw recall score is not a clean similarity); deferred.",
|
|
),
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class L10ContinuityReport:
|
|
n_turns: int
|
|
reboot_turn: int
|
|
predicates: tuple[PredicateOutcome, ...]
|
|
not_covered: tuple[tuple[str, str], ...]
|
|
deterministic_digest: str
|
|
|
|
def all_gates_pass(self) -> bool:
|
|
return all(p.passed for p in self.predicates)
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"n_turns": self.n_turns,
|
|
"reboot_turn": self.reboot_turn,
|
|
"all_gates_pass": self.all_gates_pass(),
|
|
"deterministic_digest": self.deterministic_digest,
|
|
"predicates": [asdict(p) for p in self.predicates],
|
|
"not_covered": [
|
|
{"leg": leg, "reason": reason} for leg, reason in self.not_covered
|
|
],
|
|
}
|
|
|
|
|
|
def deterministic_digest(
|
|
baseline: SoakResult, predicates: tuple[PredicateOutcome, ...]
|
|
) -> str:
|
|
"""SHA-256 over hardware-stable evidence: trace_hash sequence + verdicts."""
|
|
payload = {
|
|
"trace_hashes": list(baseline.trace_hashes()),
|
|
"verdicts": [[p.name, p.passed] for p in predicates],
|
|
"not_covered": [leg for leg, _ in NOT_COVERED],
|
|
}
|
|
serialized = json.dumps(payload, sort_keys=True, ensure_ascii=False)
|
|
return hashlib.sha256(serialized.encode("utf-8")).hexdigest()
|
|
|
|
|
|
def build_report(
|
|
*,
|
|
n_turns: int = 12,
|
|
reboot_turn: int = 3,
|
|
engine_state_root: Path,
|
|
config: RuntimeConfig | None = None,
|
|
) -> L10ContinuityReport:
|
|
"""Run the full panel and assemble the report.
|
|
|
|
Soaks: an uninterrupted ``baseline``; a second independent ``run_b`` (P2a);
|
|
a ``reboot`` leg (P2b); and two orphan-crash recoveries (P4).
|
|
"""
|
|
config = config or RuntimeConfig()
|
|
root = engine_state_root
|
|
|
|
baseline = run_soak(n_turns, engine_state_dir=root / "baseline", config=config)
|
|
run_b = run_soak(n_turns, engine_state_dir=root / "run_b", config=config)
|
|
reboot = run_soak(
|
|
n_turns, engine_state_dir=root / "reboot", reboot_at=(reboot_turn,), config=config
|
|
)
|
|
rec_a = run_soak(
|
|
n_turns,
|
|
engine_state_dir=root / "rec_a",
|
|
reboot_at=(reboot_turn,),
|
|
inject_orphan_tmp_at_reboot=True,
|
|
config=config,
|
|
)
|
|
rec_b = run_soak(
|
|
n_turns,
|
|
engine_state_dir=root / "rec_b",
|
|
reboot_at=(reboot_turn,),
|
|
inject_orphan_tmp_at_reboot=True,
|
|
config=config,
|
|
)
|
|
# Commit-point probe: run exactly ``reboot_turn`` turns, simulate the torn
|
|
# write, and read the recovered turn_count AT the crash boundary (not after
|
|
# the recovery continues and re-checkpoints).
|
|
probe_dir = root / "commit_probe"
|
|
run_soak(reboot_turn, engine_state_dir=probe_dir, config=config)
|
|
_inject_orphan_tmp(probe_dir)
|
|
recovered = read_recovered_turn_count(probe_dir)
|
|
|
|
p2b_outcome, _ = evaluate_p2b_reboot_transparency(reboot, baseline)
|
|
predicates: tuple[PredicateOutcome, ...] = (
|
|
evaluate_p1_closure(baseline),
|
|
evaluate_p2a_determinism(baseline, run_b),
|
|
p2b_outcome,
|
|
evaluate_p3_bounded_resources(baseline),
|
|
evaluate_p4_recovery_determinism(rec_a, rec_b),
|
|
evaluate_p4_commit_point(recovered, expected_turn_count=reboot_turn),
|
|
evaluate_p5b_anchor_stability(baseline),
|
|
evaluate_p5c_coherence(baseline),
|
|
)
|
|
digest = deterministic_digest(baseline, predicates)
|
|
return L10ContinuityReport(
|
|
n_turns=n_turns,
|
|
reboot_turn=reboot_turn,
|
|
predicates=predicates,
|
|
not_covered=NOT_COVERED,
|
|
deterministic_digest=digest,
|
|
)
|