ADR-072 — CI : x86_64 (speedy) runner primaire ; aarch64 en cross-check + natif sur main (révise ADR-037)
Statut : Accepté (2026-07-07, décision BDFL directe). Révise ADR-037 (« x86 sorti de la CI, aarch64 seul runner »). Sert l’invariant tier-1 x86_64 ET aarch64 (ADR-014). Compose avec le filtrage de couverture ADR-036.
Contexte
ADR-037 avait fait du raspi-srv-2 (aarch64) le seul runner CI, x86_64 étant validé
hors-CI par la barrière pré-merge. À l’usage, le Pi est lent : l’étape llvm-cov
FULL prend ~25-30 min, et chaque lot de la campagne libc (qui ajoute une crate ⇒ touche
Cargo.toml/Cargo.lock racine ⇒ déclenche le chemin FULL d’ADR-036) paie ce coût.
La CI de PR est devenue le frein principal de l’itération.
Or le code est full Rust : les seules différences x86 ↔ aarch64 sont (1) les
numéros de syscall (couche 0, scellée — aucune évolution dans la campagne libc) et
(2) la signedness de char (c_char = i8 x86 / u8 aarch64), différence
compile-time qui a causé des bugs FFI récurrents dans la libc. La première est un
risque runtime rare ; la seconde un risque compile fréquent.
Décision
x86_64 (speedy, self-hosted, déjà enregistré) redevient le runner CI primaire. La
CI de PR (fmt/clippy/test + couverture conditionnelle ADR-036, supply-chain,
loom) tourne sur air-x86_64. L’invariant aarch64 est tenu par deux filets :
cross-check-aarch64(sur speedy, chaque PR) :cargo check --target aarch64-unknown-linux-gnu --workspace --all-targets— filet compile-time (signednessc_char, layouts, signatures FFI), ~1 min, sans linker.aarch64-native(sur raspi, hors PR :push main/ hebdo / scellement) :fmt/clippy/cargo test --workspacenatifs — filet runtime (numéros de syscall, comportement réel), garant qu’aucune régression aarch64 n’atteintmain.
La barrière x86 pré-merge (cargo xtask barrier) reste le garde-fou local. La
couverture est mesurée sur x86_64 (les planchers 96 %/78 % y sont tenus, cf. barrière).
Conséquences
- CI de PR : ~30 min → ~2-5 min. Le Pi ne bride plus l’itération.
- Filet
c_charconservé (le bug le plus fréquent) sur chaque PR, à coût quasi nul, sans le Pi. - aarch64 natif toujours vérifié avant qu’un état n’atteigne
main(garde-fou (b) d’ADR-036 transposé) et au scellement des couches. - ADR-037 révisé : le choix « aarch64 seul runner » est remplacé ; speedy est réactivé (il était resté enregistré « pour l’ouverture publique »).
- Limite acceptée : une régression runtime aarch64 introduite par une PR n’est
détectée qu’au merge
main(jobaarch64-native), pas sur la PR. Acceptable : la couche 0 (syscalls) est scellée et ne bouge quasiment plus ; tout descellement couche 0 reste validé nativement (il déclenchemain/scellement).
Alternatives rejetées
- Garder aarch64 seul runner (statu quo ADR-037) : le frein d’itération est réel.
- Runners GitHub-hosted : pas de toolchain pinné ni d’aarch64 natif fiable (raison d’être du self-hosted, ADR-037/ADR-014 inchangée).
- Cross-check aarch64 SANS validation native : perdrait le filet runtime (syscalls) ;
on le garde sur
main/scellement.