Roadmap — clôture du PAL (std::sys::pal::air) : les 3 chantiers
Statut : note de roadmap (opérationnelle). Fige le plan de clôture du PAL décidé par
ADR-075. S’appuie sur l’audit
face-PAL (audit-face-pal-cloture-fr.md), le journal rt/DECISIONS.md, et
ADR-049/050/052/056. Non normative : les évolutions structurantes restent des ADR.
✅ CLÔTURE 2026-07-10 — CHANTIER B/C FAIT,
hello-stdTOURNE 2 ARCHES (M5 atteint). Le lien dehello-stdcontrelibairpasse de 12 → 0 symboles indéfinis ; il s’exécute on-target —hello from std on air+ exit 0 sur x86_64-air (carbon) ET aarch64-air (raspi). Un programme Ruststdstatic-PIE lié intégralement sans glibc. Pari ADR-076 tenu de bout en bout. Re-sceauxcouche-0-v1.12(ADR-087raw_syscall) +couche-1-v1.9(ADR-086 introspection thread). Statut vivant :etat-avancement.md. Prochaine phase = OpenSSH /air-sshd(ADR-074). Dette ouverte : retirer l’escape hatchsyscall/raw_syscall(ADR-087) avec l’équipe Rust. (Le détail ci-dessous — chantiers A/B/C — est conservé comme historique du plan ; il est désormais réalisé.)
⚠️ MISE À JOUR 2026-07-08 — chantier A FAIT, chantier B pivoté (option A). (Superseded par le bandeau de clôture ci-dessus : le chantier B/C est terminé —
hello-stdtourne on-target 2 arches, jalon M5 atteint le 2026-07-10. Le texte ci-dessous est conservé comme trace du pivot.)
- Chantier A COMPLET : les 6 briques additives couche 1 sont mergées (
AirCondvar,AirOnce, os_str, mutation d’envair_env::set/unset,yield_now/set_thread_name, destructeursthread_local). Un bug de fondation aarch64 (TCB recouvrant la zone TLS) a été traqué au gdb et corrigé, validé 2 arches.- Chantier B pivoté vers l’OPTION A (ADR-076) : le portage a montré que
std(cible unix/linux) EXIGE une libc — on abandonne le palaircustom ;stdréutilise le palunix+ la libc d’Air (libair) fournit les symboles (zéro glibc). La cible porteenv=musl+vendor=air.build-std=stdcompile entièrement pour Air, sans patch libc/std. Cible de production = compléterlibairpour lierstd→hello-stdon-target 2 arches (§5 chantier C).
1. Point de départ (dé-risqué)
Fait et prouvé on-target 2 arches (selftest rt/, exit 42) : _start + self-reloc
static-PIE, TLS Variant I/II + errno #[thread_local] + TCB, spawn clone3/CLONE_SETTLS
- join futex, allocateur réel
air-allocbranché, layering ADR-052 (air-rt = shim mince, runtime en couche 1). Migration#![no_std]: 10/10 crates que le PAL compose.
Verdict audit face-PAL : zéro gap fondateur. Chaque primitive std::sys a sa brique
couche 1. Reste : quelques briques additives + écrire le backend + bootstrapper
std.
2. Table de correspondance std::sys → brique couche 1
Primitive std::sys | Brique couche 1 | État |
|---|---|---|
alloc (GlobalAlloc) | air_alloc::GlobalAllocator | ✅ branché on-target |
| thread spawn/join | air_runtime::thread (spawn/JoinHandle) | ✅ (ergonomie boxée à câbler) |
| thread yield/sleep/id | couche-0 sched_yield · air_base_core::time::sleep · current_tid | ◐ yield/name à surfacer |
| thread_local (TLS/TCB) | air_runtime::{thread_control_block, thread_local_storage} | ◐ dtors à ajouter |
| sync Mutex/RwLock | air_thread::{AirMutex, AirRwLock} (futex, loom) | ✅ |
| sync Condvar / Once | primitives futex air_thread (publiques) | ❌ additif |
| time Instant/SystemTime | air_base_core::time::{AirInstant, AirSystemTime} | ✅ |
| fs File/metadata/dir | air_filesystem::AirFile + AirFileMetadata + read_dir | ✅ (sceau v1.0, #214) |
| net TCP/UDP/lookup | air_socket::* + AirNameResolver | ✅ |
| process Command/Child | air_process::{AirCommand, AirProcess} + air_pipe | ✅ |
| env vars | air_env::{get, vars} | ◐ set/unset additif |
| args (argv) | air_runtime::args | ✅ |
| stdio | air_stdio::{stdin, stdout, stderr} | ✅ |
| path | air_base_core::path::AirPath | ✅ |
| os_str | substrat [u8]/Vec<u8> (AirPath owned) | ◐ newtype additif |
| random (getrandom) | couche-0 getrandom (lien direct — pas air-crypto) | ✅ |
| backtrace/unwind | panic=abort → surface minimale | ✅ |
3. Chantier A — briques additives couche 1 (host-testables, sous barrière 100 %)
Chacune = descellement additif (ADR-051), aucune refonte d’API scellée :
- A1
air_thread::AirCondvar(surfutex_wait_word/futex_wake_one). - A2
air_thread::AirOnce(AtomicU32+ futex) — pourstd::sync::Once/lazy. - A3 destructeurs
thread_local!:register_dtor+ exécution en fin de thread (champ DTV présent dans le TCB). Mineur (panic=abort, threads courts) mais requis parstd::sys::thread_local. - A4 mutation d’env :
air_env::{set, unset}(pourstd::env::set_var/remove_var) — gouverner l’__environmutable (audit musl ADR-047). - A5 newtype
os_str:AirOsStr/AirOsString(paire empruntée/possédée sur[u8]). - A6
thread::yield_now(passthrough couche-0sched_yield) + nommage (prctl(PR_SET_NAME)) sur cible.
4. Chantier B — le backend std::sys::pal::air (phase 3)
Un rust-src patché (ADR-075) : ajouter sys/pal/air qui compose les briques
ci-dessus (jamais de re-syscall). Portage module par module, chacun validé par un bout
de std qui l’exerce. Ordre naturel (dépendances croissantes) :
- alloc + process::exit/abort (déjà amorcés) → un
stdqui démarre/quitte. - time, env, args →
std::env,SystemTime,Instant. - thread + thread_local + sync (mutex/rwlock/condvar/once) →
std::thread,std::sync. - fs (
File/metadata/read_dir) →std::fs. - stdio (
Stdin/out/err,is_terminal) →println!/std::io. - process (
Command/Child) →std::process. - net (TCP/UDP + lookup) →
std::net. - path / os_str →
std::path,OsStr. - random (seed HashMap via couche-0
getrandom), pipe, backtrace minimal.
5. Chantier C — bootstrap std + lane CI nightly (phase 4)
- C1 faire compiler
-Z build-std=stdpour*-linux-air(2 arches). - C2 lier et exécuter un « hello std » : ouvre un fichier (
AirFile), un socket, un thread, écrit viaprintln!— prouvé exit propre sur x86_64 (carbon) + aarch64 (raspi). - C3 lane CI nightly dédiée qui rejoue C1+C2 → referme le carve-out de
rt/(aujourd’hui hors barrière). - C4 (après démo) : enregistrer les cibles Tier-3 en amont (upstream rustc).
6. Résidus sécurité à refermer au passage
- canari de pile depuis
auxv AT_RANDOM(matérialiser%fs:0x28/tpidr_el0). mprotectRELRO après self-relocation (.data.rel.ro/.gotinscriptibles sinon).- placement d’
errnoà offset C-ABI fixe dans le TCB (utile à la future libc, pas au PAL Rust).
7. Ordre de bataille
- ADR-075 (fait) + cette note.
- Chantier A (A1→A6) — briques additives, host-testées, sous 100 %. Faible risque,
parallélisable, valeur immédiate (elles servent aussi le userland
no_std). - Chantier B — pal module par module (§4), chaque étape adossée à un fragment
std. - Chantier C — bootstrap
std+ « hello std » 2 arches + lane nightly. - Résidus sécurité (§6) au fil de l’eau.
8. Rappel : host-first
Les briques du chantier A et la logique testable se valident sur l’hôte (les crates
couche 1 tournent déjà en gnu). Seuls le backend pal (chantier B, construit via
build-std) et le bootstrap std (chantier C) exigent la cible + le nightly — validés
par selftest/hello-std on-target (carbon x86, raspi aarch64), comme le programme rt/
actuel.