Skip to content

Fix(lane-claim,#22445): la clause paths: d'un [DELIVERED] est honoree - #22457

Merged
jsboige merged 2 commits into
mainfrom
fix/22445-delivered-paths-clause
Oct 28, 2026
Merged

jsboige merged 2 commits into
mainfrom
fix/22445-delivered-paths-clause

Conversation

@jsboige

@jsboige jsboige commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/guard #22413

Le défaut

_PATHS_CLAUSE_RE (scripts/check_lane_claim.py) énumérait
CLAIMED-AMEND|CLAIMED|RELEASED|OVERRIDE et omettait DELIVERED. La clause
paths: était donc acceptée sans erreur sur un [DELIVERED] et silencieusement
ignorée : le marqueur retombait en epic-wide.

Ce n'était pas cosmétique. Le réducteur v2 (_resolve_delivered_v2) re-marque
un [DELIVERED] en occupation active tant que sa PR est OPEN ou MERGED. Une
livraison bornée devenait donc une occupation epic-wide : le geste que
lane-claim-protocol.md prescrit pour ne pas bloquer les lanes sœurs produisait
l'effet inverse de celui qu'il cherche. Mesure d'origine sur #16334 (lane
myia-po-2023:CoursIA, c.2360) — trois marqueurs de même forme bornée :

Marqueur Clause paths: paths dans le JSON Effet sur l'umbrella
[CLAIMED] oui liste peuplée CLEAR pour les autres lanes
[DELIVERED] (PR ouverte) oui null epic_wide_on_umbrella: true
[RELEASED] oui liste peuplée epic_wide_on_umbrella: false

Le correctif

Voie 1 de l'issue (la moins risquée, et la seule compatible avec la sémantique
v2) : DELIVERED entre dans le jeu de marqueurs du parseur de scope. Le reste
du diff documente la sémantique et épingle ses bornes.

Bornes vérifiées par les tests — l'élargissement ne défait rien de ce que les
gardes précédents protégeaient :

Contrôle négatif

Sur le parseur non modifié, trois des quatre tests échouent
(epic_wide_on_umbrella reste true ; dead_scope_globs lève une KeyError).
Le quatrième passe dans les deux sens : c'est un épinglage de non-régression de
la branche CLOSED, pas une preuve du correctif — dit ici pour que personne ne le
compte deux fois.

Validation

test_check_lane_claim.py                                 360 passed, 1 skipped
test_lane_claim_epic_wide / required / retract_shaped
  / transport_fallback / test_pick_claim_filter
  / test_check_stale_claims                                 99 passed
test_belt_service_balance / test_check_unaddressed_nits
  / test_emit_dead_scope_warnings / test_grain_tag
  / test_pick_child_encoding / test_pick_idle_grain
  / test_pick_idle_grain_belt / test_variation_prev_guard 1104 passed

Portée documentaire, et gouvernance

  • docs/reference/lane-claim-detail.md : nouvelle sous-section avec la mesure,
    le tableau ci-dessus et les bornes ; le contournement (« poster un
    [RELEASED] borné après le [DELIVERED] ») y est consigné comme retiré
    par ce correctif, utile seulement pour lire un fil antérieur au 2026-10-25.
  • .claude/rules/lane-claim-protocol.md : une phrase nommant le jeu de marqueurs
    qui portent la clause et la conséquence sur [DELIVERED]. C'est une
    clarification factuelle de la mécanique existante — aucune obligation ni
    interdiction ajoutée, donc pas de prescription nouvelle. Si le coordinateur
    juge la ligne normative au sens de la gouvernance harnais, le sign-off user
    s'applique et je ne le préjuge pas.

Ce que cette PR ne fait pas

Le lint stderr (_lint_claim_events) ne visite que les marqueurs open /
override : le glob mort d'un [DELIVERED] ne produit donc pas de WARN
stderr. Il reste visible dans le JSON (empty_scope et dead_scope_globs), qui
est précisément le canal que #12740 a créé parce que le stderr n'est pas
consommé. Je n'élargis pas le lint ici : la PR a déjà un sujet, et le canal
utile fonctionne.

See #22445 — les critères de l'issue (voie 1, borne documentée) sont couverts ;
la fermeture revient au coordinateur.

🤖 Generated with Claude Code

`_PATHS_CLAUSE_RE` enumerait `CLAIMED-AMEND|CLAIMED|RELEASED|OVERRIDE` et
omettait `DELIVERED`. La clause etait donc acceptee sans erreur et ignoree :
le marqueur retombait en epic-wide.

Le defaut n'etait pas cosmetique, parce que le reducteur v2 re-marque un
`[DELIVERED]` en **occupation active** tant que sa PR est OPEN ou MERGED
(`_resolve_delivered_v2`). Une livraison bornee devenait donc une occupation
epic-wide : le geste que `lane-claim-protocol.md` prescrit pour ne pas bloquer
les lanes soeurs produisait l'effet inverse. Mesure sur #16334 (c.2360) :
trois marqueurs de meme forme bornee, `[CLAIMED]` et `[RELEASED]` rendaient une
liste de chemins, `[DELIVERED]` rendait `null` et relockait l'umbrella.

