Ce que j'aurais aimé qu'on me dise sur AT Protocol et Bluesky
Cet article est une traduction française de « What I Wish Someone Had Told Me About AT Protocol and Bluesky » écrit par Rob Ricci et publié le 26 août 2026 sur son blog blog.ricci.io. Traduit et republié avec son autorisation.
Je m’intéresse à atproto (le protocole sur lequel tournent Bluesky, Blacksky et bien d’autres applications — dont pckt, qui héberge ce blog !) depuis environ un an. Je suis loin d’être un expert, mais j’ai lu beaucoup de documentation et de discussions, examiné différentes versions des schémas d’architecture, et passé beaucoup de temps à réfléchir aux implications en matière de passage à l’échelle, de décentralisation et d’autres aspects de la conception et de l’exploitation. Je fais tourner mon propre PDS. J’ai écrit des clients qui consomment le firehose des relais et analysent les données. Je pensais avoir une assez bonne vision de l’ensemble.
Et puis, un dimanche matin, certains services de Bluesky sont tombés en panne pendant quelques heures. On en apprend beaucoup plus sur un système par ses pannes que par son fonctionnement normal, et j’ai appris que beaucoup de choses que je croyais savoir n’étaient pas fausses, à proprement parler, mais incomplètes pour comprendre comment cet écosystème fonctionne réellement en pratique.
Je me suis senti un peu bête d’avoir mis si longtemps à apprendre certaines de ces choses, ou du moins à vraiment intérioriser ce qu’elles impliquent. Ce ne sont pas des secrets, ni rien de ce genre. Il ne s’agit pas d’étaler le linge sale de l’écosystème. Plein de gens savaient déjà tout cela. Mais pas moi, et peut-être pas vous non plus, et c’est pour ça que je le couche par écrit.
Quand on apprend le Web, on découvre HTML, CSS, HTTP(S), et cela suffit pour construire et servir des applications web. Mais un jour, quelque chose se casse, et… on découvre le DNS. Parce que c’est toujours le DNS. Non pas que le DNS soit mauvais (bon, d’accord, un peu, par certains côtés), mais parce qu’il est tellement central, et que c’est l’un des endroits où se cache une grande partie de la complexité d’Internet. Quand ça marche, super. Quand ça ne marche pas — ou que ça marche comme prévu, mais pas comme vous le pensiez — eh bien, il est temps d’apprendre comment fonctionne le DNS. Désolé.
Ceci ne sera pas une vue d’ensemble d’atproto, ni une exploration exhaustive de tous ses recoins. Je vais partir du principe que vous connaissez (ou croyez connaître) l’architecture au niveau, disons, de l’article de Dan Abramov « There Are No Instances In atproto » (traduit en français ici), qui est une excellente lecture.
Je le redis : je ne suis pas un expert. J’ai observé des comportements, lu du code, parcouru des spécifications, mais d’autres personnes connaissent tout cela bien mieux que moi. Les corrections, les nuances, etc. sont les bienvenues, et je mettrai ce billet à jour. Je veux aussi être clair : je décris comment les choses fonctionnent aujourd’hui, du mieux que je peux. D’après mes échanges avec des gens d’atproto, tout ceci ne correspond pas nécessairement à la façon dont c’est conçu pour fonctionner, et certaines choses décrites ici sont, en un sens, extérieures à atproto lui-même et spécifiques à Bluesky. Mais on a le système qu’on construit, pas le système qu’on conçoit.
Alors voyons ce qui est construit.
Le PDS n’est pas tout à fait là où je le pensais
Sur le schéma d’architecture standard, on voit un dépôt (repo) dans un PDS, les données circulent (éventuellement via un relais) vers un AppView qui agrège les données d’un tas de dépôts, et l’application elle-même interroge l’AppView pour obtenir cette… euh, vue.
Cette dernière étape passe quelque chose sous silence. Dans bien des cas (mais pas toujours !), l’application parle en réalité au PDS, et non (directement) à l’AppView.
Le PDS sert de proxy entre l’application et l’AppView.*Note du traducteur : ce comportement est documenté sur atproto.com, dans la spécification XRPC, section « Service Proxying ». Quand une application veut faire un appel d’API vers l’AppView, elle contacte le PDS de l’utilisateur, qui, la plupart du temps (patience, on y revient dans une minute), transmet la requête à l’AppView et renvoie la réponse.
Il y a de bonnes raisons de procéder ainsi. L’une des principales est l’authentification : l’utilisateur, via l’application, s’authentifie auprès du PDS, qui est ce qui détient les clés capables d’authentifier l’utilisateur auprès du reste du réseau. Donc : une requête arrive de l’application, le PDS sait qu’elle vient vraiment de l’utilisateur parce qu’elle passe par une session authentifiée. Le PDS fabrique un jeton capable de prouver à l’AppView que la requête vient bien de l’utilisateur, et l’envoie avec la requête. Le client peut ainsi ignorer tout un tas de choses compliquées : clés, scopes, audiences, et j’en passe. Génial ! Vous avez une application complexe qui doit parler, de manière authentifiée, à un tas de services différents ? C’est le problème du PDS. S’assurer que les jetons nécessaires pour parler à chaque service restent frais avant d’expirer ? Le problème du PDS.
Mais une chose que le schéma d’architecture standard ne laisse pas deviner, c’est que si votre PDS est en panne ou se comporte mal, l’un des modes de défaillance possibles est que vous ne pouvez plus parler à l’AppView, même si vous êtes déjà connecté.
Rien n’empêche l’application de parler directement à l’AppView, et de fait, c’est souvent le cas pour les appels qui ne nécessitent pas d’authentification. Vous pouvez aussi demander au PDS de vous fournir les jetons nécessaires, pour les transmettre vous-même à l’AppView. Mais certaines applications, à commencer par l’application Bluesky (aussi appelée social-app), sont conçues pour utiliser le proxy.
Le PDS dépend de l’AppView de Bluesky — en quelque sorte
Je n’ai cessé de dire « l’ » AppView, et j’espère que ça vous a agacé, parce que non, il n’y a pas un AppView unique. Dans le cas particulier d’une application indépendante de type Bluesky (comme Blacksky), plusieurs AppViews tournent et peuvent être utilisés. Plus généralement, d’autres applications peuvent implémenter leurs propres AppViews avec des API très différentes de celui de Bluesky, ou fonctionner sans AppView du tout.
Mais.
Il existe des appels qu’on peut faire à un AppView qui ressemble à celui de Bluesky, via le PDS, et qui sont vraiment utiles. Alors évidemment, les applications s’en servent. Probablement même quand l’application en question n’est pas Bluesky, même si (en fait, surtout si) l’application n’a pas son propre AppView.
Un bon exemple est getProfile : les données qui circulent dans l’Atmosphère désignent les comptes par leur did. Mais vous ne voulez pas afficher le did dans l’interface, vous voulez des choses comme le handle de l’utilisateur, et sans doute d’autres informations comme son nom d’affichage. Qui peut vous dire tout ça ? Eh bien, un moyen est de demander à un AppView ! Il a un point d’API qui vous le dira !
Comment le PDS sait-il à quel AppView transmettre cette requête ? Eh bien…
Il y a un en-tête, défini par l’application, dans chaque requête, qui indique où elle doit être transmise. Mais que se passe-t-il si l’application omet cet en-tête ? Le PDS de référence, fourni par Bluesky, a un AppView par défaut configuré — celui de Bluesky, évidemment, mais vous pouvez le reconfigurer pour pointer vers un autre. Certaines autres implémentations de PDS semblent avoir le même comportement par défaut — mais pas toutes.
Parce que, avoir un PDS qui pointe par défaut vers un AppView particulier, ça lie un peu ce PDS à cet AppView, non ? D’une manière qui surprend pas mal de gens qui hébergent leur propre PDS, et qui est assez contraire à la vision du monde « il n’y a pas d’instances dans ATProto ».
Disons que je monte mon propre PDS. Je laisse les réglages par défaut. Eh bien, beaucoup d’applications — y compris beaucoup qui ne sont pas Bluesky — vont finir par envoyer un tas d’appels d’API à l’AppView de Bluesky si elles n’en ont pas spécifiquement demandé un autre. Si l’AppView de Bluesky est en panne, alors ces applications ne fonctionnent plus pour moi à cause d’un réglage dans mon PDS. Tiens donc.
Mais regardons à quoi ressemble concrètement ce mode de défaillance. L’AppView de Bluesky est en panne, donc l’application principale Bluesky est en panne. Mais moi, je suis un mec cool, j’ai mon propre PDS, et je sais qu’avec atproto, je peux simplement me connecter à n’importe quelle autre application avec le même compte. Alors je file sur l’application web Blacksky et je m’y connecte. Mais certains des appels qu’elle fait (les détails dans une seconde) retombent sur l’AppView par défaut de mon PDS ! Donc, tout est plutôt cassé ! Je dois reconfigurer mon PDS pour vraiment utiliser correctement l’application Blacksky ! Les gens qui sont sur le PDS de Blacksky s’en sortent plutôt bien, parce que leur PDS (je suppose) pointe déjà vers l’AppView de Blacksky !
Donc oui, je peux me connecter à d’autres applications avec mon unique compte, mais celles qui fonctionnent réellement dépendent de… l’endroit où mon compte est réellement hébergé et de la façon dont c’est configuré.
Ce n’est pas vraiment le monde sans instances qu’on croyait avoir, si ?
Bon. Alors, peut-être que cette histoire d’« AppView par défaut » est une mauvaise idée. Je connais au moins une implémentation de PDS qui n’en a pas : vous dites au PDS vers où les appels doivent être relayés, ou vous obtenez une erreur.
Mais que faire, quand on est une application sans AppView propre, si le PDS auquel on parle n’a pas d’AppView par défaut ? Hé, moi je veux juste récupérer quelques noms d’affichage ! Mais c’est… flou. Toujours utiliser celui de Bluesky ? Avoir une liste et en chercher un qui marche ? Laisser l’utilisateur choisir ? Tant pis pour vous, il faut avoir le vôtre ? Autre chose ? Quelle est la sémantique censée s’appliquer ici ?
Ah, et : j’écris tout cela en termes de pannes. Mais des AppViews différents peuvent renvoyer des données différentes, et (dans la partie du monde où il en existe un par défaut), c’est votre PDS qui en décide, donc… ce que vous voyez réellement dans une application peut dépendre de la configuration de votre PDS. Probablement pas ce à quoi la plupart des gens s’attendraient.
RAW(r) : une partie de la sémantique applicative de Bluesky est implémentée dans le PDS
Je pensais autrefois que le PDS n’était qu’un endroit où étaient stockées les données et les clés de l’utilisateur. Comme on l’a vu plus haut, ce n’est pas toute l’histoire. Et on n’a pas fini, parce qu’en fait, le PDS implémente une partie de l’application Bluesky.
Les appels au PDS ne se contentent pas nécessairement de relayer vers un AppView ou un autre service. Certains exécutent une logique substantielle en local. Il y a ceux auxquels on s’attend, comme la lecture ou l’écriture dans un dépôt.
Mais il y en a d’autres qui m’ont surpris, et beaucoup tournent autour du Read-After-Write (RAW), la lecture après écriture. Voici pourquoi.
Vous écrivez le meilleur shitpost du monde et vous appuyez sur « envoyer ». Naturellement, vous voulez voir le fruit de votre labeur immédiatement. Mais ce n’est pas comme ça qu’atproto fonctionne. Vous l’écrivez dans votre dépôt. Il part dans le firehose, passe (probablement) par un relais, atteint un AppView, se fait indexer, et ensuite les gens le voient quand ils demandent à l’AppView (et/ou à un générateur de flux) quelque chose qui est censé le renvoyer. C’est sacrément rapide, la plupart du temps ! Mais ce n’est pas instantané. Et parfois, ça se bouche, et ça peut prendre un moment. Moi, je veux voir mon chef-d’œuvre maintenant !
Le PDS de référence a pensé à vous, avec ses optimisations RAW. Parfois, pour certains appels, il remarque que l’enregistrement que vous venez d’écrire ne fait pas partie de la réponse renvoyée par l’API, et il l’y glisse discrètement. Le méchant AppView a répondu 404 à votre œuvre ? Le PDS fabriquera un faux fil de discussion, rien que pour vous, rien que pour l’instant.
Je suis sûr que ça a été fait pour la réactivité. C’est bien plus agréable quand les choses se produisent immédiatement, et le protocole lui-même ne peut pas garantir les délais de livraison.
Mais réfléchissons à ce que cela implique.
Cela signifie que votre expérience de l’application est, encore une fois, déterminée par votre PDS. Vous utilisez une implémentation alternative qui ne fait pas ce tour de passe-passe ? Elle semblera moins réactive, même si elle diffuse vos contenus sur le réseau tout aussi vite. Mais pire : cela intègre encore plus de sémantique applicative dans le PDS. Cet appel était-il censé renvoyer cet enregistrement ? C’est de la sémantique applicative ! Le PDS doit savoir quels appels d’API renverraient cet enregistrement, et comment. Et disons que Bluesky modifie son AppView pour ne plus rattacher à leur parent les réponses contenant l’émoji 🖕 ? Vous aurez l’impression d’avoir réussi à adresser un doigt d’honneur à votre adversaire. Dans le mille !
J’ai fait exprès d’être idiot dans cette section (et SEULEMENT dans cette section, naturellement), mais le point sérieux, c’est que de véritables comportements applicatifs vivent dans le PDS — ce que vous voyez, quand vous le voyez, et même si vous le voyez tout court, dépend de votre PDS. Si Bluesky veut un jour changer quoi que ce soit à tout ça, ce que vous verrez dépendra de si votre PDS a été mis à jour, ou même s’il implémente ces fonctionnalités. Et si une autre application a besoin de ce genre de fonctionnalités, ou pourrait en tirer profit ? Il lui faudra convaincre Bluesky, et tous les autres, de les ajouter à leurs implémentations de PDS.
J’ai vu des bugs que vous, humains, ne pourriez pas croire…*Note du traducteur : le titre original, « I've Seen Bugs You People Wouldn't Believe... », détourne la réplique de Roy Batty dans Blade Runner.
Avant de conclure, regardons un exemple de la façon dont tout ce trafic qui transite par le PDS, et tout le traitement qu’il lui applique, rend possibles des bugs particulièrement pernicieux.
Dans l’appel getFeed, il y a deux étapes : rechercher le générateur de flux, puis le transmettre (avec un jeton qui lui est destiné) à l’AppView. Le PDS de référence de Bluesky a ce qui semble être un bug, où la première moitié de tout ça ignore l’AppView qu’on lui a indiqué via l’en-tête de proxy, et parle simplement à l’AppView par défaut du PDS, quel qu’il soit. Donc, oui, pendant une panne de Bluesky ? Ouvrez l’application Blacksky, très bien, mais si votre PDS est encore configuré pour utiliser l’AppView de Bluesky, vous ne pouvez pas charger les flux.
J’espère vraiment que c’est un bug, qu’il sera corrigé, et que je pourrai mettre ce paragraphe au passé. Mais c’est fou qu’un bug de PDS puisse avoir ce genre d’effet.
Ah, et pendant qu’on y est : cette recherche de flux en deux étapes avec le jeton supplémentaire, c’est… eh oui, de la sémantique applicative spécifique à Bluesky. Mais chaque PDS a intérêt à l’implémenter, sinon les gens qui essaient d’utiliser Bluesky depuis celui-ci pourraient ne pas réussir à charger les flux. Ou du moins certains d’entre eux.
Et ce n’est pas comme ça que je pensais que ça marchait.
PDS is Love, PDS is Life
Je me suis concentré ici sur le PDS parce que je pensais vraiment, sincèrement, que le PDS se contentait de stocker des données et de garder mes clés privées. Je pensais qu’en faisant tourner le mien, je m’affranchissais de toute dépendance à l’infrastructure de Bluesky. Je pensais que le choix de l’implémentation était surtout une affaire de goût, pas quelque chose qui conditionnait le fonctionnement des applications. Je pensais comprendre les modèles de défaillance : Bluesky pouvait tomber, je n’aurais qu’à passer à une autre application, et tout irait bien.
L’histoire réelle n’est pas aussi simple.
La panne la plus récente s’est clairement mieux passée que les précédentes. Et maintenant, je crois que je sais à peu près pourquoi. Certaines personnes ont pu, pour l’essentiel, continuer comme si de rien n’était. Mais cela dépendait du PDS sur lequel elles se trouvaient, ce qui n’est pas la façon dont c’est censé fonctionner. Les choses sont bien plus enchevêtrées qu’elles n’en ont l’air sur les schémas d’architecture.
Et la quantité de sémantique applicative embarquée dans le PDS ? Ça, je ne l’avais pas vue venir.
S’il vous plaît, parlez-moi de tout ce qui m’échappe encore. Je crois que je veux savoir (quoique, peut-être pas).
Chargement…