ASKLERA PDF — Feuille de route

05 — Ordre de bataille : phases → lanes

Une lane = un agent, un worktree isolé sous ~/ sur big-1 (TMPDIR=~/tmp ; /tmp est saturé), commits par index temporaire avec des blobs construits depuis HEAD pour les fichiers partagés, compare-and-swap sur update-ref, HEAD vérifié compilable depuis un worktree propre, rapport en français avec des chiffres mesurés, cargo xtask prove <ids> avant tout implemented. Six lanes en parallèle au maximum. Chaque lane cite la clause de spécification qu'elle implémente et l'oracle face auquel elle prouve, et ajoute un contrôle négatif.

Phase 0 — Reprendre ce que le quota hebdomadaire a interrompu (⏸ → 🔧)

Lane Fonctionnalité Où en est le travail (2026-09-14) Oracle Sortie
AC texte F-001 ~/ac-work/wt-dev à a6b7d93 (alignement à la majorité de trois, règle de génération §7.3.10, borne /Count commités) ; 4 fichiers modifiés, non commités : crates/apdf-content/src/{cmap,font,interpret,text}.rs ; ~/ac-work/wt-after, wt-base sont du scratch pdftotext, mutool, pdf.js via oracle_pdfjs.rs, external_corpora.rs, oracle_text.rs rapports en hausse sur les trois, 0 régression, KNOWN_GAPS vidée ou classée
AE modificateur F-002 ~/wt/ae à a6b7d93 ; non commités : crates/apdf-write/src/edit.rs, crates/apdf/src/edit.rs, crates/apdf/tests/edit_oracle.rs, plus pages.rs, revision.rs, document.rs, objects_oracle.rs, support/{mod.rs,qpdf_json_diff.py} modifiés qpdf, pdfcpu, mutool, pdftk, pyHanko ; égalité qpdf --json sur 200 fichiers après une édition neutre conformance-processors, prepress-boxes implémentées ; verbes CLI (pages/merge/split/rotate/boxes/annots/form/meta/attach/bookmarks)
AF PDF/A F-003 ~/wt-AF à aafc997 (check/a/mod.rs, verapdf_agreement.rs, Cargo.toml modifiés) ; ~/wt-AF-g1 (examples/ non suivi) ; ~/wt-AF-g2 à b150945 ; ~/wt-AF-g3 à 6cfcf51 (syntax.rs modifié) — réconcilier les quatre sur HEAD d'abord veraPDF 1.30.2 + sources ; fontTools comme troisième témoin 0 désaccord sur les corpus veraPDF ou résidus classés ; corpus réel 3b/4 fait
AG performance F-004 (petite échelle) ~/wt-AG à f28ff11 : tests/tools/bench_corpus.sh, bench_report.py non suivis ; ~/bench-AG/{before,apdf-before,smoke} exécutions de référence /usr/bin/time, criterion, perf docs/PERFORMANCE.md, ADR-benchmarks, ≥3 points chauds corrigés avec avant/après, tests d'oracle inchangés
AH fuzzing F-005 ~/wt-AH propre à f28ff11 ; graines ~/fuzz-AH/{corpus,extract} préparées ; crate fuzz/ pas encore écrite libFuzzer/cargo-fuzz, ASan docs/FUZZING.md, docs/LIMITES.md, 0 plantage ouvert
AI FDF/XFDF/AF/PDF-X F-006 ~/wt-AI propre à 66a4ae4 ; fixtures PDF/X sous ~/tmp-AB/pdfx-nutshell-fixtures/ (à copier sous ~/ d'abord) pdftk, xmllint, qpdf, pdf.js, veraPDF 3b, Ghent lignes mises à jour avec les preuves
P0-a hygiène F-007 arbre partagé assaini le 2026-09-14 ; 34 fichiers mêlés restent (git status dans le checkout principal) — résoudre chacun face au worktree de la lane propriétaire, puis cargo fmt en un seul commit, puis prove all depuis un worktree propre ; supprimer les worktrees mortes (apdf-base, apdf-laneY, wt/ad-pub, wt-AF-g* une fois réconciliées) et les cibles cargo périmées prove all porte verte au nouveau HEAD ; docs/COUVERTURE.md régénéré et commité
P0-b amont F-007 branches RUSSL fix/cms-interop-and-crl-signing, lane-r-pkcs12-rsa ; CODECS laneM-jbig2-2026-09-13, laneY-jpx-2026-09-13, commits jpeg2000 de la lane F sur argon-full-corpus-2026-08-16 — fusionner dans la lignée principale une fois les sessions qui occupent ces arbres terminées (🧭 D-7) ; rien à republier (Kellnr porte déjà les crates construites) suites amont branches fusionnées, tags sur les commits publiés

Sortie de Phase 0 : prove all vert à un HEAD qui contient AC/AE/AF/AG/AH/AI, arbre formaté, docs/PERFORMANCE.md, docs/FUZZING.md, docs/LIMITES.md présents.

État à la pause (2026-09-14, 20h45 — implémentation gelée par le fondateur tant que 06-decisions.md n'a pas de réponse)

Commité sur main entre l'arrêt du quota et la pause (aucune lane, session principale) : 89a7d7e (.gitignore /ISO_SOURCES/), e972e0a (lane AG reprise : harnais de bancs + ligne de base docs/PERFORMANCE.md — bogue de citation CSV corrigé), 56b9277 (COUVERTURE.md régénéré), 0c5092f (repli du corpus en worktree dans six modules tests/support + scripts/worktree-corpus.sh : un worktree lié avait un tests/corpus vide et chaque suite d'oracle tournait sur zéro fichier — c'est ce qui expliquait les « échecs » d'AC et d'AE, pas leur code). Checkout partagé assaini : index périmé remis à zéro, 59 fichiers périmés + 9 de churn rustfmt restaurés depuis HEAD, 5 miroirs d'AC restaurés, 28 patches non attribués parqués sous ~/mixed-patches-2026-09-15/ (README à l'intérieur), checkout propre.

Mesuré mais non commité (les worktrees restent en l'état ; reprendre = relire, puis commiter par index temporaire sur le HEAD de ce jour-là) :

Worktree Contenu Mesuré (2026-09-14) Note de reprise
~/ac-work/wt-dev (AC, base a6b7d93) ordre de lecture par blocs/segments dans apdf-content/src/text.rs (+ 3 tests unitaires), ressources de formulaire fusionnées derrière celles de la page (interpret.rs, test unitaire), petits changements cmap.rs/font.rs ; apdf-doc/src/store.rs : /Length déclaré conservé quand aucun mot-clé ne suit (bad39.pdf → « Potato », D-25) ; external_corpora.rs et oracle_text.rs comparent --layout avec pdftotext -layout et l'ordre par défaut avec mutool (D-22) à convention égale : pdf.js en ordre ≥0,9 67,9→74,1 %, mutool 64,8→71,0 % (balayage pdf.js) ; corpus épinglé face à pdftotext -layout 85,5→86,0 % (moyenne 0,909→0,912), face à mutool 73,6→80,7 % ; corpus externes face à -layout 85,1→85,2 % ; « désaccords où les oracles s'accordent » 15→11 blocages : le cas 9 de robustness.rs (200 000 (x) Tj) prend 190 s — build_blocks balaie tous les blocs pour l'entrelacement (quadratique sur une entrée hostile) : borner le balayage ; apdf-content/tests/oracle_text.rs (au niveau crate) compare encore l'ordre par défaut à -layout (73,7 % < seuil) : aligner comme les tests CLI ; écarts non classés issue13211.pdf (texte thaï dans un XObject de formulaire, polices CID 22/23 avec ToUnicode Ghostscript — l'analyseur de CMap est disculpé par deux tests de scratch ; les mauvais points de code U+0E3C/0E61/0E65 viennent d'un repli ultérieur : instrumenter decode_composite) et bad39.pdf (corrigé par le changement du store, à reclasser) ; listes KNOWN_GAPS à élaguer (12 entrées corrigées) ; régression ZapfDingbats.pdf (cellules du tableau de glyphes fusionnées) à expliquer ou corriger
~/wt-ae-new (AE rebasée sur a6b7d93+HEAD) apdf-write/src/edit.rs (1 569 lignes : édition de l'arbre de pages, annotations, aplatissement, Touched), apdf/src/edit.rs (1 385 lignes : Editor avec sauvegarde incrémentale par diff d'instantané, politique DocMDP/approbation, formulaires, info/XMP, signets, pièces jointes, étiquettes, préférences du visualiseur), apdf/tests/edit_oracle.rs (708 lignes), Document::refresh, doc de façade fusionnée les 6 tests d'oracle passent (égalité qpdf --pages/--json sur 200 fichiers du corpus, signatures pyHanko, relecture mutool/pdfdetach) une fois le corpus trouvé ; bassin de candidats pour l'édition de page élargi (40→200) ; clippy : matches! corrigé ; un avertissement resteedit_oracle.rs:169 veut .rfind(..) au lieu de .filter(..).next_back() (~/ae-new-clippy2.log) ; tests rejoués verts (~/ae-new-tests2.log : 5 + 6 passés) corriger le clippy d'une ligne, commiter ; puis les lignes conformance-processors/prepress-boxes + les verbes CLI (pas encore écrits)
~/wt-AF-new (AF réconciliée sur HEAD aed2f39) fichiers chiffrés ouverts avec le mot de passe utilisateur vide avant les règles PDF/A (comme veraPDF), check/a/syntax.rs : règle /ID d'un fichier linéarisé selon GFCosDocument.getlastID, le rapport d'accord imprime chaque manque corpus veraPDF : 1b 565/569 (était 563), 2b 960/986 (959), 3b 12/12, 4 : 455/487 (était 456 — un nouveau faux positif : 6-1-3-t02-fail-a.pdf signalé 6.1.6.1-1 par nous seuls ; causé par le changement /ID linéarisé au niveau 4 — à vérifier avant de commiter), 4e 19/19, 4f 11/11 ; Isartor 203/205 corriger ou expliquer le −1 de PDF/A-4, puis commiter ; les quatre anciens worktrees ~/wt-AF* peuvent être supprimés ensuite
~/wt-corpus commité (0c5092f) supprimer le worktree
AH, AI rien d'écrit démarrer depuis les briefs (docs/roadmap F-005, F-006)

Aussi mesuré ce jour, pour D-22 : ligne de base de performance (docs/PERFORMANCE.md) : ouverture 6 ms contre qpdf 12 / pdfinfo 19 / pdf.js 305 ms ; texte 6 ms contre pdftotext 20 / mutool 28 / pdf.js 339 ms ; rendu 109 ms contre pdftoppm 53 / mutool 38 ms (2 à 3 fois plus lent, l'étage à optimiser en premier) ; RSS maximale 898 Mo contre 4,9 Go / 6,8 Go.

Second contrôle, le même soir (21h20–21h25) : un bug d'outillage et deux constats de worktree. Une nouvelle passe de vérifications oracle/clippy sur les worktrees AC/AE/AF a été enveloppée dans des boucles until ! pgrep -f "<cmd>" >/dev/null; do sleep N; done pour être notifié à la fin. Bug : le texte de commande de chaque boucle (passé à zsh -c) contient lui-même la chaîne de recherche de son propre pgrep -f, donc pgrep -f matchait la boucle elle-même indéfiniment, même longtemps après que la vraie commande cargo ait terminé — les 7 boucles étaient encore signalées « en cours » plus de 75 minutes plus tard. Diagnostiqué via pgrep -af montrant le PID de la boucle comme son propre résultat, et via ps/uptime ne montrant plus aucun processus cargo correspondant et une charge système normale ; tuées par PID exact (pas un pkill large, conformément à la règle de la machine partagée), puis les vrais résultats ont été lus directement dans les fichiers de log que ciblaient ces boucles. Leçon pour les futurs scripts d'attente : ne jamais faire un pgrep -f sur un motif qui est une sous-chaîne de la ligne de commande de la boucle elle-même — utiliser un fichier PID ou wait $!. Constats tirés des logs : - AC, dans ~/ac-work/wt-dev (toujours basé sur a6b7d93, donc antérieur à 0c5092f) : la suite oracle apdf-content a montré un mur de tests FAILED (encodages CFF, CMaps CJK, dictionnaires de police, dictionnaires /SH et ExtGState, comptages fill/stroke, texte, Type 3, robustesse). C'est le symptôme de corpus vide d'avant 0c5092f qui réapparaît dans un worktree antérieur au correctif, pas un nouveau défaut dans les changements text.rs/store.rs/interpret.rs de cette lane — les chiffres du tableau ci-dessus (mesurés avec un corpus accessible) restent valables ; ce worktree a besoin du correctif de repli de corpus (ou de scripts/worktree-corpus.sh) avant de pouvoir être re-mesuré. Le cargo check des six crates du correctif lui-même (~/wt-corpus, déjà commité en 0c5092f) est propre. - AE, un nouveau rebase sur ~/wt/ae (distinct de ~/wt-ae-new ci-dessus) : a reproduit le même symptôme sur page_edits_agree_with_qpdf_pages_and_render_identically (1 document / 7 pages trouvées, il en faut ≥ 4) ; épingler APDF_CORPUS sur le vrai corpus du worktree principal a fait passer les 6 tests oracle, confirmant le diagnostic plutôt qu'une vraie régression. Le clippy de ce rebase signale aussi de nouveau le motif matches!, cette fois à edit.rs:1238 — en plus du edit_oracle.rs:169 déjà connu (.rfind au lieu de .filter(..).next_back()) — donc, que ce soit ~/wt-ae-new ou ~/wt/ae qui soit repris à la reprise, les deux correctifs clippy d'une ligne doivent être réappliqués avant commit. - AF : cargo test -p apdf-conform --release --no-run compile proprement (binaires de test isartor, pdfa, verapdf_agreement construits). Cela ne vérifie que la compilation, pas l'exécution de la suite : la régression PDF/A-4 455/487 notée ci-dessus reste donc ouverte et n'est ni confirmée ni infirmée par ce contrôle.

Phase 1 — Accessibilité depuis n'importe où (F-010…F-017)

Lane Contenu Dépend de Preuve
P1-adr ADR-bindings (cbindgen, napi-rs, wasm-bindgen, wit-bindgen, PyO3/maturin, UniFFI, jni, csbindgen, magnus, ext-php-rs, flutter_rust_bridge, rustler — générateurs de build) et ADR-benchmarks (criterion) pour validation du fondateur ADR accepté (🧭 D-6)
P1-a ABI C apdf-capi + apdf.h + projet de test C P1-adr projet C neuf ; abi-checker
P1-b napi-rs (Node 22, Bun) + WASM (navigateur) + composant WASI 0.2 P1-a (forme de l'API) projets Node/Bun/Deno/navigateur neufs ; table de taille
P1-c Python (wheels maturin), JVM (Maven), .NET (NuGet) P1-a projets neufs par langage
P1-d Swift/iOS, Kotlin/Android, Go, Ruby, PHP, Dart, Elixir, en-tête C++ P1-a projets neufs par langage
P1-e adaptateur FPDF_* de pdfium, API façon poppler-glib, alias CLI (pdftotext/pdftoppm/pdfinfo/pdfimages/pdffonts/pdfsig/qpdf/pdftk/cpdf), docs/MIGRATION.md P1-a test de fumée pypdfium2 face à notre .so ; sorties de référence poppler-utils
P1-f Site de documentation, matrice CI (7 cibles), builds reproductibles, paquets système P1-b/c site + matrice verte

Phase 2 — Inspecteur, linter, forensique (F-020…F-027)

Lane Contenu Preuve
P2-a Graphe d'objets + vues + historique des révisions (apdf tree, apdf revisions) qpdf --json, pdfresurrect, pdfsig ; contrôles négatifs
P2-b Linter + SARIF + corrections suggérées + profils d'industrie (eCTD, judiciaire, Factur-X, ZATCA, préréglages gouvernementaux) sarif-multitool, GitHub code scanning, contrôles croisés veraPDF/callas
P2-c Langage de requête + QDF + apdf json (compatible qpdf) qpdf --qdf, --json=2
P2-d Diff (structurel/textuel/visuel/révision) témoins Draftable/pdftk/pdftoppm
P2-e Mode forensique + apdf scrub + --rebuild (CDR) + rapport de durcissement peepdf/pdfid, PoC publiés, UNSAFE-DOCS
P2-f GUI (egui → WASM), extension VS Code, action GitHub, extension de navigateur action exécutée sur le dépôt ; captures d'écran

Phase 3 — Création et confiance (F-030…F-037)

Lane Contenu Preuve
P3-adr ADR : moteur de façonnage, césure, OCR, sous-ensemble HTML paginé 🧭 D-6/D-9
P3-a Constructeur de document (façonnage, césure, tableaux, SVG, Markdown, balisage automatique) HarfBuzz, LuaTeX, veraPDF UA-2/A-4
P3-b Hybrides de facturation électronique : Factur-X/ZUGFeRD → XRechnung → ZATCA → thaïlandais → représentations PDF avec QR (CFDI, DANFE, DIAN, SII, IRN, ATCUD, KSeF, VERI*FACTU, TicketBAI, myDATA) Mustang, KoSIT, SDK ZATCA, validateurs nationaux, Schematron Peppol
P3-c C2PA 2.4 c2patool
P3-d PAdES PQ (RFC 9882, composites) — mesurer d'abord la disponibilité de RUSSL ; lane amont si manquante OpenSSL 3.5, Bouncy Castle
P3-e Trait de signataire externe + adaptateurs (PKCS#11, CNG, CTK, SKF, KMS cloud, CSC 2.2, Aadhaar eSign, SingPass), magasins de confiance (LOTL, AATL, nationaux), oracle DSS, politiques de signature (PAdES-BR, Part 11, e-Apostille, judiciaire) DSS, SoftHSM2, bacs à sable CSC, vérificateur ITI
P3-f Couche carte à puce : transport PC/SC, découverte PKCS#15/IAS-ECC/EN 14890, modules de profil carte (PIV/CAC, IAS-ECC/CPS, EstEID, BELPIC, DNIe, CNS/CIE, JPKI, OpenPGP, famille des cartes santé) outils OpenSC, cartes de test PIV du NIST, cartes de test éditeur
P3-g Formulaires : concepteur, rendu XFA (SAP/AEM/IRS/cerfa), bac à sable du sous-ensemble JS, catalogues de pré-remplissage XFA de pdfium, Acrobat, pdf.js
P3-h Écriture de TS 32004 + déclarations /ISO_ (russl-pades en amont), EA-PDF, PDF/raster, écriture PDF Declarations, conteneurs ASiC/XAdES pyHanko, libdigidocpp, DSS

Phase 4 — Verticales (F-040…F-047)

Lanes P4-santé, P4-prépresse, P4-archivage, P4-accessibilité, P4-extraction, P4-juridique-défense, P4-mrc, P4-codes-barres-géo — chacune avec les oracles listés en 03b. Ordre selon le calendrier du marché : P4-codes-barres-géo et P4-accessibilité en premier (dépendances QR de la facturation électronique et échéances ADA Title II 2026-04/2027-04), puis P4-archivage et P4-santé, puis P4-prépresse, P4-juridique-défense, P4-mrc, P4-extraction.

Phase 5 — Produits (F-050…F-055)

P5-visualiseur-wasm, P5-visualiseur-natif, P5-serveur, P5-saas, P5-points-ancrage-os (CUPS, IFilter, QuickLook, modules complémentaires, Moodle), P5-ocr (après l'ADR), P5-html-paginé (après D-9).

Phase 6 — Écosystème (F-060…F-067), en parallèle dès que Phase 0 sort

P6-observatoire, P6-suite-de-conformité, P6-préfixe-ASKL, P6-normalisation (PDF Association, AFNOR/ISO TC 171, liaison ETSI ESI, errata), P6-safedocs, P6-fuzzing-continu, P6-registres (après D-1).

Transversal — la performance à chaque étage

Chaque lane qui touche un étage mesure avant/après avec le harnais de F-004 (criterion + ~50 fichiers) et ne livre pas une régression au-delà de 5 % sans l'expliquer. Étages : codecs (RUSSL), filtres, analyse/xref, polices, contenu/texte, rendu, écriture, conformité. Petite échelle d'abord ; le balayage complet du corpus seulement une fois F-004 stabilisé.

Modèle de rapport de lane

Objectif (F-xx, clauses) · ce qui a été livré · chiffres face à chaque oracle avec contrôles négatifs · défauts trouvés dans le code existant · ce qui a été délibérément non fait et pourquoi · ce qui reste · décisions soulevées pour le fondateur (→ 06-decisions.md) · commits (SHA, index temporaire) · emplacements du worktree et du scratch (jamais dans le dépôt).

Source: docs/roadmap-fr/05-battle-order.md · big-1 · 2026-09-14 19:32 UTC