Procédures récurrentes — CoursIA
Détail des workflows référencés dans CLAUDE.md section “PROCEDURES RECURRENTES”.
Workflow PR
- Identifier la mission (issue GitHub ou directive RooSync)
- Brancher :
git checkout -b feature/<sujet>(oufix/<sujet>) depuismainà jour - Implémenter
- Pour notebooks modifiés : re-exécuter le notebook complet, vérifier outputs, vérifier scope strict (pas de re-exec gratuite des autres notebooks de la famille)
- Pour code production : ajouter/modifier tests, lancer le build (PEP8 /
dotnet build), zéro warning - Commit message :
type(scope): description courte(Conventional commits) - Push, ouvrir la PR avec description claire (Summary + Test plan)
- Auto-review selon les 5 points (CLAUDE.md section B). Si self-review échoue : revenir au point 4
- Annoncer sur dashboard
[INFO]ou poster en commentaire de l’issue - Attendre review/merge par ai-01. Ne pas se merger soi-même (les agents)
Dispatch agents (coordinateur ai-01)
Pour assigner une tâche à une machine distante (po-2023/2024/2025/2026) :
Vérifier la disponibilité :
roosync_dashboard(action: "read", type: "workspace")+ heartbeat machineComposer un message structuré :
roosync_send( to: "myia-po-XXXX:CoursIA", subject: "[DIRECTIVE] <short>", priority: "MEDIUM" | "HIGH" | "URGENT", tags: ["po-XXXX", "<topic>"], body: "## Mission\n...\n## Deliverables\n...\n## Quality Criteria\n..." )Logger le dispatch sur le dashboard workspace
[INFO]Suivre les rapports de l’agent et acquitter via
roosync_send(action: "reply", ...)
Validation notebook (avant commit)
# 1. Validation structure
python scripts/notebook_tools/notebook_tools.py validate <path>
# 2. Verifier les outputs sont presents (regle C.2)
python -c "import json; nb=json.load(open('<path>')); print(sum(1 for c in nb['cells'] if c['cell_type']=='code' and not c.get('outputs')))"
# 0 = OK, sinon re-executer le notebook
# 3. Verifier l'absence d'erreur volontaire (regle C.1)
grep -nE "raise NotImplementedError|assert False" <path>
# Aucune occurrence acceptable
# 4. Verifier le scope (regle C.3)
git diff <path> | grep -cE '^\+\s*"source"'
# > 0 = source change, OK pour commit. = 0 = uniquement outputs, NE PAS COMMITAudit anti-régression (avant merge PR suspecte)
Pour une PR avec deletions > insertions sur code métier (Lean/Coq/Python core / tests) :
# 1. Comparer historique
git log --all -- <fichier>
git show <commit> -- <fichier>
# 2. Detecter sorry/stub introduits dans Lean
git diff <base>..<pr-branch> -- '*.lean' | grep -E "^\+.*sorry"
# Si presence : exiger justification explicite
# 3. Detecter cellule # Solution -> stub
git diff <base>..<pr-branch> -- '*.ipynb' | grep -E "^[-+].*Solution|^[-+].*pass"
# 4. Cross-check historique : si fichier mentionne en memoire/dashboard recemment, contenu probablement intentionnelPatterns red-flag complets : .claude/rules/anti-regression.md.
PR doc-honesty — alignement markdown ↔︎ output (règle C.4)
Une PR « doc-honesty » / « alignement output » / « reconcile stale » (titre ou body citant #8052 ou #3801) DOIT diagnostiquer la cause de la dérive prose ↔︎ output AVANT de ré-aligner. Détail : .claude/rules/notebook-conventions.md §C.4 + .claude/rules/pr-review-discipline.md §D.5.
Workflow 4 étapes avant ouverture
| Step | Action | Livrable |
|---|---|---|
| 1. Identifier la contradiction | Relire la cellule code + l’output committé + le markdown. Noter la valeur citée par le markdown et la valeur réellement dans l’output | claim_markdown=X, output_réel=Y, écart=Y-X |
| 2. Triage cause racine | Classifier selon .claude/rules/regles-vigilance-detail.md G.7 : (a) env/kernel (règle F : réparer), (b) claim antérieure fabriquée (revert + ré-exec), (c) moteur upstream (issue engine-fix), (d) régression dépendance (lockfile + ré-exec), (e) stochasticité non-seedée (seed + multi-seed ≥4 + verdict BEATS/NO BEATS) | cause_classification: a/b/c/d/e |
| 3. Décider du verdict | Appliquer la matrice décisionnelle (ci-dessous) | verdict: SUBSTANCE / REFRAME / COSMETIC / FABRICATION |
4. Écrire ## Diagnostic dérive dans le body PR |
Inclure : cause classifiée, verdict, action choisie. Section obligatoire dans le body, citer #8364 seul ne suffit pas (cf §D.5 pr-review-discipline) |
Section body PR présente |
Matrice décisionnelle (issue #8364 Garde-fou B)
| Verdict | Critère vérifiable | Action merge | Issue fille |
|---|---|---|---|
| SUBSTANCE | Cause corrigée : env réparé (règle F), claim antérieure revertée, seed ajouté + multi-seed OK, lockfile fixé | Merge OK | Aucune si cause fixée |
| REFRAME | Sortie honnête = la valeur réelle (output régénéré). Le markdown re-formule l’interprétation sur la valeur vraie | Merge OK si valeur vient d’une re-exec fraîche (sinon COSMETIC) | Aucune |
| COSMETIC | Cause identifiée mais non traitée — alignement markdown sans re-exec = « jambe de bois repeinte », consacre la dégénérescence | REFUS merge (CHANGES_REQUESTED §D.5) | OBLIGATOIRE See #N traitant la cause |
| FABRICATION | Markdown ajusté pour masquer une regression connue sans issue ni re-exec = falsification preuve d’exécution | REFUS merge + escalade §G.9 | Issue + revert prior |
Anti-patterns
- Citer
#8364en label sans## Diagnostic dérivedans le body = violation §D.5, reviewer DOIT posterCHANGES_REQUESTED(incident fondateur #8479, MusicGen 02-3 RTF0.5-2x→0.21-0.24xaligné sur run non-optimisé alors qu’une re-exec Stop-&-Repair était déjà due — verdict COSMETIC + CHANGES_REQUESTED obligatoire). - Aligner un nombre de perf/timing/accuracy/coût sans re-exec alors que le notebook est re-exécutable localement (kernel Python/.NET dispo, règle F) = enshrine une valeur qui changera au prochain passage kernel. C’est la dérive même que C.4 interdit.
- Fold l’alignement dans une PR markdown séparée alors qu’une re-exec Stop-&-Repair est déjà due sur ce notebook (leak cellule cassée, cause classifiée (a) env) = malhonnête. Fold dans la re-exec, pas de PR markdown isolée.
CAUSE_DOCUMENTED_ONLYsans issue fille = COSMETIC caché, CHANGES_REQUESTED (cf §D.5).- Hand-editer la sortie de cellule au lieu de re-exécuter (Stop & Repair, L948 ★★, règle secrets-hygiene #6) = BANNISSEMENT (
CHANGES_REQUESTED§D + §H sota-not-workaround). Seules exceptions tolérées : quantbooks QC (non-exécutables via MCP) +metadata.papermill.input/output_pathaubasename+probeAddressesbanner strip post-re-exec .NET.
Vérification post-fix (avant [DONE])
# 1. La PR porte bien `## Diagnostic dérive` dans le body (sinon CHANGES_REQUESTED §D.5)
# NB : --jq '.body' OBLIGATOIRE — sans lui, gh sort le wrapper JSON (une ligne, \n échappés)
# et l'ancre ^ ne peut JAMAIS matcher : la commande retourne 0 même si la section existe.
gh pr view <N> --json body --jq '.body' | grep -c '^## Diagnostic dérive'
# > 0 requis
# 2. Si verdict COSMETIC : une issue fille doit exister avec `See #N`
gh pr view <N> --json body --jq '.body' | grep -oE 'See #[0-9]+'
# > 0
# 3. Si verdict REFRAME : la valeur du markdown doit venir d'une re-exec fraîche
# (papermill/kernelspec exec récent), JAMAIS byte-surgical markdown-align sur l'ancien outputScope discipline
Une PR doc-honesty est atomique : 1 notebook (ou 1 série de notebooks homogène en cause), 1 cause classifiée, 1 verdict. Pas de composite « alignement N notebooks + fix env + régén catalogue » (G.4 / R3 catalog-pr-hygiene §1).
Refs : #8052 (Epic parent audit sémantique), #8364 (issue parent doc-honesty protocol), #3801 (Epic SOTA axe-2 registre), #8479 (incident fondateur MusicGen RTF).
Exécution Quantbooks (règle user 2026-04-29)
Pour un notebook research utilisant QuantBook() (kernel QC Cloud uniquement) :
- MCP qc-mcp d’abord : vérifier si un outil exécute le research notebook
- Fallback Playwright : automatiser la session QC Cloud Web (login, navigation projet, Run All, téléchargement notebook exécuté)
- Pas de fallback markdown explicatif : un Quantbook commit doit avoir des outputs réels QC Cloud
Productivité pendant les opérations longues (règle HARD 2026-05-11)
Quand un processus long tourne (training GPU, backtest QC, build Lean, docker pull, prover BG iter, papermill batch, multi-seed run) : ne pas attendre passivement.
- Lancer le BG, noter son ID + nature attendue
- Immédiatement continuer avec autre travail : autres tracks dispatchées, audits parallèles, préparation PR suivante, review code, planification iter suivante, MAJ docs
- Check le BG uniquement à intervalles utiles (5-10 min) via
tail -50 output | grep -E "FINAL|RESULT|ERROR"ou monitor ciblé. Jamais event-par-event réactif - Minimum 2 tracks en flight à tout moment pour chaque agent (1 BG + 1 CPU/IO local). Si un agent n’a qu’un BG, il demande immédiatement une 2e track au coordinateur via
[ASK] capacitydashboard
Anti-patterns interdits : - “Monitor event arrived, je réponds ‘j’attends’” — non, je travaille sur autre chose en parallèle - “Le BG va prendre 30 min, je fais une pause” — non, j’ai 30 min de travail parallèle disponible - Dispatcher 1 seule track BG à un agent + dire “reviens quand fini” — non, 2 tracks minimum (1 BG + 1 CPU)
Pourquoi : un BG de 30-60 min consomme 30-60 events monitor si l’agent reste réactif, sans rien produire en parallèle. Le BG tourne même sans surveillance. Coordinateur = chef d’orchestre, pas spectateur.
Incident 2026-05-11 ai-01 (Lean prover iter 6 BG) : ~35 events monitor consommés à regarder BUILD-FAIL répétés, zéro autre track avancée pendant ce temps. User signal explicite “fais en sorte que les autres agents trainers ou prouveurs fassent pareil”.
Validation pré-commit notebook H.3 (regle HARD)
# Aucun notebook commité sans cellule exécutée (execution_count != null OR outputs non vides)
python -c "import json,sys; nb=json.load(open(sys.argv[1])); bad=[i for i,c in enumerate(nb['cells']) if c['cell_type']=='code' and c.get('execution_count') is None and not c.get('outputs')]; sys.exit(1 if bad else 0)" "$nb"Si fail → (a) exécuter localement (env complet H.2), OU (b) dispatcher RooSync sur machine compatible, OU (c) déplacer dans _pending_execution/ avec issue ouverte.
Cycle merge coordinateur — leçons durables (ai-01)
Leçons récurrentes du cycle review+merge, consolidées depuis les logs de cycle. À relire plutôt que de les ré-apprendre incident par incident.
Cascade catalogue (HARD)
Toute PR touchant COURSE_CATALOG.generated.json rend les autres PRs catalog-touchers DIRTY/CONFLICTING au merge (le catalogue est régénéré globalement). Donc :
- Merger les PRs non-catalogue d’abord, puis les catalog-touchers un-par-un.
- Conflit catalogue = l’auteur rebase + régénère :
python scripts/notebook_tools/generate_catalog.py --json --git-tracked-only(parité CI = N entrées git-tracked ;--jsonnu inclut les_output.ipynblocaux = drift), puisexpand_catalog_markers.py. - JAMAIS force-resolve le conflit côté coord ; JAMAIS force-push la branche de l’auteur.
- Check CI “Notebook catalog drift (read-only, advisory)” : advisory, jamais bloquant (#15998) — le catalogue est réécrit par
catalog-cron.ymlsurmain(#2632/#2744), une PR n’a rien à régénérer. Un drift signalé = notice informative, pas un bounce. - Cascade-independence : une PR dont le drift-check = SUCCESS et qui ne touche pas le catalogue est indépendante — ne pas la hold à tort dans la file cascade.
Trap “APPROVED”
reviewDecision=APPROVED provient du bot requis clusterManager-Myia (Hermes/NanoClaw, même compte, distingués par préfixe body [Hermes]/[NanoClaw]). Mon gh pr review --request-changes en myia-ai-01 ne flippe PAS le flag aggregate. Lever un hold = soit --approve documenté par evidence, soit admin-merge via gh auth switch -u jsboige. Toujours lire body + tous comments + diff (pas le seul flag).
Qualité enrichissement
Toujours sampler le markdown ajouté avant merge : content-specific (interprétation réelle du résultat) = OK ; filler générique (“Suite du traitement”, “Analyse des résultats”) = REJET (gaming du détecteur, famille #1214).
Dead-code
Vérifier qu’un script cible est LIVE (existe + exporté + ≥1 caller réel + catalogué) AVANT d’écrire/merger des tests dessus. Un test qui importe un module supprimé casse la suite.
mergeable != ready
Un flip MERGEABLE (conflit résolu) ne lève PAS un hold qualité (gate P5, validation user). Distinguer “merge-conflict résolu” de “gate qualité franchi”.
Maturité catalogue = README au render-time
Les flips BETA→PRODUCTION se vérifient via le badge counts du README (PRODUCTION=N→M), PAS par grep maturity dans le JSON (champ vide au render). Ordering non-stable = diff symétrique = churn cosmétique ; issue_pr_associee non-préservé au regen.
Métriques outputs
output_type count ≠ missing-outputs. Le vrai métrique “non-exécuté” = execution_count: null ET outputs vide. Un diff de reserialization (churn C.3) n’est pas une régression d’exécution.
Commandes / vigilance
- Diff d’un fichier d’une PR :
gh pr diff N -- pathn’est pas supporté →git fetch origin pull/N/head:prNpuisgit show prN:path. - Une self-review de worker peut sur-alarmer (ex. flag “API key exposée” sur un print masqué) → lire le diff réel avant de propager une consigne “rotate”.
- Fast-merges (<9 min, compte
jsboige) bypassent les bots (poll ~30 min) : low-risk mais le gate review est contourné — réserver au forensic/auto trivial.
Worker discipline post-c.264 (L278-L286) — leçons cross-machine consolidées
Leçons consolidées depuis les incidents ai-01 INCIDENT c.264 r.26th (phantom-merger-self-declare) et les 3 cycles subséquents. Durcies, non-délégables, et complémentaires aux règles proactive-coordination.md / coordinator-discipline.md / verify-before-claiming.md.
L278 — Worker ne merge JAMAIS (phantom-merger-self-declare-honest). Une session worker qui invoque /coordinate ou gh pr merge = confusion de rôle. Même si sweep-ready + bots PASS, même si le worker se déclare “honest”, le merge reste coord-only. Source : ai-01 INCIDENT c.264 r.26th où worker-session a tenté d’arbitrer sur PR déjà en sweep.
L279 — Sweep-ready = DM HIGH vers ai-01, JAMAIS gh pr merge côté worker. Si ta PR est §H.4 sweep-ready (11/11 SUCCESS bots + catalog-guard ✓ + link-check ✓ + propre-rebased origin/main), tu envoies un DM roosync_send to:"myia-ai-01:CoursIA" priority:"HIGH" avec le verdict §H.4, et tu postes [DISPATCH→inbox] dashboard. Le coordinateur arbitre, merge, et acquitte. Anti-pattern : “sweep-ready + bots PASS donc je merge” = worker INTERDIT.
L280 — Cron /coordinate = ai-01 coordinateur ONLY. Worker CronCreate = prompt worker-side (/continue ou /executor), cadence 3540s (clamp runtime ≤1h), jamais /coordinate. Cause documentée : po-2026:CoursIA-2 cron /coordinate worker-side (user 2026-07-07) — inversion de rôle silencieuse. Diagnostic : si ton agent voit /coordinate arriver dans son CronCreate, c’est un signe d’inversion.
L281 — Rebase origin/main avant sweep ai-01 quand gh pr view --json baseRefOid ≠ merge-base. 3-dot canonique pour R2 substance (git diff origin/main...origin/<branch>) ≠ 2-dot héritage (git diff origin/main..origin/<branch> peut montrer 9 fichiers vs 2 = héritage Wave-25/26 sur origin/main non-rebasé). Source : incident po-2023 c.271.
L282 — Mirror-lanes collision. Une machine avec deux lanes (CoursIA + CoursIA-2) = deux workers distincts. Avant de claim, poster [CLAIMED] <#issue> — <machine:workspace> <ts> sur le dashboard de la lane ciblée — pas l’inverse. Incident fondateur : #5640/#5641 doublon sur #5635, 6 min apart, ai-01 arbitrage 13:51Z.
L283 — Condensation LLM hallucine état merge/contenu. TOUT claim d’état (merge / OPEN / contenu main) DOIT être vérifié firsthand via gh pr view --json state,mergedAt,mergeCommit + git ls-tree origin/main <file> + git log origin/main --oneline AVANT propagation. Hiérarchie de confiance : gh API > git log > dashboard intercom > status condensé. Le status condensé auto-92% peut halluciner (po-2026 c.288 : “#5657 MERGED by jsboige” alors que PR OPEN CLEAN awaiting sweep).
L284 — Commit amend légitime pour CI regression. git status montre 1 fichier modifié post CI pass → git commit --amend --no-edit (préserve c.187 atomic), puis git push --force-with-lease origin HEAD sur sa propre branche feature. Anti-pattern : créer un 2ᵉ commit “fix CI” (violerait c.187 HARD). Documenter SHA rewrite + --no-edit dans body PR + DM ai-01. Étendu (c.294) : amend légitime aussi pour CHANGES_REQUESTED fondé sur défaut vérifié firsthand.
L286 — CI check-links failure → link-depth fix via L284 amend. (1) gh run view <run-id> --log-failed | grep -B 2 -A 5 "REGRESSION\|broken link\|❌" extrait les liens cassés firsthand ; (2) chemin en ../../<file> trop court → ajouter ../ (3-up → 4-up) ; (3) lien intra-branche vers fichier absent origin/main et branche → réécrire URL externe pointant la PR livreuse. Anti-pattern : 2ᵉ commit (violerait c.187).
L786 — Honest-drain diagnostic AVANT claim (c.796). Partition drained + cross-famille tracks own par d’autres lanes → NE PAS forcer low-substance LIGHT pour combler un cycle. REARMER wakeup suivant quand grain DEEP/MED substance-available. Test : gh issue list --state open | wc -l > 0 ne suffit pas, il faut identifier le grain exécutable pour ta capability (CPU+vision OK, GPU-only exclu).
L915 — PR OPEN MERGEABLE ≠ PR mergée. Avant de claim un cycle N dépendant d’une PR OPEN MERGEABLE upstream, vérifier si elle a été mergée dans la fenêtre (gh pr view --json mergedAt). 2 options : (a) reporter c.N à mergedAt confirmé ; (b) redécouper le grain en substrate standalone + c.N+1.
Opérationnel — check pré-cycle :
# Vérifier 3-prong C715-L2 + L786-L2 + L915 AVANT claim
git log --all --oneline --grep "#<issue>" # 0 commit upstream
gh pr list --search "#<issue>" --state all # 0 PR antérieure
gh pr view <N> --json state,mergedAt,mergeStateStatus # état réel PR
gh pr view <N> --json baseRefOid # rebase vs main