Repository navigation
docs: version the spec by atServer release, with a change history - #393
Merged
Merged
Conversation
The specification now says which production release of the atServer it describes, in a header under its title, and how it is versioned. The new Appendix E lists, newest first, what each production release from 3.0.35 on changed in the protocol, one block per release, each with its publish date and the canary versions it includes. Releases that changed nothing on the wire have no block. A production release runs the code of the canary promoted to it, so a version released only as a canary is listed under the first production release that shipped it. Every "Since atServer" marker now cites that production version and links to its block: 3.16.1 to 3.16.4 become 3.16.5, and 3.17.1 (the earlier name of 3.18.0) and 3.18.0 become 3.18.1. The enroll:link text no longer contrasts 3.18.0 with 3.18.1, since 3.18.0 never reached production. The header's date is a placeholder until p3.19.0 is published.
The header names atServer 3.19.0, so the main text now describes what its code does, each change marked "Since atServer 3.19.0": - otp:list and otp:delete, otp:put needing full privilege, and OTPs that record the namespaces of the enrollment that issued them; - records in a reserved namespace changing only through the verbs that own them, passcodes read only through otp:, and the notify checks on key names; - update:json refusing an atKey owned by another atSign; - batch: answering an entry it cannot run with AT0003; - the atDirectory answering HTTP by ALPN on its Atsign Protocol port, keeping the atSign in redirects and matching atSigns in canonical form. The stream verb is removed: Appendix B.5 says so, and Appendix D.3 no longer describes its framing.
tools/check_spec_versions.py fails, naming what it found, when the header does not name the newest production block of Appendix E or differs from it in tag or date; when a "Since atServer" or Unreleased marker links a block that does not exist, or a "Since atServer" marker outside a code block is not a link; or when a production block lacks its release line or date, or the blocks are not newest first with Unreleased at the top. A new workflow runs it beside the markdown lint, on the same events.
An atServer 3.19.0 refuses to write a key whose name starts with "__" and has no namespace, so the hidden two-underscore public key form in section 6.2 now carries one, and the example in section 6.6 is public:__location.wavi rather than public:__location.
Trunk's fuller description of the otp verb replaces this branch's, and its row in Appendix A is kept. Its markers now cite production versions and link their Appendix E blocks: the otp:get rule is since 3.16.5, where canary 3.16.0 first reached production, and the enroll:request passcode rule since 3.18.1. The refusal of lookup and llookup of a passcode, since 3.19.0, is added to it.
p3.19.0 was published on GitHub on 2026-10-26, from the commit c3.19.0 was tagged on, so the header and the 3.19.0 block in Appendix E now carry that date in place of the placeholder.
The header says the spec describes atServer 3.19.0, so the body now says what that release does where it still described older behaviour: - the pol1 challenge a cross-atSign from: is given, and the prover's check of it, in sections 9.1, 15.2 and 16.3; - the to: opening of a connection to another atServer, in 15.1; - mldsa65 in the pkam grammar, and the algorithm an APKAM pkam: is verified under; - eAtn and eph in the notify grammar; - the enroll fields signingAlgo, apsk, apskLegacy, metadata and apkamPublicKeySignature, the r and rw grants, and the update, listns and infons operations; - stats 16 and 17; - the atDirectory's 400 for a long URI and the query string a redirect keeps; - what refusing keys named like a reserved namespace means for records stored earlier. The Unreleased block now reads "Nothing is listed here yet.", which no longer reads as saying at_server's trunk is unchanged.
The check now requires the header to be the line under the title and the only one in the prose, reports an Appendix E heading that is not a block heading, reads a block's release line across line breaks, refuses a date that is not a calendar date, compares a block link's version text with its anchor, and treats a ~~~ fence as code. The workflow drops a comment that restated its triggers.
Contributor
Author
|
@cpswan per your suggestion as discussed a few weeks ago ... the PR includes a workflow to help keep the spec up to date. And it's already out of date, as we've released 3.20.0 in the meantime |
Move the header to atServer 3.20.0 and open its Appendix E block. otp:get refuses a ttl of 0 or one above otp.maxTtlInMinutes with AT0022, and a new OTP with AT0028 while otp.maxLive are live. An enroll:request presenting an OTP that records namespaces may ask only for namespaces those cover, and coverage counts a grant on wavi as covering x.wavi.
keys answers only the two keys:get requests by which an enrollment collects its own encryption private key and self encryption key, and refuses every other keys request with AT0009.
enroll:infons also answers lastKeyHolderRevokedAt, the last revocation of an enrollment holding the namespace that may have held a namespace private, and enroll:list marks such an enrollment keyHolder.
A notify id longer than 36 characters is refused with AT0003, and a client's notify key longer than 255 characters, counting cached:, with AT0016. monitor sent again replaces the connection's feed. A connection whose client leaves more than 16 MiB unread is closed, HTTP connections are capped at 50 with 10 and 30 second deadlines, and the WebSocket upgrade negotiates no compression.
keys answers AT0015 when the key is not stored, and refuses with AT0009 only on a connection authenticated as an enrollment. keyHolder is shown to an enrollment's own record only without __manage, and the mark comes from an update of the advertisement, set before it is stored. A monitor replay stalls rather than closes a client that stops reading, and a failed replay closes the connection only outside a batch. An undying OTP is also freed by spending it or by a caller who may manage it. A config value below 1 MiB stops the atServer from starting.
cpswan
reviewed
Nov 9, 2026
ubuntu-26.04 has been generally available on GitHub-hosted runners since 17 September 2026, and ubuntu-latest is moving to it from 24.04 until 19 November. Naming the label keeps the image, and so the python3 the check runs on, fixed.
The job only checks out the repo and runs a standard-library Python script, which suits the 1 vCPU ubuntu-slim runner, generally available since 22 January 2026. Its image ships Python 3.12, and the job runs in seconds, well inside that runner's 15-minute job limit.
cpswan
approved these changes
Nov 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
- What I did
stream, the atDirectory's HTTP by ALPN, and the older behaviour it had missed (thepol1.challenge,to:,eph/eAtn,mldsa65)keysverb,lastKeyHolderRevokedAt, the notify id and key limits,monitorre-runs, and the connection and HTTP limitstools/check_spec_versions.py, keeps the header, markers and Appendix E in step- How I did it
See commits. Each block comes from at_server's CHANGELOG between production releases, checked against the code diff between the canaries those releases promoted. Left for later from review: the check reads only "Since atServer" markers (CR3) and does not flag an unlinked Unreleased (CR13), and atDirectory changes are dated by the atServer release that carried them (CR9).
- How to verify it
Markdown lint and the new check pass
- Description for the changelog
docs: the spec describes atServer 3.20.0 and lists what each production atServer release changed in the protocol