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).
80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
"""EngineIdentity lineage — L11 Phase 2.
|
|
|
|
Every checkpoint manifest stamps the content-derived ``engine_identity`` the
|
|
engine was running under, plus the ``parent_engine_identity`` of the prior
|
|
checkpoint — a git-like lineage chain. With a stable ratified substrate the
|
|
identity is constant (identity == parent: one stable life); a ratified change
|
|
would make identity != parent (the bump). Across reboot the chain is continuous:
|
|
the resumed life's checkpoint descends from the pre-reboot identity.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from chat.runtime import ChatRuntime, get_git_revision
|
|
from core.cognition.pipeline import CognitiveTurnPipeline
|
|
from core.config import RuntimeConfig
|
|
from core.engine_identity import engine_identity_for_config
|
|
|
|
|
|
def _manifest(state_dir: Path) -> dict:
|
|
return json.loads((state_dir / "manifest.json").read_text(encoding="utf-8"))
|
|
|
|
|
|
def _drive(state_dir: Path, n: int, config: RuntimeConfig | None = None) -> ChatRuntime:
|
|
runtime = ChatRuntime(config=config or RuntimeConfig(), engine_state_path=state_dir)
|
|
pipe = CognitiveTurnPipeline(runtime=runtime)
|
|
for _ in range(n):
|
|
pipe.run("What causes light?")
|
|
return runtime
|
|
|
|
|
|
def test_manifest_stamps_content_derived_engine_identity(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
rt = _drive(state_dir, 1)
|
|
m = _manifest(state_dir)
|
|
assert m["engine_identity"] == rt._engine_identity
|
|
# It IS the content-derived identity of the ratified substrate.
|
|
assert m["engine_identity"] == engine_identity_for_config(
|
|
RuntimeConfig(), get_git_revision()
|
|
)
|
|
|
|
|
|
def test_lineage_is_stable_across_a_continuous_run(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
_drive(state_dir, 2) # 2 checkpoints
|
|
m = _manifest(state_dir)
|
|
# Stable substrate -> identity == parent (the life is one continuous identity).
|
|
assert m["engine_identity"] == m["parent_engine_identity"]
|
|
|
|
|
|
def test_lineage_is_continuous_across_reboot(tmp_path: Path) -> None:
|
|
state_dir = tmp_path / "es"
|
|
rt_a = _drive(state_dir, 2)
|
|
id_a = rt_a._engine_identity
|
|
|
|
# Reboot: a fresh runtime over the same checkpoint dir.
|
|
rt_b = ChatRuntime(config=RuntimeConfig(), engine_state_path=state_dir)
|
|
# The resumed life inherits the pre-reboot identity as its lineage parent.
|
|
assert rt_b._loaded_engine_identity == id_a
|
|
assert rt_b._engine_identity == id_a # same substrate -> same identity
|
|
|
|
pipe = CognitiveTurnPipeline(runtime=rt_b)
|
|
pipe.run("What is a concept?")
|
|
m = _manifest(state_dir)
|
|
assert m["parent_engine_identity"] == id_a # descends from the prior life
|
|
assert m["engine_identity"] == id_a
|
|
|
|
|
|
def test_different_identity_pack_is_a_different_identity(tmp_path: Path) -> None:
|
|
rt_default = ChatRuntime(
|
|
config=RuntimeConfig(), engine_state_path=tmp_path / "a", no_load_state=True
|
|
)
|
|
rt_precision = ChatRuntime(
|
|
config=RuntimeConfig(identity_pack="precision_first_v1"),
|
|
engine_state_path=tmp_path / "b",
|
|
no_load_state=True,
|
|
)
|
|
assert rt_default._engine_identity != rt_precision._engine_identity
|