Skip to content

fix(ci,#17771): desserrer no_pr_match — résolution par tête distante + content_on_main - #17809

Merged
myia-ai-01 merged 2 commits into
mainfrom
fix/17771-prune-no-pr-match
Sep 25, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
fix/17771-prune-no-pr-match

Conversation

@jsboige

@jsboige jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/ci-python — lane myia-po-2026:CoursIA — prev: DEEP/notebook-python #16897

prédicats 1 + 2 : desserrer no_pr_match sans desserrer les gardes

diagnose_worktree termine aujourd'hui en no_pr_match (REFUSE conservatrice) dès que la résolution par le nom de branche locale échoue — même quand le travail est trivialement rattachable : checkout pr-123 (le nom local n'est pas la tête de PR), ou branche dont le contenu est déjà intégré à main sans PR rattachable. Deux prédicats ordonnés, insérés après tous les gardes existants (saleté source, untracked non toléré, submodules, commits non poussés, branche protégée) :

Prédicat 1 — résolution par la tête distante qui porte HEAD

Quand lookup_pr_for_branch(<nom local>) rend None, nouvel essai par remote_head_for_head(wt_path, branch, head_sha) :

  1. upstream explicite <branche>@{u} (hors */main, cf le faux-positif massif documenté dans get_worktree_info) → nom court ;
  2. sinon scan de tips for-each-ref refs/remotes/origin : une branche origin/* dont le TIP est exactement head_sha (origin/main/origin/HEAD exclus).

La PR retrouvée suit alors le verdict standard : OPEN → REFUSE pr_open (le garde n'est pas affaibli), MERGED/CLOSED → REMOVE.

Prédicat 2 — content_on_main

Toujours sans PR rattachable, si git merge-base --is-ancestor HEAD origin/main : chaque commit du worktree est déjà sur main → REMOVE avec motif dédié (WorktreeStatus.content_on_main, champ additif, motif aussi rendu dans render_text). Les deux autres conditions de l'issue sont structurellement garanties par les gardes amont — un commit non poussé serait sorti en unpushed_commits, une édition source en uncommitted_source_changes/untolerated_untracked. Borne au cas branche : un HEAD détaché garde son verdict dédié (detached_no_match/detached_on_main).

Tests (113 passés + 11 nouveaux, 1 skipped inchangé)

Test Garde
test_remote_head_merged_removes le lookup reçoit bien ["pr-17771", "fix/renamed"] (chute du nom local vers la tête distante)
test_remote_head_pr_open_refuses contrôle négatif exigé : PR OPEN retrouvée par tête distante → REFUSE pr_open
test_no_remote_head_keeps_conservative_refuse aucune tête distante → no_pr_match inchangé
test_ancestor_clean_removes_with_motif REMOVE + content_on_main=True + refusal_reason=None
test_not_ancestor_still_refuses commits propres (squash-merge) → REFUSE conservatrice
test_py_edit_primes_over_content_on_main contrôle négatif exigé : tête ancêtre de main MAIS édition .py non suivie → REFUSE uncommitted_source_changes, et l'appel gh lève AssertionError (jamais atteint)
test_detached_head_not_eligible HEAD détaché : head_is_ancestor_of_main ne doit même pas être appelé
TestRemoteHeadForHead (4 tests) upstream court, upstream origin/main esquivé, scan excluant origin/main/origin/HEAD, tip divergent → None

Suite complète : python -m pytest scripts/tests/test_prune_merged_worktrees.py → 113 passed, 1 skipped (326 s). install_prune_task.py non modifié (seuls l'organe et ses tests changent).

Mesure avant/après (cette machine, 2026-09-25, dry-run --json)

Même flotte de worktrees, deux passes consécutives — BEFORE depuis un worktree détaché à origin/main (9a2dd8aa4f), AFTER depuis la branche de cette PR (130e1f81cf).

Métrique Avant Après
no_pr_match 14 5
detached_no_match 0 0
removable 9 17
refusés 51 43
budget API (ancre) 14 appels 16 appels

Décomposition du −9 (verdict par verdict, diff des JSON) :

Les 5 no_pr_match restants sont des REFUSE correctes : pr-16897 (PR #16897 ouverte, en attente de merge — la tête distante a bougé depuis le checkout), pr-17639, fix/16361-renumbers, tmp-16386, fix/16861-prose-outputs (têtes divergentes de tout ref distant — rien à rapprocher sans inventer).

Conformité

See #17771
See #14195

🤖 Generated with Claude Code

- predicat 1 : resolution PR echouee par nom local -> nouvel essai par
  la branche distante portant exactement HEAD (upstream explicite puis
  scan de tips origin/*, main exclu) ; couvre checkout pr-123 et
  renommage local
- predicat 2 : branche sans PR rattachable dont HEAD est ancetre de
  origin/main -> REMOVE motive content_on_main ; les gardes amont
  garantissent deja 0 commit non pousse et source propre
- champ additif WorktreeStatus.content_on_main + motif dans render_text
- 11 tests nouveaux dont les 2 controles negatifs exiges (PR OPEN via
  tete distante ; edition .py primant sur content_on_main) et le garde
  HEAD-detache inegligible

See #17771
See #14195

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@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).

@github-actions github-actions Bot added the variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1 label Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

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

Path-collision (organ #13359/#13615)

Cette PR #17809 (fix(ci,#17771): desserrer no_pr_match — résolution par tête distante + content_on_main) 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.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@jsboige

jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

Diagnostic du rouge Scripts Tests (hérité de main, hors périmètre de cette PR). test_no_lake_ever_lost_the_gate (scripts/lean/tests/test_check_axiom_gate_coverage.py, #17097 critère 3) échoue : « a deleted dispatcher called lean-serre.yml and its lake is now served only by the matrix » (gated_paths Serre100/serre100_lean, deleted_by 52b248a3e0 = merge #17370, 2026-09-25 10:02Z). Vérifié firsthand : le test rougit sur un arbre identique à origin/main — le diff de cette PR (2 fichiers : scripts/ci/prune_merged_worktrees.py + ses tests) ne touche aucun workflow Lean. Le rouge sera levé par le re-wire/la justification côté propriétaire #17336, puis rerun des checks ici (DWELL de cette PR : 14:05Z). DM HIGH + dashboard WARN envoyés à ai-01.

@jsboige

jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2024:CoursIA-2
pr: 17809
head: ed06b87
complete: true
body: read
comments-reviewed: 4
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: a3b05d49a9ed75adbe552db36b406e0895f5bdab0fe28c979243951917f2f2f8
diff-files: 2
diff-additions: 302
diff-deletions: 5
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

2 fichiers (scripts/ci/prune_merged_worktrees.py + son test), +302/-5 : perimetre conforme au titre (desserrage de no_pr_match par tete distante + content_on_main). PR gate latest-wins success @15:04:22Z. Le commentaire non evalue est le diagnostic base-inherited du Scripts Tests, non une reserve.

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

Labels

variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants