Roadmap — clôture de la couche 1 pour la libc C et le PAL Rust
✅ PLAN ACCOMPLI (2026-07-10) — ce document est désormais HISTORIQUE. La couche 1 a été scellée
couche-1-v1.0le 2026-07-03 (ADR-062) puis re-scellée additivement jusqu’àcouche-1-v1.9(v1.1→v1.9 : errno_location, signaux/futex, air-account, credentials/drop_to_user, air-handle+moteur socket, Managers de domaine, spawn_process, introspection thread cible). Ses deux toits sont prouvés : la libc C-ABI (~256 symboles) et le PAL Rust —stdlie et tourne sur la libc d’Air, zéro glibc, 2 arches (jalon M5 atteint). Ce document décrit le plan d’origine ; le statut vivant est dansetat-avancement.md, et la prochaine phase =air-sshd(ADR-074). Le tableau de bord §8 ci-dessous reflète l’état au moment du plan, pas l’état courant.
Plan détaillé §-numéroté (les specs/audits y renvoient via « §5.3 P0.x »). Le statut vivant (ce qui est fait/en cours/à venir) est tenu dans le document de suivi
etat-avancement.md, pas ici — ce document décrit le plan, le tableau de bord §8 en donne l’ossature.
But. Faire une passe de production complète de la couche 1 avant de la sceller (
couche-1-v1.0), plutôt que sceller/desceller au fil de l’eau comme on l’a subi sur la couche 0. On n’éliminera pas tout descellement futur — on transforme les descellements structurels (« il manque une brique entière ») en descellements additifs mineurs (« il manque une fonction dans une brique existante »).Principe directeur. La couche 1 a deux toits qui s’y assoient — la libc C-ABI (ADR-046/047/053) et le PAL Rust (la
stdcible*-linux-air, ADR-049/052). Seule la couche 1 consomme la couche 0 (ADR-052) : les deux toits sont au-dessus, clients, jamais dedans. Chaque brique de cette roadmap doit répondre à « quelle fonction libc et/ou quelle primitive PAL la réclame ? » — sinon elle attend. La complétude est pilotée par la demande des deux consommateurs, pas par une exhaustivité abstraite.Sources. Inventaire couche 1 (crates + specs
docs/specs/layer-1/),docs/notes/audits/RAPPORT-CONSOLIDE-libc-fr.md(41 familles musl), ADR-046/047/053 (libc),docs/notes/audit-icu4x-rust-pur-fr.md(i18n), ADR-049/052/055/056 (PAL/runtime). Statut de départ :main = 2689d69.
Légende
- ☐ à faire · ◐ partiel/en cours · ☑ fait
- Criticité : 🔴 bi-consommateur (libc ET PAL — rigueur maximale, dette figée si erreur) · 🟠 mono-libc · 🟡 mono-PAL · ⚪ interne/packaging
- Colonnes Libc / Pal : ● consommateur direct · ○ indirect · — non concerné
1. Ce qui est DÉJÀ en place (socle acquis)
Ne pas refaire ; à auditer face-libc/face-PAL avant le sceau (§5).
| Brique | Rôle | L | P | no_std | Statut |
|---|---|---|---|---|---|
air-base-core | erreurs, ids, chemins-octets, temps monotone, encodage, log (ADR-054) | ● | ● | oui | ☑ |
air-crypto | hash, AEAD, signatures, AirRandom (CSPRNG getrandom) | ● | ● | non¹ | ☑ |
air-socket | TCP/UDP/Unix + résolveur DNS maison | ● | ● | oui | ☑ |
air-filesystem | canonicalize, écriture atomique, watcher, glob | ● | ● | oui | ◐ (find_regex différé ; prendra une dép sur air-stdio, §2.D.2) |
air-memory | arène/pool/slab + comptabilité | ● | ○ | oui | ◐ (backing mmap différé) |
air-device | énumération/surveillance (uevent/evdev) | ○ | ○ | oui | ☑ |
air-process | clone3/pidfd/execve/signaux/drop_privileges | ● | ● | oui | ☑ |
air-env | environnement process (octets), zéro-dép (ADR-055) | ● | ● | oui | ☑ |
air-alloc | allocateur global malloc↔GlobalAlloc (ADR-056) | ● | ● | oui | ☑ |
air-libm | math flottante no_std (façade libm, ADR-057) | ● | ○ | oui | ☑ |
air-config* | compilateur config + backends /etc (passwd/shadow/hosts/resolv/fstab) | ● | ○ | oui | ☑ |
air-runtime | TCB/TLS/reloc/crt0/fork/spawn (ADR-052) — prouvé on-target 2 arches | ● | ● | oui | ◐ (async runtime dans la passe, §4-K) |
air-base-capi | frontière ABI C (libair-base.so) | ● | — | n/a | ◐ (T1 fait ; T2/T3 §4-J) |
¹ air-crypto/air-base-lib tirent encore des deps qui bloquent le no_std strict → visés par §2.
Bi-consommateurs déjà acquis (🔴 mais faits) : air-alloc, air-env,
air-crypto::AirRandom, air-process, air-socket, air-runtime (TCB/TLS).
Ils restent sacrés : toute évolution passe par RFC une fois scellés.
2. Chantiers RESTANTS — bi-consommateurs 🔴 (rigueur maximale, chemin critique)
Ce sont les briques qui portent le plus de risque : une erreur d’API casse les deux toits, et la garantie ABI libc (10 ans, Principe 8) fige la dette.
2.A — i18n : Air utilise icu4x (Option V, ADR-059) 🔴 · L● P●
Sert la libc (ctype, locale, collation, strcoll, normalisation,
segmentation, calendriers) et le PAL/str (to_uppercase, normalisation,
comparaison Unicode). Brique sensible — mais plus le long pole.
DÉCISION BDFL (ADR-059, data-backée). Vérification empirique faite : la fermeture icu4x compile pour
*-linux-air(--release+default-features = false; LSTM inclus,libmOK) — la réécriture du socle n’est pas nécessaire. Air utilise icu4x (extension exception ADR-016), possède l’APIair-stringdual-face + le pipeline de données (à terme). ⇒ le §2.A se réduit à un chantier no_std, pas une réimplémentation.
- ☑ 2.A.1
air-base-lib→#![no_std]— dernière crate cœur non-no_std.#![cfg_attr(not(test), no_std)]+extern crate alloc(posé #152, ADR-048 ; confirmé ici, fermeture icu prouvée on-target). Débloque la fermeture couche 1 complète (i18n comprise) pour la cible. - ☑ 2.A.2 deps
icu_*d’air-base-lib→default-features = false(coupe transitivement la featurestd; 6 lignes du[workspace.dependencies]racine). Fermeture (air-base-lib+ icu + socle) prouvée compilable on-targetx86_64/aarch64-unknown-linux-airen release (build-std=core,alloc) — le repli logging debug d’icu_providerest inactif en release. - ☐ 2.A.3
air-stringdual-face : ajouter la face C-ABI (libc) au-dessus de l’AirStringexistant (le moteur existe déjà via icu4x). - ☐ 2.A.4 Re-sonder la fermeture couche 1 complète pour
*-linux-air(post-no_std air-base-lib) — preuve on-target. - ☐ 2.A.5 (optionnel/différé) pipeline datagen Air (host, réutilise le datagen icu4x sur sources CLDR/UCD) si Air veut maîtriser ses propres tables —
compiled_datasuffit pour démarrer. Abandonné (ADR-059): vendoring des 6 utils, port du socle, port decalendrical_calculations— inutiles, icu4x compile tel quel.air-libm(☑) reste surface math Air publique mais n’est pas requis par icu (icu tirelibmviacore_maths).- Segmentation LSTM incluse (décision BDFL) : fournie par
icu_segmenterfeatureauto— compile déjà pour la cible (prouvé).
2.B — air-thread en no_std + futex maison 🔴 · L● P●
Sert pthread_mutex/rwlock/cond (libc) et std::sync + std::thread (PAL).
C’est aussi la zone non-déterministe discutée pour l’instrumentation (loom).
- ☑ 2.B.1
MigrerDÉJÀ FAIT : la migration a eu lieu de facto au passageAirMutex/AirRwLock/AirSemaphoredu backendstd::sync→ futex maison#![no_std]d’air-thread(#182, ADR-055) —sync.rsmontre les 3 primitives surair_sys_syscall::futex+AtomicU32, « aucune dépendance àstd::sync». (L’inventaire INDEX/etat-avancement était périmé sur ce point.) - ☐ 2.B.2 Spawn Air-natif : closure boxée via
air-alloc(☑) — retirer lestd::threadconditionnel (cfg(not(target_env="air"))). - ☐ 2.B.3 Couvrir les branches de contention de façon déterministe — voir §3 (loom) : à cadrer avant le sceau, car sceller fige la surface.
2.C — Temps (monotone + horloge murale) 🔴 · L● P●
clock_gettime/time/nanosleep/gmtime (libc) ↔ Instant/SystemTime (PAL).
- ◐ 2.C.1 Confirmer que
AirInstant/AirSystemTime(base-lib core) couvrent monotone + mur +nanosleep,no_std-propres, et exposables aux deux faces. (Le calendaire au-dessus dépend de 2.A.3.)
2.D — air-stdio : brique stdio/console bas-niveau 🔴 · L● P●
FILE* (libc) ↔ std::io::{Stdin,Stdout,Stderr} (PAL). Le niveau brut
(handles fd 0/1/2 + isatty + verrou) est partagé ; le moteur FILE*
bufferisé et printf/scanf restent libc (§4). Aujourd’hui non spécifié côté
PAL (rapport PAL : « stdio bas-niveau MANQUE »).
- ☐ 2.D.1 Créer
air-stdio(brique dédiée, décision BDFL) : handles standard partagés (lecture/écriture brutes,isatty, verrou par flux, sécuritéatfork),no_std, consommée par les deux toits. - ☐ 2.D.2
air-filesystemprend une dépendance surair-stdio(décision BDFL) — les E/S de plus haut niveau s’appuient sur les handles standard.
2.E — Finitions des briques acquises 🔴/🟠
- ☐ 2.E.1
air-memory: backing mmap (différé) — piles/TLS des threads spawn. - ◐ 2.E.2
air-crypto: rendreno_std-strict (auditer les deps qui bloquent). FAIT :default-features = falsesursha2/sha3/aes-gcm/chacha20poly1305/argon2/ed25519-dalek(coupe la fuitestdtransitive ; features réactivées = strict nécessaire, aléa toujours viaAirRandomcouche 0). Preuve on-targetx86_64-unknown-linux-air(release,build-std=core,alloc) : fermeture crypto entièreno_std, zérolibc/std. Reste (chantier dédié) : suraarch64,cpufeatures(dép non-optionnelle, détection ARMv8) lielibc(getauxval) qui n’a pas de profilenv=air→ cheminlibc-freeair_auxval(AT_HWCAP)à fournir. Détail :crates/air-crypto/DEPENDENCIES.md.
3. Étude PRÉ-SCEAU — instrumentation déterministe (à trancher avant §5)
Non une brique livrée : un outillage test-only à cadrer avant le sceau (le sceau fige la surface, autant avoir les seams dans la bonne forme). Détail en mémoire projet ; motivé par la variance de couverture (plancher 96→94, #189) et par la testabilité de contrats libc.
- ☑ 3.1 loom — déterminisme de concurrence. FAIT (ADR-058) : gouvernance gravée + harnais (alias d’atomique
core/loom+ shim futexyield/no-op). Tous les verrous futex de couche 1 modélisés :air-threadAirMutex/AirRwLock/AirSemaphore(5 modèles) + leMutexd’air-alloc+ leStreamLock(verrou par flux) d’air-stdio— 7 modèles verts, exécutés en CI par un jobloomdédié (--cfg loom,--locked). Plancher couverture lignes remonté 94→96 sur mesure empirique (5 passes : 96.65–96.66 %, variance 0.01 % ⇒ #189 annulé, filet resserré). Cargo.lock complété (arêtesloom, repro ADR-025). Garde-fou : loom = sûreté ; vivacité validée on-target. - ☐ 3.2
air-fault(nom proposé ; pasair-debug, réservé auLIB_AIR_DEBUGruntime) — injection de fautes syscall (EINTR,EFAULT,mmap/mallocéchoue au N-ième). Rend testables des contrats aujourd’hui quasi-intestables : ADR-021 « EINTR remonté à l’appelant », vision « malloc échoue plutôt que hang ». Seamcfg-gated à la frontière L1→L0, zéro coût prod. - Garde-fou non négociable : le selftest on-target (
rt/, 2 arches) reste juge de la réalité. L’instrumentation monte le % de couverture ; elle ne remplace jamais la preuve on-target (piège du mock — fatal pour un projet « fait ce qu’il dit »).
4. Chantiers RESTANTS — mono-toit (importants, moins « sacrés »)
Rigueur normale couche 1 (100 % couverture), mais un seul consommateur → une erreur ne casse qu’un toit.
| # | Brique | Crit. | L | P | Contenu | Statut |
|---|---|---|---|---|---|---|
| 4-F | termios (L0, ADR-060) + air-terminal (L1, ADR-061) | 🟠 | ● | — | Descellement couche 0 famille termios/tty (attributs/contrôle-ligne/winsize/PTY/session) puis objet couche 1 air-terminal = tag + codec + modèle canonique (1ᵉʳ codec ansi/termios). Branche feat/termios-couche0 (type Termios fait). air-termdb/termcap RETIRÉ du périmètre libc = ncurses/couche 2 (xterm-only, différé). | ◐ |
| 4-G | comptes passwd/grp/shadow | 🟠 | ● | — | itérateurs owned (pas de buffer static), lckpwdf réel, atfork. S’appuie sur les backends /etc d’air-config (☑) → API comptes au-dessus. | ◐ |
| 4-H | îlot asm setjmp/longjmp | 🟠 | ● | — | inexprimable en Rust sain (saute les Drop) → surface FFI unsafe C-ABI seule, asm x86_64 + aarch64. À éviter si OpenSSH s’en passe. | ☐ |
| 4-I | moteur regex | 🟠 | ● | ○ | POSIX basic/extended. Différé post-sceau (décision BDFL/reco) : ce sera une crate additive neuve → son ajout ultérieur ne descelle rien de l’API figée. Ne bloque que air-filesystem::find_regex + libc regcomp (non-critiques). Règle 80 % (ADR-024) interdit de vendorer regex tel quel → impl. minimale possédée le moment venu. | ☐ (post-sceau) |
| 4-J | ABI C — air-base-capi T2/T3 + libair-base.so | ⚪ | ● | — | T2 (AirLog), T3 (temps POD), assemblage cdylib, liste des symboles exportés + versioning, header air_base.h. Au-dessus du sceau couche 1 (packaging de la face C). | ◐ |
| 4-K | air-runtime async (io_uring) | ⚪ | ○ | ○ | Exécuteur air-runtime-{core,io,time,signal,sync} (spec v1.0 validée). Consommateur = applis couche 2+, pas la libc/PAL (sync) — mais inclus dans la passe et le sceau (décision BDFL : sceller toute la couche 1 en une fois). Voir bloc ci-dessous. | ☐ |
4-K (détail) — air-runtime async io_uring, dans la passe
Spec docs/specs/layer-1/air-runtime.md (v1.0 validée BDFL), non implémentée.
Objet couche 1 : consomme air-sys-syscall (io_uring) directement (il EST couche 1).
- ☐ 4-K.1
air-runtime-core: exécuteur mono-thread,Task/spawn/block_on, réacteur. - ☐ 4-K.2
air-runtime-io: futures sur complétions,AirIoBuf(modèle buffers possédés, décision centrale de la spec), enregistrement fd. - ☐ 4-K.3
air-runtime-time:sleep/timeout/intervalle. - ☐ 4-K.4
air-runtime-signal: signaux async viasignalfd(ADR-020). - ☐ 4-K.5
air-runtime-sync:AirAsyncMutex,AirNotify, channel async. - ☐ 4-K.6 Mode multi-cœur : thread-per-core via
msg_ring(peut suivre env1.xadditif si besoin).
Note de cohérence. L’async ne sert pas d’assise à la libc/PAL, mais le BDFL a tranché de le produire et le sceller dans la même passe que le reste — le sceau
couche-1-v1.0couvre toute la couche 1, pas seulement le sous-ensemble face-libc/face-PAL.
5. Porte de SCEAU — couche-1-v1.0
Après §2 (et le mono-toit §4 requis par le périmètre v1), avant de construire la libc et le PAL au-dessus :
- ☐ 5.1 Audit face-libc : rejouer les 41 familles musl contre l’inventaire couche 1 — chaque fonction du périmètre v1 (ADR-046 : ~25-30 familles, cible OpenSSH) a-t-elle sa brique ? (completeness critic)
- ✅ 5.2 Audit face-PAL (fait,
docs/notes/audit-face-pal-cloture-fr.md) : ZÉRO gap fondateur ; les manques (Condvar/Once/dtors TLS/env-mutation/os_str) livrés en chantier A du PAL. Toitstden cours (chantier B, option A, ADR-076) :stdcompile sur la libc d’Air. - ☐ 5.3 Combler les manques additifs remontés par 5.1/5.2. (L’async §4-K est inclus dans la surface scellée mais n’a pas d’audit « face-toit » — ses consommateurs sont couche 2+.)
- ☐ 5.4 Sceller : figer l’API Rust couche 1 en
couche-1-v1.0(RFC). ⚠️ Sceau couche 1 = API Rust ; la C-ABI vit au-dessus (crate libc/air-base-capi) avec son propre régime de stabilité (zones air-stable). Sceau couche 1 ≠ figer les signatures C. - Modèle de re-sceau (précédent couche 0, ADR-051) : les manques futurs se traitent en descellement additif
v1.x(jalons antérieurs conservés), pas en refonte. On accepte qu’il y en aura — moins souvent que sur la couche 0.
6. Hors périmètre de ce sceau (à ne pas confondre)
- libc C-ABI (ADR-046/047) et PAL
std::sys(ADR-049 phase 3) : ce sont les toits, construits sur la couche 1 scellée — hors de cette roadmap (qui prépare leur assise). - (NB : l’
air-runtimeasync, un temps envisagé hors passe, est finalement inclus dans le sceau — cf. §4-K, décision BDFL.) - Familles libc différées post-v1 (ADR-046 D7) :
aio,ipcSysV,mq,ldso/dlopen,wordexp/glob(rejetés — RCE/injection).
7. Ordre d’exécution proposé (topologique)
- §3.1 loom (parallèle, faible risque) — stabilise la couverture avant tout figeage.
- §2.B
air-threadno_std + futex — brique de synchro fondatrice ; débloque le spawn Air-natif (adosseair-alloc☑). - §2.C temps + §2.D
air-stdio+ §2.E finitions — petits, parallélisables. - §2.A i18n Rust-pur — le long pole : 2.A.1 → 2.A.2 → 2.A.3/2.A.4 → 2.A.5 → 2.A.6 (LSTM). Peut avancer en parallèle des petits chantiers.
- §4-K
air-runtimeasync — track parallèle indépendant (ne dépend ni de la libc ni du PAL) ; peut démarrer tôt et avancer en fond. - §4 mono-toit (F/G/H) — une fois le cœur stable ; parallélisables. 4-I regex différé post-sceau (crate additive).
- §5 audits face-libc/face-PAL (completeness critic) → sceau
couche-1-v1.0(couvre toute la couche 1, async inclus). - Au-dessus du sceau : §4-J (ABI C), puis libc C-ABI et PAL
std::sys; puis §4-I regex (additif).
8. Tableau de bord (à cocher au fil des PR)
| Chantier | Crit. | Statut |
|---|---|---|
| 2.A.1 air-base-lib → no_std (Option V, ADR-059) | 🔴 | ☑ |
| 2.A.2 deps icu_* → default-features=false | 🔴 | ☑ |
| 2.A.3 air-string face C-ABI (libc) | 🔴 | ☐ |
| 2.A.4 re-sonde fermeture couche 1 on-target | 🔴 | ☐ |
| 2.A.5 datagen Air (optionnel/différé) | 🟡 | ☐ |
| — | ✗ abandonné (ADR-059) | |
| 2.B.1 futex maison air-thread | 🔴 | ☑ (via #182) |
| 2.B.2 spawn Air-natif | 🔴 | ☐ |
| 2.B.3 couverture contention déterministe | 🔴 | ☐ |
| 2.C.1 temps monotone/mur/nanosleep | 🔴 | ◐ |
2.D.1 air-stdio (brique bas-niveau) | 🔴 | ☐ |
| 2.D.2 air-filesystem → dép air-stdio | 🔴 | ☐ |
| 2.E.1 air-memory backing mmap | 🟠 | ☐ |
| 2.E.2 air-crypto no_std strict | 🔴 | ◐ (deps df=false ; x86_64 on-target ☑ ; aarch64 = cpufeatures→libc env=air, chantier dédié) |
| 3.1 loom (déterminisme concurrence) | — | ☑ (air-thread ×3 + air-alloc) |
| 3.2 air-fault (injection fautes) | — | ☐ |
4-F termios L0 (ADR-060, couche-0-v1.8) ☑ · air-terminal L1 + air-termdb | 🟠 | ◐ |
| 4-G comptes passwd/grp/shadow | 🟠 | ◐ |
| 4-H îlot asm setjmp/longjmp | 🟠 | ☐ |
| 4-K air-runtime async (core/io/time/signal/sync) | ⚪ | ☐ |
| 4-J ABI C T2/T3 + libair-base.so (au-dessus) | ⚪ | ◐ |
| 5.1 audit face-libc | — | ☐ |
| 5.2 audit face-PAL | — | ☐ |
| 5.4 sceau couche-1-v1.0 (async inclus) | — | ☐ |
| 4-I moteur regex (post-sceau, additif) | 🟠 | ☐ |