Found during the review of #273. Pre-existing, not introduced there.
DeleteDB (internal/database/webhook_db_manager.go) unlinks the suffixes {"", "-wal", "-shm"} in a loop and returns on the FIRST failure. So if the main .db unlink succeeds and the -wal unlink then fails, the caller receives an error and — since #273 — correctly reports it to the operator as "the event database file was left behind, remove it by hand".
That message is wrong in exactly that case. The main database is already gone; the history is destroyed. What is left behind is a -wal fragment, not the data. An operator told to clean up a leftover file will delete it and believe nothing was lost.
Why this is worth filing now rather than later
It is currently close to unreachable, because the databases open in rollback-journal mode and no -wal or -shm sidecars normally exist. #263 switches every handle to WAL, at which point those sidecars exist routinely and this path becomes genuinely reachable.
So the severity of this issue changes the moment that PR lands. Filing it while the connection is visible rather than rediscovering it later.
Still narrow — it needs os.Remove to fail on a sidecar after succeeding on the main file, which means a permissions or filesystem problem — and the consequence is a misleading message rather than additional data loss. Not milestoned.
Definition of done
DeleteDB attempts every suffix rather than returning on the first failure, and reports what actually happened: which files were removed and which were not.
The distinction the caller needs is preserved: "the database itself survived, retry is meaningful" versus "the database is gone, only fragments remain". Those warrant different operator guidance and must not collapse into one error string.
The caller in deleteWebhookResources surfaces that distinction rather than flattening it.
A test covering a failure on a sidecar after the main file was removed, asserting the message does not tell the operator the history is recoverable.
Note the interaction: once WAL lands, verify a normal delete removes all three files cleanly, since that is the common path and it currently has no coverage against sidecars existing at all.
Found during the review of https://git.eeqj.de/sneak/webhooker/pulls/273. Pre-existing, not introduced there.
`DeleteDB` (`internal/database/webhook_db_manager.go`) unlinks the suffixes `{"", "-wal", "-shm"}` in a loop and returns on the FIRST failure. So if the main `.db` unlink succeeds and the `-wal` unlink then fails, the caller receives an error and — since https://git.eeqj.de/sneak/webhooker/pulls/273 — correctly reports it to the operator as "the event database file was left behind, remove it by hand".
That message is wrong in exactly that case. The main database is already gone; the history is destroyed. What is left behind is a `-wal` fragment, not the data. An operator told to clean up a leftover file will delete it and believe nothing was lost.
## Why this is worth filing now rather than later
It is currently close to unreachable, because the databases open in rollback-journal mode and no `-wal` or `-shm` sidecars normally exist. https://git.eeqj.de/sneak/webhooker/pulls/263 switches every handle to WAL, at which point those sidecars exist routinely and this path becomes genuinely reachable.
So the severity of this issue changes the moment that PR lands. Filing it while the connection is visible rather than rediscovering it later.
Still narrow — it needs `os.Remove` to fail on a sidecar after succeeding on the main file, which means a permissions or filesystem problem — and the consequence is a misleading message rather than additional data loss. Not milestoned.
## Definition of done
- `DeleteDB` attempts every suffix rather than returning on the first failure, and reports what actually happened: which files were removed and which were not.
- The distinction the caller needs is preserved: "the database itself survived, retry is meaningful" versus "the database is gone, only fragments remain". Those warrant different operator guidance and must not collapse into one error string.
- The caller in `deleteWebhookResources` surfaces that distinction rather than flattening it.
- A test covering a failure on a sidecar after the main file was removed, asserting the message does not tell the operator the history is recoverable.
Note the interaction: once WAL lands, verify a normal delete removes all three files cleanly, since that is the common path and it currently has no coverage against sidecars existing at all.
Plan. Still true on next, and now reachable: event databases run in WAL mode, so -wal and -shm files exist routinely, and DeleteDB in internal/database/webhook_db_manager.go still returns on the first file it fails to remove.
DeleteDB tries all three files and returns an error that says which case happened: the database file itself is still there (deleting again may work), or it is gone and only a -wal or -shm file is left (the events are lost; the leftover can be removed by hand).
The webhook delete handler shows the operator the message for the case it got, not one message for both.
Tests: a normal delete of a database with events removes all three files; a sidecar that cannot be removed after the main file was removed gives the "events are lost" message, never one saying the history can be recovered.
Model: opus-5-5
Plan. Still true on `next`, and now reachable: event databases run in WAL mode, so `-wal` and `-shm` files exist routinely, and `DeleteDB` in `internal/database/webhook_db_manager.go` still returns on the first file it fails to remove.
- `DeleteDB` tries all three files and returns an error that says which case happened: the database file itself is still there (deleting again may work), or it is gone and only a `-wal` or `-shm` file is left (the events are lost; the leftover can be removed by hand).
- The webhook delete handler shows the operator the message for the case it got, not one message for both.
- Tests: a normal delete of a database with events removes all three files; a sidecar that cannot be removed after the main file was removed gives the "events are lost" message, never one saying the history can be recovered.
Model: opus-5-5
DeleteDB now tries the event database file and both sidecars even when one cannot be removed. Its error says which case happened, and names each file left: the database file is still on disk, or the database file is gone (so the events are lost) and only a -wal or -shm sidecar is left. The webhook delete handler logs a different message for each, and the second never says the events survive. The tests cover a normal delete with both sidecars present, and a failed removal of the database file or of a sidecar, made by putting a non-empty directory in the file's place.
Judgement call: the page the operator sees is still the generic error page; the two cases differ in the logged line, which is where #273 put the record of what is left.
Judgement call: when the database file cannot be removed, the sidecars are still removed, so that message does not promise the events are intact.
Model: opus-5-5
Done in https://git.eeqj.de/sneak/webhooker/pulls/451.
`DeleteDB` now tries the event database file and both sidecars even when one cannot be removed. Its error says which case happened, and names each file left: the database file is still on disk, or the database file is gone (so the events are lost) and only a `-wal` or `-shm` sidecar is left. The webhook delete handler logs a different message for each, and the second never says the events survive. The tests cover a normal delete with both sidecars present, and a failed removal of the database file or of a sidecar, made by putting a non-empty directory in the file's place.
Judgement call: the page the operator sees is still the generic error page; the two cases differ in the logged line, which is where https://git.eeqj.de/sneak/webhooker/pulls/273 put the record of what is left.
Judgement call: when the database file cannot be removed, the sidecars are still removed, so that message does not promise the events are intact.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found during the review of #273. Pre-existing, not introduced there.
DeleteDB(internal/database/webhook_db_manager.go) unlinks the suffixes{"", "-wal", "-shm"}in a loop and returns on the FIRST failure. So if the main.dbunlink succeeds and the-walunlink then fails, the caller receives an error and — since #273 — correctly reports it to the operator as "the event database file was left behind, remove it by hand".That message is wrong in exactly that case. The main database is already gone; the history is destroyed. What is left behind is a
-walfragment, not the data. An operator told to clean up a leftover file will delete it and believe nothing was lost.Why this is worth filing now rather than later
It is currently close to unreachable, because the databases open in rollback-journal mode and no
-walor-shmsidecars normally exist. #263 switches every handle to WAL, at which point those sidecars exist routinely and this path becomes genuinely reachable.So the severity of this issue changes the moment that PR lands. Filing it while the connection is visible rather than rediscovering it later.
Still narrow — it needs
os.Removeto fail on a sidecar after succeeding on the main file, which means a permissions or filesystem problem — and the consequence is a misleading message rather than additional data loss. Not milestoned.Definition of done
DeleteDBattempts every suffix rather than returning on the first failure, and reports what actually happened: which files were removed and which were not.deleteWebhookResourcessurfaces that distinction rather than flattening it.Note the interaction: once WAL lands, verify a normal delete removes all three files cleanly, since that is the common path and it currently has no coverage against sidecars existing at all.
Plan. Still true on
next, and now reachable: event databases run in WAL mode, so-waland-shmfiles exist routinely, andDeleteDBininternal/database/webhook_db_manager.gostill returns on the first file it fails to remove.DeleteDBtries all three files and returns an error that says which case happened: the database file itself is still there (deleting again may work), or it is gone and only a-walor-shmfile is left (the events are lost; the leftover can be removed by hand).Model: opus-5-5
Done in #451.
DeleteDBnow tries the event database file and both sidecars even when one cannot be removed. Its error says which case happened, and names each file left: the database file is still on disk, or the database file is gone (so the events are lost) and only a-walor-shmsidecar is left. The webhook delete handler logs a different message for each, and the second never says the events survive. The tests cover a normal delete with both sidecars present, and a failed removal of the database file or of a sidecar, made by putting a non-empty directory in the file's place.Judgement call: the page the operator sees is still the generic error page; the two cases differ in the logged line, which is where #273 put the record of what is left.
Judgement call: when the database file cannot be removed, the sidecars are still removed, so that message does not promise the events are intact.
Model: opus-5-5