Skip to content

Read a channel Discord denies as unavailable, not a failed backfill - #83

Open
lucasrcezimbra wants to merge 4 commits into
seasonedcc:mainfrom
lucasrcezimbra:issue-82-unavailable-backfills
Open

Read a channel Discord denies as unavailable, not a failed backfill#83
lucasrcezimbra wants to merge 4 commits into
seasonedcc:mainfrom
lucasrcezimbra:issue-82-unavailable-backfills

Conversation

@lucasrcezimbra

@lucasrcezimbra lucasrcezimbra commented Aug 17, 2026

Copy link
Copy Markdown

Discord answers Missing Access when the bot sits in a channel it has no permission to read the history of. Until now that landed in backfill_run_failures like any other broken backfill, so ingestion_status reported the channel as failed, implied history was missing, and told the owner to grant Read Message History — an action the owner often cannot take, because they may not be a server admin. An assistant reading that status had no way to tell a permission somebody set on purpose from an outage worth escalating.

What an unavailable channel is. A backfill whose Discord call comes back Missing Access (50001) or Missing Permissions (50013) now records a single backfill_run_unavailabilities row — its own append-only outcome, no failure row. ingestion_status counts those channels under channels.unavailable, names them under unavailableChannelNames, and keeps failedChannelNames for backfills that genuinely stopped short. The copy says no action is needed unless the owner wants those channels ingested, in which case a server admin grants View Channel and Read Message History.

How status reads. unavailable ranks below reactionsUnread and above completed: every actionable state still outranks it, so a real problem is never hidden behind a permission — and a store that cannot see a channel never claims to be fully caught up either.

Retry semantics. The error is not rethrown, so the scheduler stops burning five attempts on a permission that cannot change inside its backoff. The channel is deliberately not excluded from listBackfillableChannels, so the next gateway connect re-attempts it exactly once — an admin granting access later heals the reading with no bookkeeping to undo.

Archived threads heal too. The one-final-sweep rule used to spend an archived thread's single post-archiving sweep on any attempt, outcome ignored — a thread whose final sweep was denied (or stopped on an error, or hit the page limit) was never swept again and read failed forever, while the guidance promised a restart would resume it. Only a completed run spends the final sweep now: an unfinished attempt is re-tried on the next reconnect exactly like a live channel, so a denied archived thread reads unavailable, and a long one keeps advancing past a page-limit stop instead of stranding its history.

Rulings worth arguing.

  • 50013 alongside 50001. Both are permanent authorization boundaries with the same remedy sentence, so one kind covers them; anything else still reaches backfill_run_failures untouched. Splitting them would ship two copies of one next action.
  • A run outcome table, not a failure kind. Adding a kind column to backfill_run_failures would reshape an existing event table, which the append-only doctrine forbids — and it would keep calling a permission a failure. The sibling precedent is backfill_run_unread_reactions.
  • Ranked above completed, not equal to it. An unavailable channel is not a finished one; the roll-up says so rather than rounding up to "caught up".
  • channels_list untouched. The channel is visible in Discord, just unreadable, so it stays in the list — ingestion_status is the health surface the other tools already point to, and duplicating the signal would give the concept a second home to drift in.

The failed guidance was also re-ruled to fit what remains in it: it no longer suggests granting a permission, and it promises the daemon's diagnostic print only for backfills that keep stopping on an error — a backfill stopped at the page limit returns without throwing, so nothing is ever printed for it.

The dev seed now ships a #leadership channel Discord denies, so the demo store shows the distinction before anyone invites a bot; the README and docs/architecture.md teach it.

Closes #82

🤖 Generated with Claude Code

lucasrcezimbra and others added 4 commits August 17, 2026 10:43
A history backfill that Discord answers with Missing Access (50001) or
Missing Permissions (50013) is a permission somebody set, not a backfill
that broke. It now records its own append-only outcome —
backfill_run_unavailabilities — instead of a failure row, and does not
rethrow, so the scheduler stops burning five retries on a permission that
cannot change inside its backoff.

ingestion_status counts those channels apart from the failed ones and
names them under unavailableChannelNames, with copy that says no action is
needed unless the owner wants them ingested — in which case a server admin,
who may not be the owner, grants View Channel and Read Message History.
Denied channels stay in the reconnect sweep, so a permission granted later
heals the reading on its own.

Closes seasonedcc#82

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The failed status told the owner a restart prints what stopped every
backfill that keeps giving up, but a backfill stopped at the page limit
returns without throwing, so the daemon never prints anything for it.
The advice now scopes the print to backfills that keep stopping on an
error, which is the only cause the scheduler logs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The one-final-sweep rule counted any post-archiving run as the final
sweep, outcome ignored. An archived thread whose final attempt was
denied, stopped on an error, or hit the page limit was never swept
again, so its status read failed forever while the guidance promised a
restart would resume it — a restart that never re-attempted the thread.
Now only a completion spends the final sweep: an unfinished attempt is
retried on the next reconnect exactly like a live channel, so a denial
heals to unavailable and a page-limit stop keeps advancing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unavailable copy and the README said nothing from a denied channel
is in the store, and no catch-up, mention or digest can include it. A
channel ingested before the denial keeps its history, and every reader
still serves it — the denial stops new history, not the stored kind.
The copy now says exactly that. Also drops the demonstration's
failed-count check that the unavailable roll-up already makes
unreachable, since failed outranks unavailable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Treat Discord Missing Access backfills as unavailable, not failures

1 participant