A three-source conformance checker for AT Protocol Personal Data Servers (spec + lexicons + reference behavior). Pre-alpha.

Integration mode for relay-dependent reads (listHosts, listReposByCollection) #4

Closed katsuricata.com
Closed opened by and assigned to katsuricata.com

sync.listHosts and sync.listReposByCollection return 502 UpstreamFailure against the dev oracle because no relay is running. A schema check cannot distinguish "PDS broke the contract" from "dev environment has no relay", so the generator skips both with the reason documented.

These belong in an integration mode that stands up (or points at) a real relay. Design question: reuse @atproto/dev-env (TestNetwork / relay fixtures) or target a live relay? Note the full TestNetwork harness requires Postgres + Redis; TestPds-style minimal fixtures may not cover relay behavior.

Done when: both endpoints have checks that produce a real verdict in integration mode and a documented skip otherwise.

Done. Neither TestNetwork nor a live relay, as it turns out.

The reference PDS has no route for either endpoint -- they fall through to the pipethrough catchall, which 401s the unauthenticated caller and then proxies to whatever appview is configured. The 502 was just the oracle having no appview at all. So the thing a PDS actually owns here is the auth gate plus faithful proxying, and a tiny stub XRPC server playing the role of appview exercises that whole path with no Postgres or Redis in sight.

What landed:

  • StubUpstream in src/oracle.ts, plus getOracleWithStubUpstream() which boots the TestPds with its bskyAppView pointed at the stub. e2e uses this by default now.
  • Two lifecycle-mode checks in src/checks/integration.ts: sync.listHosts.integration and sync.listReposByCollection.integration. They assert the 401 unauthenticated gate against any target, and the proxied happy path plus lexicon output shape when an upstream exists.
  • For external targets the operator knob is PDSUITE_STUB_UPSTREAM_URL, documented in docs/integration-mode.md.

The three paths, verified:

  • pnpm e2e (lifecycle): both checks PASS with real 200 verdicts through the stub. 56 pass overall, exit 0.
  • mutate/readonly runs: SKIP mode-lifecycle-not-enabled, documented.
  • Against the local tranquil stack (v0.6.6): SKIP endpoint-not-implemented: -- tranquil 501s both unless you send an atproto-proxy header, which is their documented architectural rule, so the runner's absence-as-skip behavior is doing exactly what it should.

Generator skip reasons now point at the integration checks instead of a shrug. Closing.

Sign up or Sign in to add to the discussion.