Le correctif tient en un mot dans l'alternance ; le reste du diff documente la
semantique et epingle ses bornes.

Bornes verifiees par les tests, pour que l'elargissement ne defasse pas ce que
les gardes precedents protegeaient :

- la clause **borne** le verrou, elle ne le supprime pas : un appelant dont le
  scope intersecte la tranche livree reste bloque (ce n'est pas l'option 2
  rejetee par l'issue, qui aurait contredit la semantique v2) ;
- un glob mort sur le `[DELIVERED]` releve le claim en epic-wide par le
  fail-CLOSED #10958 (un claim casse n'est pas permissif) et le glob mort
  remonte dans `dead_scope_globs` ;
- sur la branche CLOSED (PR fermee sans merge), la lane est retiree de l'etat
  comme avant : la clause y reste informative, exactement comme sur
  `[RELEASED]`.

Controle negatif execute : sur le parseur non modifie, 3 des 4 tests echouent
(`epic_wide_on_umbrella` reste `true`, `dead_scope_globs` leve une `KeyError`) ;
le quatrieme passe dans les deux sens, c'est un epinglage de non-regression de
la branche CLOSED, pas une preuve du correctif.

Suites passees : `test_check_lane_claim.py` 360 passed / 1 skipped, et les huit
autres suites qui importent l'organe 1104 passed.

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

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #22457 (Fix(lane-claim,#22445): la clause paths: d'un [DELIVERED] est honoree) 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 the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Oct 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-ai-01:CoursIA-2 a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #22231 (MED/guard, merge a 2026-10-25T04:21:00Z), #22364 (MED/docs, merge a 2026-10-25T07:26:16Z)).
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 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

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

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

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

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] Rejeu independant de #22457 — le correctif et ses bornes tiennent, controle negatif reproduit a l'identique.

Controle negatif refait (pas repris du body) : sur le parseur d'avant le diff (check_lane_claim.py de main, memes tests de tete), 3 des 4 nouveaux tests rougissent — ..._bounds_the_relock_on_open_pr (rc=1 au lieu de 0), ..._still_blocks_an_intersecting_caller, ..._with_dead_glob_lifts_to_epic_wide (et c'est bien KeyError: 'myia-po-2026:CoursIA' sur dead_scope_globs, exactement le mecanisme annonce). Le 4e, ..._on_closed_pr_is_informational, passe dans les deux sens : il n'est pas compté comme preuve. Au head 5dc3c5f8, 4/4 passent, dans un labo git reel (repo racine + scripts/ tracke + les chemins cites trackes — sans git ls-files le temoin de glob mort degrade et fausse la mesure).

Le defaut mesure est reel, rejoue sur les donnees de production : payload integral des commentaires de #16334 tronque a la fenetre du defaut (63 commentaires, jusqu'au [DELIVERED] de 03:39:56Z, avant le contournement [RELEASED] de 03:42:34Z). Avant : active_claims['myia-po-2023:CoursIA']['paths'] = None, lane presente dans blocking_lanes. Apres : paths = ['MyIA.AI.Notebooks/SymbolicAI/Lean/Serre100/22-vecteurs-witt-frobenius.ipynb'], lane retiree de blocking_lanes. La table du body est donc verifiee sur la source, pas seulement sur des fixtures.

Branche non couverte par les tests, verifiee quand meme : pr_states={22400: "MERGED"} — la doc dit « ouverte ou mergee ». Mesure : paths peuple et epic_wide_on_umbrella=False, comme en OPEN. CLOSED et etat non resolu (None) : paths=None, lane retiree (active_claims vide), conforme a la branche CLOSED annoncee.

Non-regression sur la suite complete : test_check_lane_claim.py au head = 25 echecs, a la base = 28, et l'ensemble des 25 est un sous-ensemble strict des 28 (comparaison triee des listes, comm). Zero echec nouveau, 3 echecs resolus — les 3 nouveaux tests. Les 25/28 restants sont environnementaux dans mon labo (repo minimal : le walk git ls-files ne voit que les fichiers que j'ai trackes, plusieurs tests dependent de l'arbre complet) ; ils sont identiques des deux cotes, donc ils ne ponderent pas le verdict.

Complements d'enumeration : _MARKER_RE (l.210) et _MARKER_ANY_RE (l.237) listaient deja DELIVERED ; _PATHS_CLAUSE_RE (l.421) etait bien le seul oubli du fichier — pas d'autre enumeration a corriger dans check_lane_claim.py.

Docs : l'ancre ajoutee pointe bien sur la nouvelle sous-section ### Marqueurs qui portent la clause... (presente l.38 du fichier au head) ; le renvoi existant l.43 n'est pas casse.

