perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
Endpoint Conformance#
As of 2026-03-12, perlsky has three broad classes of external surface:
executable reference-differencedThese endpoints or behaviors are compared directly against the official@atproto/pdsruntime throughscript/differential-validate.locally regression-tested onlyThese endpoints are covered int/*.t, but the current official runtime either does not expose the same surface or is not a useful like-for-like oracle.intentional local divergenceThese are deliberate product or operator choices, not accidental compatibility gaps.
Executable Reference-Differenced#
The current differential harness directly compares:
- core account/session flows
describeServer,createAccount,createSession,getSession,refreshSession,deleteSession,getAccountInviteCodes, app-password lifecycle, password-boundary behavior, and email/account-delete flows - identity flows
resolveHandle,resolveDid,resolveIdentity, PLC credential/signature/update flows, and handle-conflict semantics - repo and sync flows
createRecord,putRecord,deleteRecord,applyWrites,listRecords,getRecord,getLatestCommit,getHead,getBlocks,getRepo,getCheckout,listBlobs,getBlob,listRepos,listMissingBlobs, andimportRepo - moderation/admin flows
updateSubjectStatus,getSubjectStatus,getAccountInfo,getAccountInfos,sendEmail,updateAccountEmail,updateAccountHandle,updateAccountPassword,deleteAccount,disableAccountInvites,enableAccountInvites,disableInviteCodes, and admin invite-code listing semantics - eventing and crawler behavior
subscribeRepos, firehose cursor behavior, and outbound crawler notification semantics after local repo activity
For the exact current comparison set, use:
script/differential-validate
PERLSKY_DIFF_ACCOUNT_DID_METHOD=did:plc script/differential-validate
Locally Regression-Tested Only#
These surfaces are covered locally but are not currently executable-differenced because the official runtime does not expose the same endpoint or does not provide a like-for-like comparison surface:
com.atproto.sync.requestCrawlThe reference runtime still drives crawler notices internally, but the current official build does not expose the endpoint directly as a comparable external surface.com.atproto.sync.notifyOfUpdateLocally covered int/crawler-status-surfaces.t; not wired as a comparable public surface in the current official runtime.com.atproto.admin.updateAccountSigningKeyLocally covered int/admin-account-surfaces.tand aligned to lexicon-void response semantics; no matching official external endpoint wiring was found in the current reference build.com.atproto.admin.searchAccountsImplemented and tested locally int/admin-account-surfaces.t; not exposed by the current official runtime.com.atproto.sync.listReposByCollectionPresent in the published lexicon and covered locally int/discovery-surfaces.t, but not exposed by the current official runtime.com.atproto.temp.*requestPhoneVerification,revokeAccountCredentials,checkSignupQueue, anddereferenceScopeare locally covered int/temp-endpoints.t, whilefetchLabelsis covered int/label-rpc-surfaces.t; these do not have a like-for-like official public comparison surface.- local label RPCs
com.atproto.label.queryLabels,subscribeLabels, andcom.atproto.temp.fetchLabelsare verified locally int/label-rpc-surfaces.tandt/labels.t; the official runtime does not provide a directly comparable local-labeler implementation. - local appview emulation
app.bsky.actor.getPreferences,putPreferences,notification.getPreferences,notification.putPreferencesV2, and the conservative local feed/thread/profile fallback behavior are locally regression-tested rather than compared against an official self-hosted AppView implementation.
Intentional Local Divergences#
These are currently deliberate:
- admin bearer shortcut
perlskystill accepts a local bearer-style admin secret in addition to strict Basic auth. - testing-friendly email toggles
testing_allow_unauthenticated_email_confirmandtesting_auto_confirm_emailintentionally keep no-SMTP testing practical. - self-service invite issuance
Disabled by default, but available behind
self_service_invite_codes. applyWritesmissing-delete error shape The official runtime still returns500 InternalServerErrorfor one missing-delete path;perlskyintentionally keeps the cleaner400 InvalidRequest.
Reading This With docs/TEST_AUDIT.md#
- Use this file to answer “is this surface reference-differenced, local-only, or intentionally different?”
- Use TEST_AUDIT.md to answer “what specific behaviors were audited, fixed, or are still known gaps?”