AT Protocol Curriculum Review
Independent Phase 1d text review of the 24-unit atproto curriculum (revision 1, 2026-10-22) against the recorded atproto.com, web.plc.directory, IETF and feed-generator sources, plus live checks. 24 accuracy findings (3 wrong, 4 stale, 12 overstated or imprecise, 1 unsupported, 4 omissions), 10 structure findings, 5 source findings. 14 units go back to 1b, 10 pass; every unit is inside its target length; 216 of 218 recorded quotes are verbatim.

AT Protocol Curriculum Review

Reviewed 2026-10-22 against the page dumps in atproto-src-pages/ (atproto.com guides, specs and blog; the did:plc spec; the IETF ATP charter and group page; the feed-generator README) and, where the dumps were silent or dated, against the live sites: web.plc.directory and plcred.org (PLC Organization), hubble.microcosm.blue (Hubble is live and answering getRepoStatus), the atproto.com blog index and four posts newer than the recorded set (Upcoming Relay Transition, 2026-01-24; Introducing Bluesky Protocol Services, 2026-08-13; Developer Experience Goals for Atproto Spaces, 2026-10-14; An Intro to Atmospheric Groups, 2026-10-22), the com.atproto.repo.strongRef lexicon, and a real reply record fetched from the bsky.app PDS. Three recorded page dumps (feeds, labelers, bskylabels, all from docs.bsky.app) are empty: that site has moved to bsky.network and the pages did not fetch.

The JSON scripts match the markdown scripts word for word. Length was estimated with the guide's formula (2.3 words per second plus 0.7 s per line and 1.5 s per beat). Every unit lands inside its own target.

Unit

Beats

Lines

Words

Estimate

Target

1

5

10

103

59 s

50-60

2

5

10

95

56 s

50-60

3

5

8

73

45 s

40-50

4

5

10

110

62 s

55-65

5

5

9

87

52 s

45-55

6

5

9

91

53 s

50-60

7

5

9

96

56 s

50-60

8

5

10

101

58 s

50-60

9

5

10

99

58 s

50-60

10

5

10

98

57 s

50-60

11

5

8

78

47 s

40-50

12

5

10

91

54 s

45-55

13

5

9

85

51 s

45-55

14

5

10

110

62 s

55-65

15

5

9

109

61 s

55-65

16

5

9

98

56 s

50-60

17

5

8

93

54 s

50-60

18

5

9

93

54 s

50-60

19

5

9

83

50 s

45-55

20

5

8

81

48 s

45-55

21

5

8

89

52 s

50-60

22

5

10

109

62 s

55-65

23

5

9

81

49 s

45-55

24

5

7

92

52 s

45-55

Summary

The curriculum is in better shape than the previous two series: the storage half (units 5 to 13) is right and well ordered, the recorded statements are real, and nothing is too long or too short. The faults cluster in four places. Two units teach a wrong model (unit 8 says no server can forge you, while unit 11 says your host holds your signing key; unit 7 says record-to-record links are hashes, while the AT URI spec says they are addresses with an optional hash). Four claims are stale by three to eight months (the PLC Organization has existed since early 2026; Jetstream v2 has carried history since August 2026; Spaces breaking changes have already landed and a launch is expected this year; the firehose runs at thousands, not hundreds, of events a second). Unit 4 promises recovery and never explains it. And fifteen unit cards name a metaphor the script does not speak, which the guide's Anytwo lesson forbids.

Accuracy

Each finding gives the unit and beat, the spoken line, what is wrong, the source, and a fix.

