core/tests/test_identity_continuity_proof.py
Shay f2dac1dc5c feat(identity): L11 identity continuity — same identity across reboot, not just same bytes
Builds the L11 lived-spine half on top of Shape B+ T-resume: prove the
continuous/resumed life is the SAME identity, with a content-derived, hash-chained
lineage and a falsifiable behavioral proof.

- core/engine_identity.py (L11-1): EngineIdentity = sha256 of the ratified
  PERSONALITY substrate (identity/safety/ethics/register/anchor-lens pack files)
  + code revision. Content-derived, NOT entropy — same substrate => same identity
  (cross-engine portable). The "who am I" hash; bumped by a ratified identity
  change, NOT by lived learning (that is experience, carried by Shape B+).
- engine_state + chat/runtime (L11-2): every checkpoint manifest stamps
  engine_identity + parent_engine_identity (git-like lineage). Stable substrate
  => identity == parent (one continuous life); a ratified change => the bump.
- chat/runtime + config (L11-3): on reboot, recompute identity and compare to the
  stamped one. Mismatch (substrate changed while down) surfaces a warning +
  identity_continuity_break flag; strict_identity_continuity (opt-in) refuses
  (IdentityContinuityError). Default warns — reboot is recovery, not control flow
  (ADR-0157); the operator must not be bricked by a benign ratified pack swap.
- tests (L11-4): the proof. Continuity is SUFFICIENT (byte-identical resume +
  no break under a fixed identity), identity is LOAD-BEARING (distinct packs =>
  distinct hashes), and the CONTRAPOSITIVE holds (resuming under a different
  identity raises the break). Same identity <=> continuous; different => break.

Test hygiene (required by L11's always-on identity stamping): conftest isolates
the default engine_state dir per test; the refusal-calibration cold-start probe
uses no_load_state=True. Both prevent cross-test identity-lineage pollution.

19 dedicated tests; curated smoke green (no spurious break warnings).
2026-06-05 13:52:57 -07:00

73 lines
3.2 KiB
Python

"""The identity-continuity PROOF — L11 Phase 4.
"Same identity, not just same bytes" is proven by composing three legs:
1. **Continuity (sufficient):** under a fixed identity, a rebooted resume-mode
run is BYTE-IDENTICAL to the uninterrupted run (Shape B+ P2b) AND the engine
identity is unchanged (no break). The resumed life behaves AND is-identified
as the same.
2. **Load-bearing (structural):** distinct identity packs are distinct engine
identities — identity is causal, not incidental. (The `identity_divergence`
lane separately proves distinct identities also *behave* differently.)
3. **Causal contrapositive (necessary):** resuming a checkpoint under a
DIFFERENT identity raises the continuity break — continuity holds iff the
identity is the same. Identity is necessary for continuity.
Legs 1 + 3 bracket it: same identity ⟹ continuous; different identity ⟹ break.
"""
from __future__ import annotations
from pathlib import Path
from chat.runtime import ChatRuntime
from core.cognition.pipeline import CognitiveTurnPipeline
from core.config import RuntimeConfig
from core.engine_identity import engine_identity_for_config
from engine_state import get_git_revision
from evals.l10_continuity.runner import run_soak
_PRECISION = RuntimeConfig(identity_pack="precision_first_v1")
def test_resumed_life_is_byte_identical_and_same_identity(tmp_path: Path) -> None:
# Leg 1: under a fixed (non-default) identity, reboot is fully transparent.
rebooted = run_soak(
6, engine_state_dir=tmp_path / "r", reboot_at=(3,), config=_PRECISION
)
baseline = run_soak(6, engine_state_dir=tmp_path / "b", config=_PRECISION)
assert rebooted.trace_hashes() == baseline.trace_hashes() # behavior continuous
# And the reboot carried the SAME identity (a fresh runtime over the dir
# finds no continuity break).
rt = ChatRuntime(config=_PRECISION, engine_state_path=tmp_path / "r")
assert rt.identity_continuity_break is False
def test_identity_is_load_bearing_distinct_packs_distinct_identity() -> None:
# Leg 2: three identity packs -> three distinct engine identities.
rev = get_git_revision()
default_id = engine_identity_for_config(RuntimeConfig(), rev)
precision_id = engine_identity_for_config(_PRECISION, rev)
generosity_id = engine_identity_for_config(
RuntimeConfig(identity_pack="generosity_first_v1"), rev
)
assert len({default_id, precision_id, generosity_id}) == 3
def test_continuity_breaks_under_a_different_identity(tmp_path: Path) -> None:
# Leg 3 (contrapositive): a life lived under one identity, resumed under
# another, raises the break — identity is NECESSARY for continuity.
state_dir = tmp_path / "es"
writer = ChatRuntime(config=_PRECISION, engine_state_path=state_dir)
pipe = CognitiveTurnPipeline(runtime=writer)
pipe.run("What causes light?")
pipe.run("What is a concept?")
import pytest
with pytest.warns(RuntimeWarning, match="identity continuity break"):
resumed = ChatRuntime(
config=RuntimeConfig(identity_pack="generosity_first_v1"),
engine_state_path=state_dir,
)
assert resumed.identity_continuity_break is True