Aller au contenu

Conversations de PR

Une demande de tirage est déjà l’endroit où se déroule la conversation sur le code. Les conversations de PR en font une surface d’un espace de travail Control Center, de la même manière qu’une passerelle de clavardage fait de Slack une surface : @mentionnez le robot de la GitHub App du serveur dans une PR, répondez dans ses fils de révision ou ajoutez l’étiquette ai-review, et le travail se fait dans l’espace de révision de la PR — sous la même attribution et les mêmes garde-fous que tout ce qui est saisi dans l’application. Un commentaire est lui aussi assujetti à l’appartenance; l’étiquette ne l’est pas, car elle n’a pas d’auteur. Les réponses du robot reviennent sur GitHub, dans la voie où la question a été posée.

Trois décisions façonnent la fonctionnalité, et chacune est la même décision que la passerelle de clavardage a prise pour le clavardage, reformulée pour une forge : dans quel sens la connexion s’établit, ce qui autorise un commentaire qui arrive de l’extérieur et à qui chaque partie est attribuée.

Le seul canal de poussée que GitHub offre à une application est le webhook, et un webhook exige une URL entrante — précisément ce que cette surface ne requiert jamais, délibérément. La découverte se fait donc par balayage : environ une fois par minute, une recherche avec alias par installation de l’application demande à GitHub les PR qui mentionnent le robot (ou son slug court) ainsi que les PR ouvertes qui portent l’étiquette de révision, les PR qui ont déjà un espace de révision voient leurs fils de commentaires lus, et le tout est comparé par identifiant de commentaire avec ce qui a été vu au balayage précédent.

Les conséquences de ce choix méritent d’être nommées :

  • La latence correspond à un intervalle de balayage, pas à un événement. L’accusé de réception 👀 arrive en une minute environ. Rien d’urgent n’en dépend.
  • Une seule fois, par commentaire. Les identifiants de commentaire sont uniques dans tout GitHub; chacun est consigné dès qu’il est classé comme admissible, avant que quoi que ce soit agisse sur lui. Un plantage peut faire perdre le traitement d’un commentaire, jamais le déclencher deux fois.
  • Le temps hors ligne est rattrapé, pas rejoué. L’ensemble des commentaires vus est conservé, de sorte qu’un redémarrage livre ce qui est arrivé pendant l’arrêt. La seule exception est le tout premier balayage : faute de mémoire pour comparer, tout ce qui est en attente est consigné en silence — un opérateur qui a étiqueté vingt PR avant l’existence de ce serveur ne doit pas retrouver vingt révisions en cours.
  • L’étiquette est un ensemble, pas un événement. La recherche signale la présence de l’étiquette, donc une PR étiquetée déclenche une seule fois, pour de bon. Réajouter une étiquette après l’avoir retirée est invisible pour le balayage; une mention est la voie de réexécution.

La recherche s’exécute une fois par compte d’installation, sur le client de ce propriétaire, car un jeton d’installation ne voit que les dépôts de sa propre installation — un identifiant unique à l’échelle du serveur manquerait silencieusement toutes les PR relevant des autres installations de l’application.

C’est l’appartenance qui autorise, pas le commentaire

Section intitulée “C’est l’appartenance qui autorise, pas le commentaire”

Un commentaire de PR arrive avec guère plus que l’identifiant de connexion de son auteur — une identité externe non authentifiée jusqu’à preuve du contraire. Le robot le résout au moyen d’un index inversé des membres de l’espace de travail et de leurs comptes GitHub connectés, reconstruit selon un TTL parce que des gens se connectent et sont invités pendant que le serveur fonctionne.

Un échec en mode fermé ressemble à une échelle, et chaque barreau répond dans le fil où il a refusé :

  • Un identifiant de connexion inconnu — non lié, ou lié par une personne qui n’est pas membre de cet espace de travail — reçoit le conseil de se connecter et de vérifier son appartenance
  • Un membre en lecture seule (viewer ou guest) est informé que son rôle ne peut pas lancer de travail

Les deux cas d’identifiant inconnu partagent une même réponse : l’index inversé ne renvoie qu’un membre de cet espace de travail, donc un compte non lié et un non-membre lié constituent le même échec de résolution. Aucun d’eux ne poursuit. Un commentaire n’est jamais attribué à quelqu’un qui ne l’a pas envoyé, et les propos d’un inconnu n’entrent jamais dans un espace de travail qu’il ne peut pas voir.

L’étiquette ai-review n’a aucun auteur à résoudre, elle ne gravit donc pas cette échelle. L’ajouter lance la révision dans l’espace de travail qui lie déjà le dépôt.

Chaque partie de la conversation porte une identité différente, et cette différence est la fonctionnalité même :

  • Sur GitHub, le robot est le serveur. Chaque commentaire, réaction et réponse publié par la passerelle utilise le jeton d’installation de l’application. Personne n’a cliqué quoi que ce soit dans un client, donc rien n’emprunte le compte d’une personne — la même règle qui tient les webhooks et l’interrogation périodique à l’écart des identifiants humains.
  • Dans l’espace, la question est la vôtre. Le message est attribué au membre obtenu par résolution de l’auteur, et l’exécution de l’agent se fait en son nom : les commits le désignent comme coauteur, et le cadran d’autonomie de l’espace ainsi que les garde-fous d’action s’appliquent exactement comme à un message saisi dans l’application. Les écritures vers la forge provenant de l’exécution se font toujours au nom de l’application — la même règle qu’au point précédent — et non avec le jeton personnel du membre.

Publier les constatations de révision vers GitHub demeure une décision humaine, prise dans Control Center. Une mention peut lancer une révision; seul un humain en publie une.

Tout ce qui est produit par un compte de robot est écarté avant l’exécution de quelque filtre que ce soit — le nôtre en particulier, et tout suffixe [bot], pour qu’un robot de révision appartenant à une autre application ne puisse pas non plus réveiller le nôtre. Sans cela, les propres réponses du robot arriveraient comme de nouveaux commentaires et le redéclencheraient sans fin.

Le suffixe [bot] explique aussi l’existence de la forme courte. GitHub fixe l’identifiant de connexion d’un compte d’application à <slug>[bot], n’offre aucune saisie semi-automatique pour celui-ci et ne résout jamais @slug vers l’application — accepter le slug seul relève donc d’une décision de notre mécanisme de correspondance, et le découvrir exige une voie de recherche brute dans le texte des commentaires plutôt que l’index des mentions de GitHub. Le coût est énoncé plutôt que lissé : un utilisateur humain qui partage le slug de l’application interpelle le robot à chacune de ses propres mentions en forme courte. Des noms d’application distinctifs rendent cette collision hypothétique.

  • Aucune publication automatique. Les constatations arrivent dans l’espace de révision; publier vers GitHub est une action humaine distincte
  • Aucune identité approximative. L’auteur est résolu vers exactement un membre ou bien est refusé — il n’y a pas d’attribution à l’estime
  • Aucun webhook de GitHub App. Cette surface n’en enregistre jamais, donc il n’y a aucune URL entrante à exposer pour les commentaires de PR. Les autres webhooks du produit (pipelines, synchronisation des tickets) relèvent d’une configuration distincte et facultative.