Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rapport de design — AirCom (IPC natif d’Air), incrément 0

Statut : note de travail exploratoire (non engageante). Cadre la conception d’AirCom — l’IPC natif d’Air (ADR-001, décision immuable) — avant de l’implémenter, sur le modèle du travail réseau (reseau-architecture-crates-fr.md) qui a précédé ADR-091. Livre : une reconnaissance de l’existant couche 0/1/2, un design sans-IO, un squelette buildé + prouvé, et les questions ouvertes pour l’ADR/spec. AirCom mérite une spec dédiée (ADR-001 §« Statut futur » l’annonce) ; ce rapport en est le matériau d’entrée.

Décisions structurantes émergentes → à trancher par le BDFL (voir §7) : le wire format (recommandation : Cap’n Proto, déjà tranché ADR-040), le modèle de capability (recommandation : fd-vers-connexion SCM_RIGHTS), le découpage/nommage des crates, et quatre lacunes de primitives couche 1 qui conditionnent l’IPC complet. Conformément à la consigne de mission, on s’arrête au design pour ces points — on ne bâtit pas l’IPC complet.

Auteur : Thierry DELHAISE. Date : 2026-07-12.


1. Résumé exécutif (recommandations)

SujetRecommandationBaseConfiance
Wire formatCap’n Proto (schema-first, zero-copy, versioning ABI). Codec placeholder au squelette tant que le schéma n’est pas figé.ADR-040 (déjà tranché), ADR-001, exception 80 % mutualiséeHaute — déjà décidé
Control planeUnix SOCK_SEQPACKET (frontières préservées + FD passing). Piloté par air-async (io_uring).macro-architecture §B, ADR-001Haute
Data planememfd_create + mmap SHARED + F_ADD_SEALS, fd partagé via SCM_RIGHTS. Zero-copy.ADR-001, macro-archHaute
CapabilityUn fd vers une connexion AirCom = la capability. Unforgeable par sémantique noyau ; pas de token/crypto. Révocation = fermeture fd ; délégation = re-SCM_RIGHTS.ADR-010, macro-arch §B, ADR-001 §117Haute
DécoupageDeux crates : air-com-proto (cœur sans-IO, no_std+alloc, fuzzable) + air-com (pilote air-async).ADR-091 §2.1/§2.3 ; renforcé par air-async = crate stdMoyenne (nommage à trancher)
AnatomieMotif sans-IO 9 composants (ADR-091), absences marquées.ADR-091 (normatif)Haute

Quatre lacunes de primitives couche 1 bloquent l’IPC complet (pas le squelette). Aucune ne requiert le descellement de la couche 0 (les primitives kernel existent déjà, scellées) — ce sont des façades/ops additives couche 1/2, mais elles conditionnent les incréments suivants. Détail §6. On s’arrête au design ici.


2. §A — Reconnaissance de l’existant

2.1 Transport — ce qui existe

air-socket (couche 1) — sockets BSD synchrones, no_std, zéro-C.

  • Unix domain sockets : AirUnixStream (SOCK_STREAM), AirUnixListener, AirUnixDatagram (SOCK_DGRAM) — crates/air-socket/src/unix.rs:42/47/52. Adresses AirUnixAddress::from_path et from_abstract (namespace abstrait) — address.rs:236/253.
  • FD passing SCM_RIGHTS : AirUnixStream::send_fd(BorrowedFd) / recv_fd() -> OwnedFdunix.rs:100/119 (via sendmsg/recvmsg, CMSG_CLOEXEC). Surface générale engine::{send_message, receive_message} (engine.rs:189/202) + socket_pair(domain, kind, proto) (engine.rs:312).
  • Précurseur sans-IO : le client DNS — codec pur crate::dns (build_query/parse_response, fuzzé) séparé du pilote resolver.rs. C’est le patron à reproduire (ADR-091 §… le nomme explicitement).
  • Modèle d’ownership des fds : le fd est possédé par le registre air-handle (engine.rs:302/318) ; AirSocket n’expose que as_fd() (BorrowedFd) et into_raw_fd() (RawFd, le registre garde l’ownership).

