fix(update): ignore cron/executions.db sidecars, not just the base file
`/*.db-wal` / `/*.db-shm` only match at the checkout root, so on a flat install `git stash push --include-untracked` still swept `cron/executions.db-wal` / `-shm` while the scheduler held the WAL-mode database open (cron.executions._connect opens it via open_db in WAL mode). The base file stayed put but its WAL vanished under a live writer, so the next `_connect()` failed with `disk I/O error` (review finding on #111175). Use `/cron/executions.db*` like the gateway recovery db rule already does, covering -wal/-shm/-journal and retired-WAL dirs. Every other non-root db rule in the block already uses the glob. The regression tuple gains the two sidecars, and the stash test gets the reviewer's repro against the real `_stash_local_changes_if_needed`: an open WAL connection with one committed row must still be readable from a fresh connection afterwards.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -188,7 +188,7 @@ docs/superpowers/*
|
||||
/gateway/discord_message_recovery.db*
|
||||
/sessions/
|
||||
/browser-profile/
|
||||
/cron/executions.db
|
||||
/cron/executions.db*
|
||||
/cron/jobs.json
|
||||
/cron.pid
|
||||
/gateway.lock
|
||||
|
||||
@@ -10,6 +10,7 @@ tracked .gitignore must cover the runtime state set, mirroring the
|
||||
.hermes-bootstrap-complete / .install_method precedent (#38529 / #66189).
|
||||
"""
|
||||
import shutil
|
||||
import sqlite3
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
@@ -35,6 +36,8 @@ FLAT_INSTALL_RUNTIME_STATE = (
|
||||
"sessions/2026-09-14_06-00-00_abcd123d.jsonl",
|
||||
"browser-profile/Cookies",
|
||||
"cron/executions.db",
|
||||
"cron/executions.db-wal",
|
||||
"cron/executions.db-shm",
|
||||
"cron/jobs.json",
|
||||
"cron.pid",
|
||||
"gateway.lock",
|
||||
@@ -126,3 +129,33 @@ def test_untracked_autostash_cannot_sweep_runtime_state(flat_install_repo):
|
||||
if not (flat_install_repo / rel).exists()
|
||||
]
|
||||
assert missing == []
|
||||
|
||||
|
||||
def test_untracked_autostash_leaves_open_wal_database_readable(flat_install_repo):
|
||||
"""The updater's real stash step must not unlink the -wal/-shm sidecars of a
|
||||
WAL-mode database the scheduler holds open (cron/executions.db). With the
|
||||
base file ignored but its sidecars swept, the next ``cron.executions._connect()``
|
||||
finds a database whose WAL vanished under a live writer and fails with
|
||||
``disk I/O error`` (the review repro on #111175)."""
|
||||
from hermes_cli.update_cmd_stash import _stash_local_changes_if_needed
|
||||
|
||||
db_path = flat_install_repo / "cron" / "executions.db"
|
||||
db_path.unlink() # the fixture's placeholder is not a database
|
||||
conn = sqlite3.connect(db_path)
|
||||
try:
|
||||
conn.execute("PRAGMA journal_mode=WAL")
|
||||
conn.execute("CREATE TABLE executions (id INTEGER PRIMARY KEY, status TEXT)")
|
||||
conn.execute("INSERT INTO executions (status) VALUES ('ok')")
|
||||
conn.commit()
|
||||
assert (db_path.parent / "executions.db-wal").exists()
|
||||
# A tracked local change makes the updater actually enter its stash step.
|
||||
(flat_install_repo / "app.py").write_text("print('changed')\n")
|
||||
|
||||
stash_ref = _stash_local_changes_if_needed(["git"], flat_install_repo)
|
||||
|
||||
assert stash_ref
|
||||
# Fresh connection, exactly as every cron.executions call opens one.
|
||||
with sqlite3.connect(db_path) as reader:
|
||||
assert reader.execute("SELECT status FROM executions").fetchall() == [("ok",)]
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
Reference in New Issue
Block a user