v0.51.42 — Release R
5-PR contributor batch + maintainer hardening on top of #2041.
Session recovery now has a complete bottom-of-stack: when both the JSON sidecar and the .json.bak are gone, but the canonical state.db.sessions row remains, an operator can POST /api/session/recovery/repair-safe and the session reappears in the sidebar with messages intact. Live-fire verified.
What landed
- #2040 by @ai-ag2026 — Two new endpoints:
GET /api/session/recovery/auditfor read-only recovery reports andPOST /api/session/recovery/repair-safefor deterministic repairs. Returns HTTP 409 when audit findings remain post-repair (no falseok). - #2041 by @ai-ag2026 — Reconstructs missing JSON sidecars from
state.dbrows. Never overwrites an existing sidecar; atomic write withos.link()create-or-fail; per-pid/tid tmp file. Onlysource='webui'rows are materialized. - #2042 by @ai-ag2026 — Crash-safe turn-journal RFC at
docs/rfcs/turn-journal.md. Establishes thedocs/rfcs/convention for design documents on durability and recovery surfaces. - #2044 by @watzon —
MEDIA_ALLOWED_ROOTSenv var extends/api/mediaallowed-roots whitelist with a colon-separated list of paths. Opt-in, additive; path-traversal validation unchanged. First-time contributor. - #2045 by @georgebdavis — Slack appears in the cron delivery dropdown. Backend already routes
deliver=slack. First-time contributor.
Maintainer hardening
Two concurrency hazards in #2041 fixed in the staged release rather than left as follow-up, after Opus pre-release review:
- Per-pid/tid suffix on
.json.reconcile.tmp(was a fixed path per SID, vulnerable to corruption under concurrent reconcile calls). os.link()create-or-fail replacingtmp.replace(target)— closes the TOCTOU window where a concurrentSession.save()for the same SID would be silently overwritten by the lossier state.db reconstruction.
Plus a round-trip schema-parity test (Session.load() on a materialized sidecar) and a guard test asserting the pid+tid tmp suffix is present.
Test infrastructure
tests/conftest.pyautouse session fixture stripsHERMES_WEBUI_SKIP_ONBOARDINGfrom the pytest environment. Tests that legitimately validate the short-circuit behavior can opt back in withmonkeypatch.setenv. Catches a class of bug where tests passed only because the dev env happened to lack the var.- Slice window in
test_media_html_inline_keeps_csp_sandboxwidened from 4000 → 5000 after #2044's insertion pushed the CSP block past the original window.
Tests
5108 → 5120 passing, 8 skipped, 1 xfailed, 2 xpassed, 0 regressions. Suite ~161s on Python 3.11 with HERMES_HOME isolation.
Follow-ups (deferred from Opus review)
Filed as a polish issue: silently-dropped empty-message-rows audit visibility, ok-flag semantic on repair_safe_session_recovery, os.pathsep for Windows MEDIA_ALLOWED_ROOTS compat, and readability tweak on the duplicate-detail guard.
Contributors
@ai-ag2026 (×3) · @watzon · @georgebdavis