A1. Units 4 and 24: the PLC Organization already exists (stale, wrong). Unit 4 beat 4: "An independent PLC Organization, a Swiss association, is being set up as its neutral steward." Unit 24 beat 2: "Identity is getting a neutral steward, the PLC Organization". The recorded source is the September 2025 blog ("the new entity will form as a Swiss Association"). The live directory home page (web.plc.directory, read 2026-10-22) says: "In 2026 the PLC Organization was founded to be a neutral steward for the DID PLC system." The organization's own site (plcred.org): "The PLC Organization is a small Swiss Association ('Verein') ... The Organization was established in early 2026, and is in the process of developing policies and building operational capacity." Fix unit 4 beat 4: "An independent PLC Organization, a Swiss association founded in early 2026, is its neutral steward. It is still building up. And anyone can run a read replica of the directory." Fix unit 24 beat 2: "Identity has a neutral steward, the PLC Organization, founded this year, and the directory can be replicated by anyone." Record the two new source lines.

A2. Unit 8 beat 5: your own host can forge you (wrong, cross-unit). "And the commit is signed with the key in your DID document. No server can forge a version of you." Unit 11 beat 1 says the opposite thing truthfully: "It stores your repository and holds your signing keys." Glossary: "A PDS will always store the user's data repo and signing keys." Overview: "The signing key is entrusted to the PDS so that it can manage the user's data". The host that holds the key can sign anything as you; that is exactly why the rotation key and migration exist. Fix: "No other server can forge a version of you. Your own host can, because it holds the key. That is why you get to choose it, and why you can leave it."

A3. Unit 7 beat 3: between records, a link is an address, not a hash (overstated to the point of wrong). "When a record points at another, it carries the other's CID. A link is a hash, not a location." Inside the repository, links are hashes (data model: nodes "can also reference each other strongly by hash, referred a link"). Between records they are not: a follow names a DID, a like or reply names an AT URI plus a CID. AT URI spec: "An AT URI pointing to a specific record in a repository is not a strong reference, in that it is not content-addressed." "When a strong reference to another record is required, best practice is to use a CID hash in addition to the AT URI." The com.atproto.repo.strongRef lexicon ("A URI with a content-hash fingerprint") requires both uri and cid; a reply fetched from the bsky.app PDS (app.bsky.feed.post/3myihk54vhk2d) carries parent: {uri, cid}. Fix beat 3: "Inside the repository every link is a hash: the tree points at each record by its CID. Between records, a reference is an address, often with the CID beside it." Beat 4 then lands as written. The misconception line "A link is a hash, not a location" should move to beat 2 and be said of the tree, not of record references.

A4. Unit 4 beat 2: rotation keys sign operations; they do not "replace" the signing key, and the recovery window is never taught (imprecise, omission). "The log is signed by rotation keys, which sit above the everyday signing key. Lose the signing key, and a rotation key replaces it." A rotation key signs an operation that installs a new signing key; it does not become one. did:plc spec: "The signing key does not have any control over the DID identity unless also included in the rotationKeys list. Best practice is to maintain separation between rotation keys and atproto signing keys." The unit is titled "an identity you can recover", but the thing that makes did:plc "recoverable" is not spoken anywhere: "The PLC server provides a 72hr window during which a higher authority rotation key can 'rewrite' history, clobbering any operations ... signed by a lower-authority rotation key." Overview: "rotation keys can be controlled by the user, e.g. as a paper key." Fix beat 2: "Rotation keys sit above the everyday signing key. Lose or leak the signing key, and a rotation key signs a change that installs a new one." Add a recovery beat (see S2 for where it fits): "Keep one rotation key yourself, on paper. For three days after any change, a higher rotation key can undo it. That is the recovery."

A5. Unit 12 beat 5: allowed types and sizes are the schema's call, not only the host's (partly wrong). "Size limits and allowed types are the host's call. The protocol fixes the shape, not the quota." The host applies only generic limits at upload; the record's Lexicon sets accepted MIME types and maximum size, enforced when the record is written. Blob spec: "the server does not know the intended Lexicon when receiving an upload, so can only apply generic blob limits and restrictions at initial upload time, and then enforce Lexicon-defined limits later when the record is created." Lexicon spec, blob type: "accept (array of strings, optional): list of acceptable MIME types ... maxSize (integer, optional)". Fix: "Quotas are the host's call. Which types and sizes a record may carry is the schema's call, checked when the record is written."

