core/tests/test_engine_identity.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

85 lines
3.3 KiB
Python

"""EngineIdentity — L11 Phase 1.
EngineIdentity is the content-derived sha256 of the engine's ratified personality
substrate (identity / safety / ethics / register / anchor-lens pack files) plus
the code revision. Content-derived, NOT entropy: same substrate -> same identity
(two engines with the same ratified packs ARE the same engine functionally).
This is the "who am I" hash the L11 lineage chain and reboot verification build on.
"""
from __future__ import annotations
import pytest
from core.config import DEFAULT_IDENTITY_PACK, RuntimeConfig
from core.engine_identity import (
RATIFIED_ROLES,
EngineIdentityError,
compute_engine_identity,
engine_identity_for_config,
ratified_substrate,
)
_DEFAULTS: dict[str, str] = {
"identity": "default_general_v1",
"safety": "core_safety_axes_v1",
"ethics": "default_general_ethics_v1",
"register": "default_neutral_v1",
"anchor_lens": "default_unanchored_v1",
}
def test_engine_identity_is_deterministic_and_content_derived() -> None:
a = compute_engine_identity(_DEFAULTS, git_revision="abc123")
b = compute_engine_identity(dict(_DEFAULTS), git_revision="abc123")
assert a == b # same substrate -> same identity (cross-engine portable)
assert len(a) == 64 # sha256 hex
def test_changing_identity_pack_changes_identity() -> None:
base = compute_engine_identity(_DEFAULTS, git_revision="abc123")
swapped = compute_engine_identity(
{**_DEFAULTS, "identity": "precision_first_v1"}, git_revision="abc123"
)
assert base != swapped # a different identity pack IS a different identity
def test_changing_code_revision_changes_identity() -> None:
a = compute_engine_identity(_DEFAULTS, git_revision="rev-a")
b = compute_engine_identity(_DEFAULTS, git_revision="rev-b")
assert a != b
def test_substrate_exposes_per_role_pack_content_hashes() -> None:
substrate = ratified_substrate(_DEFAULTS, git_revision="abc123")
assert set(RATIFIED_ROLES).issubset(substrate.keys())
assert substrate["code_revision"] == "abc123"
# Each role records its pack id + a 64-hex content hash of the pack file.
for role in RATIFIED_ROLES:
assert substrate[role]["pack_id"] == _DEFAULTS[role]
assert len(substrate[role]["sha256"]) == 64
# Distinct packs have distinct content hashes.
assert substrate["identity"]["sha256"] != substrate["safety"]["sha256"]
def test_missing_ratified_pack_raises() -> None:
with pytest.raises(EngineIdentityError):
compute_engine_identity(
{**_DEFAULTS, "identity": "no_such_pack_xyz"}, git_revision="abc123"
)
def test_engine_identity_for_config_resolves_defaults() -> None:
# An empty config resolves every role to its DEFAULT pack.
from_config = engine_identity_for_config(RuntimeConfig(), git_revision="abc123")
explicit = compute_engine_identity(_DEFAULTS, git_revision="abc123")
assert from_config == explicit
def test_engine_identity_for_config_honors_identity_override() -> None:
base = engine_identity_for_config(RuntimeConfig(), git_revision="abc123")
override = engine_identity_for_config(
RuntimeConfig(identity_pack="precision_first_v1"), git_revision="abc123"
)
assert base != override
assert DEFAULT_IDENTITY_PACK == "default_general_v1" # sanity on the default