* 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.
2.9 KiB
ADR-0157 — Revision-mismatch warning on engine-state load (W-023 / L10b.2)
Status: accepted Date: 2026-05-26
Context
ADR-0146 §Risks line 127 specified:
"Compare
written_at_revisioninmanifest.jsonwith the current git SHA. If they mismatch, log a warning but continue startup (do not refuse to start, as a reboot is recovery, not control flow)."
W-008 and W-022 implemented the manifest write path but never implemented
the read-side comparison. After a git pull or a branch switch the engine
silently loads a checkpoint written by a different code version, which can
produce confusing behaviour if serialization formats changed.
Decision
Inside EngineStateStore.load_manifest(), after parsing the JSON:
- Read
manifest["written_at_revision"](stored revision). - Call
_git_revision()to obtain the current HEAD short SHA. - If both values are non-empty and not
"unknown", and they differ, emitwarnings.warn(..., RuntimeWarning, stacklevel=2). - Always return the manifest — never raise, never clear state.
The warning message names both revisions and suggests clearing
engine_state/ if unexpected behaviour is observed.
Why warnings.warn not logging
warnings is already used in the codebase (core/physics/identity.py).
It is testable via pytest.warns without logger configuration, fits
RuntimeWarning semantics (a recoverable runtime anomaly), and respects
the standard Python warning filter so operators can suppress or escalate it
via -W flags or PYTHONWARNINGS.
Why suppress when either side is "unknown"
_git_revision() returns "unknown" when git is unavailable (CI
containers, packaged builds, offline environments). Storing "unknown" or
comparing against it would always trigger a spurious warning in those
environments. Suppressing when either side is unknown is the
lowest-surprise behaviour.
Invariants pinned by tests
tests/test_adr_0157_revision_mismatch_warning.py (8 tests):
- Matching revision → no
RuntimeWarning - Mismatched revision →
RuntimeWarningemitted, manifest returned intact - Warning message contains both the stored and current revisions
written_at_revision: "unknown"in stored manifest → no warning_git_revision()returns"unknown"→ no warning- Missing manifest file →
Nonereturned, no warning - Empty manifest file →
Nonereturned, no warning
Out of scope
- Schema-version migration. A
schema_versionbump requires a migration or clear-slate fallback (ADR-0146 §Risks line 125). That is separate from the revision warning and deferred to a future ADR when_SCHEMA_VERSIONis actually incremented. reboot_eventaudit trail entry — L10b.3 / W-024.
Validation
tests/test_adr_0157_revision_mismatch_warning.py(8 passed)tests/test_adr_0146_engine_state.py(8 passed — round-trip regression guard)core test --suite smoke(67 passed)