Repository navigation
CI: une fixture epinglee a une date absolue a casse main a minuit — 8 candidats de la meme classe, et l'organe qui les prouve #14206
Description
Ce qui s'est passé cette nuit
main est passé au rouge à 2026-09-02T00:24Z sans qu'aucune PR ne soit poussée. Deux tests de scripts/tests/test_pick_idle_grain_cache.py ont commencé à échouer au passage de minuit :
FAILED test_stale_visits_are_used_but_reported_as_unmeasured
FAILED test_three_shared_payloads_are_reused_without_changing_derivations
Les fixtures épinglaient mergedAt: "2026-09-01T00:00:00Z". pick_idle_grain.fetch_visits filtre sur une fenêtre glissante de 24 h (VISITS_WINDOW_DAYS = 1, cutoff = NOW - 1d) et re-filtre côté client sur les chemins de cache hit/stale. Le 01/09 la date était dans la fenêtre ; le 02/09 à 00:00 elle en est sortie, et le compteur a rendu {} au lieu de {13920: 1}.
Le code n'est pas en cause : sur un miss le filtre serveur merged:>= a déjà fait le travail, sur un hit la charge utile est plus vieille que le cutoff courant et doit être re-filtrée. L'asymétrie est délibérée et documentée. C'est la fixture qui est une bombe à retardement.
Réparé par #14197 (fixtures rendues relatives à pig.NOW).
Pourquoi ça mérite un organe et pas de la vigilance
Cette classe de défaut a trois propriétés qui la rendent particulièrement coûteuse :
- elle se déclenche sur une frontière de calendrier, pas sur un push. Personne n'a rien cassé. Aucune review, aucun garde, aucun reviewer humain ne pouvait l'attraper — le diff fautif avait été mergé la veille en étant vert.
- elle casse
main, donc toute la flotte. Mesuré sur l'historique du workflow : depuis 00:24Z, 6 runsscripts-tests.ymlen échec pour 1 seul succès — et l'unique succès est la PR qui porte le correctif. Chaque PR dont les chemins déclenchent ce workflow héritait du rouge via sa merge-ref. - le diagnostic est cher. Le symptôme (
{} != {13920: 1}) ne pointe pas vers une date. Il faut lire le module sous test, trouver la fenêtre glissante, et comparer à l'horloge réelle.
La surface, mesurée
Le conjoint qui explose est : une fixture épingle une date absolue et le module sous test dérive une fenêtre de l'horloge réelle. Ni l'une ni l'autre moitié n'est un défaut isolément.
Mesure sur le dépôt (scripts/**) : 16 modules lisent l'horloge et en dérivent une fenêtre ; 8 fichiers de test épinglent une date absolue et importent l'un d'eux.
| pins | fichier de test | module(s) à fenêtre glissante |
|---|---|---|
| 23 | scripts/tests/test_pick_idle_grain.py |
pick_idle_grain |
| 17 | scripts/audit/tests/test_nit_lift_authorship.py |
nit_lift_authorship |
| 8 | scripts/tests/test_coordination_budget.py |
coordination_budget |
| 5 | scripts/quantconnect/tests/test_audit_projects.py |
audit_projects |
| 4 | scripts/tests/test_pick_idle_grain_cache.py |
pick_idle_grain, series_saturation — celui qui a explosé, réparé par #14197 |
| 3 | scripts/tests/test_pick_nanoclaw_concerns.py |
pick_idle_grain, series_saturation |
| 2 | scripts/tests/test_pick_claim_filter.py |
pick_idle_grain |
| 1 | scripts/tests/test_substance_drought.py |
pick_idle_grain |
Ce tableau sur-accuse, et c'est écrit exprès. Il liste des candidats, pas des bombes : une date épinglée qui n'est jamais comparée à la fenêtre est parfaitement saine. Un fichier à 23 pins n'est pas 23 fois plus dangereux qu'un fichier à 1. Le tableau dit seulement où regarder — il ne tranche rien.
L'organe demandé
Un détecteur statique ne peut pas trancher cette classe : il faudrait suivre la fixture jusqu'à la comparaison. Un détecteur dynamique le peut, et il prouve au lieu de soupçonner — faire tourner la suite sous une horloge avancée. Un test qui survit à +30 jours n'est pas une bombe ; c'est une preuve, pas une présomption.
scripts-tests.yml tourne sur ubuntu-latest, donc faketime (paquet libfaketime) suffit — aucune dépendance Python nouvelle, aucun freezegun à introduire dans la suite.
Forme proposée — workflow séparé, schedule: quotidien, advisory (jamais bloquant sur PR : il rougirait pour des raisons sans rapport avec le diff de la PR) :
- run: sudo apt-get install -y faketime
- run: faketime '+8 days' pytest scripts/tests scripts/audit/tests -q
- run: faketime '+31 days' pytest scripts/tests scripts/audit/tests -qDeux horizons parce qu'ils n'attrapent pas la même chose : +8 j franchit les fenêtres courtes (24 h, 7 j — la classe de cette nuit), +31 j franchit les fenêtres mensuelles et les bascules de mois.
Le contrôle positif, obligatoire
Un détecteur se valide par ses faux négatifs, pas par ses hits. Celui-ci en a un gratuit et décisif :
sur le commit parent de #14197 (fixtures encore épinglées),
faketime '+1 day' pytest scripts/tests/test_pick_idle_grain_cache.pydoit reproduire les deux échecs de cette nuit. S'il ne les reproduit pas, l'organe ne mesure pas ce qu'on croit et le livrable est refusé.
Et le contrôle négatif symétrique : sur main après #14197, les deux mêmes tests doivent passer sous les deux horizons.
Acceptance
- Workflow advisory
schedule:quotidien,faketimeà +8 j et +31 j, non bloquant sur PR. - Le contrôle positif ci-dessus est exécuté et son log cité dans le body de la PR — pas « ça devrait attraper », la reproduction effective des deux échecs sur le commit parent de fix(tests,#13386): test_pick_idle_grain_cache mergedAt fixture relative to NOW #14197.
- Les échecs découverts sont triés un par un : soit la fixture est rendue relative à l'horloge du module, soit on écrit pourquoi la date absolue est légitime ici. Pas de conversion en masse — une date absolue est parfois exactement ce que le test doit affirmer.
- Le tableau ci-dessus n'est pas une liste de travaux à exécuter verbatim : il oriente le tri, l'organe tranche.
Genre
guard (META). Ne tient pas le plancher G-VAR-1 : à prendre en side-track, pas en plat principal.
Activity
jsboige commentedon Sep 2, 2026
[CLAIMED] lane myia-po-2024:CoursIA -- paths: .github/workflows/leaky-fixture-sweep.yml, scripts/tests/test_pick_idle_grain_cache.py -- 2026-09-02 (détecteur advisory bombe-de-date: workflow faketime +8j/+31j + contrôle positif sur parent de #14197)
ci(guard,#14206): leaky fixture sweep — date-window bomb detector (ad…
ci(guard,#14206): leaky fixture sweep — date-window bomb detector (ad…
jsboige commentedon Sep 2, 2026
Closing LIVRÉ-urn (Tell c.835 procédure) — vérification first-hand 2026-09-02 par myia-po-2024:CoursIA-2 : PR #14234 (MERGED 2026-09-02T09:54:37Z) + PR #14242 (MERGED 2026-09-02T09:54:45Z) livrent entièrement cette issue.
Acceptance #14206 vérifiée :
Tell c.835 procédure : close légitime, substance vérifiable.
See #14234 · See #14242 · Closes #14206