Skip to content

fix(recovery): name every legacy journal blocking startup, not just the first - #866

Open
m4bard wants to merge 1 commit into
Listenarrs:canaryfrom
m4bard:fix/bug26-journal-repair-visibility
Open

fix(recovery): name every legacy journal blocking startup, not just the first#866
m4bard wants to merge 1 commit into
Listenarrs:canaryfrom
m4bard:fix/bug26-journal-repair-visibility

Conversation

@m4bard

@m4bard m4bard commented Aug 21, 2026

Copy link
Copy Markdown

Summary

When a legacy file-mutation journal blocks startup reconciliation, the exception names only the first of them. The query that produced it collects every affected journal and the update marks every one, so an operator learns about one, resolves it, restarts, and meets the next.

This reports the count and the identifiers instead. Full write-up in #865.

Changes

Fixed

  • EnsureCurrentRecoveryProtocolAsync names how many journals are affected and lists their operation ids and states, capped at ten with a remainder count, and folds the stored Error reason into the message.

What this deliberately does not do

It does not add a repair mechanism and it does not change the refusal.

Declining to resume a mutation that cannot be safely resumed is correct and is clearly deliberate. What is missing is a route out of that state, and what "resolved" should mean for an interrupted mutation is a design decision rather than something to infer from the outside. The issue lays out both that and the separate question of whether a handful of rows should disable filesystem operations application-wide.

This is worth having on its own because the exception message is the entire brief an operator gets. git grep FileMutationJournal across listenarr.api returns nothing, so there is no endpoint, no controller and no DTO for these rows. Nothing else tells anyone what is wrong or how much of it there is.

Testing

FileRegistrationRecoveryProtocolTests seeds three journals on the previous protocol version, runs ReconcileAsync, and asserts the thrown message carries the count and every operation id.

Verified as a real guard: with the original single-journal message restored the test fails on the missing substring, and passes with the change.

Full suite: 3,030 passed, 0 failed, 125 skipped, against a 3,029 baseline on 03958c15.

Note

I have not reproduced the originating condition end to end. Creating it needs a mutation genuinely in flight across a version boundary. What is verified from source is the query, the mark, the throw, and that nothing ever clears NeedsAttention for these rows. The runtime evidence in the issue is a reporter's rather than mine, and the issue says so.

…he first

A file-mutation journal left on an older protocol version disables filesystem
mutations for the whole application. Scan, import and move all return 503 and the
startup error is logged once per restart. There is no in-app route to clear the
state: git grep FileMutationJournal across listenarr.api returns nothing, so this
exception message is the entire brief an operator gets.

It named unsupported[0] only, while the query that produced it collects every
affected journal and the update marks every one of them NeedsAttention. With three
stuck rows an operator learns about one, resolves it, restarts, and meets the next,
with no way to know how many remain.

Report the count and the identifiers, capped at ten with a remainder, and fold the
stored Error text into the message so the reason travels with the list rather than
living only in a column nothing surfaces.

This does not add a repair mechanism and does not change the refusal. Refusing to
proceed on a state that cannot be safely resumed is the right instinct and is
deliberate. What is missing is a way out, and designing that is a maintainer's call
rather than something to infer. This makes the position knowable in one restart
instead of N while that is decided.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant