Ga naar inhoud

PR-gesprekken

Een pull request is al de plek waar het gesprek over code plaatsvindt. PR-gesprekken maken er een oppervlak van op een Control Center-werkruimte, net zoals een chatbrug van Slack er een maakt: @-vermeld de GitHub App-bot van de server in een PR, antwoord binnen zijn reviewthreads of voeg het label ai-review toe, en het werk gebeurt in de reviewruimte van de PR — onder dezelfde attributie en beveiligingen als alles wat in de app wordt getypt. Een opmerking is bovendien afhankelijk van lidmaatschap; het label niet, want het heeft geen auteur. De antwoorden van de bot komen terug op GitHub, op de plek waar de vraag is gesteld.

Drie beslissingen bepalen de functie, en elke beslissing is dezelfde die de chatbrug voor chat nam, opnieuw geformuleerd voor een codehost: welke richting de verbinding opgaat, wat een opmerking van buitenaf autoriseert en aan wie elke kant wordt toegeschreven.

Het enige pushkanaal dat GitHub voor een app biedt, is een webhook, en een webhook heeft een inkomende URL nodig — precies het enige dat dit oppervlak bewust nooit vereist. Het opsporen gebeurt dus in een pollronde: ongeveer elke minuut vraagt één per appinstallatie gealiaste zoekopdracht aan GitHub om PR’s die de bot (of zijn korte slug) vermelden, en om open PR’s die het reviewlabel dragen; van PR’s die al een reviewruimte hebben worden de opmerkingenthreads gelezen, en alles wordt op opmerking-id vergeleken met wat de vorige pollronde zag.

De ontwerpgevolgen zijn het benoemen waard:

  • Latentietijd is een pollinterval, geen gebeurtenis. De 👀-bevestiging komt binnen ongeveer een minuut. Er hangt niets dringends aan.
  • Precies één keer, per opmerking. Opmerking-id’s zijn uniek binnen heel GitHub; elk id wordt vastgelegd zodra de opmerking als in aanmerking komend is geclassificeerd, voordat er iets op wordt ondernomen. Een crash kan de verwerking van een opmerking kwijtraken, maar kan die nooit dubbel laten vuren.
  • Offline tijd wordt ingehaald, niet opnieuw afgespeeld. De seen-set wordt opgeslagen, dus een herstart levert wat binnenkwam terwijl de server uit stond. De enige uitzondering is de allereerste pollronde: zonder geheugen om mee te vergelijken wordt alles wat nog openstaat stil geregistreerd — een beheerder die twintig PR’s van een label voorzag voordat deze server bestond, mag niet terugkomen op twintig lopende reviews.
  • Het label is een verzameling, geen gebeurtenis. De zoekopdracht rapporteert de aanwezigheid van een label, dus een PR met label wordt één keer geactiveerd, ooit. Een label opnieuw toevoegen nadat je het hebt verwijderd, is onzichtbaar voor de pollronde; een vermelding is het pad om opnieuw te draaien.

De zoekopdracht draait één keer per installatieaccount met de eigen client van die eigenaar, omdat een installatietoken alleen de repo’s van zijn eigen installatie ziet — één credential voor de hele server zou stilletjes elke PR onder de andere installaties van de app missen.

Een PR-opmerking komt binnen met weinig meer dan de login van een auteur — een niet-geverifieerde externe identiteit tot het tegendeel blijkt. De bot herleidt die login via een omgekeerde index van de leden van de werkruimte en hun gekoppelde GitHub-accounts, die op een TTL opnieuw wordt opgebouwd omdat mensen zich aanmelden en uitgenodigd worden terwijl de server draait.

Fail-closed gedrag ziet eruit als een ladder, en elke trede antwoordt in de thread waarin hij weigerde:

  • Een onbekende login — niet gekoppeld, of gekoppeld door iemand die geen lid is van deze werkruimte — krijgt het verzoek om in te loggen en te controleren of diegene erbij hoort
  • Een lid met alleen-lezenrechten (viewer of guest) krijgt te horen dat hun rol geen werk kan starten

De twee gevallen van een onbekende login delen één antwoord: de omgekeerde index levert alleen een lid van deze werkruimte op, dus een niet-gekoppeld account en een gekoppeld account dat geen lid is, zijn dezelfde misser. Geen van hen gaat verder. Een opmerking wordt nooit toegeschreven aan iemand die hem niet heeft verstuurd, en de woorden van een vreemde komen nooit een werkruimte binnen die diegene niet kan zien.

Het label ai-review heeft geen auteur om te herleiden, dus het beklimt deze ladder niet. Door het toe te voegen start de review in de werkruimte die de repository al koppelt.

Elke kant van het gesprek draagt een andere identiteit, en dat verschil ís de functie:

  • Op GitHub is de bot de server. Elke opmerking, reactie en elk antwoord die de brug plaatst, rijdt mee op het installatietoken van de app. Niemand heeft ergens in een client op geklikt, dus niets leent het account van een persoon — dezelfde regel die webhooks en polling van menselijke credentials afhoudt.
  • In de ruimte is de vraag van jou. Het bericht wordt toegeschreven aan het lid waaraan de auteur is herleid, en de agentrun wordt namens hen uitgevoerd: commits vermelden hen als medeauteur, en de autonomieregelaar en actiebeveiligingen van de ruimte gelden precies zoals voor een bericht dat in de app is getypt. Schrijfacties naar de codehost vanuit de run gaan nog steeds uit als de app — dezelfde regel als in het punt hierboven — niet op het persoonlijke token van het lid.

Het publiceren van reviewbevindingen terug naar GitHub blijft een beslissing van een persoon, genomen in Control Center. Een vermelding kan een review starten; alleen een mens publiceert er een.

Alles wat door een botaccount is geschreven, wordt weggegooid voordat er welke poort dan ook draait — specifiek het onze, en elk achtervoegsel [bot], zodat de reviewbot van een andere app de onze ook niet kan wekken. Zonder dit zouden de antwoorden van de bot zelf als nieuwe opmerkingen binnenkomen en hem voor altijd opnieuw activeren.

Het achtervoegsel [bot] is ook de reden dat de korte vorm bestaat. GitHub legt de login van een appaccount vast op <slug>[bot], biedt daarvoor geen automatisch aanvullen en herleidt @slug nooit naar de app — dus het accepteren van de kale slug is een beslissing van onze matcher, en om die te vinden is een aparte zoekroute op de ruwe tekst van opmerkingen nodig in plaats van de vermeldingsindex van GitHub. De prijs wordt benoemd in plaats van verzwegen: een menselijke gebruiker die dezelfde slug heeft als de app, richt elke vermelding in korte vorm van zichzelf ook aan de bot. Onderscheidende appnamen maken die botsing hypothetisch.

  • Geen automatische publicatie. Bevindingen belanden in de reviewruimte; publiceren naar GitHub is een aparte, menselijke actie
  • Geen fuzzy identiteit. De auteur wordt aan precies één lid gekoppeld of wordt geweigerd — er is geen attributie op basis van een gok
  • Geen webhook voor de GitHub App. Dit oppervlak registreert er nooit een, dus er is geen inkomende URL om voor PR-opmerkingen bloot te stellen. Andere productwebhooks (pipelines, ticketsynchronisatie) zijn een aparte, optionele instelling.