A6. Unit 16 beat 3 and card: history is no longer what sets Tap apart (stale). "Tap goes the other way: it keeps the verification and adds the history." Since 2026-08-13 Jetstream v2 keeps history too: "It keeps a compressed archive of the whole network and adds a new way to consume it, alongside the live tail: Network Replay lets you catch up from any point in the past and cut over to live with no gap" (Introducing Bluesky Protocol Services). The Jetstream README now opens "Full-network archive, replay, and streaming service for atproto." The contrast the unit should draw is verification: Tap "handles MST integrity checks, identity signatures, and all the cryptographic validation" and backfills from the authoritative PDS; Jetstream, old or new, hands you JSON you trust. Fix beat 3: "Tap goes the other way: it keeps the verification. Track a repository, and Tap fetches its past from the host, checks every commit, then hands you the live events." Fix beat 2 to add "and, since version two, can replay the past" or leave history out of both. Record the August 2026 post. The card's idea sentence and the unit 24 line "Tap and Hubble fill the gaps" survive.

A7. Unit 16 beat 1: "hundreds of events a second" is two years stale (stale). The recorded Jetstream post (October 2024) says "hundreds of events per second" and "over a thousand"; the November 2024 relay post says "sustained traffic of over 2,000 events per second"; the May 2025 relay post says "thousands of messages per second". Fix: "thousands of events a second". Record the May 2025 line, which is already in the recorded set.

A8. Unit 24 beat 3: "Sync one point one is in" (overstated). The producer side is rolled out (bsky.network moved to the Sync 1.1 relay on 2026-01-27 per Upcoming Relay Transition) and Tap "serves as a reference implementation for Sync 1.1" (Spring 2026 roadmap). But the same roadmap says: "There are a few remaining pieces of Sync 1.1 to implement: defined block ordering for repository CAR file exports, and exporting subsets of repositories by collection." The relay transition post: "strict verification will still be disabled for now." The repository spec (February 2026) says streamable CAR ordering "has not been included in popular implementations or deployed broadly". Fix: "Sync one point one runs on the relays, with Tap as the reference consumer; a few pieces are still to come."

A9. Unit 14 beat 2: dropping failed commits is still a plan (status nuance). "Commits that fail the check are meant to be dropped." The hedge is honest, but the latest recorded status is older than the unit implies. May 2025: "the relays currently attempt strict validation on every message and log failures (even if they are passed through on the firehose in 'lenient' mode)". January 2026: "strict verification will still be disabled for now. We do intend to enable strict MST verification in the near future." Fix: "Commits that fail are logged today, and will be dropped once strict checking is switched on." Record the January 2026 line.

A10. Unit 14 beat 3: "cheap to run" hides the real cost (overstated). The AT Stack page: "A full network relay isn't particularly expensive to operate ... though it does require significant ingress and egress network bandwidth, which is the main cost in operating a relay." Self-hosting: "Hosting your own Relay is possible, though bandwidth intensive." Fix: "That makes it cheap in storage. The cost is bandwidth."

A11. Unit 18 beat 4 and check question: "The app decides what each label does" (overstated, unsupported). The label spec says only that behaviour is defined outside the label: "The behavior, definition, meaning, and policies around labels are generally communicated elsewhere." In the Bluesky application the labeler's declaration record (app.bsky.labeler.service, labelValueDefinitions) carries a default severity and blur setting per label value, and the user can override it per labeler; the app enforces the result. None of that is in a recorded statement, and "the app decides" alone is the wrong answer to the check question "Who decides what a label does to a post?" Fix beat 4: "What a label does, hide, warn, blur, is set outside the label: the labeler suggests, the user adjusts, the app enforces. Speech and reach are two layers." Record a source for labeler definitions (the Bluesky labeler lexicon or the moved docs.bsky.app moderation page, whose dump is empty).

