···1313The current baseline for saying "the audited suite is green" is:
14141515- `prove -lr t`
1616- - latest full green result in the realigned Meridian worktree: `Files=61, Tests=3119`
1616+ - latest full green result in the realigned Meridian worktree: `Files=61, Tests=3128`
1717- `prove -lv t/server-auth.t`
1818- `perl -c script/differential-validate`
1919- `PERLSKY_RUN_REFERENCE_DIFF=1 prove -lv t/reference-differential.t`
···7676- `com.atproto.identity.resolveHandle` should treat well-formed but unresolved handles as `400 InvalidRequest` with `Unable to resolve handle`, matching the official runtime instead of returning a local `404 HandleNotFound`.
7777- Remote `did:web` DID docs, conservative `resolveIdentity` handle validation, and external handle adoption all need explicit coverage because small resolver-policy drifts turn into visible interop bugs quickly.
7878- Remote `did:plc` DID docs should resolve through the PLC directory defaults even when `plc_url` is not explicitly configured; gating that path on local config silently breaks federated identity lookups.
7979-- Missing-repo read paths now match the official runtime more closely: `describeRepo`, `sync.getLatestCommit`, `sync.getRecord`, `sync.getRepo`, `sync.getCheckout`, `sync.getHead`, and `sync.getRepoStatus` report `400 RepoNotFound`, while `listRecords` reports `400 InvalidRequest` / `Could not find repo: ...`.
7979+- Missing-repo read paths now match the official runtime more closely: `describeRepo`, `sync.getLatestCommit`, `sync.getRecord`, `sync.getRepo`, `sync.getCheckout`, `sync.getHead`, `sync.getRepoStatus`, `sync.getBlocks`, `sync.getBlob`, and `sync.listBlobs` report `400 RepoNotFound`, while `listRecords` reports `400 InvalidRequest` / `Could not find repo: ...`.
8080- `com.atproto.repo.getRecord` must honor `cid` when present, and `putRecord` / `deleteRecord` must actually enforce `swapRecord`; those negative edges are now covered directly.
8181- `com.atproto.repo.createRecord` follows the reference runtime by ignoring a stray `swapRecord` field, and direct reference coverage now pins `putRecord` / `deleteRecord` `swapCommit` and `swapRecord` mismatch semantics explicitly.
8282- App-password sessions follow the official runtime more closely than the older local assumptions did: access-token scopes use the `com.atproto.appPass` / `com.atproto.appPassPrivileged` names, standard app-password sessions may list app passwords, privileged-only `getServiceAuth` failures report `InvalidRequest`, and revoked refresh tokens on `refreshSession` fail with `400 ExpiredToken`.
+3-3
lib/ATProto/PDS/API/Sync.pm
···9494 });
95959696 $registry->register('com.atproto.sync.getBlocks', sub ($c, $endpoint) {
9797- my $account = _readable_repo_by_did($c);
9797+ my $account = _readable_repo_by_did($c, missing_status => 400);
9898 my @cids = flatten_params($c->every_param('cids'));
9999 xrpc_error(400, 'InvalidRequest', 'At least one CID is required') unless @cids;
100100 my $repo_car = $c->store->repo_car($account->{did});
···112112 });
113113114114 $registry->register('com.atproto.sync.getBlob', sub ($c, $endpoint) {
115115- my $account = _repo_by_did_or_error($c);
115115+ my $account = _repo_by_did_or_error($c, missing_status => 400);
116116 my $blob = $c->store->get_blob($c->param('cid') // q());
117117 xrpc_error(404, 'BlobNotFound', 'Blob was not found')
118118 unless $blob && $c->store->blob_owned_by_did($c->param('cid') // q(), $account->{did});
···156156 });
157157158158 $registry->register('com.atproto.sync.listBlobs', sub ($c, $endpoint) {
159159- my $account = _readable_repo_by_did($c);
159159+ my $account = _readable_repo_by_did($c, missing_status => 400);
160160 my $page = $c->store->list_blobs_by_did(
161161 $account->{did},
162162 since => $c->param('since'),