perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

Align createRecord swap semantics with reference

alice 2e0c5946 1b94db18

+30 -10
+1 -1
docs/TEST_AUDIT.md
··· 54 54 - 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. 55 55 - 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. 56 56 - `com.atproto.repo.getRecord` must honor `cid` when present, and `putRecord` / `deleteRecord` must actually enforce `swapRecord`; those negative edges are now covered directly. 57 - - `com.atproto.repo.createRecord` must not ignore `swapRecord`, and `swapCommit` mismatches need direct negative coverage on write paths instead of relying on indirect `applyWrites` behavior. 57 + - `com.atproto.repo.createRecord` follows the reference runtime by ignoring a stray `swapRecord` field, while `swapCommit` mismatches still need direct negative coverage on write paths instead of relying on indirect `applyWrites` behavior. 58 58 - `com.atproto.server.requestPasswordReset` and `com.atproto.server.deleteAccount` now follow the reference form-token flow, with focused regression coverage for missing-account and bearerless deletion semantics. 59 59 - `com.atproto.server.createAccount` with an explicit `did` must behave like an authenticated migration flow: require auth from that same DID, keep the existing DID document, and start the new account deactivated until activation catches the DID document up to the new PDS. 60 60 - `com.atproto.server.checkAccountStatus` must validate the stored DID document against the PDS service endpoint and signing key, and `com.atproto.repo.describeRepo` must derive `didDoc` / `handleIsCorrect` from that document instead of hardcoding success.
-6
lib/ATProto/PDS/API/Repo.pm
··· 48 48 collection => $body->{collection}, 49 49 rkey => $body->{rkey}, 50 50 value => $body->{record}, 51 - (exists $body->{swapRecord} 52 - ? ( 53 - swap_record_present => 1, 54 - swap_record => $body->{swapRecord}, 55 - ) 56 - : ()), 57 51 }, include_result => 1); 58 52 }); 59 53
+26
script/differential-validate
··· 1351 1351 'deleteSession revocation behavior matches the official reference PDS', 1352 1352 ); 1353 1353 1354 + note('Comparing createRecord stray swapRecord handling'); 1355 + for my $name (sort keys %server) { 1356 + my $res = post_json($server{$name}{origin}, 'com.atproto.repo.createRecord', { 1357 + repo => $server{$name}{did}, 1358 + collection => 'app.bsky.feed.post', 1359 + rkey => 'swapcreate', 1360 + swapRecord => 'bafyreifakecidmismatch', 1361 + record => { 1362 + %{$record}, 1363 + text => "swap create validation for $name", 1364 + }, 1365 + }, auth_header($server{$name}{access})); 1366 + check($res->is_success, "$name createRecord ignores a stray swapRecord like the reference runtime"); 1367 + next unless $res->is_success; 1368 + my $json = $res->json || {}; 1369 + $server{$name}{create_record_swap} = { 1370 + uri_ok => (($json->{uri} // q()) =~ m{/app\.bsky\.feed\.post/swapcreate\z}) ? 1 : 0, 1371 + cid_ok => (defined $json->{cid} && length $json->{cid}) ? 1 : 0, 1372 + }; 1373 + } 1374 + 1375 + check( 1376 + same_hash($server{reference}{create_record_swap}, $server{perlsky}{create_record_swap}), 1377 + 'createRecord agrees on stray swapRecord handling', 1378 + ); 1379 + 1354 1380 note('Comparing getServiceAuth post-takedown behavior'); 1355 1381 for my $name (sort keys %server) { 1356 1382 my $update = post_json(
+3 -3
t/repo-api.t
··· 134 134 swapRecord => 'bafyreifakecidmismatch', 135 135 record => { 136 136 '$type' => 'app.bsky.feed.post', 137 - text => 'create should reject swapRecord', 137 + text => 'create ignores stray swapRecord', 138 138 createdAt => '2026-03-10T00:00:45Z', 139 139 }, 140 - })->status_is(400) 141 - ->json_is('/error' => 'InvalidSwap'); 140 + })->status_is(200) 141 + ->json_is('/uri' => "at://$did/app.bsky.feed.post/swap-create"); 142 142 143 143 $t->post_ok('/xrpc/com.atproto.repo.putRecord' => { Authorization => "Bearer $access" } => json => { 144 144 repo => $did,