Repository navigation
fix(ci,#15545): arm positive control in slides-composition-advisory — dead scanner now fails - #15561
Conversation
… committed fixture deck, dead scanner now fails The CI call never armed --baseline-slide: '0 findings' was indistinguishable from a dead flagging path (glyphBBox v1 on #15381 rendered 0 its whole life, green read as no-defect). Fix per issue: - slides/_composition-control/slides.md: dedicated fixture deck, slide 2 carries a deterministic HORS_CANVAS defect (absolute P at top:600px on 552px canvas — font/theme independent) - workflow: control runs unconditionally after the slidev binary check, before deck discovery early-exit; PASS = scanner exit 1 AND controle_positif_ok true; anything else = ::error meta-failure (4th meta-failure cause, #8807 trap 1 class) - fixture excluded from real-deck discovery (find + DIRS branches) - tests: fixture integrity locked (2 slides, top:600px on slide 2, P tag, default canvas 980x552) so CI contract cannot drift silently - pre-existing test repair (same file, 1 line): exec namespace lacked n_rec added by #15351 — test_controle_positif_warning_when_baseline_omitted was red on main E2E validated locally: fixture served via slidev, scanned with --baseline-slide 2 -> controle_positif_ok=true, exit 1, slide 2 flagged at bbox [0,600,240,640]. 15/15 tests green. Closes #15545 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
G-VAR-2 light cap reached (advisory, non bloquant). |
|
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: CONCERNS
[Hermes] — #15561 review du head 6c903ed6af6d (0 review cluster sur ce SHA).
Vérifié firsthand :
- Fixture déterministe :
top:600px+height:40px→ bbox[0,600,240,640]vs canvas 552 px — déborde par construction, indépendant des fontes ✓. Canvas par défaut 980×552 verrouillé par test. - Câblage : contrôle AVANT l'early-exit « aucun deck impacté » (bloc déplacé, vérifié dans le workflow au head) ✓ ; exclusion de la fixture des decks réels sur les DEUX branches (
find -not -path '*/_composition-control/*'+grep -vsur DIRS) ✓. - 3 tests verrouillent le contrat workflow↔scanner (2 slides, défaut slide 2, canvas 980×552) — anti-dérift réel ✓. Réparation
n_recdans_buildcohérente avec le body (1 ligne, même fichier) ✓. - Security scan : 0 match.
- Arithmétique : 600−552 = 48 px de débord, cohérent avec le commentaire du test ✓.
Concern (asymétrie fail-loud, non-bloquant mais contractuelle) : la branche « serveur fixture jamais prêt » (CTRL_READY -ne 1) émet l'annotation ::error mais ne pose ni META_FAIL=1 ni exit 1 — alors que le body et le commentaire (d) la classent 4e cause de méta-défaillance « ::error + exit 1, même classe que zéro deck découvert ». La cause parallèle « binaire slidev introuvable » pose bien META_FAIL (ligne ~119). Conséquence : une nuit sans deck (MAPS vide, CHANGED vide) avec fixture jamais servie → exit 0 vert avec instrument non validé, uniquement une annotation. Accessoirement le texte d'erreur « aucun deck mesuré » devient faux quand MAPS non vide (les decks sont mesurés quand même dans la boucle). Fix trivial : META_FAIL=1 dans la branche CTRL_READY -ne 1 (l'exit final le relaie déjà).
La logique positive-control elle-même (exit 1 attendu + controle_positif_ok: true, exit 2 = scanner mort) est saine et c'est un vrai gain anti-vert-muet.
…is pret Revue Hermes (CONCERNS) : la branche CTRL_READY!=1 annotait ::error sans poser META_FAIL -- une nuit sans deck avec fixture jamais servie sortait exit 0 vert avec instrument non valide, contredisant la cause (d) du header. Symetrie retablie avec la branche parallelle "binaire slidev introuvable" ; le message "aucun deck mesure" devient "mesure des decks eventuels SANS GARANTIE" (vrai quand MAPS non vide). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Réserve Hermes (asymétrie fail-loud) — corrigée au head
Le scénario dénoncé (nuit Contexte du FAIL Scripts Tests précédent (05:23Z) : flake infra, pas le diff — |
jsboige
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: fix 2780e4b relu au head — la concern est soldée, symétrie fail-loud rétablie aux deux sorties)
[Hermes] — suivi de ma review CONCERNS du head 6c903ed6af6d. Le commit 2780e4bf traite exactement le point soulevé, et je le vérifie plutôt que de le croire sur parole :
META_FAIL=1posé dans la brancheCTRL_READY -ne 1(ligne 208 du workflow) — la meta-défaillance « fixture jamais servie » n'est plus une simple annotation : elle rougit désormais.- Honoré aux deux sorties : l'early-exit « aucun deck impacté » (ligne 249) teste
META_FAILavant de rendreexit 0— c'est précisément le cas que je décrivais (nuit sans deck + fixture jamais servie = vert muet) — et le chemin nominal (ligne 322) le teste également. La symétrie avec la branche parallèle « binaire slidev introuvable » est rétablie. - Message corrigé : « aucun deck mesuré » → « mesure des decks éventuels SANS GARANTIE » — la prose ne ment plus quand
MAPSest non vide, comme relevé. - CI au head 2780e4b : seul rouge =
PR gateen DWELL (tête du 06:19:20Z, 108/120 min — plancher de dwell, ré-agrégé par le balayage horaire, aucun geste requis). Rien d'imputable au diff ; le relaisSlides composition PR relayest vert.
La logique du contrôle positif (exit 1 attendu ↔ controle_positif_ok: true, exit 2 = scanner mort) reste inchangée et saine. Aucun point ouvert de mon côté.
…5846) * ci(slides,#15835): run slidev build on the PR that touches a deck Nothing in CI built the slides on a pull request. The only slides workflow wired on `pull_request` measured COMPOSITION (empty bands, gap_max); the one that actually builds ran cron-only. A PR could therefore break a deck and stay green end to end -- #15808 wrote down the assumption ("the repo CI will replay it (to be confirmed)"), and the answer was no. That is the one job a CI exists to make unnecessary. The wiring, following the issue's own four points: - a `pull_request` leg filtered on `paths: ['slides/**']` on the EXISTING build workflow -- one build path, not a second implementation that will drift from the first (point 4); - it builds only the decks of the diff, and all of them when shared slides infra moved (point 1); - it BLOCKS: exit 1 on a build failure, so the check-run goes red on the PR that introduced it (point 2). The nocturne leg stays advisory -- under `schedule` there is no PR to gate and the label/built output is the payload, so #8817's contract is preserved verbatim where it was written. A scope change, not a pendulum; - `actions/setup-node` caches npm by `slides/package-lock.json` (point 3), with `cache-dependency-path` set because the lockfile is not at the repo root and the default lookup would silently cache nothing. The same-repo guard is the UNIVERSAL form, and that is load-bearing rather than stylistic. The direct form (`head.repo.full_name == github.repository`) is FALSE under `schedule` -- the field is null -- so the job would be SKIPPED and the nocturne extinguished: exactly the #12817 tranche-2 regression this file already documents. Measured on a mutated copy, the policy scanner accepts BOTH forms, so nothing but prose keeps that trap closed. Second, unplanned find: the discovery was ALREADY red on main. The composition organ's committed positive-control fixture, slides/_composition-control/slides.md (#15561, 2026-09-11), tripped the symmetric zero-target check, so the job died before the build loop and reached no deck at all -- nocturne red 2026-09-12T07:58Z with M=17, N=19, ZERO_TARGET_DIRS=1. Fixed by excluding that fixture BY NAME; a blanket `_*` rule reads tidier and would reopen the hole the check exists to close (renaming 01-introduction to _introduction would go silent instead of loud). Verification: - scripts/ci/check_self_hosted_runner_policy.py --check: 159 workflows OK - scripts/tests/test_check_self_hosted_runner_policy.py: 58/58 - scripts/ci/check_unique_check_run_names.py --check: no duplicates - guard negative control on a copy: removing `if:` -> VIOLATION SAME_REPO_GUARD rc=1; the direct form -> OK rc=0 (the blind spot above) - the extracted step replayed locally on three simulated diffs: broken deck -> ::error:: + exit 1; sound deck -> "build cleanly" + exit 0; no deck touched -> exit 0 Closes #15835 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * ci(slides,#15835): self-cover the label poser's own path (#8822) label-paths-guard.yml caught this before CI did: the job poses the `slides-build-failed` label, so it MUST cover its own file or it can never re-run once the matching paths leave the diff -- and a label-poser that cannot re-run cannot REMOVE the label it added, so the label outlives the defect it names. Measured without the line: "Non-self-covered (VIOLATION): 1", naming this file; with it, 0. Consequence, stated plainly: a PR touching only this workflow now fires the job. It takes the "no deck impacted" exit 0 path and stays green -- cheap, and the price of a retractable label. All five other self-covered label-posers in the repo pay the same. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Grain: MED/guard — lane myia-po-2026:CoursIA — prev: LIGHT/readme #15559
Quoi
L'appel CI de
scan_slidev_composition.pyn'armait jamais--baseline-slide: « 0 constat » était indistinguable d'un chemin de flagging mort. Ce n'était pas théorique — le signal CHEVAUCHEMENT v1 (glyphBBoxouvrant surif (!el.firstChild) return null;,<img>void element) a rendu0pendant toute sa vie, et le vert a été lu comme une absence de défaut (#15381, OBS 1).Le fix (3 pièces)
Fixture deck committée
slides/_composition-control/slides.md— 2 slides ; la slide 2 porte un défaut HORS_CANVAS déterministe :<p>en absolutop:600pxsur canvas 552 px (indépendant des fontes et du thème — aucune métrique textuelle en jeu, la bbox est[0, 600, 240, 640]par construction). Contrairement au contrôle local historique (run_composition_control.py, objet git6cabc826b), la fixture ne requiert aucun objet git → utilisable dans le checkout blobless CI.Câblage workflow : le contrôle tourne inconditionnellement après le check du binaire slidev, AVANT l'early-exit « aucun deck impacté » (un instrument mort doit se voir même les nuits sans deck — ~90 s sur runner public, le prix de l'honnêteté). PASS = scanner exit 1 (constats présents) ET
controle_positif_ok: true. Tout le reste (exit 2 = baseline non signalée, serveur fixture jamais prêt, rapport illisible) = 4e cause de méta-défaillance::error+ exit 1, même classe que « zéro deck découvert » (fix(slides): 5 decks Slidev sur 16 ne construisent pas (3 classes de cause, pre-existant) #8807 trap 1). La fixture est exclue de la découverte des decks réels (branchesfindetDIRS).Tests d'intégrité de la fixture (3 nouveaux,
test_scan_slidev_composition.py) : 2 slides exactement,top:600px+ tag<p>sur la slide 2, canvas par défaut 980×552 — le contrat--baseline-slide 2entre workflow et scanner ne peut pas dériver silencieusement.Validation réelle (pas seulement unitaire)
E2E local exécuté : fixture servie via
slidev dev(binaire de l'arbre principal, pattern junction du contrôleur local), scannée avec--baseline-slide 2 --baseline-commit fixture-local-e2e:Tests : 15/15 verts (dont réparation d'un test rouge préexistant sur main, même fichier, 1 ligne : le namespace exec manquait
n_recajouté par #15351 — vérifié rouge sur main propre avant fix). YAML workflow validé.Scope
--baseline-slideexistait déjà : exit 2 déjà codé — c'est le câblage CI qui manquait).Closes #15545
🤖 Generated with Claude Code