Ouvrir une PR
Ouvrez une pull request pour la branche courante sur la plateforme de PR détectée (Azure DevOps ou GitHub). Le titre et la description sont rédigés pour correspondre aux conventions des PR passées de l'utilisateur appelant plutôt qu'à un style d'équipe fixe, puis affichés pour confirmation. La PR n'est jamais créée sans approbation explicite — ouvrir une PR est une action tournée vers l'extérieur.
Cette compétence est indépendante du backend : les mécanismes propres à la plateforme (création de PR, vérification des doublons, étiquetage, lien de backport) se trouvent dans les documents de référence des adaptateurs backend sous resources/backends/, et les mécanismes de lien de ticket se trouvent dans les documents de référence des adaptateurs tracker sous resources/trackers/. Le corps de la compétence détecte la plateforme et le tracker, charge les adaptateurs correspondants et suit leurs recettes — il ne contient aucun analyse de champ spécifique à az/gh ni aucun analyse d'identifiant/URL spécifique au tracker. Il emprunte les barrières de sécurité d'un flux de création de PR mais est délibérément plus étroit : il ouvre une PR pour la branche telle quelle — en la publiant d'abord sur le distant si elle n'y est pas encore, car la PR en a besoin. Il ne fusionne pas la branche de base, ne supprime pas les branches et ne traite pas les commentaires de révision (c'est le rôle de resolve-pr-comments).
Étape 0 — Détecter la plateforme + le tracker, charger les adaptateurs, annoncer
Avant toute chose, déterminer le backend et le tracker ciblés par cette exécution :
- Plateforme de PR — depuis
git remote get-url origin:dev.azure.comou*.visualstudio.com→ Azure DevOps (resources/backends/azure-devops.md).github.com→ GitHub (resources/backends/github.md).- Ambigu ou autre hôte → indiquer la limitation et demander à l'utilisateur quelle plateforme cibler plutôt que de deviner.
- Tracker de tickets (priorité — le premier qui correspond l'emporte) :
- La configuration explicite l'emporte : si
.claude/pr-lifecycle.json(optionnel, dans.gitignore) fixe le type de tracker, l'utiliser (et prendre l'URL de base Jira à partir de celui-ci). - sinon inférer le type à partir d'une référence de ticket existante :
[A-Z][A-Z0-9]+-\d+→ Jira (sur les deux plateformes) ; une référence de ticket numérique simple → GitHub Issues — mais seulement sur un distant GitHub (sur Azure DevOps#<n>est un lien d'élément de travail, pas un ticket GitHub, donc un nombre seul n'implique pas GitHub Issues là-bas). - sinon par défaut selon la plateforme : un distant GitHub → GitHub Issues (zéro configuration) ; un distant Azure DevOps → Jira.
- Aucun ticket du tout → ne pas produire de ligne de tracker (comme actuellement).
- Jira →
resources/trackers/jira.md; GitHub Issues →resources/trackers/github-issues.md.
- La configuration explicite l'emporte : si
- Annoncer la plateforme et le tracker détectés afin qu'une supposition erronée silencieuse soit impossible.
Charger les adaptateurs backend et tracker correspondants et exécuter les parties spécifiques à la plateforme/tracker des étapes ci-dessous via ceux-ci. La seule couture backend dans ce corps est la reconnaissance de la chaîne distante pour sélectionner l'adaptateur — aucun accès aux champs au-delà. (Les chemins des adaptateurs sont relatifs à la racine du plugin — plugins/pr-lifecycle/resources/backends/ et resources/trackers/ — pas au répertoire de la compétence.)
Étape 1 — Déterminer la branche cible
- Lire la branche par défaut du dépôt lui-même ; ne jamais supposer.
git symbolic-ref --short refs/remotes/origin/HEADdonneorigin/<branche>— supprimer le préfixe. Cette référence est écrite pargit clone, donc un distant construit pargit init+git fetchpeut en être dépourvu ; demander alors directement au distant avecgit ls-remote --symref origin HEAD, qui est en lecture seule et ne modifie aucun état local. - Ce n'est que lorsque ni l'un ni l'autre ne fonctionne que l'on recourt à celle de
main/masterque le distant possède réellement — et si les deux existent, demander. Un dépôt en cours de renommage conserve l'ancienne branche comme branche obsolète, donc choisir silencieusement baserait la PR sur la mauvaise cible, ce qui invalide également le compte d'avance de l'étape 2 et l'historique dont l'étape 3 apprend la convention de l'utilisateur. - Si la branche courante cible une ligne de version (par exemple
release/2.5), la traiter comme un backport (voir le format de backport ci-dessous). - Si la cible correcte est véritablement ambiguë, demander plutôt que de deviner.
Étape 2 — Préconditions (s'arrêter et signaler si l'une échoue)
Exécuter ces vérifications avant de rédiger quoi que ce soit, car chacune est un blocage courant en première exécution :
- A des commits à PR. La branche doit être en avance sur la cible :
git fetch, puisgit rev-list --count origin/<cible>..HEADdoit être supérieur à 0. - Sur le distant — publier si nécessaire. La création de la PR nécessite que la branche source soit sur le distant. Une branche non encore poussée n'est pas un arrêt : après confirmation, ouvrir-pr la publie (
git push -u origin <branche>) dans le cadre de la création à l'étape 4. (En mode non interactif, elle ne pousse pas et ne crée pas — voir l'étape 4.) - Pas de doublon. Vérifier l'existence d'une PR ouverte existante pour cette source vers cette cible via la recette de vérification des doublons de l'adaptateur backend. S'il en existe une, s'arrêter et rediriger l'utilisateur vers celle-ci — ne pas ouvrir une seconde PR, et ne pas modifier celle existante ici.
Étape 3 — Apprendre la convention de l'utilisateur, puis rédiger
Identifier l'utilisateur à partir de git config user.email (préféré) et user.name, puis lire ses PR récentes fusionnées dans ce dépôt : git log <cible> --author="<email ou nom>" (essayer les deux formes ; traiter comme "aucun historique" uniquement lorsque les deux ne retournent rien). À partir des dernières, inférer la casse du titre et la mise en page de la description (sectionnée ou liste à puces plate) par majorité — la plus récente par date de commit départage les égalités, une seule PR antérieure est utilisée directement. Annoncer le résultat (appris de K de vos PR passées ou aucun historique correspondant -> utilisation des valeurs par défaut), afin qu'une supposition erronée silencieuse soit impossible.
L'apprentissage couvre comment ce dépôt et cet utilisateur rédigent les choses, pas seulement la typographie : la casse du titre, la mise en page de la description (sectionnée ou liste à puces plate), et la forme du préfixe de ticket dans le titre — entre crochets ([acme-123] …), nu (acme-123 …), un type Conventional Commits (fix(scope): …), ou pas de préfixe du tout. Lire la forme à partir du même historique ; si les PR observées ne portent pas de préfixe de ticket, ne pas en ajouter un. Les valeurs par défaut ci-dessous sont ce qu'il faut utiliser lorsqu'il n'y a pas d'historique à partir duquel apprendre, jamais un format à imposer à un dépôt qui fait visiblement autre chose.
L'apprentissage ne doit jamais supprimer ou réorganiser le contenu obligatoire ci-dessous — le lien du ticket, le résumé et les puces ; le diagramme du point 4 est optionnel, et le pied de page de provenance du point 5 est désactivé par défaut, mais lorsque le pied de page de provenance est activé, l'apprentissage doit le garder en dernier et ne jamais le supprimer. Ne pas biaiser l'apprentissage vers ce dépôt s'il est mono-auteur — la convention qui compte est celle de l'utilisateur, dans le dépôt où la compétence s'exécute.
Format par défaut (le repli ; la convention apprise de l'utilisateur remplace la présentation)
Titre : dériver l'identifiant du ticket et sa casse à partir de l'adaptateur tracker :
- Tracker Jira :
[acme-xxxxx] <résumé concis d'une ligne>— la clé en minuscules entre crochets (l'adaptateur fournit également la forme majuscule pour l'URL). - Tracker GitHub Issues :
#<n> <résumé concis d'une ligne>— la référence#<n>à la place de la forme entre crochets. - Aucun ticket trouvé : omettre la ligne de ticket, et titrer comme ce dépôt titre les PR sans ticket.
ad-hoc <résumé>est le repli uniquement lorsque l'historique de l'étape 3 ne vous a rien donné à copier — c'est un marqueur d'une équipe, pas une convention à introduire dans un dépôt qui ne l'a jamais utilisée. Un<résumé>simple est le défaut plus sûr. - Deux identifiants de ticket différents ou plus signifient demander lequel, plutôt que de prendre silencieusement le premier.
Description (PR standard) :
- Lien du ticket — construit par l'adaptateur tracker : pour Jira,
https://<jira_base_url>/browse/<KEY>(clé majuscule) ; pour GitHub Issues,#<n>(GitHub crée automatiquement un lien vers un ticket du même dépôt). C'est la première ligne pour que la plateforme crée le lien automatiquement ; omettre toute la ligne uniquement lorsqu'il n'y a pas de ticket. - Résumé — une ou deux phrases.
- Description — une liste à puces, une puce par changement discret sous forme d'action plus bref pourquoi/impact. Omettre les identifiants de fichier / classe / méthode / chemin — décrire l'intention, ne pas coller le diff.
- Un court diagramme ASCII, encadré par un bloc de code (optionnel) — en inclure un uniquement lorsqu'une image permet au relecteur de comprendre le changement plus vite qu'avec du texte ; sinon, l'omettre. Lorsque vous le faites : un véritable diagramme de structure monospace (boîtes / flèches, ou un petit arbre / tableau — jamais du texte déguisé en diagramme), resté de haut niveau, encadré par des triples backticks, dessiné avec des glyphes ASCII simples (
+ - | > v), pas Mermaid ; diviser tout diagramme large ou complexe en diagrammes plus petits plutôt que de forcer un bloc illisible. Instructions complètes pour le dessin, la raison de l'encadrement/encodage et une forme d'illustration :resources/diagram-guidance.md. - Marqueurs de provenance IA (optionnel — désactivé par défaut) — le pied de page (un séparateur
---, puis🤖 _Drafted with Claude Code._) et l'étiquetteai-assistedappliquée à l'étape 4 sont ajoutés uniquement lorsque la demande invoquante demande explicitement à marquer / étiqueter / signaler la PR comme assistée par IA (ou transmet une activation explicite). En l'absence de cette formulation — y compris pour chaque appel automatisé du pipelineresolve-issue, qui ne porte pas une telle formulation — n'ajouter ni l'un ni l'autre. Annoncer la décision sur la même ligne que le résultat de plateforme/tracker/apprentissage (provenance : désactivé (dire "marquer comme assisté par IA" pour ajouter), ouprovenance : activé (pied de page + étiquette au mieux)) afin qu'un marqueur silencieusement supprimé soit impossible. Lorsqu'activé, le pied de page est le dernier élément sur chaque chemin — l'ajouter après le corps de la convention apprise et ne jamais laisser l'apprentissage le supprimer ou le réorganiser — et il s'affiche à l'identique sur Azure DevOps et GitHub, le marqueur portable ; l'étiquette est le badge natif de la plateforme à côté de celui-ci (au mieux — voir l'étape 4). Si une équipe a un jour besoin d'une divulgation obligatoire de l'IA à des fins d'audit, la réintroduire alors comme indicateur de configuration — délibérément pas construit maintenant.
Backport (cible release/*) :
- Titre (tracker Jira) :
[acme-xxxxx] [release] <résumé>; (tracker GitHub Issues) :#<n> [release] <résumé>. - La description est le lien du ticket, puis
cherry pick from <lien-PR>où l'adaptateur backend fournit la syntaxe du lien de PR (Azure DevOps!<numéro_pr>, GitHub#<numéro_pr>— les deux s'affichent comme un lien vers cette PR), puis — uniquement lorsque la provenance est activée (étape 3, point 5) — le pied de page de provenance IA (---+🤖 _Drafted with Claude Code._). Pas de bloc de résumé, de puces ou de diagramme — la véritable révision a eu lieu sur la PR d'origine. - Demander à l'utilisateur (ou accepter en entrée) le numéro de la PR source à partir de laquelle la cerise a été extraite, et réutiliser le résumé d'une ligne de cette PR pour
<résumé>. Un backport n'apprend que la casse du titre, pas la mise en page de la description.
Sur chaque chemin (y compris le backport) : le titre et la description sont en français. Ne pas ajouter de mention Co-Authored-By de votre propre chef — c'est une préoccupation de commit, pas de description de PR, et savoir si ce dépôt en veut une est la décision du dépôt, observable depuis son propre historique (git log -n 50 --format=%b | grep -c '^Co-Authored-By') plutôt que quelque chose que cette compétence décide. Par défaut, ne pas l'ajouter ; si les commits du dépôt en portent régulièrement, suivre cela plutôt que de le remplacer. Le pied de page de provenance IA et l'étiquette ai-assisted sont une chose différente et sont désactivés par défaut — ajoutés uniquement sur l'activation explicite décrite à l'étape 3 (pied de page) et appliquée à l'étape 4 (étiquette) — et ne sont jamais la mention interdite.
Étape 4 — Présenter, confirmer, créer
Afficher le titre et la description rédigés et permettre à l'utilisateur de les modifier. Ensuite :
- Autonome : créer uniquement après que l'utilisateur a explicitement confirmé. Si la branche source n'est pas encore sur le distant, la publier d'abord (
git push -u origin <branche>), puis créer la PR via la recette de création de l'adaptateur backend — en écrivant la description complète dans un fichier temporaire et en le passant comme indicateur de corps de fichier de l'adaptateur, jamais comme chaîne en ligne. L'adaptateur documente les pièges d'encodage de fichiers de la plateforme (par exemple les bizarreriesaz.cmdcp1252/UTF-8@<fichier>d'Azure DevOps) et — uniquement lorsque la provenance est activée (étape 3) — comment l'étiquetteai-assistedest appliquée (Azure DevOps crée le tag en ligne via--labels; GitHub l'ajoute après la création avecgh pr edit --add-label, cargh pr create --labelabandonne si l'étiquette n'existe pas). Lorsqu'activée, l'étiquette est au mieux dans les deux cas (voir Limites exprimées) ; par défaut, aucune étiquette n'est appliquée. Retourner l'URL de la PR. - Impossible d'obtenir une confirmation (exécution en mode non interactif, ou dans un sous-agent qui ne peut pas demander) : ne pas pousser la branche et ne pas créer la PR. Afficher le titre et la description préparés pour que l'utilisateur les crée manuellement, et le dire. Ne pas utiliser d'indicateur d'ouverture dans le navigateur (par exemple Azure DevOps
--open) dans un contexte non interactif. Lorsque la provenance a été activée, la description imprimée porte déjà le pied de page ; dire à l'utilisateur d'ajouter l'étiquetteai-assistedlorsqu'il crée la PR. Par défaut (aucune activation), aucun marqueur n'est imprimé ni mentionné.
L'invariant : ne jamais publier la branche ni ouvrir une PR sans une confirmation humaine explicite — les deux sont des actions tournées vers l'extérieur.
Barrières de sécurité
- Ne jamais résoudre automatiquement les conflits de fusion — s'arrêter et les signaler.
- Ne jamais supprimer de branches.
- Ne jamais forcer le push sans demande explicite.
Limites exprimées
- Si l'outil de PR de la plateforme détectée est manquant ou non authentifié (voir la précondition de chaque adaptateur backend — par exemple
az+ l'extensionazure-devopspour Azure DevOps,ghauthentifié pour GitHub), le dire et afficher le titre et la description préparés pour une création manuelle — ne pas échouer silencieusement. - La convention apprise est au mieux : si un workflow de squash n'a laissé aucun corps de description, la casse provient toujours du sujet du commit et la mise en page revient à la valeur par défaut — annoncé, pas silencieux.
- Les marqueurs de provenance sont désactivés par défaut — pas de pied de page et pas d'étiquette à moins que la demande invoquante n'active explicitement (étape 3, point 5). Lorsqu'activée, l'étiquette
ai-assistedest au mieux : si la plateforme la rejette (une organisation qui interdit les tags de PR ad-hoc sur Azure DevOps, ou une étiquette qui n'existe pas encore sur GitHub), supprimer l'étiquette, créer la PR avec le seul pied de page (le marqueur activé), et le dire — l'adaptateur backend documente le comportement par plateforme.