The load-bearing L10 milestone: with resume mode enabled, a reboot resumes the
SAME life. Wires SessionContext.snapshot/restore (Phases A-C) into the
engine-state checkpoint and flips the L10 spike's P2b oracle to transparent.
Persistence is OPT-IN (RuntimeConfig.persist_session_state, default False): it is
a deliberate always-on-runtime mode, and per-turn snapshotting has an O(turns)
cost, so demos / evals / one-shot runtimes do NOT pay for resume they don't use.
This keeps every existing ChatRuntime byte-for-byte unchanged (no perf tax, no
pinned-lane SHA drift, no test breakage); only the L10 continuity lane and the
production L10 process enable it.
Phase D (wiring):
- core/config.py: persist_session_state flag (default False).
- engine_state/__init__.py: bump _SCHEMA_VERSION 1->2; add save_session_state /
load_session_state (atomic, ADR-0156). v1 checkpoints still load (1 <= 2) with
no session_state -> fresh session.
- chat/runtime.py: when persist_session_state, checkpoint_engine_state saves the
session snapshot BEFORE the manifest (manifest = the commit marker / WAL force
boundary); _load_engine_state restores it into self._context.
Phase E (flip the oracle):
- evals/l10_continuity/runner.py: the continuity lane forces persist on (it IS
the resume-mode lane).
- tests/test_l10_continuity.py: test_p2b_documents_current_resume_gap ->
test_p2b_reboot_is_transparent (asserts post_reboot_transparent, divergence
None). predicates.py / runner.py / contract.md: P2b is now the
resume-as-same-life guard.
- tests/test_adr_0146_engine_state.py: manifest schema_version 1 -> 2.
Validation: full spike (P1 closure, P2a determinism, P2b NOW TRANSPARENT, P3
bounded, P4 crash-recovery determinism + commit point, P5b/P5c) +
reboot-restores-lived-state + v1 back-compat + ADR-0146, all green;
[run K -> reboot -> run M] byte-identical to [run K+M]. With persistence off
(default), the curated smoke + showcase budget + pinned lanes are unchanged.
Closes the A->E Shape B+ scope (docs/analysis/L10-shapeBplus-persistence-scope-2026-06-05.md).
Versioned additive-optional migration (L10 scoping step-2 ruling): a checkpoint
schema bump is a recorded lineage transition, not death-and-rebirth.
- engine_state.load_manifest() now REFUSES (IncompatibleEngineStateError) a
checkpoint whose schema_version > this build's _SCHEMA_VERSION, and tolerates
<= current (older/equal read any missing newer fields via additive-optional
defaults). Never silently mis-loads newer state.
- chat.runtime._load_engine_state() loads the manifest FIRST so the version
refusal gates before any recognizers/candidates are read.
- DerivedRecognizer.from_json documents the additive-optional convention
(new fields .get-defaulted + omitted-when-default), mirroring DiscoveryCandidate.
Tests (TDD): refuses newer schema_version; tolerates older. Prerequisite for the
L10 continuity spike's P2 byte-identity gate (it may now assume a fixed schema
within a run, with version bumps handled explicitly).
* feat(W-024): reboot_event audit trail entry (L10b.3, ADR-0158)
L10 scope §Sub-question 3: a reboot_event analog of TurnEvent, written
to the telemetry JSONL, lets future audit reconstruct when this engine
instance lost and regained its lifetime.
- serialize_reboot_event / format_reboot_event_jsonl in chat/telemetry.py
emit type="reboot" with restored_turn_count, stored/current revisions,
revision_matched, recognizers_count, candidates_count
- ChatRuntime._load_engine_state() buffers the JSONL line in
_pending_reboot_payload (str|None); ChatRuntime.attach_telemetry_sink()
flushes it exactly once when a sink is first attached
- Reboot event precedes all turn events in the session audit stream
- Pinned by 11 tests: serializer structure, determinism, revision_matched
logic, runtime integration (emit-once, no-checkpoint, no-load-state,
revision match, ordering)
Closes L10b: W-022 (atomic writes) + W-023 (revision warning) + W-024
together satisfy ADR-0146's atomic/observable/auditable checkpoint triad.
* fix(W-024): expose cached public git revision helper
* feat(W-022): ratify-proposal workflow_dispatch for mobile ratification
Adds .github/workflows/ratify-proposal.yml — a manually triggered
workflow that lets the operator ratify engine-authored proposals from
the GitHub mobile app without needing terminal access.
Inputs: proposal_id (required), review_date (default: today UTC),
operator_note (optional). Runs `core teaching review --accept`,
commits the updated corpus + proposal log to main, and posts a
job summary with the accepted chain_id.
Shared CONTEMPLATION_ENABLED kill switch disables the entire
learning-arc loop (contemplation + ratification) with one toggle.
ADR-0155 / ADR-0057
* feat(W-023): revision-mismatch warning on engine-state load (L10b.2, ADR-0157)
ADR-0146 §Risks line 127 specified that load_manifest() should compare
written_at_revision against the current git SHA and warn if they differ,
but never refuse to load (reboot is recovery, not control flow).
- EngineStateStore.load_manifest() emits RuntimeWarning when stored and
current revisions are both known and do not match
- Suppresses warning when either side is "unknown" (offline/packaged builds)
- Always returns the manifest; no state is cleared or rejected
- Pinned by 8 tests covering match, mismatch, unknown suppression, and
missing/empty manifest edge cases
ADR-0156 §Out of scope closes; L10b.3 (reboot_event audit entry, W-024) remains.