air-async (couche 2) + air-uring (couche 1) — l’exécuteur io_uring que consomme AirCom (son 1er gros consommateur).

  • Exécuteur : Runtime::{new, spawn, block_on, handle} + block_on libre (crates/air-async/src/lib.rs:441/551/576/419). Mono-thread, !Send.
  • I/O socket : TcpListener/TcpStream — noms « Tcp » mais agnostiques au fd (from_owned(OwnedFd), accept/read/write = IORING_OP_ACCEPT/RECV/SEND sur un BorrowedFd). AF_UNIX fonctionne aujourd’hui via from_owned (les tests d’air-async le prouvent : tests.rs wrappe une paire UnixStream).
  • Multishot + provided buffers : incoming() (accept multishot), recv_multishot(&BufferGroup) (net.rs:70/168).
  • Timers : roue de timers (sleep/interval/timeout), fichiers (read_at/write_at/fsync).
  • Ops io_uring exposées par air-uring (arm_*) : timeout, socket, connect, accept, receive, send, read, write, fsync, accept_multishot, receive_multishot (crates/air-uring/src/lib.rs:643..930).

Data plane (memfd/mmap) — couche 0 (air-sys-syscall::mem, ::fs) :

  • memfd_create(&CStr, MemfdFlags) (mem.rs:1051, flags CLOEXEC|ALLOW_SEALING), ftruncate (fs.rs:1980), mmap_file(fd, len, off, prot, MapFlags::SHARED) (mem.rs:274), munmap (mem.rs:695), add_seals/get_seals (F_ADD_SEALS, fs.rs:2486/2504), MmapRegion::from_file (région partagée Arc, io_uring-compatible, avec futex_word intra-région — mem.rs:510/601).

Wire format — Cap’n Proto déjà dans le workspace : capnp = "=0.26.0" (pin strict, pur Rust, zéro dep transitive, zéro C), consommé par air-config-schema / air-config-compile. Codegen commité (regenerate.sh + capnpc hors du chemin de build critique, ADR-025). Décidé par ADR-040, explicitement mutualisé avec AirCom.

Capabilities — la doctrine (aucun code encore) :

  • ADR-010 : entitlements déclaratifs signés, deny-by-default, 4 familles (dont AirCom) ; air-launchd (couche 5) applique au lancement et distribue les capabilities AirCom initiales par FD passing. « Pas d’autorité ambiante ».
  • macro-architecture §B (le plus précis) : « Une capability AirCom est un handle opaque non-falsifiable. Techniquement : FD vers une connexion AirCom, plus métadonnées de type » ; control plane = SEQPACKET ; délégation = re-SCM_RIGHTS (modèle seL4 / Mach ports) ; révocation = fermeture fd ; capability implicite universelle = air-registry.

2.2 Transport — ce qui manque (lacunes couche 1)

Voir §6 pour le détail et l’impact. En bref :

  1. Aucune façade couche 1 sur memfd/mmap (les primitives sont couche 0, scellées ; air-com couche 2 ne peut pas les toucher — check-layers).
  2. Aucun FD passing asynchrone : air-uring n’a pas d’arm_recvmsg/ arm_sendmsg (le passage de fd SCM_RIGHTS sur io_uring n’existe pas). Seul le chemin synchrone air-socket existe.
  3. Aucun wrapper SEQPACKET dans air-socket (couche 0 a bien SocketType::SeqPacket = 5, mais L1 ne l’enveloppe pas).
  4. Aucun pont OwnedFd entre air-socket (fds possédés par le registre) et air-async (from_owned(OwnedFd)) — modèles d’ownership incompatibles.

3. §A (suite) — décisions de reconnaissance

3.1 Wire format : Cap’n Proto (recommandé — déjà tranché)

Cap’n Proto satisfait toutes les exigences AirCom d’ADR-001 : schema-first, versioning à règles testables en CI (ADR-012), zero-copy natif (mmap du data plane), FD passing de 1ʳᵉ classe (tables de capabilities capnp). La dépendance est déjà auditée et mutualisée (règle 80 %, docs/EXCEPTIONS.md) — aucune nouvelle exception pour AirCom. Le workflow codegen commité (regenerate.sh) est prouvé sur air-config-schema et réutilisable tel quel.

