diff --git a/.claude/rules/pr-review-discipline.md b/.claude/rules/pr-review-discipline.md index 746035b35f..04803bd951 100644 --- a/.claude/rules/pr-review-discipline.md +++ b/.claude/rules/pr-review-discipline.md @@ -8,9 +8,7 @@ S'applique à **tous les reviewers**, humains et bots (clusterManager-Myia, jsbo ## Émission du verdict — un point qui tient le merge porte un marqueur (HARD, #14682) -Toute review (bot ou humaine) dont le corps formule **un point tenant le merge** porte un **marqueur reconnu** : préfixe de verdict (`[Hermes] COMMENT_WITH_CONCERNS`, `CHANGES_REQUESTED`) ou glyphe de sévérité (🟡, 🔴). L'organe B.0 (`scripts/check_unaddressed_nits.py`, `CONCERN_MARKERS`) ne lit **que** ces marqueurs : une réserve bloquante posée en prose libre **sans** marqueur lui est invisible et rend `rc=0` — instance fondatrice **#14658** (réserve qualifiée « le seul point bloquant pour un LGTM plein », prose française sans marqueur, `rc=0`). - -La réciproque est tranchée par mesure (**#14682**, scan de 80 PRs mergées) : **ne pas élargir** `CONCERN_MARKERS` à des mots de prose (« bloquant », « à corriger », « est faux ») — un tel filet sur-accuse d'un facteur 5 (4 des 5 détections : de la prose qui *décrit* un blocage de job ou de garde, pas qui *pose* une réserve). Le contrat est côté émission, pas côté filet. +Toute review (bot ou humaine) formulant **un point tenant le merge** porte un **marqueur reconnu** : préfixe de verdict (`[Hermes] COMMENT_WITH_CONCERNS`, `CHANGES_REQUESTED`) ou glyphe de sévérité (🟡, 🔴). L'organe B.0 (`scripts/check_unaddressed_nits.py`, `CONCERN_MARKERS`) ne lit **que** ces marqueurs : une réserve bloquante posée en prose libre **sans** marqueur lui est invisible et rend `rc=0`. **Ne pas élargir** le filet à des mots de prose : il sur-accuse d'un facteur 5 (mesure #14682) — le contrat est côté émission, pas côté filet. Instance #14658 + scan 80 PRs : [pr-review-context.md](../../docs/reference/pr-review-context.md). ## Critères CHANGES_REQUESTED obligatoires (HARD) @@ -29,7 +27,7 @@ Un reviewer **DOIT** poster `state: CHANGES_REQUESTED` (pas COMMENTED, pas APPRO Toute PR touchant `*.lean` ou `agent_tests/prover/` **DOIT** inclure dans le body : -1. Compte de `sorry` **réel** avant/après — `python scripts/lean/count_code_sorry.py --json`, champ `distinct_code_sorry`. **Pas `grep -c sorry`** : il compte la prose (docstrings, `-- commentaires`, feuilles de route), et les modules Lean du dépôt documentent précisément leur propre absence de `sorry`. Mesuré le 2026-08-14 sur les 21 lakes : **484 naïfs pour 21 réels (23×)**, dont **9 lakes à 0 réel** — un reviewer appliquant `grep` à la lettre exigerait la justification de 68 `sorry` dans `grothendieck_lean`, qui n'en a aucun. Le gate CI mesure déjà juste (`sorry-filter-mode: real` de `lean-axiom.yml`) : c'est le texte de cette règle qui pointait le mauvais instrument. +1. Compte de `sorry` **réel** avant/après — `python scripts/lean/count_code_sorry.py --json`, champ `distinct_code_sorry`. **Pas `grep -c sorry`** : il compte la prose, pas les preuves (mesure du 2026-08-14 : 484 naïfs pour 21 réels sur les 21 lakes, [pr-review-context.md](../../docs/reference/pr-review-context.md)). Le gate CI mesure déjà juste (`sorry-filter-mode: real`) : c'est le texte de cette règle qui pointait le mauvais instrument. 2. Lien vers `Lake build SUCCESS` (CI ou commit local prouvable) 3. Lien vers `Proof integrity SUCCESS` (job CI `proof-integrity` → `LeanVerifier.check_axioms(module, fail_on_sorry=True)`) 4. Si refactor du prover Python : justifier pourquoi il est nécessaire au claim Lean (sinon split) @@ -38,11 +36,11 @@ Toute PR touchant `*.lean` ou `agent_tests/prover/` **DOIT** inclure dans le bod **Un `proof-integrity SUCCESS` antérieur au 2026-07-28 ne prouve PAS l'absence de `native_decide`** (parser aveugle aux noms longs wrappés ; corrigé #8740). Ne pas ré-invoquer un vert plus ancien comme preuve. -**B.3 se lit « non applicable » — et doit être ÉCRIT tel quel dans le body** dans deux cas, jamais sauté en silence : (a) le job n'est pas câblé sur le lake de la PR (#8677) ; (b) il l'est, mais ses `target-modules` n'atteignent pas le module modifié, ni directement ni par clôture d'imports (#8782) — un vert hors-cible est indiscernable d'un vert sur cible dans le rollup. Le job advisory `target-coverage` rend l'écart lisible. Câblage = **exactement** les workflows appelant `lean-axiom.yml` (`grep -ln 'lean-axiom' .github/workflows/*.yml`, moins le fichier lui-même) — mesure mécanique, pas un compte recopié. Triage par lake : [lean-axiom-coverage.md](../../docs/reference/lean-axiom-coverage.md) ; incidents : [pr-review-context.md](../../docs/reference/pr-review-context.md). +**B.3 se lit « non applicable » — et s'ÉCRIT tel quel dans le body** dans deux cas, jamais sauté en silence : (a) le job n'est pas câblé sur le lake de la PR (#8677) ; (b) il l'est, mais ses `target-modules` n'atteignent pas le module modifié (#8782) — un vert hors-cible est indiscernable d'un vert sur cible dans le rollup (job advisory `target-coverage`). Câblage = **exactement** les workflows appelant `lean-axiom.yml` (`grep -ln 'lean-axiom' .github/workflows/*.yml`, moins le fichier lui-même). Triage : [lean-axiom-coverage.md](../../docs/reference/lean-axiom-coverage.md) ; incidents : [pr-review-context.md](../../docs/reference/pr-review-context.md). ### C. ML : multi-seed obligatoire -Toute PR claim « BEATS » / « improvement » sur métriques ML/trading **DOIT** inclure : (1) walk-forward 5-fold ; (2) **≥4 seeds** parmi 0/1/7/42/99 ; (3) **la conjonction** edge ≥ 2σ cross-seed **ET** Diebold-Mariano `dm_p_median < 0.05` — les deux, pas σ seul (σ mesure la dispersion inter-seeds, pas la significativité) — le DM portant sur une **perte de précision** (`loss_fn="mse"` ou `"mae"` dans `MyIA.AI.Notebooks/QuantConnect/ML-Training-Pipeline/scripts/dm_test.py`) ; `loss_fn="linear"` est un **contrôle de biais**, jamais la jambe de la conjonction — mesuré sur #10956/#10961, `d_mean = mean(e_a) − mean(e_b) = biais_a − biais_b`, aveugle à la dispersion : un modèle strictement plus précis peut « perdre » le test face à une baseline plus biaisée ; (4) comparaison à majority baseline + coûts de transaction (5bps SPY, 10bps crypto) ; (5) **pas de FAANG/Mag7** en training ; (6) verdict honnête « BEATS » / « NO BEATS » / « INCONCLUSIVE » — jamais « promising » ; (7) **rapport de biais par modèle** dans le body (`mean(e)` signé ou biais OOS, modèle ET baseline) — le contrôle qui aurait fait apparaître `har_bias_oos = −0.227` (#10938) avant qu'une lecture soit construite dessus ; un edge porté par le biais (pas par la précision) se déclare comme tel. +Toute PR claim « BEATS » / « improvement » sur métriques ML/trading **DOIT** inclure : (1) walk-forward 5-fold ; (2) **≥4 seeds** parmi 0/1/7/42/99 ; (3) **la conjonction** edge ≥ 2σ cross-seed **ET** Diebold-Mariano `dm_p_median < 0.05` — les deux, pas σ seul (σ mesure la dispersion inter-seeds, pas la significativité) — le DM portant sur une **perte de précision** (`loss_fn="mse"` ou `"mae"`) ; `loss_fn="linear"` est un **contrôle de biais**, jamais la jambe de la conjonction (aveugle à la dispersion : un modèle plus précis peut « perdre » face à une baseline plus biaisée, #10961 CE1) ; (4) comparaison à majority baseline + coûts de transaction (5bps SPY, 10bps crypto) ; (5) **pas de FAANG/Mag7** en training ; (6) verdict honnête « BEATS » / « NO BEATS » / « INCONCLUSIVE » — jamais « promising » ; (7) **rapport de biais par modèle** dans le body (`mean(e)` signé ou biais OOS, modèle ET baseline) — un edge porté par le biais (pas par la précision) se déclare comme tel. Les trois contre-exemples inscrits qui fondent (3) — `+19.97σ` avec `DM p = 0.236` ; `dm_stat` bit-identique sous `mse` pour `e` et `-e` ; et le modèle 11× plus précis « BEATEN » sous `linear` face à une baseline biaisée (#10961, CE1) — sont mesurés dans [pr-review-context.md §C](../../docs/reference/pr-review-context.md). @@ -59,7 +57,9 @@ Single-seed ou single-fold = **CHANGES_REQUESTED** sauf flag explicite `[POC]` d **Refus si :** le body **ne contient pas** `## Diagnostic dérive` (citer #8364 en label ne suffit pas) · verdict `CAUSE_DOCUMENTED_ONLY` **sans** issue fille traitant la cause (= « jambe de bois repeinte ») · la valeur ré-alignée est un **nombre de perf/timing/accuracy/coût** ET le notebook est **re-exécutable localement** (règle F) : elle doit venir d'une **re-exécution fraîche**, jamais d'un byte-surgical markdown-align — enshriner un nombre qui changera au prochain passage kernel *est* la dérive que C.4 interdit. Si une re-exec est **déjà due** : **folder** l'alignement dedans (incident #8479, [détail](../../docs/reference/pr-review-context.md)). -6. **PRs notebook : vérifier le verdict du check-run `Output-failure ratchet (base vs PR)`** (organe `scripts/notebook_tools/check_output_failure_text.py`, enregistré **bloquant** dans `scripts/ci/fast_lane_registry.py`). Le check-run DOIT être `success`. `TOOL_FAILURE` (bannières « `program is not installed` » ou rendu d'échec) ou `MACHINE_PATH` (chemin machine dans une sortie) qui **augmente** sur la PR (N → N+k, type `0 → 21`) = **régression → `CHANGES_REQUESTED`**, même si les points 1-3 passent : les bannières d'échec ne sont **pas** des exceptions Python, elles ne déclenchent ni `exec_count` nul ni `grep -nE "raise NotImplementedError|assert False|1/0"` — une PR qui **remplace** un rendu SVG de factor-graph par une bannière est le dégât exact de #3473/#11685, pas un « ça tourne ». Récurrence : #13517 (PR #13036 LDA — bannières 0→21, `MACHINE_PATH` 0→14, approuvée par Hermes alors que le garde rend rc=1) ; juin → #3473 (~15 filles) ; 18/08 → #11693. +6. **PRs notebook : vérifier le verdict du check-run `Output-failure ratchet (base vs PR)`** (organe `scripts/notebook_tools/check_output_failure_text.py`, **bloquant** dans `scripts/ci/fast_lane_registry.py`) — il DOIT être `success`. `TOOL_FAILURE` (bannières « `program is not installed` ») ou `MACHINE_PATH` qui **augmente** sur la PR (ex. `0 → 21`) = **régression → `CHANGES_REQUESTED`**, même si les points 1-3 passent : les bannières ne déclenchent ni `exec_count` nul ni le grep de 2 — remplacer un rendu SVG par une bannière est le dégât exact de #3473/#11685, pas un « ça tourne ». Récurrences (dont #13517 LDA, approuvée par Hermes malgré `rc=1`) : [pr-review-context.md](../../docs/reference/pr-review-context.md). + +7. **PRs notebook : lire le check-run ADVISORY `Output-collapse ratchet (base vs PR, advisory)`** (organe `scripts/notebook_tools/check_output_collapse.py`, enregistré `blocking=False` dans `scripts/ci/fast_lane_registry.py`, #15327). Conclusion neutre par design — le signal vit dans le détail du check-run. Un finding `SIGNATURE` (sortie base substantielle remplacée par « `Execution sautee (API non configuree)` » et consœurs) = **re-exécution sans les clés → `CHANGES_REQUESTED`** : les cellules se sont « exécutées avec succès » en dégradation gracieuse (`if api_ok:`), c'est le contournement de C.2 par la porte de secours. Contre-exemple mesuré (fondateur) : #15209, `Lean-7b-Examples.ipynb` `6b327a9bf` → `56d98429a` — 11 → 11 cellules, 0 erreur, `execution_count` réels partout, et **10637 → 2985** caractères de sortie (cellules `2195 → 147`, `2568 → 38`, `2074 → 42`) : tous les organes verts, la perte réelle. Un finding `MAGNITUDE` (perte d'un ordre de grandeur par cellule, non couvert par les exemptions automatiques contenu-déplacé/purge-diagnostic) exige une **justification dans le body** (allègement déclaré, au même titre que les autres ratchets) — sans elle : `CHANGES_REQUESTED`. **Advisory `.NET execution_count` ≠ outputs vides autorisés (#5214).** L'advisory autorise à sauter la ré-exécution **CI** (pas de kernel .NET en CI), **pas** à committer des sorties vides : `.NET Interactive` s'exécute **localement** sur chaque worker → une cellule .NET committée **DOIT** porter `execution_count != null`. `validate_pr_notebooks.py` FAIL sur `.NET` + `null`, et ne tolère `null` que là où l'exécution locale est aussi impossible (QC Cloud, Lean). Verdict attendu dans le body : `EXEC_PROVED` vs `STRUCTURAL_ONLY` (refus). diff --git a/.claude/rules/proactive-coordination.md b/.claude/rules/proactive-coordination.md index 28e6357057..137458ecbc 100644 --- a/.claude/rules/proactive-coordination.md +++ b/.claude/rules/proactive-coordination.md @@ -43,10 +43,10 @@ Tirage pondéré dans **trois urnes** : **grain** (issue unitaire → la livrer) > **Test de fin de cycle.** Ai-je, ce cycle, sorti un grain de **substance** du pool global et l'ai-je transformé en PR (ou fait avancer un livrable multi-cycle) ? **Si non, et que `gh issue list` renvoie >0** — *quel que soit le label* que je m'apprête à poster — **c'est un échec de méthode, pas un cycle honnête.** Un scan forensic qui trouve 0 défaut, une `candidate-delivered`, une édition de body seule, un HOLD ou une attente mécanique ne sont **pas** des livrables : ce sont des préludes au pick suivant, jamais leur substitution. - **Trois évasions mortes** (liste des labels bannis : [détail, section Vocabulaire](../../docs/reference/proactive-coordination-detail.md)) : - - **« Pas ma famille / ma capability »** — FAUX. L'assignation de famille est un ordre de **préférence de reporting**, pas une frontière. **Les seules vraies barrières sont deux** : (a) **GPU-only** (forward-pass, génération image/vidéo) ; (b) **vision-only** (QA visuel → lanes MiniMax/ai-01). **Tout le reste est piochable par n'importe quelle lane.** - - **« Tout ce qui reste est gated »** — un *gate* qualifie une **prochaine action précise**, pas une issue entière. Avant de le déclarer, **énumérer chaque issue ouverte + son gate précis** ; si UNE a un sous-grain exécutable (doc, notebook CPU, audit, prose, test, module numpy), **le prendre**. - - **« Les micro-fixes suffisent »** — non : nettoyage/tooling/accents/doc sont plafonnés et ne sont JAMAIS le plat principal. Viser un grain **DEEP ou MED** chaque cycle (tiers : [variation-protocol.md](variation-protocol.md)). + **Trois évasions mortes** (labels bannis : [détail, section Vocabulaire](../../docs/reference/proactive-coordination-detail.md)) : + - **« Pas ma famille »** — FAUX : famille = préférence de **reporting**, pas frontière. **Seules deux vraies barrières** : (a) **GPU-only** ; (b) **vision-only** (→ lanes MiniMax/ai-01). Le reste est piochable partout. + - **« Tout ce qui reste est gated »** — un *gate* qualifie une **prochaine action**, pas une issue entière : énumérer chaque issue ouverte + son gate précis ; si UNE a un sous-grain exécutable (doc, notebook CPU, audit, test), **le prendre**. + - **« Les micro-fixes suffisent »** — non : nettoyage/tooling/doc plafonnés, jamais le plat principal ; viser **DEEP/MED** chaque cycle (tiers : [variation-protocol.md](variation-protocol.md)). **Mécanisme never-empty (ordre strict, inversé le 2026-08-20).** (1) **Tirer** — `pick_idle_grain.py`, au démarrage du cycle, systématiquement. (2) Un **steering nommé** du coordinateur (deep-queue, DM `[DISPATCH→inbox]`) **prime sur le tirage quand il existe** : c'est l'exception qui passe devant, pas la règle qu'on consulte d'abord. Le brûler dans l'ordre, ne pas attendre entre items, `[CLAIMED]` avant chaque. (3) Ni tirage exploitable ni steering → le pool global reste la source : « rien à faire » demeure **structurellement impossible** tant que `gh issue list` renvoie >0. La deep-queue est un **bootstrap éphémère**, jamais la condition du travail. @@ -54,16 +54,14 @@ Tirage pondéré dans **trois urnes** : **grain** (issue unitaire → la livrer) ## Leçons ancrées (checks pré-`[DONE]`) -- **L721 ★ — stale-tracker guard.** Avant **tout** claim de « 0 PR / saturated / idle » : la requête DOIT interroger le **tag de lane** (la même clé que `pick_idle_grain.py` lit), **PAS** `--author ` — les workers poussent sous le compte `jsboige` **partagé**, donc `--author ` rend **0** alors que la lane porte ses PRs (#13870). La requête se valide par ses **faux négatifs symétriques** (une lane connue pour N PRs doit en rendre N). Forme canonique bash + mesures de référence : [détail, section L721](../../docs/reference/proactive-coordination-detail.md). Repli : une PR sans tag `Grain:` lisible est invisible aux deux requêtes — traiter par le sweep `GRAIN-ORPHANS-SWEEP` (#13086), **pas** en relâchant la requête. -- **L740 ★ — CronList 7-day verify.** Les crons `CronCreate` sont **session-only, auto-expirent à 7 j**. Avant `[DONE]`, vérifier qu'ils vivent encore et **re-armer** — un cron expiré = wakeup mort = lane-idle silencieuse. -- **L898 ★★★ — collision guard : avant d'ÉCRIRE, pas avant de pousser.** Avant de poser un `[CLAIMED]`, rédiger un steer/verdict, éditer un fichier **ou** `git push` : `git worktree list` + `gh pr list --search head:` + `gh pr list --search ""` + `gh pr list --state open --json files` sur le **chemin** visé. Relire l'artefact sur `main` **ne remplace pas** ce check : `main` ne montre pas ce qui est *ouvert*. Coût ~10 s ; coût de l'omission = travail dupliqué et rétractation publique. -- **L1356 ★★★ — preflight de claim : `--state all`, jamais `--state open` seul (incidents #13562/#13608).** Une PR **MERGÉE** qui a livré l'issue en rider (référence sans `Closes #N`) est invisible aux filtres open — **« OPEN + zéro PR liée » n'est PAS une preuve de fraîcheur**. Avant tout `[CLAIMED]` : (1) `gh pr list --state all --search ""` — une PR merged sur le sujet = grain livré ; (2) inspecter les worktrees orphelins nommés pour l'issue (une session antérieure y a peut-être déjà travaillé). Si livré : poster `[INFO] candidate-delivered` avec preuve — **ne pas réimplémenter, ne pas closer soi-même**. Recette et incidents complets : [détail, section L1356](../../docs/reference/proactive-coordination-detail.md). +- **L721 ★ — stale-tracker guard.** Avant tout claim « 0 PR / saturated / idle » : interroger le **tag de lane** (`Grain:`), **PAS** `--author ` (compte `jsboige` partagé, #13870) ; la requête se valide par ses **faux négatifs symétriques**. Repli : PR sans tag lisible → sweep `GRAIN-ORPHANS-SWEEP` (#13086). Forme canonique + mesures : [détail, section L721](../../docs/reference/proactive-coordination-detail.md). +- **L740 ★ — CronList 7-day verify.** Les crons `CronCreate` sont **session-only, expirent à 7 j** : avant `[DONE]`, vérifier `CronList` et **re-armer** — un cron expiré = lane-idle silencieuse. +- **L898 ★★★ — collision guard : avant d'ÉCRIRE, pas avant de pousser.** Avant `[CLAIMED]`/steer/édit/push : `git worktree list` + `gh pr list --search head:` + `--search ""` + `--state open --json files` sur le **chemin** visé. Relire `main` ne remplace pas ce check (`main` ne montre pas l'*ouvert*). Coût ~10 s ; omission = travail dupliqué + rétractation publique. +- **L1356 ★★★ — preflight de claim : `--state all`, jamais open (incidents #13562/#13608).** Une PR **MERGÉE** ayant livré en rider (sans `Closes #N`) est invisible aux filtres open : avant tout `[CLAIMED]`, (1) `gh pr list --state all --search ""`, (2) inspecter les **worktrees orphelins** nommés pour l'issue. Si livré : `[INFO] candidate-delivered` avec preuve — pas de réimplémentation, pas de close soi-même. Recette complète : [détail, section L1356](../../docs/reference/proactive-coordination-detail.md). ## Règle de sélection -Le pool par défaut est **`gh issue list --state open` (global, cross-lane)** ; les 8 sources priorisées du détail sont un **ordre de préférence DANS ce pool**, pas une restriction à ta famille. Prendre **un item à la fois** (`[CLAIMED]` avant de commencer), livrer, puis **re-piocher aussitôt**. Le garde-fou G.5 « pas de shopping cart » interdit d'ouvrir N **deep-tracks parallèles**, il ne plafonne **pas** le nombre de PRs séquentielles. - -**Anti-pattern interdit** : auditer la tranche étroite de SA famille, la trouver cohérente, puis poster un `[ASK coordinator]` — alors que le pool offrait des dizaines de grains cross-lane. **Le coordinateur n'est PAS un distributeur de grains** : il merge les PRs, alimente le pool en issues scopées, et déconflitte les claims. +Prendre **un item à la fois** (`[CLAIMED]` avant), livrer, **re-piocher aussitôt** — G.5 interdit N deep-tracks **parallèles**, pas N PRs **séquentielles**. **Anti-pattern interdit** : auditer la tranche étroite de SA famille puis poster un `[ASK coordinator]` alors que le pool offrait des grains cross-lane — c'est le silo (incident fondateur R5/R7, [détail §Incident fondateur R5/R7](../../docs/reference/proactive-coordination-detail.md)). **Le coordinateur n'est PAS un distributeur de grains** : il merge, scoper les issues, déconflitter les claims. ## Voir aussi diff --git a/.claude/rules/sota-not-workaround.md b/.claude/rules/sota-not-workaround.md index b811abeeae..846309fe9a 100644 --- a/.claude/rules/sota-not-workaround.md +++ b/.claude/rules/sota-not-workaround.md @@ -68,44 +68,16 @@ Les bots **DOIVENT** poster `CHANGES_REQUESTED` quand une PR notebook (interne/c **Exception PR etudiante** (cf [student-pr-reviews.md](student-pr-reviews.md)) : NE PAS appliquer A/B — review bienveillante, pas de CHANGES_REQUESTED sur scaffolding. -## Ou se depose une entree de registre, et quand l'axe-2 sera fini - -**Une entree va dans le fichier, jamais dans un commentaire d'issue.** Le registre est -[`docs/ledgers/3801-sota-axe2.md`](../../docs/ledgers/3801-sota-axe2.md) ; une entree y est une section -`## Entry #NNN — (owner , c.NNN)` suivant la « Convention d'entree » que le ledger -documente lui-meme en tete. Elle arrive **par PR**, comme tout fichier du depot. - -La regle le precise parce que l'inverse s'est produit : **sept entrees ont ete postees en commentaires -sur l'EPIC #3801 apres sa fermeture** (la derniere le 2026-08-07). Elles existent, elles sont perdues — -aucune requete `--state open` ne les atteint, et le `grep` d'un auditeur sur le depot ne les voit pas. - -**Critere de fin de l'axe-2** — trois conditions, toutes verifiables : - -1. **chaque famille de notebooks du depot porte une entree** ; -2. **chaque entree porte un verdict agrege** (un des 5) ; -3. **chaque verdict != `SOTA-OK` est solde** : soit une PR de fix **mergee** citee dans l'entree, soit un - `INTRINSIC` etabli par la checklist 6 axes ci-dessus. - -La condition 1 se **mesure**, elle ne se recopie pas — le denominateur est la liste des familles telle -qu'elle est sur le disque au moment de la mesure, pas un compte fige dans un document : - -```bash -grep -c '^## Entry #' docs/ledgers/3801-sota-axe2.md # entrees au registre -grep -oE '^## Entry #[0-9]+ — [^(]+' docs/ledgers/3801-sota-axe2.md | sed 's/^## Entry #[0-9]* — //;s/ *$//' | sort -u # familles couvertes -``` - -**Attention au grain** : le ledger indexe par **famille** (`Search`, `Tweety`), pas par repertoire. -Comparer son compte a un `find MyIA.AI.Notebooks -name '*.ipynb'` agrege par repertoire donne deux -nombres qui ne se soustraient pas — c'est un piege de denominateur, pas un ecart de couverture. - -**Les tableaux « Cumul entries » du ledger ne sont pas cet instrument** : il y en a **deux**, tous deux -perimes, mesure du 2026-09-03 — `## Cumul entries` (l.485) s'arrete a l'entree **8**, datee du 2026-07-10, -et `### Cumul entries (registre axe-2 SOTA)` (l.854) s'arrete a l'entree **22**, datee du 2026-07-11 — -alors que le fichier porte **30** entrees. Le plus recent des deux, le seul qu'un auditeur presse -consulterait, sous-compte donc d'un facteur ~1,4 ; le plus ancien, si c'est celui qu'il trouve en premier, -d'un facteur ~3,8. Aucun des deux ne repond a la condition 1. Le rafraichir — et **fusionner les deux -tableaux dupliques en un seul**, la duplication etant elle-meme la cause du piege de lecture — est un -grain a part, hors du perimetre de #14519 qui portait sur l'ancre de cette regle. +## Registre axe-2 — ou deposer une entree, quand sera-t-il fini + +**Une entree va dans le ledger, jamais dans un commentaire d'issue** — sept entrees postees sur l'EPIC +#3801 apres sa fermeture sont perdues pour toute requete `--state open` et tout grep du depot. +Le ledger est [`docs/ledgers/3801-sota-axe2.md`](../../docs/ledgers/3801-sota-axe2.md) (section +`## Entry #NNN — (owner , c.NNN)` par PR). + +**Critere de fin de l'axe-2** (3 conditions mesurables), **pieges de denombrement** (grain par famille, +deux tableaux « Cumul entries » perimes a fusionner) et commandes de mesure : [sota-verdicts-detail.md +§4](../../docs/reference/sota-verdicts-detail.md). ## Voir aussi - CLAUDE.md section F — env/kernel : reparer, jamais contourner diff --git a/docs/reference/pr-review-context.md b/docs/reference/pr-review-context.md index e5babe6dd8..88d43ea21e 100644 --- a/docs/reference/pr-review-context.md +++ b/docs/reference/pr-review-context.md @@ -91,6 +91,8 @@ Mesure d'intégration (#10232), série gagnante `e` vs son opposé `-e` contre b Le tableau montre les deux instruments et leur angle mort : `mse`/`mae` mesurent la précision (insensibles au signe), `linear` distingue le signe mais mesure le biais. La jambe DM de §C porte donc sur une perte de précision ; `linear` reste disponible comme contrôle de biais (détection de sous/sur-prévision). Pin de régression : `test_dm.py::test_linear_loss_distinguishes_opposite_series` (valide — signes opposés = déclaration de biais, pas de précision). +**Instance fondatrice du rapport de biais par modèle — #10938.** Le point (7) de la règle (`mean(e)` signé ou biais OOS, modèle ET baseline, dans le body) est né d'un `har_bias_oos = −0.227` (#10938) non déclaré, découvert **après** qu'une lecture avait été construite sur l'edge qu'il portait : c'est précisément le contrôle que le rapport de biais par modèle aurait fait apparaître avant. Un edge porté par le biais (pas par la précision) se déclare comme tel. + ### D.5 — #8479 MusicGen : l'alignement qui enshrine un nombre périssable Notebook MusicGen 02-3 : le RTF documenté `0.5-2x` a été « aligné » en `0.21-0.24x` **sur un run non-optimisé**, alors qu'une re-exécution Stop-&-Repair était **déjà due** sur ce notebook (cellule cassée). @@ -111,6 +113,22 @@ D'où la clause « audit fichier ENTIER » : le format slim `+5/−5` du rollout Audit associé au même mandat : Tweety / GameTheory / Search = **stale-body sévère** ; SymbolicLearning / SemanticWeb / SmartContracts = ciblé ; Sudoku = trivial. +### Émission du verdict — instance fondatrice et mesure (#14682) + +**#14658** : réserve qualifiée « le seul point bloquant pour un LGTM plein », posée en **prose française sans marqueur** → invisible à l'organe B.0 (`scripts/check_unaddressed_nits.py`, `CONCERN_MARKERS`), `rc=0`, merge passé. + +**Ne pas élargir `CONCERN_MARKERS`** — mesure #14682, scan de 80 PRs mergées : un filet à mots de prose (« bloquant », « à corriger », « est faux ») **sur-accuse d'un facteur 5** (4 détections sur 5 = de la prose qui *décrit* un blocage de job ou de garde, pas qui *pose* une réserve). Le contrat est côté **émission** : le reviewer pose `CHANGES_REQUESTED` / `[Hermes] COMMENT_WITH_CONCERNS` / 🟡 / 🔴, il ne rédige pas « il faudrait corriger » en prose libre. + +### B.1 — pourquoi pas `grep -c sorry` (mesure 2026-08-14) + +Sur les 21 lakes : **484 faux `sorry` pour 21 réels (23×)** — `grep -c sorry` compte la prose (docstrings, `-- commentaires`, feuilles de route). **9 lakes à 0 réel** affichent des comptes naïfs positifs ; ex. `grothendieck_lean` : 68 naïfs, 0 réel — un reviewer appliquant `grep` à la lettre exigerait la justification de 68 `sorry` qui n'existent pas. L'instrument : `python scripts/lean/count_code_sorry.py --json`, champ `distinct_code_sorry` (la même mesure que le gate CI `sorry-filter-mode: real` de `lean-axiom.yml`). + +### D.6 — récurrences du ratchet `Output-failure` + +- #13517 : PR #13036 (LDA) — bannières `TOOL_FAILURE 0 → 21`, `MACHINE_PATH 0 → 14`, **approuvée par Hermes** alors que le garde rend `rc=1`. +- #3473 (juin 2026) : famille ~15 filles de bannières d'échec passées sous la détection d'erreurs Python classique. +- #11693 (18/08) et #11685 : remplacements de rendus SVG/figures par des bannières « program is not installed ». + ## Incident fondateur B.0 — PR #10761 (récit déporté de CLAUDE.md, 2026-08-21) **Incident fondateur — PR #10761** : mergée le 2026-08-14T04:15Z sous `myia-ai-01` malgré 2 nits user du 2026-08-13T11:07 (**17 h avant**) et une review Hermes `COMMENT_WITH_CONCERNS` confirmant ces 2 nits + 3 points neufs. `mergeStateStatus: CLEAN`, `reviews[].state: COMMENTED` : les deux champs qu'un merge-gate lit d'ordinaire étaient verts, et le notebook a été mergé en attribuant à tort le théorème de Sendov à T. Tao (la preuve est de **Lech Mazur** ; Tao en signe la digestion, il l'écrit lui-même). Epic de reprise : **#11044**. diff --git a/docs/reference/sota-verdicts-detail.md b/docs/reference/sota-verdicts-detail.md index c0e6ffd16e..a2913a5572 100644 --- a/docs/reference/sota-verdicts-detail.md +++ b/docs/reference/sota-verdicts-detail.md @@ -52,6 +52,38 @@ Le vrai cas discriminant pour CP-SAT en coloration est le **graphe aléatoire de Un notebook MiniZinc couvre l'optimisation via la syntaxe `solve minimize obj;` (**chaîne dans le modèle**), pas via `.minimize(` Python. Un `grep '.minimize('` renvoie `opt=0` sur des notebooks qui traitent bel et bien l'optimisation. Pour MiniZinc, grepper `solve (min|max)imize` dans les chaînes de modèle. +## 4. Registre axe-2 — critère de fin et pièges de dénombrement + +Une entrée de registre est une **section `## Entry #NNN — (owner , c.NNN)`** dans +[`docs/ledgers/3801-sota-axe2.md`](../ledgers/3801-sota-axe2.md), la « Convention d'entrée » se lit en +tête du fichier, et l'entrée arrive **par PR** — jamais en commentaire d'issue : sept entrées ont été +postées sur l'EPIC #3801 après sa fermeture (la dernière le 2026-08-07) ; aucune requête `--state open` +ne les atteint et un `grep` d'auditeur sur le dépôt ne les voit pas. + +**Critère de fin de l'axe-2** — trois conditions, toutes vérifiables : + +1. **chaque famille de notebooks du dépôt porte une entrée** ; +2. **chaque entrée porte un verdict agrégé** (un des 5) ; +3. **chaque verdict != `SOTA-OK` est soldé** : soit une PR de fix **mergée** citée dans l'entrée, soit un + `INTRINSIC` établi par la checklist 6 axes (section 2). + +La condition 1 se **mesure**, elle ne se recopie pas : + +```bash +grep -c '^## Entry #' docs/ledgers/3801-sota-axe2.md # entrées au registre +grep -oE '^## Entry #[0-9]+ — [^(]+' docs/ledgers/3801-sota-axe2.md | sed 's/^## Entry #[0-9]* — //;s/ *$//' | sort -u # familles couvertes +``` + +**Piège du grain** : le ledger indexe par **famille** (`Search`, `Tweety`), pas par répertoire — comparer +son compte à un `find MyIA.AI.Notebooks -name '*.ipynb'` agrégé par répertoire donne deux nombres qui ne +se soustraient pas. + +**Piège des « Cumul entries »** : il y en a **deux**, tous deux périmés (mesure du 2026-09-03) — `## Cumul +entries` (l.485) s'arrête à l'entrée **8** (2026-07-10) et `### Cumul entries (registre axe-2 SOTA)` +(l.854) à l'entrée **22** (2026-07-11), alors que le fichier porte **30** entrées. Le plus récent +sous-compte d'un facteur ~1,4 ; le plus ancien, d'un facteur ~3,8. Rafraîchir et **fusionner les deux +tableaux en un seul** est un grain à part (le fichier dépasse #14519). + ## Voir aussi - [`.claude/rules/sota-not-workaround.md`](../../.claude/rules/sota-not-workaround.md) — la règle (tables opératoires)