~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A space's syncer refused for want of scope is not asked again at every sweep

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/syncer-scope

On prod, one organization's space fails to sync every 30 s, all day, because its syncer's login doesn't grant the space: 134 of the last 200 warnings were this one line, each a wasted call to its PDS. Now a syncer refused for want of scope isn't asked again for an hour, or until it logs in or delegates again; the space's readers sync it meanwhile, as they already do once a space goes stale. A quick look will do: start at to_sync in spaces.rs.

Claude Opus 5.5 · high

What changes

spaces::follow skips a syncer refused for want of scope. Each sweep (every 30 s) and each notified write picks the spaces to sync through to_sync, which now leaves out any whose syncer was refused that space for want of scope within the last hour. A sync that fails that way records it with refused_for_scope, the same mark the background reader checks in discover already keep. So the space not synced warning for such a space is logged once an hour, not twice a minute.

A new grant clears the mark. spaces::in_scope_again forgets an account's refusals; the pages' login (login::keep) and the gateway's delegation callback call it once they save the new session. That also helps the reader checks in discover, which until now waited out the hour after someone logged in again.

docs/design/access.md says both.

Why

admin_logs on prod: space not synced for at://did:plc:e7rftrdyz5e2rw4y6ocszew2/space/dev.knotless.org/self every 30 s, with InvalidToken (403): Scope does not permit reading … from getDelegationToken. Its syncer's grant stays as it is until that account logs in again, so asking again at every sweep can't succeed. Unfollowing the space would drop what its index holds for every reader; skipping its syncer leaves the space to its readers, whose syncs already take over once it is a minute stale (private.rs, sync_stale).

How it was checked

spaces::tests::syncers_out_of_scope_wait_till_they_log_in_again: to_sync takes every space on a sweep and only the told ones otherwise; once a syncer is refused one space for want of scope it is left out, the other still synced; after in_scope_again it is back. The login and delegation callbacks run in the existing gateway tests. Left to CI.

Shortcomings

The marks live in memory, so a restart asks every syncer again once. A space whose only syncer is out of scope and that no one reads goes unsynced until someone does, as it did before, minus the failing calls.

Approved

This pull stops follow from asking a space's syncer again every sweep once its grant was refused for want of scope. to_sync drops those syncers, and refused_for_scope records the refusal after each sync. A fresh login or delegation clears the marks through in_scope_again. I read all the changed files and found nothing that must change. The marks use the same (did, uri) key and one-hour window the reader checks already use, so the two paths stay consistent. The skipped syncer's spaces stay covered by readers' sync_stale syncs, as the body says. The new test covers skipping, the sweep-versus-due filter, and clearing. I did not read the check results; the body leaves the checks to CI.

Minor: in_scope_again runs in the gateway callback even when session::save failed. That only means one extra attempt, so it is harmless.

Merged as 0fe872e