Repository navigation
feat(ci,#15322): translation hot-drift per-PR advisory gate - #15438
Conversation
A prose-realignment PR that edits the source of a cell carrying a deposited translation without resyncing its CSV row turns the hot-subset ratchet red on MAIN for the whole fleet (36 PRs at once; incidents #15253/#15136/#15216). The ratchet stays repo-wide; what was missing is attribution. New organ check_pr_translation_drift.py reuses the check_translation_sync predicate verbatim and intersects it with the merge-base delta, so only cells THIS diff puts into the hot subset flag. Advisory (blocking=False, TRANCHE2 native entry + dispatch-only stub); calibration over 98 landed notebook PRs: 6 flagged, 6/6 true positives. Self-test replays the founding occurrence (#15136, b07ca49a). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
G-VAR-2 light cap reached (advisory, non bloquant). |
myia-ai-01
left a comment
There was a problem hiding this comment.
CHANGES_REQUESTED — workflow self-hosted non autorisé au head exact e901e72.
Le détecteur et son principe d’attribution par merge-base sont favorables, mais le nouveau stub .github/workflows/translation-hot-drift-advisory.yml cible le pool self-hosted sans être autorisé par la politique canonique. Le run CPU frais 34436118077 échoue précisément sur :
Violation(workflow='translation-hot-drift-advisory.yml', job='advisory', code='WORKFLOW_NOT_ALLOWED', message='self-hosted runners are restricted to explicitly allowed workflows').
C’est un défaut propre à ce diff, pas l’ancien rouge medical_chatbot_en. Ajouter le workflow à l’allowlist canonique avec le test de politique correspondant, en suivant le précédent d’un advisory réellement autorisé ; exécuter localement test_check_self_hosted_runner_policy.py ainsi que les suites annoncées. Puis intégrer le main courant : #15433 modifie aussi le registre TRANCHE2 et le pin convergent doit être recalculé sur l’état effectif, sans hardcoder « 6 » depuis le body. Répondre explicitement à cette review, checks frais et nouveau DWELL requis.
…-pr-drift-advisory
Le stub workflow_dispatch self-hosted n'etait pas dans l'allowlist canonique (WORKFLOW_NOT_ALLOWED prouve par le run CPU 34436118077) : entree SELF_HOSTED_WORKFLOW_ALLOWLIST commentee (profil repeated-prose/ markdown-decent : cible d'identite fast-lane TRANCHE2 + re-run manuel du self-test) et test de politique dedie. Merge de main au passage (apporte la reparation #15341 : le rouge herite medical_chatbot_en disparait de l'arbre). Pin TRANCHE2 recompte sur l'etat effectif post-merge : 5 gardes. Suites locales : scanner policy rc=0, 58 tests policy, 137 tests (detecteur + fast-lane + policy), self-test OK. See #15322 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Réponse à la review CHANGES_REQUESTED (head
Checks frais partis sur |
myia-ai-01
left a comment
There was a problem hiding this comment.
APPROVED — re-review terminale au head exact d6e894ea0e5339c1070d6395c09cb7eb05810eff.
Je lève ma review CHANGES_REQUESTED du 2026-09-10T04:19:59Z : le défaut WORKFLOW_NOT_ALLOWED est traité en substance et la réponse écrite nomme la réserve.
Vérifications firsthand :
- body, commentaires, reviews, zéro thread inline et diff intégral des sept fichiers relus ;
translation-hot-drift-advisory.ymlprésent dansSELF_HOSTED_WORKFLOW_ALLOWLIST, avec test dédié de membership et fixture Linux self-hosted acceptée ;- scanner exact-head :
151 workflows / 193 jobs / 124 self-hosted, zéro violation ; - suite ciblée réellement exécutée : 137 passed, sans skip dans ce lot ;
- self-test : positif/négatif/attribution + replay fondateur, rc=0 ;
- TRANCHE2 exact-head = 5 gardes (quatre hérités + celui-ci), le nouveau garde est
blocking=False; le moteur fast-lane rend sonrc=1en conclusionneutralet ne le compte pas dansblocking_failed; maina été intégré avant la réparation. Le seul commit désormais en avance sur cette branche est #15405, documentaire et disjoint de ses sept chemins : pas de collision imposant un nouvelupdate-branch.
Les quatre acceptances de #15322 sont satisfaites : attribution par PR, réutilisation de check_translation_sync.check_csv, livraison advisory avec calibration, contrôle positif vivant. Le PR gate rouge restant est le DWELL figé du head poussé à 04:31Z : rerun post-plancher requis, aucune autorisation de merge avant cela.
Path-collision (organ #13359/#13615)Cette PR #15438 (
|
…gration Merge origin/main (incl. #15438 + #15434), regenerate latest.{md,json} via the canonical tool (scripts/audit_workflow_paths_filters.py): - total workflows 150 -> 151 (translation-hot-drift-advisory.yml present, workflow_dispatch-only, has_pull_request=false) - PR-triggered 86 unchanged, paths-filtered 79 unchanged - same 6 exempt_documented entries, workflows_unfiltered_eligible=0 - 9 tests pass Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…hs (unfiltered eligible = 0) (#15417) * fix(guards,#12773): audit reconnait les exemptions documentees de paths (unfiltered eligible = 0) EXEMPT_DOCUMENTED (6 workflows, ref de decision par entree : pr-gate/secret-scan #10600, perimeter-review-guard #11268, always-on x2 #13234, notebook-plan-loss-gate #14391/#14429) + champ par workflow + compteurs workflows_exempt_documented / workflows_unfiltered_eligible (JSON et sommaire markdown). La mesure sans-filtre eligible passe a 0 : les 11 eligibles de la tranche 2 sont traites, le dernier residu (plan-loss) est couvert par une exemption ecrite, pas par un oubli. latest.md/latest.json regenere. * fix(guards,#15417): refresh canonical audit artifacts after main integration Merge origin/main (incl. #15438 + #15434), regenerate latest.{md,json} via the canonical tool (scripts/audit_workflow_paths_filters.py): - total workflows 150 -> 151 (translation-hot-drift-advisory.yml present, workflow_dispatch-only, has_pull_request=false) - PR-triggered 86 unchanged, paths-filtered 79 unchanged - same 6 exempt_documented entries, workflows_unfiltered_eligible=0 - 9 tests pass Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Grain: MED/guard — lane myia-po-2023:CoursIA — prev: MED/notebook-python #15436
Résumé
Closes #15322 — une PR de réalignement de prose qui modifie la source d'une cellule portant une traduction déposée, sans resynchroniser sa ligne CSV, fait rougir le cliquet hot-subset (#13551) sur main, donc sur toutes les PRs ouvertes qui l'héritent (36 PRs rouges d'un coup ; incidents documentés #15253/#15136/#15216). Le cliquet reste repo-wide — ce qui manquait est l'attribution. Ce grain livre un garde par-PR advisory qui répond à la seule question que le cliquet ne peut pas poser : quelles cellules ce diff fait-il entrer dans le sous-ensemble chaud ?
Périmètre
Le détecteur
scripts/translation/check_pr_translation_drift.pyet sa suitescripts/translation/tests/test_check_pr_translation_drift.py; l'entrée du garde dansscripts/ci/fast_lane_registry.py(TRANCHE2, append en fin de liste) avec le pin de compte correspondant dansscripts/tests/test_fast_lane.py; le stub dispatch-only.github/workflows/translation-hot-drift-advisory.yml; son entrée dans l'allowlist canoniquescripts/ci/check_self_hosted_runner_policy.pyavec le test de politique dédié dansscripts/tests/test_check_self_hosted_runner_policy.py(réparation, cf section suivante). Aucun notebook, aucun CSV de traduction touché.Design
check_translation_sync.check_csvelle-même — anomalieSRC_DRIFTà la tête sur une ligne avec traduction déposée, exactement la construction du cliquethot_anomalies.cell_hashdiffère entre merge-base et tête des notebooks changés. La dérive pré-existante sur la base, non touchée par la PR, ne flagge jamais ; une cellule déjà dérivée que la PR re-modifie flagge (la nouvelle modification est non-resynchronisée aussi — une différence d'ensembles hot@head − hot@base la raterait, test épinglé).pull_request.base.sha(leçon fix(guard,#14333): organe stale-base muet -- mesurer le merge-base, pas la pointe de base #15427) :resolve_baseen mode live ; merge-base explicite des deux refs historiques en mode replay.translate_game_rules.py+ arrêt des resync CSV dans le vide #6949.Calibration du taux (acceptance 3, mesurée firsthand)
Replay de chaque PR atterrie touchant des notebooks entre le 2026-08-20 et le 2026-09-10 (first-parent d'origin/main) : 98 PRs, 6 déclenchements (6,1 %), 6/6 vrais positifs :
917fbe0d5)378af0229)272cbf3a7)af91114ec)f6123c4d5)b93de5b56)Vérification vrai-positif : les 8 cellules FT-05 flaggées à l'atterrissage sont toutes
SYNCdansfinetuning.csvactuel — la dérive était réelle et a été réparée après coup. Un taux de 6 % à précision 6/6 est un signal, pas un bruit : l'advisory est la forme correcte à la livraison ; la bascule en bloquant attend la poursuite de la mesure (point 2 de l'issue).Contrôle positif (acceptance 4)
test_replay_documented_incidents).--self-test(pré-contrôlepre_argvdu garde) : contrôles positif/négatif/attribution sur fixtures synthétiques + replay du cas fondateur chore(genai,#11840): strip emojis H1 from 8 GenAI/Image + SemanticKernel notebooks (tranche 1/2, scope claim-amend) #15136 (b07ca49a).Câblage (prouvé)
Entrée TRANCHE2
blocking=False, needs_base=True, absorbed=True+ stub workflow dispatch-only (le test d'absorption exige un fichier source sans triggerpull_request). Preuve d'exécution locale :fast_lane.py --dry-run --only "Translation hot-drift (base vs PR, advisory)"→ garde sélectionné par paths, phase 1 (self-test) exit 0, scan exit 0, verdictsuccess(« OK » — aucune cellule, ce diff ne touche pas de notebooks). En advisory, un déclenchement publierait une conclusion neutre nommant les cellules, jamais un gate.Réparation après CHANGES_REQUESTED (head
e901e72409→e1c094a4a1→d6e894ea0e)La review ai-01 a prouvé par un run CPU frais (34436118077) que le stub ciblait le pool self-hosted sans être autorisé par la politique canonique (
WORKFLOW_NOT_ALLOWED). Corrections :SELF_HOSTED_WORKFLOW_ALLOWLIST(check_self_hosted_runner_policy.py) avec commentaire de propriété au profil des précédents repeated-prose-advisory / markdown-deaccent-advisory (cible d'identité fast-lane TRANCHE2 + re-run manuel du self-test, jambe Linux containerisée, rollback = revert).test_translation_hot_drift_advisory_is_allowlisted: assertion d'entrée dans l'allowlist + fixture synthétique workflow_dispatch / labels Linux acceptée sans violation.e1c094a4a1) : le rouge héritémedical_chatbot_endisparaît de l'arbre (réparation fix(genai,#15218): medical chatbot — honnêteté factory kernel (définir != instancier) #15341 atterrie sur main entre-temps — vérifié firsthand : plus aucune anomalie medical_chatbot au check de sync, rc=0).Suites relancées localement après réparation : scanner policy rc=0 (151 workflows / 193 jobs / 124 self-hosted, zéro violation), 58 tests policy, 137 tests au total (détecteur + fast-lane + policy), self-test du détecteur rc=0.
Tests
pytest scripts/translation/tests/test_check_pr_translation_drift.py→ 7 passed (flag exact, pivot-only/synced silencieux, attribution, re-modification, cellule nouvelle sans ligne, remède-par-resynchro éteint le flag, replays + self-test).pytest scripts/tests/test_fast_lane.py→ 72 passed (pin TRANCHE2 mis à jour, compte effectif 5).pytest scripts/tests/test_check_self_hosted_runner_policy.py→ 58 passed (réparation).medical_chatbot_en(STRUCTURE_DRIFT, réparé par fix(genai,#15218): medical chatbot — honnêteté factory kernel (définir != instancier) #15341) est éteint depuis l'intégration de main — vérifié firsthand sur l'arbre de cette branche (check de sync rc=0, aucune anomalie medical_chatbot).Empilement connu
#15433 (non mergée) ajoute aussi un garde TRANCHE2 et met à jour le même pin (4→5). Les deux diffs touchent des régions distinctes du registre (insertion mi-liste vs append final) mais le pin de compte convergera à 6 au rebase de la seconde mergée — résolution triviale documentée ici. Le pin de CETTE branche est le compte effectif de son arbre (5), pas un compte anticipé.
🤖 Generated with Claude Code