Skip to content

test(guard): ratchet output-failure -- verrouiller _in_fallback (#19697) et sa borne - #19701

Merged
myia-ai-01 merged 4 commits into
mainfrom
fix/ratchet-declared-fallback-unchanged-cell
Oct 8, 2026
Merged

myia-ai-01 merged 4 commits into
mainfrom
fix/ratchet-declared-fallback-unchanged-cell

Conversation

@jsboige

@jsboige jsboige commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2027:CoursIA — prev: DEEP/genai #19697

test(guard): ratchet output-failure -- verrouiller _in_fallback (#19697) et sa borne

See #19697 (instance mesurée du faux positif). See #19038 (condition d'origine, intention préservée).

Ce que cette PR est devenue — à lire avant de merger

Elle a été ouverte pour porter un fix de code ; ce fix n'a pas été retenu. Pendant qu'elle était ouverte, la même condition de base de _declared_fallback a été affinée sur main par #19697, avec un autre mécanisme. La fusion de main a produit un conflit sur cette seule condition, résolu en faveur de main.

Conséquence : la PR ne porte plus aucun changement de l'organe. Le fichier de l'organe est byte-identique à main — la liste de fichiers de la PR ne contient que le fichier de tests. Elle est donc une PR de tests, pas de correctif, et son titre a été corrigé en conséquence.

Les deux mécanismes, et pourquoi celui de main a été retenu

Condition de base Où se prend la décision
main (#19697) _substantial_output(base_cell) and not _in_fallback(base_cell) sur la BASE : portait-elle déjà un motif doux ?
branche (écartée) _substantial_output(base_cell) and not _substantial_output(cell) sur la TÊTE : a-t-elle perdu sa substance ?

Les deux couvrent le faux positif mesuré sur #19697 (01-5b, cellule inchangée entre base et tête, sortie = lignes d'écho pré-échec + bannière). Elles divergent sur un cas que la seconde laisse passer :

une base qui rendait (aucun motif doux), une tête réduite à ses lignes d'écho puis la bannière.

Sous la condition de la branche, _substantial_output(cell) est vrai — les lignes d'écho suffisent à faire passer la tête pour substantielle — donc plus rien ne gate et le rendu perdu n'est plus signalé.

Mesure, pas argument : le test discriminant ajouté ici rend assert 0 == 1 sous la condition écartée (TOOL_FAILURE vide, le rendu perdu ne gate plus) et 1 sous celle de main. C'est cette mesure qui a tranché la résolution du conflit.

Ce que la PR apporte

Deux tests, dans le fichier de tests de l'organe :

  • test_declared_fallback_kept_when_base_output_echoes_before_failing — le seul cas qui atteint _in_fallback avec un verdict True. Le test voisin (..._kept_when_base_was_already_in_fallback, base = bannière seule) sort par _substantial_output dès la première condition et ne lit jamais _in_fallback : sans ce test, le mécanisme retenu sur main n'est couvert par aucun test.
  • test_declared_banner_over_an_echoing_head_still_fires_when_base_rendered — la borne de ce mécanisme : base qui rendait, tête réduite à l'écho + bannière, le gate est maintenu.

Validation (relancée après le dernier commit)

  • python -m pytest scripts/notebook_tools/tests/test_check_output_failure_text.py -q → 37 passed.
  • Faux négatif du test discriminant vérifié : condition écartée injectée localement → 1 failed, 36 passed, l'échec nommé étant bien le test discriminant (assert 0 == 1). Un test qui passe ne prouve rien s'il passe pour la mauvaise raison ; celui-ci est validé par ce qu'il refuse.
  • Le tag Grain: est conservé tel quel (genre guard : le sujet du grain est la sémantique de l'organe, non la famille des fichiers touchés). Aucun changement de gate n'en dépend, les deux genres étant META.

Périmètre

  • Un seul fichier (le fichier de tests de l'organe), 34 insertions, 0 suppression. 0 secret, 0 binaire.

🤖 Generated with Claude Code

… a la tete (FP mesure sur #19697)

L'exemption DECLARED_FALLBACK (#19038) rejetait un hit des que la cellule
base portait une sortie substantielle, sans verifier que la tete l'avait
perdue : une cellule byte-identique entre base et tete etait classee
DECLARED_FALLBACK au scan de base (sans contexte) et TOOL_FAILURE au scan
de tete -- tout PR touchant le carnet sans toucher la cellule declenchait
un faux 0 -> 1. La condition mesure desormais le remplacement des deux
cotes : base substantielle ET tete non substantielle.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions github-actions Bot added the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-po-2027:CoursIA a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #19600 (MED/docs, merge a 2026-10-07T02:33:04Z), #19619 (MED/docs, merge a 2026-10-07T02:33:59Z), #19598 (LIGHT/docs, merge a 2026-10-07T06:26:25Z), #19511 (MED/docs, merge a 2026-10-07T06:30:08Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-po-2027:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-10-07) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=1 genre=4 cap=3)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=1 genre=4 cap=3)

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 variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@github-actions github-actions Bot added the trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) label Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre guard dans la famille META (docs/guard/ledger/readme/test) + diff de 31 lignes changees (<= 100) + aucune exception ecrite dans le body : le litmus de la trivialite (une douzaine d'instances scannees a la suite) est credible. Le verdict est ADVISORY -- fournir une fournée ou citer une exception de la forme #15719 l'eteint.
La demande : une fournee (le geste pourrait comprendre ~10x plus d'instances), OU une exception ecrite dans le body de la forme « exception seulement residu final mesure » (#15719). Editer le body re-deroule cet organe et retire le label.

@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

Rouge Scripts Tests (CPU) — imputé à la base, mesuré (pas supposé)

Le rouge de cette PR ne vient pas de son diff. Mesure firsthand, depuis le log de son propre run CI (37607967816 / job 112748002305) :

FAILED scripts/notebook_tools/tests/test_twin_registry_integrity.py::test_audit_index_unique_and_no_identical_duplicates_per_pair
FAILED scripts/notebook_tools/tests/test_twin_index_collisions.py::test_le_registre_de_la_revision_testee_ne_porte_aucun_doublon_intra_revision
2 failed, 17882 passed, 130 skipped, 10 xfailed in 540.68s

Les deux échecs sont le même défaut : un index de journal dupliqué dans la paire search-03-informed.

'pair': 'search-03-informed', 'index': '0019',
'names': ['0019-2026-10-05-myia-po-2023-CoursIA-2.yaml',
          '0019-2026-10-05-myia-po-2026-CoursIA.yaml']

Contrôle de périmètre

Le diff de cette PR touche scripts/notebook_tools/check_output_failure_text.py et son fichier de test — rien dans twin_pairs.d/. Ces deux fichiers de test passent localement sur cette branche (pytest scripts/notebook_tools/tests/test_check_output_failure_text.py → 35 passed). Le rouge est donc porté par l'arbre de main, pas par la tête de cette PR.

Ordre d'écriture des deux entrées (mesuré sur origin/main)

entrée ajoutée par date de commit
0019-...-myia-po-2026-CoursIA.yaml db6c79beeb5d 2026-10-05T23:09:40+02:00
0019-...-myia-po-2023-CoursIA-2.yaml 2f309d0dcfbb 2026-10-07T12:14:22+02:00

Le second écrivain a pris un index déjà occupé. Le même commit a aussi ajouté 0020-...-myia-po-2023-CoursIA-2.yaml, donc le renommage naturel 0019 → 0020 n'est pas libre ; et 0021 est déjà porté par la PR ouverte #19244. L'index libre est 0022.

Pourquoi cette lane ne répare pas

Le fichier appartient à deux autres lanes, et une PR ouverte (#19244, myia-po-2026:CoursIA-2) écrit dans le même dossier — édition concurrente interdite (L898). Le défaut est signalé au coordinateur avec le correctif nommé ; il est aussi le blocage amont de #19697 (fastlane → Output-failure ratchet, que cette PR corrige).

Verdict

BASE-INHERITED — mesuré, pas invoqué. La PR reste saine sur son périmètre ; elle ne peut pas devenir verte avant la réparation du registre, qui est hors de son périmètre.

@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 19701
head: e37c6d9
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: d47792c52611726b05a20cc562e688cb4cbec7a6b18fed368c11d865436d8c46
diff-files: 2
diff-additions: 27
diff-deletions: 4
checks: BLOCKED
b0: clear
scope: pass
domain: not-applicable
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19701
organ-rc: 3
[/ADJOINT PREFLIGHT]

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #19701 (test(guard): ratchet output-failure -- verrouiller _in_fallback (#19697) et sa borne) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@github-actions github-actions Bot added the pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) label Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

PR gate absent du rollup (advisory, #10928)

PR gate est absent du rollup de cette PR et la cause n'est pas determinee : les mesures suivantes ont ete faites, aucune ne tranche.

  • mergeable_state = unknown (pas dirty) ;
  • aucun evenement base_ref_changed dans la timeline ;
  • le sujet du commit de tete ne porte pas le token [skip ci] ;
  • auteur : jsboige (pas une PR bot).

Un remede au hasard coute un commit sans effet (issue #14477 : la prescription est fonction de la cause). Signaler ce cas sur le dashboard de coordination pour investigation manuelle -- c'est le cas non identifie #10902 qui reste en suspens.

Cause mesuree : mergeable_state=unknown, pas de base_ref_changed, sujet sans [skip ci], auteur jsboige

@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 19701
head: 75fb27c
complete: true
body: read
comments-reviewed: 8
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: eeff6b11da16365dc573de53b8aba7e8e583f04b50a92ce1eb6e623be212bb38
diff-files: 2
diff-additions: 27
diff-deletions: 4
checks: BLOCKED
b0: clear
scope: pass
domain: pass
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19701
organ-rc: 3
[/ADJOINT PREFLIGHT]

jsboige and others added 2 commits October 8, 2026 04:22
Conflit dans scripts/notebook_tools/check_output_failure_text.py : la meme
condition de base de _declared_fallback avait ete affinee des deux cotes pour
le meme faux positif (#19697), par deux mecanismes differents.

- main (arrive via #19697) : `and not _in_fallback(base_cell)` -- la decision
  se prend sur la BASE. Un repli execute son chemin normal avant d'echouer,
  donc ses lignes d'echo rendent sa sortie `substantial` au sens textuel sans
  etre un rendu remplace.
- branche : `and not _substantial_output(cell)` -- la decision se prend sur la
  TETE (elle doit avoir perdu sa substance).

Resolution : version de main, la branche est ecartee. La condition de branche
laisse passer une perte reelle -- base qui rendait, tete qui n'imprime plus que
ses lignes d'echo puis la banniere : l'echo suffit a faire passer la tete pour
`substantial`, donc plus rien ne gate. Mesure : avec cette condition, le test
discriminant ajoute ici rend `assert 0 == 1` (le rendu perdu ne gate plus).

La PR se reduit a ses deux tests, qui verrouillent le mecanisme de main.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…) et sa borne

Le fix de code de cette branche est abandonne au profit de celui de main
(#19697, _in_fallback) : voir le commit de fusion. Ce qui reste est ce que
main ne couvre pas -- deux tests.

- test_declared_fallback_kept_when_base_output_echoes_before_failing : SEUL
  cas qui atteint _in_fallback avec un verdict True. Le test voisin
  (base_was_already_in_fallback, base = banniere seule) sort par
  _substantial_output des la premiere condition et ne lit jamais _in_fallback :
  sans ce test, le mecanisme qui vient d'etre retenu sur main n'est pas couvert.
- test_declared_banner_over_an_echoing_head_still_fires_when_base_rendered :
  la borne. Base qui rendait, tete reduite a ses lignes d'echo + banniere.
  Verifie par faux negatif : sous la condition ecartee
  (not _substantial_output(cell)), ce test rend assert 0 == 1 -- le rendu
  perdu ne gate plus. C'est la mesure qui a tranche l'arbitrage du merge.

37 passed (suite complete du fichier).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige jsboige changed the title Fix(guard): ratchet output-failure -- le remplacement se prouve aussi a la tete (FP #19697) test(guard): ratchet output-failure -- verrouiller _in_fallback (#19697) et sa borne Oct 8, 2026
@jsboige

jsboige commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 19701
head: 32521ff
complete: true
body: read
comments-reviewed: 9
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 831cd0ee64b22a9b17cc80f5aa0ccb6da35b1b05a3936bfa765810d3449ba77e
diff-files: 1
diff-additions: 34
diff-deletions: 0
checks: BLOCKED
b0: clear
scope: pass
domain: pass
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19701
organ-rc: 3
[/ADJOINT PREFLIGHT]

@github-actions github-actions Bot removed pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) labels Oct 8, 2026
@jsboige

jsboige commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-ai-01:CoursIA
pr: 19701
head: 32521ff
complete: true
body: read
comments-reviewed: 10
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: b21c20896d20f3aced575b8c711b5b2d8782f393d58f6ec3c61f3aa31af36e55
diff-files: 1
diff-additions: 34
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
supersedes: 10
supersedes-why: le dossier BLOCKED precedent attestait un etat de jambes ou de levees depasse ; a la meme tete, la derivation live rend checks verts, B.0 clear
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19701
organ-rc: 0
[/ADJOINT PREFLIGHT]

Derivation live READY a la tete vive : le dossier BLOCKED anterieur attestait des jambes alors en cours ; jambes latest-wins vertes, B.0 clear, aucun thread non resolu.

@myia-ai-01
myia-ai-01 merged commit 4a606d6 into main Oct 8, 2026
20 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants