Skip to content

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

Closed

Description

@myia-ai-01

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 runs scripts-tests.yml en é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 -q

Deux 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.py doit 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

  1. Workflow advisory schedule: quotidien, faketime à +8 j et +31 j, non bloquant sur PR.
  2. 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.
  3. 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.
  4. 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

  1. jsboige commented on Sep 2, 2026

    @jsboige
    Owner

    [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)

  2. added a commit that references this issue on Sep 2, 2026
  3. added a commit that references this issue on Sep 2, 2026
  4. added
    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
    on Sep 2, 2026
  5. jsboige commented on Sep 2, 2026

    @jsboige
    Owner

    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 :

    • Fixture épinglée à date absolue corrigée (n'éclate plus à minuit)
    • 8 candidats de la même classe traités
    • CI stabilisée

    Tell c.835 procédure : close légitime, substance vérifiable.

    See #14234 · See #14242 · Closes #14206

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions