Carte des chantiers, ordonnée par surface développeur
Établie le 2026-08-21, sur décision BDFL. Relevé fait contre le code, pas contre des
notes : chaque chiffre vient de statuts.toml, de xtask/controleurs-reference.toml ou
d’une mesure de couverture datée.
Le compte exact, remesuré le 2026-08-21 :
xtask/controleurs-reference.tomlporte 26 entrées d’écart sur 24 crates —air-libc-capietair-libc-spawnen cumulent deux chacune. Et 19 crates déclarentrole = "manager"quand 11 seulement en portent un : l’écart entre les deux nombres EST la dette du rang 1.
Pourquoi cette carte existe
Air produit un système d’exploitation : des APIs et des bibliothèques sur lesquelles des
développeurs tiers bâtiront des applications. Le produit est libair — la surface publique
stable —, pas air-sshd, qui est un démonstrateur et une fonction de forçage.
Or la roadmap au 2026-08-15 ordonnait les chantiers par ce qui débloque air-sshd, reléguant
les managers manquants au point 5. Le démonstrateur devenait la spécification. Cette carte
inverse l’ordre : le domaine décide la forme de l’API, le consommateur la prouve par l’usage.
Le symptôme, chiffré
Sur les 1078 branches non couvertes de la couche 2, air-sshd en concentre 553 — la
moitié. Un démonstrateur qui porte la moitié de la dette de test de la couche qu’il démontre
n’est pas un démonstrateur : c’est un monolithe qui implémente en son sein ce qui aurait dû
être des APIs. Refonder air-sshd et air-launchd sur des managers éprouvés ne les retarde
pas : cela réduit leur surface de test au profit de tests d’API réutilisables.
La règle qui commande tout le reste — et elle est déjà décidée
ADR-149 D4 :
Le contrat d’API d’Air, ce sont les managers de domaine et les types publics. Tout le reste est interne, et Air se réserve d’en changer la structure comme bon lui semble.
et D9 :
Une crate de couche N ne peut atteindre la couche N-1 que par ses managers de domaine et ses types publics. Jamais un contrôleur, jamais une fonction libre.
Ce que cette règle achète : un contrat de dix ans envers les développeurs sans figer le cœur. Tant que le tiers ne voit que des managers, les contrôleurs restent à nous — on peut les refondre de version en version. Le jour où un tiers dépend d’un contrôleur, ce contrôleur devient contractuel, et le cœur est gelé avec lui.
Les rangs :
| Rang | Visibilité | Rôle |
|---|---|---|
| Couche 0 | N’exporte rien | La couche mince où unsafe est toléré. Aucun développeur externe n’y accède |
| Contrôleur (couche 1) | Public ou interne | Sémantique objet sur une portion du système, un objet du noyau |
| Manager (couche 1) | Public | Coordonne les contrôleurs. C’est la surface offerte aux tiers |
Rang 1 — Les huit managers dus et non écrits
Chaque domaine existe et fonctionne, mais sans porte : le tiers n’a que des fonctions libres, donc aucune garantie.
| Crate | Dette | Ce qu’un tiers vient y chercher |
|---|---|---|
air-account | 38 opérations libres | Identité, comptes, groupes, credentials. Le domaine où une API laxiste devient une faille |
air-terminal | 21 — « cas extrême » | Console, TTY. Prérequis d’ADR-008/ADR-026 (air-tui), donc de tout l’applicatif texte |
air-thread | 14 | Fils d’exécution — toute application non triviale |
air-config-compile | 10 | La porte d’entrée stricte du Principe 11 |
air-crypto | 7 | Signer, chiffrer, vérifier |
air-config | 4 | Lecture de configuration |
air-device | surface complète, point d’entrée manquant | Le moins cher des huit |
air-sandbox | mécanisme livré, médiateur absent | La cage. Bloqué sur une décision, pas sur du code — voir ci-dessous |
air-sandbox — ce qui bloque est une décision, et elle s’est réduite
Cette note le classait « à instruire, pas à coder ». Le mot était juste, la source manquait : l’instruction avait déjà eu lieu, et elle est datée.
L’amendement d’ADR-112 du 2026-08-03
énonce l’écart sans le farder : le mécanisme est livré et éprouvé — AirSandbox pose la
cage, air-sshd la consomme en production —, mais il ne joue pas le rôle de médiateur de
domaine qu’ADR-077 attend d’un manager. Et il nomme les quatre questions qui bloquent :
la largeur des enveloppes par défaut, la forme de l’arbitre de lancement, l’articulation manifeste/octroi, le sort des binaires de provenance étrangère.
Il conclut : « Dépendance de décision, pas de code. » ADR-150 (2026-08-03) en a levé trois
en fixant le manifeste, l’octroi et la procédure d’arbitrage à l’exec. Restait bloquante la
largeur des enveloppes par défaut — elle détermine ce que le manager doit savoir poser.
Ce qui a changé le 2026-08-21
Deux constats réduisent cette dernière question sans la trancher :
1. La dérivation octroi → cage est déjà écrite — en couche 2. air-bundle/src/ceiling.rs,
crate déclarée contrôleur, traduit un octroi en catégories d’appels système. La règle qui dit
quelle cage mérite quel octroi vit donc un étage au-dessus de celui qui doit la tenir. Ce n’est
pas une conception qui manque : c’est une inversion de couche.
2. air-launchd::launch() porte des faits de domaine qui ne lui appartiennent pas. Il pousse
dans chaque cage deux catégories qu’aucun octroi ne demande — RuntimeBootstrap, sans quoi
« tout binaire natif Air meurt par SIGSYS juste après ARCH_SET_FS », et l’autorisation
d’exécuter son propre programme. Ce sont des faits sur toute cage posée avant un execve,
pas sur le lancement. Le commentaire dit comment ils ont été trouvés : « Constaté en supervisant
un vrai service pour la première fois, le 2026-08-14 : Started puis ChannelClosed, rien
d’autre. »
Un fait de domaine logé chez un appelant se paie une fois par appelant, et dans la monnaie la
plus chère : un processus qui meurt muet. Le prochain — le worker privsep d’air-sshd, le shell
d’Air, une application tierce — le redécouvrira par le même SIGSYS sans trace noyau.
Tranché le 2026-08-22 (BDFL). La question ne portait pas sur « la cage par défaut d’une application » — une application empaquetée n’en a jamais, la sienne vient de son octroi. Elle portait sur la racine d’une chaîne, et la seule racine encore ouverte était la session de l’utilisateur.
Décision : le lanceur médie, la session ne plafonne pas
(ADR-150 D12) — motif déjà
implémenté par ADR-147 pour air-sshd. L’enveloppe de session est C + Landlock $HOME en
lecture-écriture, /usr et /lib en lecture, sans réseau (D13) : 65 appels système sur 92.
air-sandbox n’a donc plus de dépendance de décision. Il reste à écrire, pas à instruire.
Le patron existe et a été éprouvé deux fois : air-uring et air-keystore ont été soldés
le 2026-08-11. Manager additif, route parallèle maintenue, descellement unique en fin de
campagne. On rejoue la méthode, on ne la réinvente pas.
Rang 2 — Les seconds chemins : la condition du contrat de dix ans
Seize entrées où la mauvaise porte est celle qu’on emprunte — 4 fuites, 7 bridges, 3 vocabulaires impurs, 2 services consommés. Ce ne sont pas des sujets ouverts : ce sont des violations de règles déjà décidées (ADR-149 D5, D7, D9).
- Quatre fuites de contrôleur vers la couche 2 —
air-handle,air-poll,air-random,air-stdio, consommés directement parair-libc-*,air-sshd,air-keystore-cli. Soit ils deviennent des managers, soit leurs consommateurs passent par la bonne porte. Découvertes par le gate : l’audit manuel d’ADR-077 ne regardait pas le graphe de consommation. - Sept bridges qui court-circuitent le manager — et le registre le dit lui-même : « ils le
font au nom des développeurs C, c’est-à-dire là où la surface est la plus stable et la plus
visible ». C’est la non-conformité de
libair_c: à la v1, elle ne doit s’appuyer que sur nos managers. Même exigence pour le PAL de lastdRust. - Trois vocabulaires impurs —
air-base-core,air-config-schema,air-jsonexposent des opérations dans des crates qui ne devaient porter que des types. - Deux services qui exposent quand même une API (
service-consomme, ADR-149 D7) —air-agent, dontair-sshdconsomme le protocole en dépendance livrée, etair-launchd, consommé parair-launch-temoinen dev seulement. « Ni un démon ni un outil utilisateur n’a vocation à exposer une API réutilisable ; qu’une crate les LIE signifie qu’ils portent une bibliothèque qui mérite d’être extraite » (BDFL, 2026-08-05).
Rang 3 — Les frameworks applicatifs, rien n’est commencé
| Domaine | ADR | Dépend de |
|---|---|---|
| TUI / console | 007 air-console, 008 air-tui, 026 contrat 1.0 | air-terminal (rang 1) |
| Vues / UI | 009 air-view/air-ui, 003 Wayland, 018 imagerie | — |
| Accessibilité | 017 — « citoyen de première classe » | 002 (modèle d’objet) |
| i18n | 016 | — |
| Fondations développeur | 084 air-url | — |
Le chaînage est l’argument : air-terminal débloque air-tui, qui débloque tout
l’applicatif console.
Rang 4 — Sécurité active
- ADR-089 —
SecurityManager: aujourd’hui une réservation, pas une spécification. Décision BDFL du 2026-08-21 : la couture se pose dès les managers du rang 1. L’ajouter après coup exigerait de rouvrir huit surfaces publiques — donc de rompre le contrat qu’on vient d’établir. - ADR-156 (Landlock v7) et ADR-148 (namespaces) élargissent le confinement offert au tiers.
Ce qui est explicitement différé
La clôture d’air-sshd : ADR-119 (extensions SFTP), ADR-120 (hostbased), ADR-121
(provisioning), ADR-107 (pipeline linux-air), et le passage sous air-launchd. Ainsi que
les additifs réseau/crypto 078 à 083, qui servent le même front.
Ce n’est pas un abandon : c’est l’ordre inverse. air-sshd sera refondé sur les
managers une fois ceux-ci éprouvés, et son périmètre de test se réduira d’autant.
Critères d’acceptation d’un manager
Ce qu’une session doit rendre, et sur quoi une PR sera refusée :
- La surface du DOMAINE, pas celle de l’appelant. Un manager qui n’expose que les verbes
qu’
air-sshdappelle est un manager raté, même vert. - Le type force la vérification :
#[must_use]partout,Resultlà où ça peut échouer — jamais unbool, jamais un code, jamais une sentinelle. Newtypes qui rendent le mauvais paramètre incompilable (parse, don’t validate, Principe 4).Option<T>au lieu des sentinelles du noyau (ADR-021). - Les erreurs restituent ce que le noyau a dit, au lieu de l’aplatir.
- Le refus est précis : nous sommes intransigeants sur les données, donc le message doit dire quoi est non conforme — sans quoi le développeur devine.
- Les chemins d’échec sont testés, et prouvés capables d’échouer : saboter la garde, montrer le test rouge, restaurer. Un test jamais vu rouge n’a rien démontré.
- Fuzzing sur toute API qui lit de l’externe (
CLAUDE.md, non négociable). - Les tests sont pédagogiques : fonctions utilitaires nommées, noms qui énoncent la propriété, commentaire disant ce qui casserait si la garde tombait. Nos tests sont le code que nous serons en droit d’attendre des développeurs.
- Doc-tests qui se lisent comme du code d’appelant — c’est le seul exemple que le compilateur vérifie.
Premier mouvement
| Machine | Chantier | Pourquoi celui-là |
|---|---|---|
| hydrogen | air-terminal → AirTerminalManager | Le cas extrême (21 opérations), et la clé de tout l’applicatif texte |
| speedy | air-account → AirAccountManager | La plus grosse dette (38), et le domaine de l’identité |
| carbon | Vérification seule | Étalon de couverture — jamais de production |
| raspi-srv-2 | Vérification aarch64 | Et la mesure du délai de « prêt » d’ADR-161 D6, non mesuré |
Licence du document : MPL 2.0