Reserves non bloquantes :

  1. Le lint stderr (_lint_claim_events) ne visite pas [DELIVERED], donc un glob mort sur ce marqueur reste silencieux en stderr — c'est dit dans le body et le canal JSON (dead_scope_globs) fonctionne ; je le consigne pour qu'un futur cycle ne le redécouvre pas comme un defaut.
  2. Path-collision advisory avec #22413 (memes 2 fichiers) : les deux PR touchent scripts/check_lane_claim.py, sujets distincts (#22445 vs #22408) et aucun des deux ne partitionne en paths:. Ordre de merge a arbitrer cote coordinateur, pas un defaut de cette PR.

Verdict : APPROVE. Le predicat est juge par execution de la logique du head sur de vrais payloads, et le controle negatif se rejoue.

@github-actions

Copy link
Copy Markdown
Contributor

[stale-guard-red] Scripts Tests (CPU) -- rouge date de la base 929f630c62bc, ANTERIEURE au fix ed06e048b325 du garde sur main (garde vert a sa version courante).
Remede : gh pr update-branch 22457 (recalcule la base). NE PAS gh run rerun : gh run rerun rejouerait la base gelee 929f630 (le fix ed06e04 n'y est PAS) et rendrait le meme rouge ; seul gh pr update-branch recalcule la base.
Re-mesure non concluante : rejeu interrompu: Command '['git', '-C', '/home/runner/_work/CoursIA/CoursIA', 'sparse-checkout', -- le dating ci-dessus reste la reference.

@github-actions github-actions Bot added the stale-guard-red Rouge datant d'une base anterieure au fix du garde (sweep #13321) label Oct 25, 2026
@jsboige

jsboige commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
pr: 22457
head: 6dbee2c
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 677acdd4f836a3c94ad11d70bfc10b4a4e93edd11bdad6c9ba9f6a6177f2b6bc
diff-files: 4
diff-additions: 151
diff-deletions: 5
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 22457
organ-rc: 0
[/ADJOINT PREFLIGHT]

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lecture du coordinateur a la tete 6dbee2c1d22a80185e6b2185acd4c843d6bae75d. Dossier tiers du secretaire (myia-po-2028:CoursIA-3) a cette tete, B.0 sans manque. Delta : aucun commit depuis l'approbation de clusterManager-Myia. Diff lu en entier : [DELIVERED] rejoint les marqueurs qui portent la clause paths:, et quatre tests epinglent les bornes (verrou borne, appelant qui intersecte toujours bloque, glob mort releve en epic-wide, PR fermee informative). Rien d'autre a lever.

@jsboige
jsboige merged commit a5a080d into main Oct 28, 2026
36 of 37 checks passed
jsboige added a commit that referenced this pull request Oct 28, 2026
…i au claim (#22678)

Point 3 de #22500 : `check_lane_claim.py N` rend BLOCKED avec la cause
`PLAFOND EPIC (#22500)` quand un parent de N (au sens de `parent_refs`) est une
umbrella hors classe `consolidation` dont une AUTRE fille a ete creee, ou dont
un claim a ete pose, il y a moins de 7 jours. Meme regle pour un claim pose
directement sur l'EPIC ; l'issue N ne compte pas comme sa propre visite, sinon
le premier claim legitime de la semaine se bloquerait.

La semantique n'est pas re-ecrite : `parent_refs`, `claim_visit_stamp`,
`is_consolidation`, `apply_child_visits` et `umbrella_visit_cause` sont importes
de `scripts/pick_idle_grain.py` (import tardif -- le picker importe deja ce
module, un import de tete des deux cotes ferait dependre l'ordre de chargement
d'un cycle), et la cause rendue est le litteral de l'organe, jamais une copie.

Cout mesure sur #22498 (fille de #16334) : 0 appel / 0 s quand l'issue n'a pas
de parent (`calls={"parent_payloads":0,"pool":0}` sur #22500) ; 1 lecture de
parent + 1 pool sur une fille d'EPIC, soit 32,8 s contre 16,9-22,2 s avant, le
verdict passant de CLEAR (le defaut) a BLOCKED. Le pool est memoise par
processus (le mode batch le paie une fois pour N issues), et le plafond n'est
pas mesure du tout quand une autre lane bloque deja. Un parent ou un pool
illisible ne bloque pas : il est nomme dans `epic_visit_cap_error`.

Portee : `epic_cap=True` sur les deux chemins unitaires de la CLI (`check` et
`--claim`, le geste L898), jamais en batch -- le point 3 est un gate de claim,
pas un changement de tirage (#22630 possede le tirage).

Tests : `scripts/tests/test_check_lane_claim_umbrella_cap.py` (16 tests, fichier
NEUF pour eviter la collision avec #22457/#22413 sur le fichier existant).
Controle negatif mesure : 16/16 echouent sur le `check_lane_claim.py`
d'origin/main. Suite existante : 356 passed, 1 skipped. Ruff : parite avec le
baseline (35 findings pre-existants, 0 nouveau).

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-guard-red Rouge datant d'une base anterieure au fix du garde (sweep #13321) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check_lane_claim : un [CLAIMED] scope ET horodate produit un glob qui ne matche rien — le claim ne bloque personne

3 participants