core/evals/l10_continuity/contract.md
Shay 5ed9fbb8e7 feat(persistence): Shape B+ Phase D+E — opt-in lived-state persistence; reboot transparent
The load-bearing L10 milestone: with resume mode enabled, a reboot resumes the
SAME life. Wires SessionContext.snapshot/restore (Phases A-C) into the
engine-state checkpoint and flips the L10 spike's P2b oracle to transparent.

Persistence is OPT-IN (RuntimeConfig.persist_session_state, default False): it is
a deliberate always-on-runtime mode, and per-turn snapshotting has an O(turns)
cost, so demos / evals / one-shot runtimes do NOT pay for resume they don't use.
This keeps every existing ChatRuntime byte-for-byte unchanged (no perf tax, no
pinned-lane SHA drift, no test breakage); only the L10 continuity lane and the
production L10 process enable it.

Phase D (wiring):
- core/config.py: persist_session_state flag (default False).
- engine_state/__init__.py: bump _SCHEMA_VERSION 1->2; add save_session_state /
  load_session_state (atomic, ADR-0156). v1 checkpoints still load (1 <= 2) with
  no session_state -> fresh session.
- chat/runtime.py: when persist_session_state, checkpoint_engine_state saves the
  session snapshot BEFORE the manifest (manifest = the commit marker / WAL force
  boundary); _load_engine_state restores it into self._context.

Phase E (flip the oracle):
- evals/l10_continuity/runner.py: the continuity lane forces persist on (it IS
  the resume-mode lane).
- tests/test_l10_continuity.py: test_p2b_documents_current_resume_gap ->
  test_p2b_reboot_is_transparent (asserts post_reboot_transparent, divergence
  None). predicates.py / runner.py / contract.md: P2b is now the
  resume-as-same-life guard.
- tests/test_adr_0146_engine_state.py: manifest schema_version 1 -> 2.

Validation: full spike (P1 closure, P2a determinism, P2b NOW TRANSPARENT, P3
bounded, P4 crash-recovery determinism + commit point, P5b/P5c) +
reboot-restores-lived-state + v1 back-compat + ADR-0146, all green;
[run K -> reboot -> run M] byte-identical to [run K+M]. With persistence off
(default), the curated smoke + showcase budget + pinned lanes are unchanged.

Closes the A->E Shape B+ scope (docs/analysis/L10-shapeBplus-persistence-scope-2026-06-05.md).
2026-06-05 13:17:30 -07:00

5.2 KiB
Raw Blame History

L10 Continuity Lane — Contract

Status: spike (falsifiable experiment) · Parent: docs/analysis/L10-continuity-spike-design-2026-06-05.md · Not in default smoke (a soak; run on demand / nightly).

This lane drives the real turn loop (ChatRuntime + CognitiveTurnPipeline) over a deterministic, cyclic, in-vocabulary corpus for N turns, with optional reboot and orphan-crash legs, and evaluates falsifiable predicates over the recorded evidence. It is the empirical gate between the two L10 targets:

  • T-resume — provable same-life resume (determinism + recovery): P1P4.
  • T-experience — a continuous experiencing field-life (content stays meaningful over a long horizon): P5.

Run: PYTHONPATH=. .venv/bin/python -m evals.l10_continuity [n_turns] [reboot_turn]

Predicates

ID Proves Fails loudly when Mutation-verified bite
P1 closure versor_condition < 1e-6 every turn a construction breaks closure (no repair allowed) a record with versor_condition ≥ 1e-6 trips it
P2a determinism two independent runtimes → byte-identical trace_hash sequence the pipeline is nondeterministic a perturbed hash trips it
P2b reboot transparency a reboot never changes turns before the reboot point determinism/state leaks backward across reboot a pre-reboot hash divergence trips it
P3 bounded resources vault grows linear-bounded/monotonic per turn an unbounded cache/store leaks a 10k-entry vault record trips it
P4 recovery determinism two crash-recoveries from one checkpoint converge torn read / nondeterministic boot divergent recovery tails trip it
P4 commit point recovered turn_count == committed turns (ARIES force boundary) the checkpoint isn't the atomic commit boundary None/mismatched count trips it
P5b anchor stability field anchors without collapse (dist_to_anchor↛0) or freeze (turn_movement↛0) the field is swallowed by the attractor, or frozen collapsing distance / zero movement trips it
P5c coherence surfaces stay non-empty and not collapsed to one repeated output the field wanders into noise or freezes onto one output empty / single-surface records trip it

Each predicate has a *_holds test (real soak) and a *_bites test (mutation), per the CLAUDE.md schema-as-proof discipline: a predicate that cannot fail under the violation it nominally catches is decoration, not proof.

Not covered (no silent skips)

  • P5a — recall precision@k stability. Requires a held-out probe set with known-relevant entries and a metric grounded in the vault's actual scoring semantics (the raw recall score is not a clean similarity). Recorded as not_covered in the report; a follow-up increment.

The headline result (P2b) — resume-as-same-life

A reboot is now fully transparent: post_reboot_transparent == True, first_divergence is None. With Shape B+ persistence wired (SessionContext.snapshot/restore → engine_state schema v2), the lived field / vault / anchor / graph / referents / dialogue survive a reboot, so [run K → reboot → run M] is byte-identical to the uninterrupted [run K+M]. test_p2b_reboot_is_transparent is the load-bearing guard.

This flipped from the original Shape B (ADR-0146) behavior, where only recognizers / discovery candidates / turn_count survived and the lived field/vault were discarded — post_reboot_transparent == False, divergence at the first post-reboot turn ("many lives sharing a checkpoint"). The spike measured that gap, defined the persistence work, and now confirms it closed.

Thresholds (empirical basis, not arbitrary)

All gating thresholds are set from measured real-soak data and deliberately conservative — these are catastrophe gates (collapse / freeze / unbounded leak are yes/no failures of the T-experience claim), not early-warning trend detectors. Gradual-drift detection is a deliberate long-horizon follow-up; tightening toward the healthy band would risk false positives on a different corpus or longer horizon.

Threshold Measured healthy Default floor/ceiling Rationale
P5b dist_to_anchor ~4.06.2 (steady) collapse_floor=1.0 ~75%+ drop toward anchor = pathological collapse
P5b turn_movement median ~1.5 freeze_floor=0.05 ~1/30th of healthy = frozen field
P3 vault growth ~23 entries/turn vault_per_turn_ceiling=4 ~130200% of as-designed writes

P5b vs P5c division of labour: P5b catches the field freezing (movement→0) or collapsing onto the anchor (distance→0); P5c catches the output collapsing to a single repeated surface. The P5c real-soak test runs over more than one corpus cycle so the horizon exercises repetition (a 6-turn run == the cycle length would trivially yield 6 distinct surfaces and prove nothing).

Freeze handle

report.deterministic_digest is a SHA-256 over only hardware-stable evidence (the trace_hash sequence + each predicate's (name, passed) verdict), excluding RSS / wall-clock / raw floats. Pin it once the lane is trusted; a regression flips it.