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

ADR-057 — libm Air (air-libm) : vendoring de libm (rust-lang) en surface math couche 1

Statut : Accepté (2026-07-01, par délégation d’autonomie BDFL pour ce lot ; gravé pour revue a posteriori). RFC de structure (ADR-015). Companion d’ADR-053 (la libc Air s’appuie sur icu4x — dont la math flottante no_std) et d’ADR-024 (règle des 80 % / exceptions nommées). S’appuie sur l’audit docs/notes/audit-icu4x-rust-pur-fr.md (§3 « le SEUL primitif système manquant — math flottante no_std (libm) » ; §8 « ce qu’Air N’A PAS : un libm no_std »).

Catégorie : Architecture (couche 1, fondateur). Toute évolution structurante = RFC.

Contexte

L’audit icu4x (docs/notes/audit-icu4x-rust-pur-fr.md) a établi un fait net : le runtime d’icu4x est déjà no_std et de calcul pur (Air a core + alloc), et le seul primitif système qui lui manque est une bibliothèque mathématique flottante no_std — un libm. Deux consommateurs incontournables du périmètre i18n d’Air en dépendent (§3) :

  • calendrical_calculations (dépendance d’icu_calendar) — math calendaire (astronomie des calendriers lunaires/solaires). Non contournable : le calendrier en a besoin.
  • icu_segmenter/src/complex/lstm — math du modèle LSTM (segmentation par IA des écritures sans espaces : thaï/khmer/lao/birman), activée par la feature auto/lstm que le projet retient.

Tous deux passent par core_maths, une fine façade no_std sur la crate libm. Air ne fournit aujourd’hui aucun libm no_std (la math flottante était explicitement hors de la v1 libc, ADR-046). C’est, selon l’audit, le vrai manque systémique pour la libc / i18n future. Une décision était requise (audit §8) : (a) fournir un libm Air, (b) restreindre le périmètre. (b) ne suffit pas seule — même sans LSTM, le calendrier garde besoin de libm. Air aura donc besoin d’un libm no_std.

Il n’y a aucun consommateur aujourd’hui : cet ADR pose une fondation (une bibliothèque en attente de consommateurs), comme on coule des fondations avant d’élever les murs. Le câblage effectif (icu4x → core_maths/libm sur *-linux-air) viendra avec la réimplémentation i18n (ADR-053).

Décision

D1 — Vendorer la crate libm (rust-lang) comme exception nommée (ADR-024, modèle icu4x)

Air vendore libm (la crate rust-lang) sous le régime des exceptions explicitement nommées à la règle des 80 % du Principe 6 (ADR-024 ; docs/EXCEPTIONS.md), exactement comme icu4x (ADR-016) et la crypto auditée (ADR-034). Justification de l’exception :

  • Rust pur, no_std, zéro dépendance runtime. libm est un portage de fdlibm en Rust pur, #![no_std], sans aucune dépendance transitive — il respecte la cible *-linux-air et la politique « zéro surface C/C++ » (#81 ; aucun *-sys, aucun cc).
  • Maintenu par le projet Rust, qualité std. libm est fusionné dans compiler-builtins : c’est le libm que la std Rust utilise elle-même sur les cibles no_std/wasm. Sa correction (ULP, cas limites NaN/inf/dénormaux) est éprouvée et continûment testée par l’amont.
  • Réimplémentation disproportionnée et risquée. Réécrire un libm correct from scratch (dizaines de fonctions transcendantes, précision ULP, sous-flots) serait énorme et porteur d’un risque de bugs numériques précisément là où Air ne peut pas se permettre l’à-peu-près. Le bénéfice « moins de code externe » serait annulé par le coût « plus de code maison moins testé » — le même raisonnement que pour icu4x et la crypto.
  • Licence permissive. libm 0.2.x est publié sous MIT (liste blanche deny.toml ; l’amont rust-lang/compiler-builtins est dual MIT/Apache-2.0).

D2 — Surface exposée par une crate couche 1 air-libm (no_std, ré-export)

La math d’Air est exposée par une nouvelle crate crates/air-libm, #![no_std] (couche 1, publish = false), qui ré-exporte la surface de libm (pub use libm::*;). Cette frontière nommée donne à Air un point de contrôle unique sur sa surface math (un seul endroit où la version est pinnée, auditée, documentée), sans réinventer ni masquer l’amont. air-libm n’a pas de logique propre en v1 : c’est délibéré (une façade de ré-export), pour ne pas dupliquer ni dériver de l’amont.

D3 — Pas de consommateur en v1 (fondation)

Aucune crate Air ne consomme air-libm aujourd’hui. La crate est posée en prévision de la libc / i18n (ADR-053) : c’est une fondation, pas un service actif. La preuve de viabilité est apportée par le build *-linux-air (la cible réelle) et par les tests de fumée (D4), pas par un consommateur.

D4 — Mandat de test (Principe 1, couche 1 = 100 %)

air-libm n’ayant quasiment pas de code propre (ré-export), le 100 % de couverture de la couche 1 est atteint de façon non équivoque : il n’existe aucune ligne de logique air-libm susceptible d’être manquée (un pub use ne génère pas de région exécutable). Des tests de fumée à valeurs connues exercent néanmoins la surface ré-exportée (sqrt, cbrt, cos, exp, pow, floor, fabs, log, hypot, sin, tan, …, avec tolérance epsilon sur les transcendantes — jamais d’== nu) pour prouver que la passerelle fonctionne. libm lui-même (la dépendance externe) n’est pas mesuré (externe, comme icu4x / la crypto auditée).

Conséquences

  • Air dispose d’une surface math no_std nommée et pinnée — la dernière brique système qui manquait à la réimplémentation i18n (ADR-053) est en place, prête à être câblée.
  • Une exception de dépendance de plus, explicitement consignée (docs/EXCEPTIONS.md + crates/air-libm/DEPENDENCIES.md), auditée par cargo deny (licence) et cargo audit.
  • Zéro coût runtime tant qu’aucun consommateur ne tire air-libm : la crate est compilée et testée, mais aucune binaire produit ne l’embarque encore.

Alternatives rejetées

  • Réécrire libm from scratch. Énorme, risque ULP/cas-limites élevé, pour une qualité de tests et de revue inférieure à l’amont rust-lang. Disproportionné (D1).
  • Dépendance libm non nommée (déclarée comme une dépendance ordinaire sans entrée d’exception). Viole le Principe 6 / ADR-024 : sous le seuil des 80 %, toute dépendance structurante exige une exception explicite. Rejeté au profit du vendoring nommé (modèle icu4x).
  • Restreindre le périmètre i18n pour éviter libm. Insuffisant : le calendrier (non contournable) garde besoin de math flottante (audit §3/§8). Rejeté.
  • Câbler un consommateur dès maintenant. Prématuré : la réimplémentation i18n (ADR-053) n’est pas faite. On pose la fondation et on prouve le build *-linux-air, sans inventer d’usage.

Mise en œuvre (esquisse)

  1. crates/air-libm (no_std, dep libm = "=0.2.x") : pub use libm::*; + doc de module (rôle, attribution amont) + tests de fumée 100 %.
  2. Workspace : ajout aux members + libm dans [workspace.dependencies] (pin strict, repro ADR-025).
  3. Doc : ADR-057, EXCEPTIONS.md (entrée libm), DEPENDENCIES.md, registre ADR, SUMMARY, INDEX.
  4. Preuve de build *-linux-air (crate-sonde jetable rt/, non committée).