Skip to content

tooling(#13972): infer_genre lit le tag Grain du body avant le regex titre - #13977

Closed
jsboige wants to merge 1 commit into
mainfrom
feature/cycle-66-pioche
Closed

jsboige wants to merge 1 commit into
mainfrom
feature/cycle-66-pioche

Conversation

@jsboige

@jsboige jsboige commented Sep 1, 2026 •

Copy link
Copy Markdown
Owner

Grain: LIGHT/tooling -- lane myia-po-2026:CoursIA -- prev: LIGHT/guard #13974 cycle 75

Grain

Issue #13972, sous-point acceptance 1 : tag Grain: du body autoritatif sur le regex titre+labels.

Diagnostic

pick_idle_grain.infer_genre(title, labels) regarde le titre et les labels. Quand le titre contient notebook, le regex matche notebook-python (META, jamais eligible a une restriction CONTENU). Mais le body peut porter un tag Grain: <TIER>/<GENRE> qui contredit ce regex.

Cas #10475 (2026-09-01, secheresse 9 sur myia-ai-01:CoursIA) :

  • body premiere ligne : Grain: MED/docs (CONTENU)
  • titre : 2.11 LASSO - notebook regression notebook-tools ...
  • infere sans le fix : notebook-python (META, sort du jeu restreint CONTENU)
  • infere avec le fix : docs (CONTENU, sort du jeu comme attendu)

Mesure du 2026-09-01 : 3 candidats sous restriction CONTENU, 2 META (#10475, #13745). Le garde peut certifier la sortie de secheresse tout en la prolongeant silencieusement.

Fix

infer_genre(title, labels, body=None) tente d'abord parse_grain_tag(body). Si parseable, son champ genre est retourne. Sinon, fallback au regex historique, puis docs par defaut. Le parser grain_tag.py etait deja importe dans pick_idle_grain (utilise pour le guard et le prev), donc zero nouvelle dependance.

-def infer_genre(title: str, labels: list[str]) -> str:
+def infer_genre(title: str, labels: list[str], body: str | None = None) -> str:
+    if body:
+        tag = parse_grain_tag(body)
+        if tag and tag.get("genre"):
+            return tag["genre"]
     hay = (title + " " + " ".join(labels)).lower()
     for pattern, genre in GENRE_RULES:
         ...

L'appelant unique (fetch_pool) passe it.get("body") or "" -- le body est deja charge par le gh issue list --json ... body.

Verification

$ python -m pytest scripts/tests/test_pick_idle_grain.py -q
============================= 81 passed in 0.23s ==============================

79 originaux + 2 nouveaux :

Diff

 scripts/pick_idle_grain.py            | 21 +++++++++++++++--
 scripts/tests/test_pick_idle_grain.py | 43 +++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 2 deletions(-)

Hors scope (acceptance points 2/3/4 explicites dans l'issue)

Ces 3 points sont des grains dedies, atomiques, chacun avec son propre controle positif. Un grain composite (1 PR = 4 acceptance points + test E2E) violerait la regle A du PR-review-discipline (composites trop larges).

Refs #13972 · See #13086

Note post-merge (cycle 82)

Body edite au cycle 82 pour ajouter le prefixe Grain: manquant en premiere ligne (le tag etait en fin de body, non detectable par le parser canonique). Le tag est maintenant conforme au format Grain: TIER/GENRE -- lane ... -- prev: TIER/GENRE #N. Pas de modification de code ; le diff reste +62/-2.

…titre

Issue #13972 (acceptance point 1) : quand une issue declare son
genre via un tag `Grain: <TIER>/<GENRE>` dans son body, ce tag est
autoritatif (variation-protocol.md §1 : « Le GENRE est le TYPE DE
TRAVAIL, jamais la famille ou vivent les fichiers »). Sans ce
contrat, le picker peut proposer une issue META sous une restriction
CONTENU : #10475 a son tag `Grain: MED/docs` en premiere ligne du
body mais son titre contient « notebook » -- le regex historique
inferait `notebook-python` (META) au lieu de `docs` (CONTENU).

Mesure du 2026-09-01 (lane `myia-ai-01:CoursIA`, secheresse 9) :
3 candidats, 2 META sous etiquette CONTENU (#10475 et #13745). Le
garde peut certifier la sortie de secheresse tout en la prolongeant
silencieusement.

Fix : `infer_genre(title, labels, body=None)` tente d'abord
`parse_grain_tag(body)`. Si le tag est parseable, son champ `genre`
est retourne -- le regex titre+labels devient un fallback. Fallback
final inchange (`docs`) -- ne casse pas les 79 tests existants.

Tests (81 passants = 79 originaux + 2 nouveaux) :
- `test_infer_genre_reads_body_grain_tag_before_title_heuristic_13972` :
  body `Grain: MED/docs` + titre « notebook regression » -> genre
  `docs` (autoritatif). Couvre #10475.
- `test_infer_genre_falls_back_to_title_heuristic_when_no_grain_tag` :
  controle positif -- sans tag Grain dans le body, le regex titre
  continue de matcher `notebook-python`.

Hors scope du grain (acceptance points 2, 3, 4 de l'issue) :
- discrimination `scripts/notebook_tools/**` vs `MyIA.AI.Notebooks/**`
- annotation des clauses d'auto-exclusion (« ne compte pas comme le
  plat principal »)
- vivier CONTENU retrecit reste non-vide (validation end-to-end sur
  secheresse 9 du 2026-09-01)

Grain cible volontairement un point d'acceptance, pas la totality :
un commit atomique par point, avec controle positif, est plus
verifiable qu'un PR composite.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added variation-tag-lane-missing Tag Grain sans 'lane <machine:workspace>' (cap G-VAR-2 incomptable) variation-tag-prev-absent Tag Grain sans 'prev: <TIER>/<GENRE> #<PR>' (adjacence G-VAR-3 inevaluable) labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Grain tag obligatoire (#10045, bloquant).

Grain tag present but lane machine:workspace missing.

Pour passer ce gate, le body doit porter en tete une ligne de la forme :

Grain: <DEEP|MED|LIGHT>/<genre> -- lane <machine:workspace> -- prev: <TIER>/<GENRE> #<PR>

Le <genre> doit figurer dans l'enumeration §1 de variation-protocol.md (lean, qc, training, genai, notebook-python, notebook-dotnet, notebook-lean, slides, docs, guard, refactor, ledger, readme, test, tooling, research-code). Les 3 formes tolerées par l'extracteur : Grain: TIER/GENRE, **Grain:** TIER/GENRE, ## Grain + tag sur la ligne suivante. La lane doit suivre le format <machine>:<workspace> (cf. lane-claim-protocol.md).

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bash Syntax Advisory — shebang / executable-bit warnings

See the Shebang + dry-run advisory job log for the per-file ::warning:: lines. Non-blocking.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #13977 (tooling(#13972): infer_genre lit le tag Grain du body avant le regex titre) 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.

@github-actions github-actions Bot added pr-overlap Advisory: another open PR touches the same files (organ #13615) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) and removed variation-tag-lane-missing Tag Grain sans 'lane <machine:workspace>' (cap G-VAR-2 incomptable) variation-tag-prev-absent Tag Grain sans 'prev: <TIER>/<GENRE> #<PR>' (adjacence G-VAR-3 inevaluable) labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-po-2026:CoursIA a deja consomme son budget LIGHT du jour (#13901 (merge a 2026-09-01T04:42:58Z)).
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.

@jsboige

jsboige commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #13972 fix on main (commit b0c508b, merged 2026-09-01 09:29Z).

This PR (cycle 66, commit 7f2ef7b) implemented the same fix — infer_genre
reading the Grain: tag from body before falling back to title regex — but
the merged version is more polished (helper authoritative_genre +
canonicalize_genre, 5 tests vs 2, closes #13972 outright).

Closing to clear the DIRTY/mergeable=CONFLICTING slot from the
30-stale-PRs queue (cycle 94 G-VAR recovery). The intent of this PR lives
on main via b0c508b; rebasing would produce a no-op or duplicate test
suite, neither of which adds value.

Grain: LIGHT/guard -- lane myia-po-2026:CoursIA -- prev: MED/guard #14045 cycle 93.

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

Labels

pr-overlap Advisory: another open PR touches the same files (organ #13615) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant