Mit gesetztem DATABASE_URL_APPVIEW liefen diese Tests zum ersten Mal
überhaupt (ohne die Variable überspringen sie sich still) — und fielen
um. Zwei Ursachen:
1. Sechs Integrationstests hingen wie zuvor die Unit-Tests am globalen
run_once()-Batch. select_candidates/resolve_batch sind dafür jetzt
pub, damit auch die Integrationstests ihren eigenen DID durchreichen
können statt zu hoffen, dass er es in den Batch schafft.
2. Die Dispatch-Tests für did:web und did:plc verdrahteten den fremden
Stub als pds_resolver — also eine lokale PDS, die behauptet, eine
fremde DID zu kennen. Die Moduldoku sagt ausdrücklich, dass die PDS
vor der Methodenverzweigung befragt wird, damit ein did:key-Nutzer
der eigenen PDS ohne Umweg über plc.directory auflöst. Die Fixtures
haben also gegen die dokumentierte Regel getestet statt gegen die
Verzweigung, um die es ihnen ging. Jetzt kennt die PDS-Stub die DID
nicht, wie es der Realität entspricht.
Neu: pds_resolves_did_key_before_method_dispatch pinnt die PDS-zuerst-
Regel selbst — dasselbe DID-Verfahren, umgekehrtes Ergebnis, und der
Unterschied ist allein, ob die PDS den Nutzer hostet.
sync_skips_already_resolved prüft weiter über select_candidates: dass
ein DID mit Handle gar nicht erst bei einem Resolver landet, ist der
Punkt des Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013HC9HLrUU1LNwkzp8nkDLX
The AppView's handle_sync worker consulted the public PLC directory
and the did:web: HTTPS resolver only. DIDs hosted on the local PDS
(notably did🔑 users and any other operator-hosted method)
weren't reachable without an external round trip, and unresolvable
DIDs (did🔑 not on this PDS, did:foo: anything) blocked the
100-row batch forever because did🔑 sorts lexicographically
before did:plc: / did:web:.
This commit adds:
* `PdsHandleResolver` (at-identity) — POSTs the DID as the
`handle` field to the PDS's resolveHandle XRPC method. The PDS
now recognises a `did:` prefix and does a PK lookup on
`users.did`, returning `{did, handle}`. The resolver reads
the `handle` field, so the AppView finally gets a real local
handle for did🔑 users without ever dialing plc.directory.
* A 2 s timeout per request (was 10 s) and `DISPATCH_CONCURRENCY =
8` so the worker caps a 100-DID batch at ~2 s with parallel
dispatch instead of the ~17 min worst case the old serial + 10 s
setup allowed.
* A new `posts.handle_sync_attempted_at` column (migration 0006)
and `mark_attempted()` helper. The SELECT filter excludes rows
attempted within the last hour, so an unresolvable DID dominates
at most one batch before the worker advances. Cleared on success.
* `PDS_INTERNAL_URL` config so the AppView can reach the PDS via
a cluster-internal hostname when the public URL isn't routable
from inside the cluster.
Tests:
* `crates/at-identity/src/pds_handle.rs` — 4 unit tests against a
stub HTTP server (200/404/5xx/missing-did-field).
* Existing handle_sync integration tests updated to wire in the
new `pds_resolver` field.