Repository navigation
feat(guards,#15867): les deux organes de liens couvrent les decks slides/ - #15871
Conversation
…des/**/slides.md `slides/` n'etait dans le scope d'AUCUN des deux organes de liens : la tranche #15023 (PR #15865) a ecrit 17 liens relatifs morts sur 03-logique et les deux organes rendaient « 0 casse ». Meme mode de defaillance que #7422 (index.md pourrissait parce que rien ne le regardait). - check_docs_links.py : scope deck `slides/**/slides.md` (DECK_DIR), resolu DEPUIS le repertoire du deck (le `..` sort de slides/ vers MyIA.AI.Notebooks/). Le scope reste deck-only, mesure : slides/**/*.md = 119 fichiers, 734 casses/1367 (analysis/, extracted/, *.marp.md) -- l'elargir rougirait toute PR. - DeckScopeEmpty : slides/ present sans aucun deck => exit 2 explicite, jamais un « 0 casse » depuis une portee vide (piege 1 de l'issue). - --expect-broken N : controle positif en bande (modele scan_slidev_composition.py). Arme et non atteint => exit 2. Matrix mesuree sur un lien casse volontairement : bare=1, --expect-broken 1=1 (controle satisfait), --expect-broken 2=2, --check --base origin/main=1 (regression non excusee). Advisory « controle non arme » confinee au bare scan : --check garde son contrat d'une ligne unique. - check_link_label_agreement.py : DECK_GLOB + meme garde anti-scan-silencieux. Le predicat existant n'a PAS ete assoupli : il compare un identifiant de famille extrait des DEUX cotes, donc le basename sans extension et la glose hors crochets ne le concernent pas (l'egalite naive label==basename ferait 108/108 faux positifs, mesure). - fast_lane_registry.py : le garde check-links declenche maintenant sur slides/** -- sans quoi une PR deck-only (#15865) ne lance jamais l'organe (entree de registre != cablage). La parite test trouve AUSSI que .claude/agents/** et .claude/skills/** etaient scannes depuis #7422 sans jamais declencher le garde : couverts. Mesures sur origin/main : 702->720 fichiers, 6845->6953 liens (+108, le compte exact de l'issue), 0 casse avant/apres ; label organ 2076->2093 fichiers (+17 decks, _archive exclu -- divergence documentee et epinglee), 0 desaccord sur tout le depot. Acceptance 4 : l'etat des 17 liens casses n'est PAS dans l'historique git (les deux commits de #15865 sont deja a 60 liens / 0 casse -- mesure). Demontree par reconstruction : lien casse volontairement sur un deck => detecte et nomme (slides/05-theorie-des-jeux/slides.md:116), restaure par cp backup. Closes #15867. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: diff local base↔head des 5 fichiers + câblage lu au code au head + comptage indépendant 18 decks via git tree + check-links success au head)
[NanoClaw] — Review structurelle (5 fichiers, +492/−4) : file list + diff local base↔head (c2957441→d5cf08d6) filtré aux seules lignes changées, puis lecture ciblée des fichiers chargeurs au head — pas de full-diff API.
Objet (ancre vérifiée OPEN, créée 22:53Z) : #15867 — les DEUX organes de liens ignoraient slides/ : 108 liens non couverts, 17 liens morts écrits par la tranche #15023 passés sous le radar. Mode de défaillance déjà documenté dans l'organe lui-même (#7422 : index.md pourrissait, rien ne le regardait).
Ce que j'ai vérifié moi-même (pas recopié du body) :
- Le câblage, pas seulement le scope — c'est le cœur de la PR et il est réel : la voie rapide (
fast_lane_registry.py) décide surpathsde ce que la gate tire, etslides/**y est ajouté, ÉPINGLÉ par un test de parité contre les scopes réellement scannés. Ce même test expose un second trou du même type (.claude/agents/**,.claude/skills/**scannés depuis #7422, jamais câblés) — corrigé ici. Un organe qui scanne sans gate qui déclenche est un vert de complaisance ; cette PR ferme la classe, pas l'instance. - Les deux pièges de l'issue, au code : garde anti-portée-vide dans les DEUX organes (
DeckScopeEmptyexit 2 danscheck_docs_links.py:186-213; stderr + rc=2 danscheck_link_label_agreement.py:174-183) — un « 0 constat » depuis un scope vide est devenu impossible.slides/absent ⇒[]silencieux (cas des fixtures), présent-vide ⇒ refus explicite : l'asymétrie est la bonne. - Contrôle positif
--expect-broken N(l.587-610) : in-band,rc=1= finding réel,rc=2= contrôle non tenu, advisory confiné au bare scan pour préserver le contrat une-ligne-sur-vert de--check. Le modèle (scan_slidev_composition.py) est cité, la matrix est mesurée. - Comptage indépendant : arbre git récursif au head → 18 fichiers
slides.md, dont03-logique(le deck de l'incident) etS4-trading-algorithmique/_archive/slides.md(la divergence_archivedocumentée existe bien) — recoupe le « +18 côté liens / +17 côté label » du body. - +364 lignes de tests épinglant l'acceptance SUR LE VRAI DÉPÔT (
test_decks_are_scanned_on_the_repo,test_real_deck_links_are_all_valid,test_deck_scope_is_not_the_whole_slides_treeavec la justification mesurée 119 fichiers / 734 liens cassés si le scope s'élargissait).
Réserves (non bloquantes) :
- La démonstration du défaut historique est par reconstruction, et le corps le dit (⚠ 4) : les 17 liens cassés ne sont dans AUCUN SHA de l'histoire (#15865 est déjà à 0 cassé au premier push). La couverture neuve reste justifiée indépendamment (108 liens scannés par personne), mais le dossier repose sur la reconstruction, pas sur un replay — à savoir si l'issue sert d'ancre d'audit plus tard.
slides/**dans lespathsde la gate déclenche aussi suranalysis//extracted/(artefacts hors scope de l'organe) : bruit de gate sans vert faux. Acceptable en l'état.- CI incomplète à l'instant de la mesure (Scripts Tests CPU, PR gate, Analyze csharp
in_progress) ;check-linkset les guards concernés sont déjàsuccess.
0 gh pr diff / 0 /files avec patch (diff local uniquement), 0 secret (grep motifs usuels base↔head).
— [NanoClaw]
Path-collision (organ #13359/#13615)Cette PR #15871 (
Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur |
Grain: MED/tooling — lane myia-po-2023:CoursIA — prev: LIGHT/docs #15792
Summary
slides/n'était dans le scope d'aucun des deux organes de liens. La tranche de contenu #15023 (PR #15865) a écrit 17 liens relatifs morts sur03-logique; les deux organes rendaient « 0 lien cassé ». Même mode de défaillance que le précédent documenté danscheck_docs_links.pylui-même (#7422:index.mdpourrissait parce que rien ne le regardait).Ce qui change
scripts/check_docs_links.pyslides/**/slides.md(DECK_DIR),DeckScopeEmpty,--expect-broken Nscripts/notebook_tools/check_link_label_agreement.pyDECK_GLOB, garde anti-scan-silencieuxscripts/ci/fast_lane_registry.pycheck-linksdéclenche surslides/**(et.claude/agents/**,.claude/skills/**)scripts/tests/test_check_docs_links.pyscripts/notebook_tools/tests/test_check_link_label_agreement.pyLe cablage, pas seulement le scope
Ajouter
slides/à l'organe ne suffit pas :docs-link-check.ymlestworkflow_dispatch-only depuis #12567 — sur PR, l'organe est rendu par la voie rapide, qui décide depuispaths. Sansslides/**dans cette liste, une PR deck-only comme #15865 ne lance jamais le garde. Un test de parité épingle désormais chaque scope scanné (SCAN_SCOPES+ decks) contre lespathsdu garde.Ce test a trouvé un second trou du même type :
.claude/agents/**et.claude/skills/**sont scannés par l'organe depuis #7422 sans jamais déclencher le garde. Couverts ici (même classe de défaut, même sujet).Les deux pièges de l'issue, couverts
slides/présent mais sans aucun deck ⇒DeckScopeEmpty(exit 2, motif nommé), dans les DEUX organes. Un « 0 constat » depuis une portée vide est impossible...normalisé avant le test d'existence — un lien de deck sort deslides/versMyIA.AI.Notebooks/: la résolution est deck-relative. Rectification au passage :check_docs_links.pyrésolvait déjà depuis le répertoire de la source (check_link,l.257), pas depuis la racine — la difficulté 1 de l'issue était un non-problème pour cet organe. Mesuré, pas supposé.Contrôle positif (
--expect-broken N, modèlescan_slidev_composition.py)Matrix mesurée sur
05-theorie-des-jeuxavec un lien cassé volontairement (restauré parcpbackup) :slides/05-theorie-des-jeux/slides.md:116 -> .../GameTheory-99-Absent.ipynbnommé--expect-broken 1--expect-broken 2POSITIVE CONTROL FAILEDexplicite--check --base origin/mainL'advisory « contrôle non armé » est confiné au bare scan :
--checkgarde son contrat d'une ligne unique sur vert (docs-link-check.yml).Acceptance
slides/**/slides.md. Mesure : 702→720 fichiers, 6845→6953 liens (+108, le compte exact de l'issue), 0 cassé avant/après. Label organ : 2076→2093 fichiers (+17 decks), 0 désaccord sur tout le dépôt.TestPositiveControl(le seuil, pas l'arbre, décide du verdict).test_real_deck_links_are_all_valid)._link_exists_in_treesur les deux SHA ; la réparation est antérieure au premier push). Le lien cassé volontairement ci-dessus est le même acte de preuve, reproductible depuis la ligne de commande.Deux prémisses de l'issue, corrigées par mesure
check_docs_links.pyrésout depuis la racine » : non — résolution source-relative depuisl.257(source_path.parent), idem_link_exists_in_tree. Le correctif 1 de l'issue était déjà en place.label == basenameferait 108/108 faux positifs (mesuré, épingle par testtest_naive_basename_equality_would_false_positive).Scope deck-only, et pourquoi
slides/**/*.md= 119 fichiers, 734 cassés / 1367 (analysis/,extracted/,*.marp.md), mesuré sur origin/main — l'élargir rougirait toute PR. Le scope resteslides/**/slides.md, épingle par test.Divergence documentée :
check_docs_links.pygarde l'archive (slides/S4-trading-algorithmique/_archive/slides.md, doctrine_archivede #9814) ;check_link_label_agreement.pyexclut_archivepour tous ses scopes (notebooks compris) — épinglée par test, l'archive ne porte aucun lien.ipynb.Closes #15867.
🤖 Generated with Claude Code