A12. Unit 19 beat 2: the authorization server is the host or an entryway (overstated). "You log in at your own host, not in the app. The host is the authorization server." OAuth spec: "Sometimes the PDS is also the 'Authorization Server' ... while in other situations a separate 'entryway' service acts as the Authorization Server for multiple PDS instances." Self-hosting: "Bluesky runs many PDSs with an 'entryway' in front of them." Most accounts in the network log in at an entryway. Fix: "You log in at your host, or at the login service your host names. Never inside the app."

A13. Unit 19 beat 3: the DPoP key belongs to the session, not the app (imprecise). "tokens bound to the app's own key". OAuth spec: "DPoP ... is required to bind auth tokens to specific client software instances (eg, end devices or browser sessions)"; "the client generates a new DPoP key for the user/device/session". The card says "app instance" correctly. Fix: "and tokens bound to a key this copy of the app made for this session."

A14. Unit 19 beats 1 and 5: two words (low). "No registration, no shared secret": the spec calls it "automated client registration using client metadata", so say "No registration form". "App passwords were the old way": they still exist and are still accepted (XRPC spec, App Passwords section), so "are the old way".

A15. Unit 20 beat 3: permission sets belong to a namespace, not to an app, and cannot hold every scope (overstated). "An app can bundle its scopes into a permission set, published as a Lexicon." Permissions spec: "Permission sets are published as public lexicon schemas, and are constrained in scope to named resources under the same NSID hierarchy as the NSID of the permission set itself." For blob, account and identity: "Permissions of this type can not be included in permission sets, and must be requested directly by client apps." Fix: "Whoever owns a schema namespace can bundle its record and service scopes into a permission set, published as a Lexicon. Named and owned, like any schema."

A16. Unit 21 beat 5 and check question: activating the new account is missing (omission). "Deactivate the old account. The network sees the events and follows you home." The new account starts deactivated and must be activated. Account spec, migration steps: "updating account status on both PDS instances, such that old is inactive, and new is active." Migration guide: "The user can activate their account on the new PDS with a call to com.atproto.server.activateAccount, and deactivate their account on the old PDS ... At this point the migration is complete." The check question "Which change finalizes a migration?" has two defensible answers in the sources: the recorded line says the identity move "is not finalized till the change on the identity's did document is made", and the guide then says "However, the new account is not yet 'active'." Fix beat 5: "Activate the new account, deactivate the old. The network sees the events and follows you home." Make the check question "Which change makes the network treat the new host as yours?" (the DID document) or state which answer is expected.

A17. Unit 21 beat 5: the rotation key has to be one you kept (omission). "If the old host is gone, a rotation key still lets you move." By default the host holds the rotation keys too. The AT Stack, PDS duties: "secret key management: AT signing key, and PLC rotation key". Migration guide: "For users who are able to securely manage a private cryptographic keypair ... it is recommended to include a self-controlled PLC rotation key." Hubble post: "with a rotation key and a backup of your data, you're in complete control." Fix: "If the old host is gone, a rotation key you kept yourself still lets you move." This also pays off A4's recovery beat.

A18. Unit 22 beat 5: "breaking changes are promised before the full release" has aged (stale). The August post is recorded correctly, but the 2026-10-14 post says: "Released a couple rounds of breaking changes ... We expect to launch atproto Spaces this year. And that means that we're starting to lock in the core primitives for Spaces, because we're confident that most pieces are going to stop churning from here." Fix: "The alpha opened in August twenty twenty six. Breaking changes have landed since; the core is settling, and a launch is expected this year." The same post confirms beat 3's model ("Spaces sync without a relay ... each space functions as a sync boundary"); record it.

