Removes code_revision from the engine-identity hash: engine_identity is now the
sha256 of the 5 ratified packs ONLY. The build revision is provenance (the
manifest's written_at_revision), not identity — so a behavior-neutral rebuild is
the SAME identity and the always-on daemon no longer flag-day strict-breaks on
every commit (the ADR-0220 defect).
Core:
- core/engine_identity.py: ratified_substrate/compute_engine_identity drop the
git_revision arg (packs-only); add compute_legacy_engine_identity (reproduces
the pre-split packs+rev hash, for migration verification), ENGINE_IDENTITY_SCHEME=2,
IdentityReconciliation enum, and reconcile_loaded_identity — the single source of
truth for the runtime guard AND the workbench reader.
- chat/runtime.py: the load guard reconciles via scheme. Current scheme -> direct
packs-only compare. Legacy (code_revision-folded) stamp -> a VERIFYING migration:
reconstruct the legacy hash from the persisted written_at_revision; a match proves
packs unchanged (warn + re-stamp, resume, no break) — a mismatch means the packs
genuinely changed (DIVERGED -> strict-refuse). Preserves 'distinct packs => refuse'.
- engine_state/save_manifest: stamp identity_scheme alongside engine_identity
(additive-optional; no schema_version bump).
- workbench/readers.py: continuity reader uses the same reconcile (no phantom break
on legacy checkpoints). cli.py break message reworded (packs, not 'build revision').
Callsite cleanup: drop the now-unused git_revision arg + imports across
always_on.py, evals/l10_always_on/runner.py, workbench/readers.py.
Tests:
- test_identity_provenance_split.py (new): 5 reconcile unit proofs + 3 runtime
integration proofs incl. the wrong=identity defense (legacy stamp of DIFFERENT
packs still strict-refuses) and the re-stamp migration.
- test_engine_identity.py: invert the code-revision test (rev no longer changes
identity); assert the substrate is packs-only.
- Restore 3 lineage tests silently red since ADR-0219 (flat-path _manifest helper
now resolves the gen-dir).
- Update remaining callsites/monkeypatches for the new signature.
Hygiene: .gitignore now covers the ADR-0219 gen-dir runtime files
(current, gen-*/, session_state.json, proposals.jsonl).
Verified: 59 identity/migration/lineage/workbench + 32 L10 + 76 invariants/cli +
34 smoke pass; serving lane SHAs unchanged (no derivation/reliability_gate touch).
The always-on PROCESS shipped (run_continuous + daemon + CLI), but the claim "it holds
over uptime" was UNFALSIFIED: the existing evals/l10_continuity soak drives the TURN loop
and is disjoint from run_continuous; the daemon path was covered only by ≤5-beat unit
tests. This lane converts "built" → "proven over horizon" for the idle path.
evals/l10_always_on/ mirrors the l10_continuity predicate/mutation harness but drives the
IDLE heartbeat: it seeds a real continuous life (held self + a cognitive turn to excite the
field), runs N beats with NO user turn, and gates four falsifiable predicates, each with a
*_holds (real soak) AND a *_bites (mutation) test per CLAUDE.md schema-as-proof:
- H1 closure — every observed idle beat versor_condition < 1e-6 (held over uptime, READ
never repaired); bites on a breached beat AND on a vacuous no-field soak.
- H2 bounded idle — a no-work beat adds NOTHING to the vault (no idle leak — invisible at
5 beats, fatal at 100k); bites on idle vault growth.
- H3 convergence — a saturated idle life SETTLES and stays settled (no re-awakening), at
rest at the end, closure intact on the tail; bites on never-settling + on re-awakening.
- H4 reboot resume — a reboot mid-soak resumes the SAME life (strict identity guard passes,
pre-reboot DERIVED learning survives, post-reboot closure holds); bites on failed
resume + on lost learning.
Measured (5000 idle beats, reboot@2500, ~20s): ALL gates pass — versor_condition flat at
1.389e-07 (no drift, no repair), vault bounded at 6 (no idle leak), converged at beat 1
with a 4999-beat at-rest tail, reboot resumed the same life with learning intact. This is
the empirical resolution of the L10 riskiest-unknown FOR THE IDLE PATH (the closure-by-
construction ruling covered the field-transition walk; this covers indefinite idle uptime).
Honestly NOT covered (recorded in the report, no silent skip): the continuously-LEARNING
life's resource cost under a sustained new-fact stream (O(n²) snapshot; per-run lived_life)
— out of scope until an afferent/intake feed + incremental persistence exist (the next
frontier).
Run on demand: PYTHONPATH=. python -m evals.l10_always_on [n_beats] [reboot_beat]. Path-
scoped out of CI smoke (like l10_continuity); runs in post-merge full-pytest. Additive — a
new eval lane, no existing files touched. 12/12 lane tests + architectural invariants green.