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).
75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
"""Reboot identity verification — L11 Phase 3.
|
|
|
|
On reboot the engine recomputes its identity from the current ratified substrate
|
|
and compares it to the identity stamped in the checkpoint. A match = continuous
|
|
identity. A mismatch = the substrate changed while the engine was down (a pack
|
|
mutated), so resuming would carry the lived state into a DIFFERENT identity —
|
|
surfaced (warn + ``identity_continuity_break`` flag) by default, refused under
|
|
``strict_identity_continuity``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from chat.runtime import ChatRuntime
|
|
from core.cognition.pipeline import CognitiveTurnPipeline
|
|
from core.config import RuntimeConfig
|
|
from core.engine_identity import IdentityContinuityError
|
|
|
|
|
|
def _drive(state_dir: Path, n: int = 2, config: RuntimeConfig | None = None) -> None:
|
|
runtime = ChatRuntime(config=config or RuntimeConfig(), engine_state_path=state_dir)
|
|
pipe = CognitiveTurnPipeline(runtime=runtime)
|
|
for _ in range(n):
|
|
pipe.run("What causes light?")
|
|
|
|
|
|
def test_same_substrate_reboot_has_no_break(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
_drive(state_dir)
|
|
rt = ChatRuntime(config=RuntimeConfig(), engine_state_path=state_dir)
|
|
assert rt.identity_continuity_break is False
|
|
|
|
|
|
def test_substrate_change_during_downtime_surfaces_break(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
_drive(state_dir) # stamps the default identity
|
|
# Boot under a different identity pack over the same checkpoint dir.
|
|
with pytest.warns(RuntimeWarning, match="identity continuity break"):
|
|
rt = ChatRuntime(
|
|
config=RuntimeConfig(identity_pack="precision_first_v1"),
|
|
engine_state_path=state_dir,
|
|
)
|
|
assert rt.identity_continuity_break is True
|
|
|
|
|
|
def test_strict_mode_refuses_on_identity_mismatch(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
_drive(state_dir)
|
|
with pytest.raises(IdentityContinuityError):
|
|
ChatRuntime(
|
|
config=RuntimeConfig(
|
|
identity_pack="precision_first_v1", strict_identity_continuity=True
|
|
),
|
|
engine_state_path=state_dir,
|
|
)
|
|
|
|
|
|
def test_strict_mode_allows_matching_identity(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
_drive(state_dir)
|
|
# Same substrate + strict mode -> boots cleanly, no break.
|
|
rt = ChatRuntime(
|
|
config=RuntimeConfig(strict_identity_continuity=True),
|
|
engine_state_path=state_dir,
|
|
)
|
|
assert rt.identity_continuity_break is False
|
|
|
|
|
|
def test_genesis_runtime_has_no_break(tmp_path: Path) -> None:
|
|
# No checkpoint to compare against -> no break.
|
|
rt = ChatRuntime(config=RuntimeConfig(), engine_state_path=tmp_path / "fresh")
|
|
assert rt.identity_continuity_break is False
|