A19. Unit 24 beat 4: "permissioned data is the team's main focus" is a March forecast read in October (stale). Spring 2026 roadmap: "Permissioned data will probably be a major focus for the Bluesky protocol team through the summer." By October it is the Spaces alpha with weekly posts and a launch expected this year. Fix: "The open front is non public data: Spaces is in alpha, and a launch is expected this year."

A20. Unit 23 beat 2: "Users cannot recover" (overstated). Hubble post: "For you as a user, this is recoverable! ...if you've taken some preparations ... with a rotation key and a backup of your data, you're in complete control." Fix: "Apps cannot backfill. Users without their own backup cannot recover."

A21. Unit 17 beat 3: the recorded source says the requesting server hydrates, not the AppView (unsupported). "The AppView fills the skeleton in with the posts, the authors, the counts." Feed-generator README: "Those posts are then hydrated into full views by the requesting server and sent back to the client", and its flow: "The PDS hydrates the feed ... In the future, the PDS will hydrate the feed with the help of an App View, but for now, the PDS handles hydration itself." The AT Stack page repeats "hydrated into full views by the requesting server". In the Bluesky deployment today the AppView serves the feed endpoint and calls the generator, so the line is probably right in practice, but no recorded statement says so and the README says the reverse. Either record a current source (the moved custom-feeds page, whose dump is empty) or say "the app's server fills the skeleton in".

A22. Unit 13 beat 3: identity events do not say what changed (low). "Other events say a handle or key changed, or an account was deactivated, or taken down." Sync spec, #identity: "Indicates that there may have been a change to the indicated identity ... Does not indicate what changed." Fix: "Other events say your identity may have changed, or that an account was deactivated, or taken down."

A23. Unit 9 beat 3: four kinds of schema, but the spec has five (low omission). "A schema defines a record type, a query, a procedure, or a subscription." Lexicon spec primary types: "query ... procedure ... subscription ... record ... permission-set: describes a bundle of auth permissions." The idea map lists five; unit 20 then says a permission set is "published as a Lexicon" and the viewer has not heard that kind. Fix: "or a subscription, or a bundle of permissions."

A24. Unit 5 beat 1: "All your public data lives in one repository" (low). Blobs are public data that live beside the repository, which unit 12 then says. Repository spec: blobs "are also referenced by content hash, but are not stored directly in the repository." Fix: "All your public records live in one repository."

