Scripts du dépôt — référence maintenance & alignement d’environnement

Référence des scripts réutilisables du dépôt CoursIA. Règle générale (CLAUDE.md) : ne jamais écrire un script ad-hoc d’exécution / validation / maintenance — il existe presque toujours un outil dédié ici. Si manquant, l’ajouter dans scripts/notebook_tools/ (pas à la racine scripts/).

Les scripts scripts/fix_*.py / scripts/recycle_*.py à la racine sont des one-offs historiques (corrections ponctuelles déjà appliquées) — ne pas les réutiliser comme outils génériques.

Outils notebooks canoniques — scripts/notebook_tools/

CLI multi-famille

Script Usage
notebook_tools.py CLI principal : validate / execute / skeleton / analyze (multi-famille)
notebook_helpers.py Helpers partagés (import, pas d’exécution directe)
extract_notebook_skeleton.py Extraire le squelette (structure cellules) d’un notebook
notebook_lint.py Lint structurel notebooks (+ test_notebook_lint.py)

Exécution

Script Usage
wsl_papermill.py Papermill INSIDE WSL pour kernels GameTheory/Lean Python (execute / batch / check-env) — cf .claude/rules/wsl-kernels.md
batch_reexecute.py Re-exécution Papermill en lot
dotnet_executor.py, exec_dotnet_persist.py, exec_single_cell.py Exécution .NET Interactive : moteur cell-by-cell canonique (dotnet_executor.py), wrapper CLI historique (exec_dotnet_persist.py) et exécution ciblée
execute_qcpy_docker.py, qc_quantbook_execute.py Exécution QuantConnect (Quantbooks via Docker/QC Cloud)
_exec_bdd_csharp.py Archivé 2026-10-01 (palier 1 #18153) — voir scripts/notebook_tools/_archive/README.md

notebook_tools.py execute — Options avancées

python scripts/notebook_tools/notebook_tools.py execute <target> [options]
Option Description Cas d’usage
--kernel <name> Force un kernel specifique (ex. python3, .net-csharp, python3 (PyMC)) Cibler un env conda precis quand le kernel par defaut manque des deps
--cwd <path> Execute depuis ce repertoire au lieu du dossier parent du notebook Executer dans un worktree de curation, ou isoler load_dotenv()
--env KEY=VAL Injecte une variable d’environnement (repeter pour plusieurs) --env BATCH_MODE=true, overrides ponctuels
--scrub-keys Retire les cles API LLM (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) du sous-processus Test explicite d’un comportement sans credentials ; ne valide pas une démonstration qui revendique un appel LLM réel
--batch-mode Active BATCH_MODE=true (env + param Papermill) Notebooks interactifs en validation non-interactive
--cell-by-cell Execution cellule par cellule (.NET/Lean) Kernels persistants
--timeout N Timeout par notebook en secondes (defaut: 300) Notebooks longs

Cookbook — cas d’usage courants :

# Re-exec dans un worktree de curation
python scripts/notebook_tools/notebook_tools.py execute /tmp/worktree/SC-11.ipynb --cwd /tmp/worktree

# Forcer un kernel conda specifique
python scripts/notebook_tools/notebook_tools.py execute MyIA.AI.Notebooks/Probas/PyMC/ --kernel "python3 (PyMC)"

# Re-exec avec une variable d'environnement non sensible
python scripts/notebook_tools/notebook_tools.py execute MyIA.AI.Notebooks/GenAI/ --env BATCH_MODE=true

# Vérifier explicitement le chemin sans credentials (test négatif uniquement)
python scripts/notebook_tools/notebook_tools.py execute path/to/notebook.ipynb --scrub-keys

Capture des outputs .NET post-#r (#5005)

Les notebooks .NET Interactive contenant une directive #r "nuget: ..." ou #r "<dll>" perdent leurs outputs stdout (Console.WriteLine) si exécutes via le chemin Papermill par defaut (drain iopub / timing nbclient 2.7.0).

Recommandations :

  • --cell-by-cell (chemin jupyter_client direct) : OK depuis le fix du warmup post-wait_for_ready (cf PR feature/5005-cell-by-cell-warmup, fichier scripts/notebook_tools/notebook_helpers.py). Pas de régression Python/Lean (warmup conditionnel .net-*).
  • dotnet_executor.py directement : chemin canonique pour les notebooks .NET, déjà fonctionnel avant le fix. À privilégier pour les re-exécutions de validation.
# Validation .NET canonique (chemin kc.execute() direct, sans Papermill)
python scripts/notebook_tools/dotnet_executor.py <notebook> --kernel .net-csharp --timeout 240

# Equivalent via le CLI multi-famille (depuis le fix warmup)
python scripts/notebook_tools/notebook_tools.py execute <notebook> --cell-by-cell --kernel .net-csharp --timeout 240

Diagnostic : le bug n’est PAS dans le kernel .NET Interactive ni dans le mode HTTP — un test jupyter_client direct (kc.execute() + get_iopub_msg) capture 9/9 outputs post-#r. Le défaut venait des wrappers client (Papermill + cell-by-cell sans warmup).

Catalogue (anti-drift)

Script Usage
generate_catalog.py Régénère COURSE_CATALOG.generated.json + .md. Flags : --json-only, --series X, --status X, --check. Lancer la copie du worktree pour cibler ce worktree
catalog_coverage.py Couverture du catalogue
expand_catalog_markers.py Expansion des marqueurs catalogue
fix_catalog_drift.py Corriger le drift catalogue
verify_catalog_readme.py Vérifier cohérence catalogue ↔︎ README
count_notebooks_by_series.py, generate_parcours.py Comptage + génération de parcours

Qualité / conformité (règles C.1/C.2/C.3, anti-leak)

Script Usage
audit_c1_c3.py Audit C.1 (pas d’erreur volontaire) + C.3 (scope re-exécution)
check_c2_compliance.py Audit C.2 (outputs + execution_count présents)
detect_solution_leaks.py, audit_solution_leaks.py Détection fuite de solutions (labeling Exemple/Exercice)
validate_pr_notebooks.py Validation des notebooks d’une PR
generate_review_dossier.py Dossier de revue éditoriale (Epic #11259 T2) : depuis le seul chemin d’un notebook, relance les instruments canoniques (validate_pr_notebooks, pedagogy_density, count_exercises) + lookups (périmètre production-scope.md, registre editorial-review-registry.md, jumeaux twin_pairs.d, host-path outputs) et émet un dossier markdown 5 sections (identification / verdicts instruments / constats preuve-citée + correctif rédigé / 3 questions jugement / verdict EDITORIAL_REVIEW_CARD). Éphémère par design (stdout ou --output) — jamais un fichier du repo ; advisory exit 0. 12 tests unitaires : test_generate_review_dossier.py
capture_user_remarks.py Boucle de capture (Epic #11259 T3) : remarques user en vrac (fichier ou stdin, blocs séparés par --- ou une par ligne) → issues GitHub scopées, une par remarque unitaire. L’outil garantit fidélité verbatim (citation à l’identique, jamais reformulée) et rattachement mécanique (plus long segment de tokens consécutifs du stem cité dans la remarque — préfixe ou segment médian ; UNIQUE/AMBIGUOUS/NONE, jamais deviné) ; l’acceptance reste à instruire par l’agent. Dry-run stdout par défaut, --create pour gh issue create (label user-remark). Advisory exit 0. 20 tests unitaires : test_capture_user_remarks.py
diagnose_broken.py, forensic_scan.py Diagnostic notebooks cassés / scan forensic (HEAD, erreurs dures uniquement)
regression_scan.py Détecteur de régression output-health (axe-2) : marqueurs doux de dégradation env que forensic_scan/diagnose_broken ratent (token-starve, Graphviz non disponible, MiniZinc/Tweety manquant, .env mono-endpoint, INFEASIBLE/Solution valide: False). 3 modes : --snapshot (défaut, dégradés à HEAD), --history (git-walk git log --follow + git show par notebook → pointe le commit/date/auteur régressant + recoveries), --guard --base <ref> --head <ref> --paths … (CI, exit 1 si healthy→degraded). Allowlist regression_allowlist.json (dégradations démontrées/externes acquittées). Git local-only, stdlib pure. Ne juge PAS la fidélité prose↔︎sortie (axe-1 = humain/bot)
scan_md_hierarchy.py Audit mise en forme (EPIC #3966) : flague HINT-AS-HEADING (indice/objectif/etape en heading -> grande police), H1-DEEP, MULTI-H1. Render-agnostic (parse JSON). Verif visuelle finale via nbconvert+Playwright : cf notebook-formatting.md
audit_pip_install_cells.py Audit cellules !pip install (leak vector + env anti-pattern, secrets-hygiene §6 triage C = source-leak). Classifier UNCONDITIONAL_BASH / UNCONDITIONAL_SYS / CONDITIONAL_TRY / NON_BASH. Modes --scan / --scan-all / --scan-all --check (exit 1 si HIGH) / --json. Compteur initial repo = 70 HIGH-severity sur 203 notebooks (c.460). 13/13 tests unitaires PASS
pip_leak_delta.py Guard delta pip-leak : compare deux scans JSON d’audit_pip_install_cells.py et fail si la PR introduit des leaks HIGH nouveaux (pas un fail absolu --check — le repo porte encore des HIGH hérités drainés un-PR-par-notebook). CI-ready (exit 1 sur delta > 0)
detect_fabricated_outputs.py Détecteur sorties textuelles FABRIQUÉES committes comme résultats d’exécution (Prong-A, registre #3801) : placeholder textuel (Row N) ou dataframe backtest-entièrement-à-0.0 en lieu et place du vrai résultat. Companion image-axis de detect_blank_figures.py
audit_engine_named_not_invoked.py Audit claim → wiring → invocation → proof des moteurs annoncés (Google ADK, OpenAI/Anthropic, BigQuery et moteurs Smart Contracts). Reconnaît les helpers notebook-wide appelés, refuse qu’un print de setup tienne lieu de preuve, expose les cellules d’évidence et compare deux snapshots JSON avec --compare-base/--compare-head pour ne bloquer que les régressions
detect_smartcontract_drift.py Détecteur borné Smart Contracts (#15246) : UserOperation ERC-4337 non packée, réseaux Goerli/Mumbai présentés comme actifs et suites Foundry seulement imprimées. Exclut le contexte historique, les exercices C.1 et les cheatcodes/mocks Solidity légitimes ; mode delta par snapshots JSON
strip_fabricated_quantbook_outputs.py Strip des sorties text/PNG fabriquées des quantbook.ipynb (cf #6891, Side A). Les 8 quantbooks QC non-ré-exécutables via MCP portaient des outputs fabriqués ; cet outil les retire proprement (exception quantbook QC, cf secrets-hygiene §6)
detect_quantbook_window_divergence.py Détecteur période annoncée ≠ période calculée dans les quantbooks (#8772, classe doc-honesty #8052/#8364). Deux signaux : (A) lookback ENTIER passé à qb.History(...) — qui s’ancre sur qb.Time = StartDate, donc recule depuis la période déclarée — sans qu’aucune ligne n’imprime la fenêtre obtenue ; (B) SetStartDate placé dans un try: qui a échoué, la sortie committée venant du repli yfinance ancré à l’heure d’exécution. Args découpés par scanner à parenthèses équilibrées (une regex \([^)]*\) casse sur History(list(...), 365*5, ...)). Écarte les cellules de référence class X(QCAlgorithm) (ancrage glissant = effet voulu), les appels sur self, et les arguments ambigus. Le fix attendu est de DIVULGUER, pas de re-fenêtrer : re-fenêtrer avant #8734 échangerait un défaut de doc contre un défaut de données (forward-fill constant)
detect_bare_cross_dir_load.py Détecte un #load "X.cs" bare (nom nu, sans séparateur) dont le .cs n’existe PAS dans le dossier du notebook — anti-pattern du rollout SVG inline (#6927) où le kernel résout un #load relatif et échoue silencieusement / charge le mauvais fichier
check_notebook_navlinks.py Vérifie les liens de navigation relatifs cassés dans les cellules markdown des .ipynb (« précédent / suivant »). check_docs_links.py couvre uniquement les fichiers markdown (CLAUDE.md, docs/, README) ; cet outil couvre le markdown intérieur des notebooks
check_plotly_static_risk.py Détecte les cellules Plotly-CDN dans les .ipynb = blanc en static rendering (cf #6927). Le pattern canonique record PlotlyHtml + Formatter.Register émet un <script src="https://cdn.plot.ly/..."> externe qui rend en kernel live mais pas sur GitHub/nbviewer

Render-suite SVG inline (rollout #6927)

La migration Plotly-CDN → SVG inline text/html (canon ai-01 svg-6927-canon.md) est gardée par 5 détecteurs couvrant tous les cas de figure cassé. detect_svg_decimal_commas.py (dans la section Tests ci-dessous) traite le cas virgule-décimale fr-FR. | Script | Usage | |——–|——-| | detect_svg_broken_geometry.py | Détecte les sorties SVG dont un élément a une dimension négative (rect/use/image à width='-...' ou height='-...') = élément invisible, rendu cassé | | detect_svg_empty_display.py | Détecte les cellules .NET qui display() un chart SVG mais produisent un output vide (figure blanche sur GitHub/nbviewer) | | detect_svg_offscreen_flat.py | Détecte les SVG plats dont une géométrie de données est projetée au-delà du viewBox (>15% de sa hauteur) : barre/ligne/point rendu hors cadre = figure amputée (cas résiduel que les autres détecteurs ne voient pas) |

Papermill forensic & path-leak (anti-leak metadata)

Script Usage
detect_papermill_failed_state.py Détecte les notebooks dont l’exécution papermill ne s’est pas terminée proprement (#7079) : inspecte le bloc top-level metadata.papermill → deux classes papermill_hard_failure (exception non-None) et papermill_pending (status=“pending”)
detect_papermill_cell_level_state.py Companion cell-level du précédent : papermill écrit un status par-cellule que le détecteur top-level ne voit pas. Inspecte metadata.papermill de chaque cellule pour les échecs granulaires
detect_papermill_path_leak.py Détecteur read-only des fuites de chemins machine-locales dans les notebooks (companion de scrub_papermill_paths.py). Deux classes content-based : leak metadata.papermill chemin absolu + fuites dans les outputs. Cf secrets-hygiene §6 Stop & Repair (on ré-exécute, on ne scrubbe pas les outputs)
scrub_papermill_paths.py Scrub des chemins absolus machine-locaux du metadata papermill (metadata.papermill.output_path/input_path au basename). Seule normalisation manuelle tolérée hors outputs (metadata, pas une sortie de cellule) — cf secrets-hygiene §6 exceptions

Cure des accents FR & gates de régression — #2876

Script Usage
detect_accent_stripping.py Détecteur historique : dictionnaire conservateur ACCENT_PAIRS (source de vérité partagée). Le stripped form n’est pas un mot FR valide → non-ambigu
detect_link_target_regression.py Détecteur de régression des accents dans les TARGETS de liens markdown [texte](cible) (registre #2876). Un cure ad-hoc par regex globale \b(mot)\b peut accentuer la cible d’un lien → 404 ; cet outil garde les targets intacts
restore_accents_canonical.py CURE canonique (PR #7186). Markdown-only STRICT by construction : skip code/outputs/link-targets, préserve casse + structure (paragraph breaks). 4 bright-lines + 1 structurelle. Référence complète : accent-cure-defense-in-depth.md
check_identifier_regression.py GATE identifiants code (PR #7157, MERGÉ). Détecte l’over-reach (cure qui accentue un identifiant). _STRIP_RE retire commentaires+chaînes avant comparaison base(main) vs head(branche). CI-ready (exit 1)
detect_caps_regression.py GATE caps (PR #7198 MERGÉ ; #7197 CLOSED, son contenu absorbé en git-ref mode par PR #8917bd71b). Détecte une cure qui minuscule l’initiale capitalisée (H1/H2/table-header/début-phrase/all-caps). Scan line-aligned positionnel (clé anti-FP)

Workflow PR accents : générer via restore_accents_canonical.py (passe les gates by construction), jamais via un script ad-hoc. Périmètre, défense-in-depth (3 rôles), 4 classes de défauts, bright-lines, méthodologie : cf accent-cure-defense-in-depth.md.

Diagnostic / reporting / spécifiques

Script Usage
qc_classify.py Classification stratégies QC (BROKEN/NEEDS_IMPROVEMENT/HEALTHY)
epita_prcon_autograde.py Autograde EPITA Programmation par Contraintes
weekly_digest.py Digest hebdomadaire d’activité
fix_audio_dependencies.py Dépendances audio ; optimize_dvs.py archivé 2026-10-01 (palier 1 #18153)
_alpha_diag.py, generate_16e.py Diagnostics ponctuels

Audit, coûts & fidélité — scripts/audit/

Pipeline d’audit qualité et de matrice de coût (EPIC #8056) + audit sémantique claims↔︎outputs (#8052). Complémentaire de scripts/notebook_tools/ (qui cible exécution / lint / catalogue) : cette famille cible les axes transverses (coût, fidélité prose↔︎sortie, sorry Lean, registre datasets). Deux familles : checkers read-only gatables en CI (exit-code gatable), populateurs qui écrivent nb.metadata['cost'].

Checkers (read-only, gatables CI)

Script Usage
check_cost_metadata.py Cohérence matrice de coût (#8056) : lit nb.metadata['cost'] (canonique) avec fallback legacy YAML ---cost--- ; flague gpu_required:false mais imports CUDA / torch.cuda
check_dataset_registry.py Cohérence registre datasets (#8055 tr.2) : verdicts DRIFT / MISSING / CARD_REQUIRED / OK (litmus : EXTRACT, pas DECIDE), sortie YAML
check_denominators.py Détecteur léger de divergence entre 3 sources (disque / forensic / catalogue), #8050 ; --strict → exit 1 sur drift
check_editorial_review.py Cohérence registre editorial-review (YAML ↔︎ catalogue) : 6 validations dont reviewer != owner_logique, evidence_pr en état MERGED
check_lean_notebook_sorry.py Tally sorry par notebook Lean (#8051, kernel lean4-wsl) : strip commentaires puis compte sorry word-bounded. N’alimente plus l’axe scientific_review depuis #14831 : l’echelle mesure le risque du contenu, pas la rigueur formelle, et le compte de sorry ne concerne qu’une poignee de notebooks. sorry_free reste rendu comme preuve a cote
extract_claims_vs_outputs.py Audit sémantique cellule-par-cellule (#8052 P0) : compare prose markdown (claims) vs sorties code (outputs) ; 5 classes de mismatch

Populateurs (écrivent nb.metadata['cost'])

Script Usage
populate_cost_metadata.py Populate metadata['cost'] pour ~69 notebooks QC QuantBook sans coût (#8056) ; qcc_tokens_est = max(400, n_code_cells×70)
populate_gametheory_cost.py Populate coût GameTheory (48 NBs, CPU-pure : nashpy + numpy + matplotlib)
populate_semantickernel_cost.py Populate coût GenAI / SemanticKernel (26 NBs, API-heavy : gpt-4o / Azure)

Réparation d’assets (Stop & Repair)

Script Usage
regen_img1_dalle3.py Réparation asset DALL-E legacy via vraie regen DALL-E 3 (#8624, Stop & Repair L948) — jamais hand-edit d’output

Maintenance & environnement — scripts/

Chemin Usage
scripts/environment/setup_environment.ps1 Setup environnement (alignement machine)
scripts/environment/audit_environment.ps1 Audit de l’environnement local
scripts/environment/install-ffmpeg.{ps1,sh} Installer ffmpeg (audio/vidéo)
scripts/kernels/lean4-wsl/ Kernel Lean 4 WSL
scripts/kernels/validate_lean11.py Validation Lean-11
scripts/lean/setup_lean4_all.py Point d’entrée unique setup kernel Lean 4 : --wsl-only / --register / --validate / --check-wrapper (orchestre WSL install + registration Windows + validation) — cf docs/wsl-kernels-detail.md
scripts/lean/lean_kernel_check.py Détection canonique régression wrapper kernel.json (#1618) : inspect_kernel_wrapper (partagé par les 2 validateurs + l’orchestrateur)
scripts/lean/smoke_test_epita_is.py Smoke-test kernels Lean EPITA-IS
scripts/lean/check_i18n_siblings.py Checker i18n sibling-pair (EPIC #4980) : vérifie la byte-identity du body (signatures, preuves, tactiques) entre un Foo.lean FR-canonical et son miroir Foo_en.lean. Seules les docstrings/commentaires diffèrent. Sorties OK / OK-CONSUMER / DRIFT / ORPHAN = point de départ d’investigation, jamais un grain verbatim (3 formes légitimes, cf i18n-sibling-patterns.md)
scripts/lean/po2026_recover_build.py Recette récupération lake build po-2026 (codification #6771, self-repair règle F) : cold-rebuild unreliable → script documenté dans po2026-local-build-troubleshooting.md (archivé c.700, canonique = script 309L). Valide firsthand sur knot_lean
scripts/lean/check_mathlib_cache.py Vérifie qu’un cache Mathlib est réellement atteignable pour chaque lake, en traversant les junctions (realpath + os.walk) — find renvoie 0 sur un cache sain de 8124 oleans et os.path.islink() renvoie False sur une junction, combinaison qui fabrique un faux verdict « cache purgé » (5 cycles de lane Lean perdus, 2026-07-29). Statuts ok/partial/cold/absent, dédoublonne les lakes partageant un cache physique. Advisory (exit 0) ; --strict exit 1. La preuve décisive reste un lake build réel
scripts/lean/check_lake_direct_invocation.py + lake_direct_allowlist.json Garde CI anti-invocation-directe lake (#15666 T4, câblé fast-lane TRANCHE15) : refuse toute NOUVELLE invocation directe de lake build/lake env lean dans du code d’orchestration Python hors allowlist — chaque voie directe réintroduit le défaut fondateur (2026-09-12 : ~30 lean.exe à 95 % CPU). Détection AST (3 formes : appel subprocess inline, jeton lake/lake.exe en tête de liste de commande ou join de chemin, fragment f-string en position de commande) ; docstrings, sondes which, tests d’appartenance, itérateurs de probe et prose d’erreur ne comptent pas — chaque classe de FP a son négatif dans test_check_lake_direct_invocation.py. L’allowlist documente la dette (ratchet descendant : entrée stérile = STALE signalé). --all --check (CI) / --list (bootstrap) / --include-tests. Exit 0 OK / 1 violation hors allowlist
scripts/lean/setup_shared_mathlib.ps1 Mutualisation checkouts Mathlib via junctions NTFS (#2611) : -Mode Scan (inventaire groupes), Apply (cache .mathlib-cache/ + junctions, -Build vérifie, -RemoveBackups libère l’espace), Rollback (restaure les checkouts physiques). Précondition : lake-manifest.json identique sur TOUTES les deps transitives + même lean-toolchain. Ne jamais lake update un projet junctionné
scripts/check_grain_free.py Grounding pré-dispatch (une commande avant d’écrire un steer) : agrège l’état de l’issue, les contraintes de forme de son acceptance (cases - [ ] portant une négation — c’est ce que #10990 interdisait), les PRs ouvertes et mergées la référençant, et délègue les claims à check_lane_claim.py (autorité). --lane obligatoire. Exit 0 CLEAR / 1 FLAGGED / 2 UNKNOWN — une surface non interrogeable rend UNKNOWN, jamais une liste vide : « rien trouvé » et « pas regardé » ne partagent pas de valeur de retour. Complète check_lane_claim.py --paths, qui exige de connaître les chemins — ce qu’on n’a pas encore au moment de dispatcher
scripts/check_adjoint_prevalidation.py Gate d’entrée en review ai-01 (#16442) : exige un dossier [ADJOINT PREFLIGHT] complet de la lane adjointe, lié au SHA exact et à une empreinte des surfaces body/comments/reviews/threads/checks. Toute absence, mutation observable des surfaces actuelles ou valeur non canonique échoue fermé ; un événement GitHub ensuite supprimé/reverté n’est pas reconstructible par cet organe stateless. --template génère le bloc complet (empreinte incluse) et --fingerprint expose l’empreinte seule. Exit 0 READY / 1 BLOCKED / 2 UNKNOWN. READY autorise la lecture finale du coordinateur, jamais le merge
scripts/check_pr_perimeter.py Source de vérité périmètre pour reviews (#11268) : énumère les fichiers effectifs d’une PR (gh pr view --json files), nomme tout .github/workflows/** dans une section dédiée, détecte les mouvements de baseline/seuil du diff avec leur sens (sorry-baseline 16→14 = TIGHTEN ; un desserrement sans --baseline-justified => CHANGES_REQUESTED), et confronte l’assertion de périmètre du reviewer (--assert "...") à la liste réelle — la review #11227 (« 2 fichiers twins uniquement » sur 3 fichiers dont un workflow) ne peut plus être produite à l’insu. --scan-thread scanne le body PR + les reviews top-level et confronte chaque assertion trouvée à la liste effective ; câblé par .github/workflows/perimeter-review-guard.yml (déclenché sur pull_request + pull_request_review) — une fausse assertion devient un check rouge bloquant. Exit 0 OK / 1 FAIL (écart assertion, workflow non nommé, desserrement nu) / 2 erreur gh. À exécuter AVANT toute assertion de périmètre dans une review
scripts/coordination/debt_ledger.py Reducteur des ledgers partages (issue-debt + gpu-reservation) : schema versionne, validation stricte des observations (UTC explicite, provenance obligatoire, cles inconnues refusees), fusion par champ « plus recente observation compatible gagne » avec provenance et historique. La lecture se fait dans la forme du producteur, pas dans une forme inventee : l’export roosync_dashboard read imbrique son journal (data.intercom.messages) et son auteur est un objet (machineId:workspace), que l’adaptateur normalise — un lecteur qui ne regarde qu’au premier niveau voit « pas de messages » sur un export sain. Contrat de fenetre archive-aware : l’export declare sa couverture (window.kind = full / incremental, --window-full pour un export muet ; absent = incremental, fail-closed), un incremental sans snapshot precedent leve MISSING_CHECKPOINT, et le snapshot precedent est plie champ par champ comme checkpoint quand le dashboard a condense la queue. Le transport partage n’est pas un fichier : observations = messages append-only du dashboard dedie (un par kind), snapshot ecrit par ai-01 seul en section status — jamais d’ecriture sous $ROOSYNC_SHARED_PATH (Drive : pas de verrou, assert_local_output refuse, sans override). CLI init (dry-run par defaut) / append (imprime l’appel MCP, n’ecrit rien) / reduce (artefacts locaux atomiques sous verrou). Porte deux kinds depuis #16737 : issue-debt (cle owner/repo#N, EAT, closeability, follow-ups) et gpu-reservation (cle <machine>#gpu<n>, etats held/released/stale, resume held_by_machine/holders/stale_holds, dashboard dedie CoursIA-gpu-reservation-ledger — registre d’occupation, pas un verrou dur). Schema, contrat et metriques : scripts/coordination/README.md ; lectures : scripts/tests/test_debt_ledger.py
scripts/ci/measure_runner_demand.py Baseline exhaustive de demande GitHub Actions (#12704) : collecte une fenêtre UTC avec bisection anti-cap 1 000 + pagination de tous les jobs, mesure attente (started_at-created_at), travail runner (completed_at-started_at), provenance same-repo/fork/unknown et dénominateurs ; replay offline par --input. Co-résidence (#15574) : bloc co_residence (hôte présumé du préfixe du runner_name, pic et moyenne de concurrence par job) et bloc runners_inventory (--runners, slots enregistrés par hôte, trois états measured/unavailable/not_collected, jamais un parc vide). Exit 0 mesure valide / 2 instrument ou snapshot incomplet. Procédure : docs/ci/self-hosted-runners.md · organe : .github/workflows/runner-coresidence-advisory.yml
scripts/ci/manage_self_hosted_runner.py + self_hosted_runner_profiles.json Cycle de vie Windows des runners éphémères isolés (#12704) : profils distribués po-2023..po-2026 avec archive/SHA-256 épinglés ; commandes install, register, verify, teardown en dry-run par défaut, mutations uniquement avec --apply; compte local dédié, ACL négatives .secrets/SSH/gh, tokens via ACTIONS_RUNNER_INPUT_*, extraction anti-Zip-Slip/ADS et teardown borné par manifeste. register --apply est le bouton d’activation séparé, jamais lancé pendant la préparation. Procédure : docs/ci/self-hosted-runners.md
scripts/ci/pool_review_verdicts.py Vue de triage du pool : verdict lu dans les corps, pas reviewDecision (#16926) : sous token COMMENT-only (#15511) le champ reviewDecision vaut null à perpétitude sur ~82 % du pool y compris les PRs portant un VERDICT: LGTM argumenté — trier dessus fabrique le faux compte « sans review ». L’organe balaye le pool en GraphQL paginé borné (page 50 + retry 5xx unique : les fenêtres reviews+comments font 504/502 au-delà, mesures 2026-09-20), lit le préfixe VERDICT: en début de ligne sur les deux surfaces (reviews[] + commentaires de persona, marqueur importé du canon check_unaddressed_nits), latest-wins, et distingue SANS-REVIEW (aucune voix) de VOIX-SANS-VERDICT et des états réels CHANGES_REQUESTED/APPROVED qui gouvernent. --gradient rend la répartition par quartile d’âge (l’enseignement #16926 : les PRs vieillissent parce qu’elles portent une réserve vivante). Advisory : exit 0, ou 2 si le balayage est illisible. Tests : scripts/tests/test_pool_review_verdicts.py
scripts/mcp-maintenance/ Maintenance MCP (config, docs, scripts) — cf README_MCP_MAINTENANCE.md
scripts/validation/dispatch.py + matrix.yml Matrice de validation / dispatch
scripts/genai-stack/genai.py GenAI Docker (ComfyUI + Qwen) + validation — cf docs/genai/genai-services.md
scripts/livecoding_video_pipeline.py Pipeline livecoding-video #15604 (étapes 1 + 4) : composition Strudel par template (compose_strudel, visuals .scope()/.pianoroll() opt-in) et capture navigateur --capture — pattern injecté par hash d’URL (build_repl_url, encodage encodeURIComponent(base64) observé sur le bouton share), clic play trusted (headed requis : clic JS ≠ user gesture, AudioContext live suspendu), gate checksum canvas avant enregistrement, canvas.captureStream + MediaRecorder (webm), Export to WAV natif du REPL (rendu offline du moteur strudel — aucun routage audio système VB-Cable), mux ffmpeg H.264/AAC. Tests : scripts/tests/test_livecoding_video_pipeline.py. Étapes 2/3/5/6 deferred avec claim par phase
scripts/repair_genai_notebooks.py, scripts/audit_genai_corruption.py Réparation / audit corruption GenAI
scripts/fix_robust_dotenv.py Robustesse chargement .env
scripts/scan_student_forks.py Scan des forks étudiants
scripts/series_progress_manager.py Suivi de progression des séries
scripts/validate_qc_projects.py Validation projets QuantConnect
scripts/update_navigation.py Mise à jour navigation README
scripts/extract_pptx_titles.py, scripts/extract_slidev_titles.py Extraction titres slides (PPTX / Slidev)
scripts/execute_with_env.py, scripts/execute_dotnet_notebook.py, scripts/execute_sudoku_python.py Wrappers d’exécution avec env
scripts/quantconnect/, scripts/smartcontracts/, scripts/sudoku/, scripts/datasets/, scripts/tests/ Outils par domaine

Tests — scripts/tests/ + scripts/notebook_tools/tests/

scripts/tests/ regroupe des fichiers de test (1701 tests) ; scripts/notebook_tools/tests/ en regroupe aussi (3199 tests — couvre les modules notebook_tools : CLI, helpers, skeleton, lint, catalogue, qualité C.1/C.2/C.3, leak detection, forensic, execution, enrich, reporting), soit 4900 tests au total (snapshot pytest --collect-only 2026-07-21). Couverture de scripts/tests/ par domaine :

Domaine Fichiers Modules couverts
genai-stack/ 9 config.py, commands/{validate,audio_apis,models,notebooks,auth,gpu}.py, core/{comfyui_client,auth_manager}.py, models.py
sudoku/ 9 core/{solvers,graph,dataset,generation,models,training,evaluate}.py, sudoku_rrn, sudoku_solvers (evaluate.py = GPU-only, partiellement couvert)
smartcontracts/ 2 validate_sc_notebooks.py
extract-titles (top-level) 4 extract_pptx_titles.py, extract_slidev_titles.py, extract_titles.py, extract_readme_figures.py
ml/ 1 garch_baseline
autres (top-level + misc) 26 check_docs_links, regen_quarto_render, quarto_render_timing (mesure phases #14597), render_envs (secrets), scan_student_forks, series_progress_manager, update_navigation, validate_qc_projects, execute_sudoku_python, execute_qcpy_docker, translation_sync, translate_csv, detect_{ascii_workaround,blank_figures,svg_decimal_commas}, verify_{prosody,transcript}, audit_exposed_services, auth_manager, configure_max_quantization, container_startup, download_yfinance, manage_crypto_archive, notebook_tools_pure, repair_genai_notebooks, validation_dispatch

Lancer la suite : python -m pytest scripts/tests/ -v (depuis la racine du repo).

Modules genai-stack non testes (intentionnellement) : commands/docker.py (subprocess Docker), commands/quant.py (API externe).

Voir aussi

Retour au sommet