Le cœur (Framer/Codec) reste sans-IO : capnp est un runtime de (dé)sérialisation octets↔message pur, sans I/O — il vit dans le cœur air-com-proto, fuzzable. Le squelette utilise un codec placeholder trivial (tag + u64) pour prouver la frontière Codec↔Framer↔StateMachine sans figer prématurément le schéma AirCom (le .capnp viendra avec la spec).

3.2 Modèle de capability : fd-vers-connexion, SCM_RIGHTS (recommandé)

Aligné mot pour mot sur macro-architecture §B et ADR-001 §117 :

  • Une capability = un fd vers une connexion AirCom (SEQPACKET), + métadonnées de type. Unforgeabilité par le noyau : on ne fabrique pas un fd qu’on n’a pas reçu. Pas de token, pas de nonce, pas de crypto, pas de memfd/sealing pour la capability elle-même (le sealing sert au data plane).
  • Distribution initiale par air-launchd (couche 5) via SCM_RIGHTS selon les entitlements signés. Délégation p2p par re-SCM_RIGHTS à travers AirCom lui-même. Révocation par fermeture du fd côté serveur.
  • Renfort : la sandbox io_uring couche 0 (RestrictionSet::from_entitlements, io_uring/sandbox.rs:125) est le « double verrou » — la couche 5 traduira les entitlements signés en RestrictionSet. (Non implémenté ; point d’intégration.)