Everything else checked out against the recorded statements, including the claims the brief singled out: unit 2 (two resolution methods; "The link between handle and DID must be confirmed bidirectionally, otherwise anybody could create handle aliases for third-party accounts"); unit 4 beat 1 (genesis hash, truncated to 24 characters); unit 6 (TID "length is always 13 ASCII characters"; self; at://.../app.bsky.actor.profile/self in the AT URI spec); unit 7 beats 1, 2, 4 and 5 (DRISL-CBOR, SHA-256, strongRef verified live); unit 8 fields and "rev ... used as a logical clock"; MST locality and CAR-slice diffs (repository spec, Repository Diffs); unit 9 (com.atproto.lexicon.schema records, _lexicon TXT record); unit 10 (atproto-proxy, token "issued and signed by the user's identity"); unit 11; unit 12 beats 1 to 4; unit 13 (commit carries "CAR 'slice' for the corresponding repo diff", seq and cursor, "binary DRISL-CBOR encoding over WebSockets", "primarily designed for server-to-server"); unit 14 beat 4 (Blacksky "runs a full-network relay", also listed as atproto.africa on the AT Stack page; partial relays); unit 16 beat 2 (no signatures or Merkle nodes, filter by collection); unit 17 beats 1, 2 and 4 (service DID, skeleton of post URIs, declaration record in the author's repo); unit 18 beats 1 to 3 and 5 (#atproto_label, atproto-accept-labelers); unit 19 beat 1 (clientid is a metadata URL, no clientsecret), beat 3 (PKCE, PAR, DPoP all required), beat 5 ("slightly restricted permissions"); unit 20 beats 1, 2, 4 and 5; unit 21 beats 1 to 4 (public getRepo, getRecommendedDidCredentials includes "a PDS-managed atproto signing key", adversarial migration); unit 22 beats 1 to 4 (per-space permissioned repos on the author's PDS, space authority is a DID, "access control not confidentiality", no relay); unit 23 (non-archival relays, Hubble by fig of microcosm, $20,000 grant, no blobs, deletion respected, 43+ million repositories, and Hubble is live today); unit 24 beat 1 (working group created April 2026 with the four scope items as the blog lists them; the charter additionally names an encoding and export format and an operational-considerations document).

Structure

S1. Fifteen card metaphors are never spoken. Unspoken: unit 1 (bag), 2 (id number, name tag), 3 (page with three rows), 4 (ledger, master keys), 5 (ledger box, seal), 7 (fingerprint), 9 (dictionary), 10 (telephone directory), 13 (pipe of numbered cards), 15 (cached query), 16 (three taps on one pipe; only the product name Tap is spoken), 19 (key cut for one lock), 20 (key labeled with one drawer), 21 (moving house, boxes), 24 (map). Partly spoken: 6 (address, not street), 8 (only goes up, not sealed page), 12 (shelf, not parcel), 23 (copy, not library). Fully spoken: 11, 14, 17, 18, 22. The guide: "A unit card's metaphor must be spoken in the script." Either say each once, on the beat whose screen draws it, or change the card to what the script says. Unit 7's "fingerprint" is the easiest: the AT URI and strongRef texts both use the word.

S2. Unit 4 carries two ideas and skips the one in its title. Beats 1, 2 and 5 teach the did:plc mechanism; beats 3 and 4 teach governance and replicas, which unit 24 beat 2 repeats. Meanwhile the recovery window (A4) is absent. Recommend: beat 3 "The log is kept by a central directory. Not a blockchain: a server that checks and stores signed operations." Beat 4 becomes the recovery beat from A4. Move the Organization and replicas to unit 24 only (with A1's fix). The idea sentence then reads: "A did:plc identity is a log of signed operations whose genesis hash is the DID; rotation keys above the signing key can replace it, and for three days can undo a change."

S3. Unit 4's misconception is not addressed. The card says "did:plc is a blockchain. Addressed at beat 3 (a directory, a log)", but beat 3 only says "kept by a central directory". web.plc.directory: "It does not make use of any blockchain or cryptocurrency technology." Say it (S2's beat 3 does).

S4. Check questions and screens that need words the script never says. Unit 19: the check question asks "What binds an access token to one app instance?", whose answer is DPoP, but PAR, PKCE and DPoP appear only on the beat 3 screen; narration says "A pushed request, a code challenge, and tokens bound to the app's own key." Either speak the three names once or ask "What is a stolen token useless without?" Unit 5's check question uses "commit", first spoken in unit 8; unit 5's script says "signed root". Say "commit" in unit 5 beat 4 or ask about "the signature on a version". Unit 17 beat 2's screen shows "the request: who is asking" (the signed request), which the narration never mentions; cut it from the screen or add "signed by your host" to the line.

S5. Terms used before they are defined. "labeler" in unit 18 beat 1 before beat 2 defines it (move "whatever the labeler defines" to after beat 2, or say "whatever the service that issued it defines"). "scopes" in unit 19 beat 5, one unit before unit 20 defines a scope. "OAuth" is first spoken in unit 19 beat 5 and never defined; say in beat 1 "This is OAuth, the same login handshake the web uses." "backfill" in unit 23 beat 2 is jargon nobody defined; say "cannot load the past". "DID" is never expanded; add "a decentralized identifier" in unit 2 beat 1. Acronyms the posts will use but the scripts never speak (NSID, MST, CAR, XRPC) should be defined in the post of the unit that introduces the thing.

S6. Unit 16's idea statement and beats disagree after A6. The card's idea ends "choose by how much you must verify"; beat 3 sells history. Once A6 lands, the unit pivots cleanly on verification, with backfill as Tap's verified way of getting the past.

S7. Idea-map dependencies are incomplete. Unit 21 "needs: 4, 11" also uses blobs (12) and events (13). Unit 23 "needs: 14" also leans on migration (21) and backfill (16). Unit 24 "needs: all" is fine. Cosmetic, but the map is what the next reorder will be checked against.

S8. Unit 17 is a Bluesky application feature and should say so. Feed generators are app.bsky lexicons, not core protocol; the AT Stack page: "App Views are application-level tooling, rather than inherent parts of the AT protocol." The Anytwo lesson: name the product when a unit is about one app. Open beat 1 with "In Bluesky, a custom feed is a service with its own DID." Labels (unit 18) are protocol level and need no such clause.

S9. Screens with more than four things. Unit 24 beat 1: an IETF chip plus four scope items (five). Unit 8 beat 1: a card plus four fields (borderline, same as the last series). Unit 20 beat 2: four chips plus the beat 1 chip if it stays (five).

S10. Screen labels the narration does not say. Unit 19 beat 3 (PAR, PKCE, DPoP, see S4); unit 13 beat 4 "a cursor" (narration: "your last number"); unit 17 beat 2 "who is asking".

Order and one-idea checks otherwise pass: every unit's needs are met earlier; unit 22's "public by default" opener is a setup, not a second idea; units 16 and 23 each pair two things under one claim and stay inside the guide's test. Every misconception other than unit 4's is addressed on the beat the card names.

Sources

Q1. The quotes are real. 218 quoted fragments in "Recorded source statements" were matched against the page dumps after normalizing quote marks. 216 are verbatim. Two differ trivially: the feed-generator quote drops the README's backticks around SkeletonFeedPost[]; and the Spaces quote "there is no concept of a relay for data stored in a space. Applications will sync space data directly from PDS hosts." joins two sentences that are not adjacent on the page (between them: "For public data, the relay helps provide applications access to all of the data across the network. However for spaces, it's often not desirable to rebroadcast content.") without an ellipsis. Add one.

Q2. Recorded statements that are now stale, with the newer line to record. PLC Organization: add web.plc.directory "In 2026 the PLC Organization was founded..." and plcred.org "established in early 2026" (A1). Jetstream: the recorded post is October 2024; add Introducing Bluesky Protocol Services (2026-08-13) on Jetstream v2 network replay (A6). Spaces: add the 2026-10-14 post ("lock in the core primitives", "launch atproto Spaces this year", "Spaces sync without a relay") (A18). Relays: add Upcoming Relay Transition (2026-01-24) for the bsky.network cutover and "strict verification will still be disabled for now" (A8, A9).

Q3. Spoken claims with no recorded statement behind them. Unit 17 beat 3, AppView hydration (A21). Unit 17 beat 5, "A popular feed can run from someone's own small server": true, and the 2026-04-14 post "Serving the For You Feed ... from their living room" would support it; record it. Unit 18 beat 4, who decides label behaviour (A11). Unit 16 beat 1's event rate (A7). Unit 11 beat 4 "on a small server": the self-hosting page does not say small; the PDS repository README does. Unit 7 beat 4's reply reference: not in any recorded statement; record com.atproto.repo.strongRef ("A URI with a content-hash fingerprint", uri and cid required) and the AT URI best-practice line.

Q4. Three page dumps are empty and two listed pages are missing. feeds.txt, labelers.txt and bskylabels.txt are two bytes each (docs.bsky.app has moved to bsky.network), and applications and permissions-guide from the fetch list were never written. The two weakest claims in the series (A11, A21) are exactly the ones those pages would have settled.

Q5. One recorded page contains an error the author did not quote. The AT Stack page says "Relays handle all of your events, like retrieving large-scale metrics (likes, reposts, followers), content discovery (algorithms), and user search", which describes AppViews; the same page's Relays section says relays "do not interpret records". The curriculum quotes the right sentences. Worth a note so nobody "fixes" unit 14 from that line later.

Other

O1. Unit 8 beat 1 and screen omit version and prev. The simplification is fine for the ear; the post should say the commit also carries a format version and a usually-null previous-commit pointer, so a developer who opens a commit is not surprised.

O2. Unit 11 says the host holds your signing keys; it usually holds a rotation key too. The AT Stack page lists "secret key management: AT signing key, and PLC rotation key" among PDS duties. One clause in unit 11 beat 1 ("and usually a rotation key, unless you keep your own") makes A17's "a rotation key you kept yourself" land.

O3. Unit 15 beat 4 is true but, after unit 23, incomplete. "A new app can index records that existed before it did" now means fetching from each PDS (or Hubble), not from a relay. The post for unit 15 should say where the old records come from, since unit 23 will tell the viewer the relay does not have them.

O4. Unit 10 beat 4 is right and a developer will want one more word. The forwarded request carries a short-lived token signed with the account's signing key that the PDS holds ("issued and signed by the user's identity"). "The host signs the forwarded request on your behalf" is accurate; the post can name it an inter-service token.

O5. Unit 22 could mention the new group host role in its post. The 2026-10-22 post describes "a DID with a bunch of permissioned spaces under it" and group hosts that "do for groups what a PDS does for users". Not needed in the video; useful in the post and in unit 24's "open front".

Verdicts

Pass: units 1, 2, 3, 5 (one word, A24), 6, 9 (one phrase, A23), 10, 11, 13 (one line, A22), 15. Back to 1b: units 4 (A1, A4, S2, S3), 7 (A3), 8 (A2), 12 (A5), 14 (A9, A10), 16 (A6, A7, S6), 17 (A21, S8), 18 (A11), 19 (A12, A13, S4), 20 (A15), 21 (A16, A17), 22 (A18), 23 (A20), 24 (A1, A8, A19). Fifteen units also need their metaphor spoken or their card changed (S1).

Class

Count

Ids

Wrong

3

A1 (PLC Organization already founded), A2 (your host can forge you), A5 (blob limits are the schema's too)

Stale

4

A6 (Jetstream v2 has history), A7 (event rate), A18 (Spaces churn), A19 (focus forecast)

Overstated or imprecise

12

A3, A4, A8, A9, A10, A11, A12, A13, A15, A20, A22, A24

Unsupported by recorded sources

1

A21 (AppView hydrates)

Omission producing a wrong model

4

A4 (recovery window), A16 (activation), A17 (own rotation key), A23 (fifth schema kind)

Structure

10

S1 to S10

Sources

5

Q1 to Q5

Other

5

O1 to O5

Accuracy findings: 24. Length: all 24 units inside target. Recorded quotes: 216 of 218 verbatim, the other two trivially off.

Verdict. The series teaches the right model of identity, repositories and sync, and its sources are honest; it is not ready for Phase 2. Fix the two wrong models first (A2 in unit 8, A3 in unit 7), because every later unit about hosts and verification builds on them. Then bring the four stale facts up to October 2026 (A1, A6, A18, A19 with A7 and A8), give unit 4 the recovery mechanism its title promises (A4, S2), and speak or drop the fifteen unspoken metaphors (S1). The rest is one clause each.

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime

Attributes
name
AT Protocol Curriculum Review
summary
Independent Phase 1d text review of the 24-unit atproto curriculum (revision 1, 2026-10-22) against the recorded atproto.com, web.plc.directory, IETF and feed-generator sources, plus live checks. 24 accuracy findings (3 wrong, 4 stale, 12 overstated or imprecise, 1 unsupported, 4 omissions), 10 structure findings, 5 source findings. 14 units go back to 1b, 10 pass; every unit is inside its target length; 216 of 218 recorded quotes are verbatim.