* 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.
72 lines
2.9 KiB
Markdown
72 lines
2.9 KiB
Markdown
# 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_revision` in `manifest.json` with 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:
|
|
|
|
1. Read `manifest["written_at_revision"]` (stored revision).
|
|
2. Call `_git_revision()` to obtain the current HEAD short SHA.
|
|
3. If both values are non-empty and not `"unknown"`, and they differ,
|
|
emit `warnings.warn(..., RuntimeWarning, stacklevel=2)`.
|
|
4. 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 → `RuntimeWarning` emitted, 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 → `None` returned, no warning
|
|
- Empty manifest file → `None` returned, no warning
|
|
|
|
## Out of scope
|
|
|
|
- **Schema-version migration.** A `schema_version` bump 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_VERSION` is actually incremented.
|
|
- **`reboot_event` audit 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)
|