Conséquence pour le cœur sans-IO : le cœur ne détient aucun fd. Le Session Context (#8) porte les métadonnées de capability (le quoi) ; le pilote détient les fds (le comment). Le squelette matérialise cette frontière (SessionContext::grant_capability, placeholder).


4. §B — Design sans-IO d’AirCom (le cœur du rapport)

4.1 Deux étages (ADR-091 §2.1)

                ┌──────────────────────── air-com-proto (couche 2) ────────────────────────┐
  octets  ───▶  │  Framer → Codec → StateMachine → (Session Context)                        │  ───▶  messages typés
  (feed)        │  CŒUR SANS-IO — pur, no_std+alloc, FUZZABLE, zéro socket/async/horloge     │       + octets (poll_transmit)
                └───────────────────────────────────────────────────────────────────────────┘
                                                   ▲  API (pas d'I/O)
                ┌──────────────────────────────────┴──────── air-com (couche 2) ────────────┐
                │  PILOTE I/O — la SEULE partie qui touche un socket : câble le cœur à        │
                │  air-async (io_uring). Control plane (SEQPACKET) + data plane (memfd).      │
                └───────────────────────────────────────────────────────────────────────────┘
                                                   ▲
                                          air-async (io_uring) / air-socket

4.2 Anatomie canonique à 9 composants appliquée à AirCom

#ComposantRôle dans AirComSqueletteCible (spec)
1FramerDélimiter les messages control-plane✅ préfixe de longueur u32 (transport flux)Trame = 1 recvmsg sur SEQPACKET (le noyau délimite ⇒ Framer trivial)
2Codec(dé)sérialiser méthode/args ↔ message typé✅ placeholder Ping/Pong (tag+u64)Cap’n Proto (schema-first, versioning ADR-012)
3StateMachineÉtats connexion + requête/réponse✅ discipline requête→réponseMulti-états : ouverture/handshake, requêtes concurrentes, fermeture, erreurs protocolaires
4HandshakerÉtablissement + négociationmarqué absentNégociation de version de schéma + jeu d’extensions (la capability, elle, est déjà établie via SCM_RIGHTS)
5Flow ControllerBack-pressure explicite (reactive streams)marqué absentCrédits/fenêtres pour le streaming data-plane (ADR-001 §back-pressure)
6MultiplexerPlusieurs requêtes/canaux sur un fdmarqué absentIds de requête, isolation inter-canaux (façon canaux SSH / streams h2)
7Timer ManagerÉchéances (timeout requête, keepalive)marqué absent (dans le cœur)Horloge injectée dans le cœur ; roue air-async dans le pilote
8Session ContextÉtat/params/capabilities par connexion✅ role/id + compteur de capabilitiesMétadonnées de capabilities négociées, secrets zeroïsés au drop, zéro fuite inter-sessions
9Extension hooksPoints d’extension (entitlements, négos)marqué absentRegistre de hooks à interface étroite (entitlements ADR-010, extensions de schéma)

Les 5 absences sont marquées explicitement (marqueurs unité channel::{Handshaker, FlowController, Multiplexer, TimerManager, ExtensionHooks}

  • commentaires // NO …) — « on retrouve toujours les mêmes cases » (ADR-091 §2 règle 3).

4.3 Control plane vs data plane (le découpage clé d’AirCom)

  • Control plane — petits messages de signalisation/appel de méthode. Transport SEQPACKET (frontières préservées, FD passing). C’est le domaine du cœur sans-IO (Framer/Codec/State) — la surface hostile fuzzée.
  • Data plane — charges volumineuses (images, frames, buffers GPU). Transport memfd + mmap SHARED (scellé), dont le fd est passé sur le control plane par SCM_RIGHTS : zero-copy inter-processus. Le cœur ne voit que la référence (id/offset/len) ; le pilote fait le mmap. Back-pressure explicite (Flow Controller, #5) pour le streaming.

Cette séparation est la raison d’être du refus de D-Bus (ADR-001 §« zero-copy et back-pressure ») : le control plane reste léger, le data plane ne copie jamais via un broker.

4.4 Découpage en crates (recommandé)

Deux crates (choix retenu, cf. §7 pour le nommage) :

  • air-com-proto (couche 2, #![no_std]+alloc) — le cœur sans-IO. Deps : air-base-core seulement (+ capnp à terme). Fuzzable en isolation (fuzz/ : une cible par parseur — Framer, Codec, Handshaker).
  • air-com (couche 2, std) — le pilote sur air-async. Deps : air-com-proto, air-async, air-sys-types.

Pourquoi deux crates plutôt qu’un seul proto/+io/ (les deux sont permis par ADR-091 §2.3) : air-async est un crate std (Rc/RefCell/thread-locals) ; un crate unique forcerait le cœur à hériter de std et empêcherait le no_std visé par ADR-091, et ferait entrer air-async dans le build de fuzz du cœur. La séparation en crates garantit un cœur no_std réellement isolé (fuzz sans socket, sans exécuteur). C’est aussi le précédent quinn-proto/quinn.


5. §C — Squelette minimal + preuve (livré, host gnu)

Crates créés ([package.metadata.air] layer = 2 pour les deux) :

crates/air-com-proto/           — CŒUR SANS-IO (no_std + alloc)
  src/framer.rs   (1) préfixe de longueur, borné MAX_FRAME_LEN, fuzz-ready
  src/codec.rs    (2) Ping/Pong placeholder (cible : Cap'n Proto)
  src/state.rs    (3) machine requête/réponse (transitions illégales rejetées)
  src/session.rs  (8) Session Context (role/id/capabilities)
  src/channel.rs  assemblage feed/poll_transmit + marqueurs d'absence 4/5/6/7/9
crates/air-com/                 — PILOTE I/O (std, sur air-async)
  src/io.rs       serve_pong / request_pong / unix_stream_pair (+ tests)
  examples/ping_pong.rs         — PREUVE exécutable

Preuve — aller-retour Ping → Pong entre deux services in-process sur une paire de sockets Unix pilotée par air-async (io_uring) :

$ cargo run -p air-com --example ping_pong
AirCom incrément 0 — Ping(0x0a1cc0de12345678) → Pong OK (1 requête servie)
$ echo $?
0

Portes vertes (host x86_64-unknown-linux-gnu, carbon) :

  • cargo fmt --check ✅ · cargo clippy -- -D warnings ✅ (lints deny arithmétique/cast respectés : checked_*/try_from, zéro as).
  • cargo test ✅ — 19 tests (18 cœur : framer/codec/state/session/channel ; 1 pilote : round-trip de bout en bout) + 3 tests pilote additionnels (2 allers- retours, pair fermé, mapping errno).
  • cargo xtask check-layers VERT ✅ — air-com/air-com-proto ne sautent pas en couche 0 (arêtes 2→2 et 2→1 conformes M ∈ {N-1,N}). Le seul advisory restant est l’escape hatch cible-only préexistant d’air-libc-capi (ADR-087).
  • cargo machete ✅ (zéro dep inutilisée). Zéro dépendance externe.
  • Couverture ✅ — cœur air-com-proto 94–100 %/fichier (session.rs/state.rs = 100 %) ; pilote air-com/io.rs = 93 % régions / 97 % lignes / 100 % fonctions (> 90 %, cible couche 2). Reste non couvert : les branches d’échec transport rares (write partiel à 0, échec socketpair).

Un seul bloc unsafe dans tout le livrable : la conversion de fd bootstrap std OwnedFd → air OwnedFd (io.rs, // SAFETY: présent, idiome copié des tests d’air-async). Le cœur air-com-proto n’expose aucune fn unsafe.

Choix de squelette assumés (et pourquoi) :

  • Transport = SOCK_STREAM (pas SEQPACKET) : air-socket n’a pas de wrapper SEQPACKET (lacune §6.3) ; on re-délimite au Framer.
  • Bootstrap de la paire via std::os::unix (pas air-socket) : pas de pont OwnedFd propre depuis air-socket (lacune §6.4). air-async pilote ensuite toute l’I/O — c’est bien « piloté par air-async ».
  • Pas de FD passing dans la preuve : le passage de fd asynchrone n’existe pas (lacune §6.2) et le data plane memfd n’a pas de façade L1 (lacune §6.1). Les démontrer proprement (dans les règles de couche) exige de combler ces lacunes d’abord — d’où l’arrêt au design.

6. Lacunes de primitives couche 1 (STOP-and-report)

Aucune de ces lacunes ne requiert le descellement d’une couche 0 scellée : les primitives kernel (memfd/mmap/seal/sendmsg/recvmsg/SEQPACKET) existent toutes en couche 0 et y sont scellées/testées. Ce sont des façades/ops additives couche 1 (et une future arête couche 1→0 dans air-uring). Mais elles conditionnent l’IPC complet — d’où le report avant de bâtir.

6.1 Façade couche 1 de mémoire partagée (memfd + mmap + seals) — manquante

Les primitives sont couche 0 (air-sys-syscall::mem/::fs). air-com (couche 2) ne peut pas les appeler (check-layers interdit 2→0). air-memory (couche 1) n’expose qu’un raw_mapping anonyme (piles de threads) ; son backing mmap/MmapRegion est explicitement différé (backing.rs, « heap en v1 »). → Requis : un module/crate couche 1 « shm » packageant memfd_create → ftruncate → mmap SHARED → add_seals → poignée typée » (candidat : étendre air-memory, ou un air-shmdédié). **Bloque le data plane zero-copy.** Envisager aussi une varianteAirHandleKind::Memfd/Shmdansair-handle`.

6.2 FD passing asynchrone (recvmsg/sendmsg io_uring) — manquant

air-uring expose arm_{socket,connect,accept,receive,send,read,write,fsync,…} mais pas arm_recvmsg/arm_sendmsg (donc pas de SCM_RIGHTS sur io_uring), et aucun escape-hatch SQE brut. Le passage de capability/fd async est donc impossible sans ajout. → Requis : arm_sendmsg/arm_recvmsg (+ take_*) dans air-uring (couche 1, arête 1→0 conforme) + futures SendMsg/RecvMsg dans air-async (couche 2). Le chemin synchrone existe (air-socket::AirUnixStream:: {send_fd,recv_fd}) et peut servir de secours pour le bootstrap de air-launchd, mais l’IPC en régime établi veut l’async. Bloque les capabilities async + data-plane fd async.

6.3 Wrapper SEQPACKET dans air-socketmanquant

La couche 0 a SocketType::SeqPacket = 5 mais air-socket n’enveloppe que SOCK_STREAM/SOCK_DGRAM (unix.rs). Le control plane AirCom veut SEQPACKET (frontières préservées ⇒ Framer trivial, FD passing). → Requis : un AirUnixSeqpacket (ou paramétrer les wrappers Unix par SocketType). Additif couche 1. Contournement squelette : SOCK_STREAM + Framer à préfixe.

6.4 Pont OwnedFd air-socketair-asyncmanquant

air-socket possède ses fds via le registre air-handle (into_raw_fd garde l’ownership) ; air-async::TcpStream::from_owned veut un OwnedFd. Il n’y a pas de conversion propre (risque de double-close). → Requis : air-socket exposant un into_owned_fd() (via air_handle::AirHandle::into_owned_fd, qui existe), ou air-async acceptant une source de fd du registre. Additif couche 1. Contournement squelette : bootstrap via std::os::unix (idiome des tests air-async).

Note de gouvernance : air-socket (couche 1, campagne ADR-069) est vraisemblablement scellé — 6.3 et 6.4 le touchent et pourraient donc exiger un descellement couche 1 (décision BDFL), contrairement à 6.1/6.2 qui sont des ajouts sur des crates couche 1/2 en cours de construction (air-memory partiel ; air-uring/air-async incréments actifs). À arbitrer.


6.5. Lacunes couche 1 comblées (mise en œuvre — branche feat/aircom-couche1-gaps)

Statut : fait. Les quatre lacunes du §6 sont comblées, host-first, à rigueur couche 1 (100 % de couverture lignes sur le neuf, aucune fonction unsafe exposée, check-layers vert). Aucun descellement couche 0 (les primitives kernel existaient déjà, scellées). Le seul descellement est couche 1 additif sur air-socket (§6.3/6.4) — zéro changement sémantique des API STREAM/DGRAM existantes ; à re-sceller couche-1-v2.1 après revue BDFL.

#LacuneSolution (crate, couche)API ajoutéePreuve
1Façade shmair-shm (nouvelle crate, couche 1)AirShmSegment (create/from_owned_fd/add_seals/seals/as_fd/into_owned_fd/map_readonly/map_writable) + AirShmMap/AirShmMapMut (vues possédées &[u8]/&mut [u8])9 tests, 100 % lignes ; write→seal→read + adoption de fd
2SCM_RIGHTS asyncair-uring (couche 1) + air-async (couche 2)Reactor::{arm_sendmsg,arm_recvmsg,take_sendmsg,take_recvmsg} ; TcpStream::{send_message,recv_message} (futures SendMsg/RecvMsg)envoi/réception d’un fd async en loopback socketpair (couche 1) + aller-retour in-process (couche 2) ; orphelin recvmsg annulé et libéré au CQE
3SEQPACKETair-socket (couche 1, descellement additif)AirUnixSeqpacket / AirUnixSeqpacketListener (connect/pair/bind/accept/send/recv/send_fd/recv_fd)11 tests : frontières préservées, troncature, FD passing, accept
4Pont OwnedFdair-socket (couche 1, descellement additif)AirSocket::{into_owned_fd,from_owned_fd} (+ sur AirUnixStream/AirUnixSeqpacket)aller-retour registre→sortie→ré-adoption sans double-close

Choix de conception clés :

  • Lacune 1 → crate dédiée air-shm, pas air-memory. air-memory est un crate d’allocateurs (arène/pool/slab) + comptabilité ; un segment memfd partageable (un fd, pas un allocateur) est un concern distinct. air-shm : zéro dépendance externe, no_std+alloc, air-base-core/air-sys-syscall/ air-sys-types.
  • Lacune 4 — NON, ce n’était pas un vrai conflit d’ownership. Le diagnostic redouté (« registre air-handle vs ownership air-async incompatibles ») ne se matérialise pas : le primitif air_handle::AirHandle::into_owned_fd existe déjà (ADR-069, pensé pour l’interop) — il retire l’entrée du registre et transfère l’ownership seul au OwnedFd (pas de double-close), et le type de fd est identique des deux côtés (air_sys_types::fd::OwnedFd). Le pont est donc un simple move : AirSocket::into_owned_fd → TcpStream::from_owned. Contrepartie assumée et documentée : le fd cédé devient invisible à air_handle::live_count/ kind_of et au close() de la façade libc — c’est le rôle d’un escape-hatch d’interop. Pas de STOP nécessaire.
  • Lacune 2 — couche 0 déjà prête. air_sys_syscall exposait déjà submit_send_message/submit_receive_message (SCM_RIGHTS, OwnedOp::SendMsg/ RecvMsg, modèle orphelin S1) ; l’ajout couche 1 est une paire de façades minces arm_*/take_*, arête 1→0 conforme — zéro descellement couche 0.

Preuve d’intégration réunissant les 4 lacunes : air-com::capability (capability_and_shm_dataplane_roundtrip) — un aller-retour AirCom entre deux services in-process passe un fd (capability) par SCM_RIGHTS async sur un control plane SEQPACKET (bridgé OwnedFd) portant un segment shm scellé zero-copy ; le pair mmap le segment via le fd reçu et lit la charge utile (assert d’égalité). Seul le fd a traversé le socket — la charge n’est jamais copiée.

Barrière : check-layers vert (55 crates, air-shm=1 ; seul advisory = l’escape-hatch cible-only préexistant d’air-libc-capi, ADR-087) ; fmt/clippy -D/tests verts ; machete vert. La couverture root/sudo de la barrière complète est laissée à l’arbitrage CI (la couverture lignes per-crate du neuf est à 100 % en local).


7. Questions ouvertes pour l’ADR / la spec AirCom

  1. Nommage des crates — à trancher (ADR-029). La macro-architecture §B nomme air-aircom (transport+runtime), air-aircom-schema (compilateur), air-aircom-codegen, air-registry. La mission et ce squelette ont utilisé air-com (pilote) + air-com-proto (cœur). Divergence à réconcilier : garder air-aircom (cohérence macro-arch) ou acter air-com / air-com-proto (+ air-com-schema) ? La spec AirCom doit figer le jeu de crates (proto/pilote/schema/codegen/registry) et leurs couches.
  2. Codec Cap’n Proto : figer le premier schéma AirCom (.capnp) et la politique de versioning (champs réservés, InterfaceV2 coexistant — ADR-012). Réutiliser le workflow regenerate.sh/codegen commité d’air-config-schema.
  3. Modèle d’objet (ADR-002) : AirCom transporte des invocations sur des AirObject. Articuler la StateMachine (#3) + Multiplexer (#6) avec le modèle d’objet C-ABI et le cx.capability::<T>() de macro-arch §B.
  4. air-registry (couche 5) : format du handshake de découverte, capability implicite universelle, one-fd-par-service vs canal bootstrap multiplexé (macro-arch laisse ouvert).
  5. Transport control plane : confirmer SEQPACKET (vs STREAM+framing) et trancher la lacune §6.3.
  6. Data plane : conventions de memfd (taille, sealing obligatoire ? F_SEAL_WRITE pour un partage read-only ?), et l’API L1 shm (§6.1).
  7. Sync vs async (ADR-038) : AirCom expose-t-il une API synchrone de 1ʳᵉ classe (via air-socket) en plus de l’async (air-async) ? Le cœur sans-IO le permet « gratuitement ».
  8. Régime de fuzz (ADR-091 §5) : cibles fuzz/ par parseur (Framer, Codec capnp, futur Handshaker) ; model-based testing de la StateMachine ; virtual clock pour le Timer.

8. Conclusion

AirCom s’inscrit proprement sur l’existant : air-async pilote AF_UNIX aujourd’hui, Cap’n Proto est déjà auditée et mutualisée, le modèle de capability (fd + SCM_RIGHTS) est cohérent ADR-010/ADR-001, et le motif sans-IO ADR-091 s’applique naturellement (control plane fuzzable, data plane zero-copy à part). Le squelette prouve la boucle cœur↔pilote↔io_uring de bout en bout (Ping→Pong, exit 0, check-layers vert). Quatre lacunes de primitives couche 1 (façade shm, FD passing async, SEQPACKET, pont OwnedFd) conditionnent l’IPC complet et appellent des décisions d’arbitrage/descellement — on s’arrête donc au design, avec une spec AirCom à ouvrir (ADR-001 l’annonce) pour figer nommage, schéma, registre et transport.


Licence du document : MPL 2.0 — note de travail, exploratoire (non engageante).