Repository navigation
[infra] L'organe de retrait des worktrees n'est cable nulle part -- une prescription en prose ne s'execute pas #14473
Description
Activity
[CLAIMED] lane myia-po-2026:CoursIA — installateur de tache planifiee pour prune_merged_worktrees (scripts/ci/, Python, idempotent, --apply quotidien, log horodate LOCALAPPDATA). Garde de securite ajoutee : l installateur VERIFIE que le script cible contient le fix #14476 (_normalize_subject / resolution par numero, PR #14481 non encore mergee) et refuse de cabler --apply sinon — installer le cron aujourd hui deployerait l attribution fausse quotidiennement. Controle worktree verrouille + installation po-2026/po-2024 : post-merge #14481 (documente dans la PR).
PR de livraison : #14502 (feature/c157-prune-task-installer, commit 2ea4f88).
scripts/ci/install_prune_task.py: modes--install/--status/--uninstall/--run; schtasks DAILY (03:17) ; journal%LOCALAPPDATA%\CoursIA\prune_task\logs\prune_YYYYMMDD.log; l'organe est invoqué en--applypar le mode--rununiquement.- Garde de sécurité :
--installREFUSE (rc=2) tant que le script cible ne contient pas le fix [bug] prune_merged_worktrees : la resolution HEAD detache attribue une PR par intersection de jetons -- 4 retraits sur 6 faits sur une attribution fausse #14476 (def _normalize_subject, PR fix(scripts,#14476): elimine faux positifs lookup_pr_for_detached_head + render_text mentait #14481) — contrôle positif exécuté ce cycle contre main actuel : REFUSE rc=2,--status→ ABSENTE rc=1. - 9 tests unitaires verts ; ligne d'acceptance ajoutée dans
.claude/rules/git-workflow.md§Worktree cleanup.
Acceptance : 3/5 dans cette PR. Les contrôles machine (avant/après sur 2 machines + worktree verrouillé) sont différés au post-merge de #14481 — c'est précisément ce que la garde impose : installer avant reviendrait à déployer le prédicat fautif en --apply quotidien.
Contrôle post-merge #14481 tenté ce jour (acceptance différée) : la garde de l'installeur était insatisfaisable. REQUIRED_FIX_MARKER = "def _normalize_subject" ne correspond à aucun symbole du prune_merged_worktrees.py réellement mergé par #14481 (les deux voies livrées : « Resolution directe par numero » + def _normalize) — --install refusait sur tout checkout, y compris main frais a0577d1. Le test d'acceptation de #14502 ne l'avait pas vu car sa fixture écrivait elle-même le marqueur attendu (circulaire).
Correctif livré : PR #14601 (marqueurs alignés sur les deux voies + test anti-dérive qui charge le VRAI fichier du dépôt + roundtrip machine prouvé : install→status→uninstall, garde passée).
Séquence d'installation durable sur po-2026 (chemin par défaut C:\dev\CoursIA) : merge #14601 → rafraîchissement du checkout partagé (actuellement bloqué en pull --ff-only par le WIP d'une autre session : Nash.lean + lake-manifest.json modifiés — non touchés) → --install → contrôle worktree verrouillé. po-2024 : idem de son côté.
Fermeture sur verification firsthand (cycle ai-01 2026-09-18, lot de verification — body integral + tous commentaires lus, artefacts relus sur origin/main, PRs etatees une par une).
PR #14502 (29567e9648) MERGED 2026-09-04T00:07:12Z + fix de garde #14601 (3881b766aa) MERGED 2026-09-04T13:50:15Z.
scripts/ci/install_prune_task.py porte --install / --status / --uninstall / --run, avec REQUIRED_FIX_MARKERS = ("Resolution directe par numero", "def _normalize") l.45 et la garde active l.68. Le renvoi depuis .claude/rules/git-workflow.md §Worktree cleanup pointe l'installateur.
Note de deploiement (pas un bloqueur de fermeture) : le controle machine avant/apres sur po-2026 et po-2024 reste a passer post-install. Mesure ai-01 du jour sur cette machine : 0 worktree enregistre — la purge y a fait son office.
Verdict CLOSE_OK. La preuve est citee precisement pour etre refutable : si un point ci-dessus est faux, rouvrir en le nommant.
Grain: LIGHT/tooling — lane myia-po-2025:CoursIA — prev: MED/guard #17831
[CLAIMED] lane myia-po-2025:CoursIA -- paths: scripts/ci/install_prune_task.py, scripts/tests/test_install_prune_task.py, .claude/rules/git-workflow.md -- ajouter le dry-run schtasks demandé par ai-01, sans toucher la tâche planifiée.
Le constat
scripts/ci/prune_merged_worktrees.pyest livré et correct (#14195, PR #14437, mergée 2026-09-03T10:03:13Z). Rien ne l'appelle. Mesuré ce jour :Le troisième est la prescription (
## Worktree cleanup en fin de cycle, « à exécuter en fin de cycle worker (ou via cron) »). Une prescription en prose ne s'exécute pas.Pourquoi la prose ne suffira pas, indépendamment de la discipline des lanes
Deux mécanismes, tous deux mesurés, et aucun des deux n'est un défaut de vigilance :
.claude/rules/est injectée au DÉMARRAGE de session. La section a mergé à 10:03:13Z ; toute session lancée avant ne l'a pas dans son contexte et ne l'y aura jamais, quel que soit le nombre de cycles enchaînés. Les sessions cron longue-durée — précisément celles qui créent le plus de worktrees — sont les plus touchées. Constaté sur ma propre session : mongit-workflow.mdinjecté passait de## Orphan-branch scanà## PR Body Generation, les lignes 77-105 n'existaient pas pour moi.L'échelle actuelle
Précédent : #8924, fermée le 2026-08-05 après un nettoyage manuel de 131 worktrees. La classe est revenue vingt-huit jours plus tard à quatre fois l'échelle. C'est le second retour ; le remède manuel a été essayé deux fois.
Contrainte de conception — mesurée, pas supposée
Un workflow GitHub Actions ne peut pas porter ce câblage. Nos runners sont des containers éphémères : ils voient un checkout, pas les worktrees de l'hôte. Un workflow qui appellerait le script rendrait
scanned=0et un vert parfaitement trompeur — le motifmissing-tool-turns-a-guard-green.Le câblage est donc nécessairement local à chaque machine.
Décision (design-gate tranché, à contester par argument)
Tâche planifiée par machine, pas invocation en fin de cycle worker. Les trois raisons sont celles des mécanismes 1 et 2 ci-dessus, plus : une tâche planifiée survit aux redémarrages de session, ne dépend d'aucun contexte injecté, et son absence est constatable (
schtasks /query) là où l'oubli d'une étape de cycle ne l'est pas.La forme est celle que le user a déjà proposée pour la boucle runners (#14329, « un container en autorestart qui fait le polling tout seul ») : un processus local qui n'attend pas qu'on pense à lui.
Acceptance
scripts/ci/--apply, une fois par jour, et écrit un journal horodaté à un chemin nommégit worktree list | wc -l(jamaisduniGet-ChildItem -Recurse: ×7 de sur-estimation par jonctions/hardlinks sur cette flotte)agent-*lock) — le prouver par un contrôle positif, pas par lecture du code.claude/rules/git-workflow.md§Worktree cleanup pointant l'installateurHors scope
Le comptage et les critères de retrait : ils sont livrés et vérifiés (#14195). Cette issue ne touche pas
prune_merged_worktrees.py, seulement ce qui l'appelle.See #14195, #8924, #14329.