Saltar para o conteúdo

Conversas de PR

Uma pull request já é o sítio onde acontece a conversa sobre código. As conversas de PR transformam-na numa superfície de um espaço de trabalho do Control Center, tal como uma ponte de chat transforma o Slack numa: mencione com @ o bot da GitHub App do servidor numa PR, responda dentro das respetivas threads de revisão ou adicione a etiqueta ai-review, e o trabalho acontece no espaço de revisão da PR — sujeito à mesma atribuição e às mesmas barreiras que qualquer coisa escrita na aplicação. Um comentário está também condicionado pela pertença; a etiqueta não, porque não tem autor. As respostas do bot voltam para o GitHub, no canal onde a pergunta foi feita.

Três decisões moldam a funcionalidade, e cada uma é a mesma decisão que a ponte de chat tomou para o chat, reformulada para uma forge: em que direção corre a ligação, o que autoriza um comentário que chega do exterior e a quem é atribuído cada lado.

O único canal de push que o GitHub oferece a uma aplicação é um webhook, e um webhook precisa de um URL de entrada — exatamente a única coisa de que esta superfície nunca precisa. Por isso, a descoberta é uma varredura: a cada minuto, mais ou menos, uma pesquisa com alias por instalação da aplicação pede ao GitHub as PRs que mencionam o bot (ou o respetivo slug curto) e as PRs abertas que têm a etiqueta de revisão, as PRs que já têm um espaço de revisão têm as suas threads de comentários lidas, e tudo é comparado por id de comentário com o que foi visto na varredura anterior.

Vale a pena nomear as consequências de conceção:

  • A latência é um intervalo de varredura, não um evento. O reconhecimento 👀 chega dentro de cerca de um minuto. Nada de urgente depende disso.
  • Exatamente uma vez, por comentário. Os ids de comentário são únicos em todo o GitHub; cada um é registado no momento em que é classificado como elegível, antes de qualquer ação sobre ele. Uma falha pode perder o tratamento de um comentário, nunca acioná-lo duas vezes.
  • O tempo offline é recuperado, não reproduzido. O conjunto de comentários já vistos é persistido, pelo que um reinício entrega o que chegou enquanto o servidor estava em baixo. A única exceção é a primeira varredura de sempre: sem memória com que comparar, tudo o que está pendente é registado em silêncio — um operador que etiquetou vinte PRs antes de este servidor existir não pode voltar e encontrar vinte revisões a correr.
  • A etiqueta é um conjunto, não um evento. A pesquisa comunica a presença da etiqueta, pelo que uma PR etiquetada dispara uma vez, e uma só. Voltar a adicionar uma etiqueta depois de a remover é invisível para a varredura; uma menção é a via de repetição.

A pesquisa corre uma vez por conta de instalação, no cliente do próprio proprietário dessa conta, porque um token de instalação só vê os repos da sua própria instalação — uma única credencial a nível de servidor deixaria passar em silêncio todas as PRs sob as outras instalações da aplicação.

Um comentário numa PR chega com pouco mais do que o login do autor — uma identidade externa não autenticada até prova em contrário. O bot resolve-a com base num índice inverso dos membros do espaço de trabalho e das respetivas contas GitHub ligadas, reconstruído de acordo com um TTL porque há pessoas que iniciam sessão e são convidadas enquanto o servidor corre.

Falhar de forma fechada assemelha-se a uma escada, e cada degrau responde na thread em que recusou:

  • Um login desconhecido — não ligado, ou ligado por alguém que não é membro deste espaço de trabalho — é instruído a iniciar sessão e a confirmar que pertence ao espaço
  • Um membro só de leitura (viewer ou guest) é informado de que o seu papel não pode iniciar trabalho

Os dois casos de login desconhecido partilham uma única resposta: o índice inverso só devolve um membro deste espaço de trabalho, pelo que uma conta não ligada e um não membro ligado são a mesma falha. Nenhum deles avança. Um comentário nunca é atribuído a alguém que não o enviou, e as palavras de um estranho nunca entram num espaço de trabalho que não conseguem ver.

A etiqueta ai-review não tem autor para resolver, pelo que não sobe esta escada. Adicioná-la inicia a revisão no espaço de trabalho que já tem o repositório ligado.

Cada lado da conversa transporta uma identidade diferente, e essa diferença é a funcionalidade:

  • No GitHub, o bot é o servidor. Todos os comentários, reações e respostas que a ponte publica usam o token de instalação da aplicação. Ninguém clicou em nada num cliente, pelo que nada pede emprestada a conta de uma pessoa — a mesma regra que mantém os webhooks e a sondagem fora das credenciais humanas.
  • No espaço, a pergunta é sua. A mensagem é atribuída ao membro em que o autor foi resolvido, e a execução do agente corre em nome dele: os commits indicam-no como coautor, e o seletor de autonomia e as barreiras de ação do espaço aplicam-se exatamente como a uma mensagem escrita na aplicação. As escritas na forge feitas pela execução continuam a sair como a aplicação — a mesma regra do ponto anterior —, e não com o token pessoal do membro.

Publicar os resultados da revisão de volta no GitHub continua a ser uma decisão de uma pessoa, tomada no Control Center. Uma menção pode iniciar uma revisão; só um ser humano publica uma.

Tudo o que é da autoria de uma conta de bot é descartado antes de qualquer barreira ser avaliada — a nossa especificamente, e todos os sufixos [bot], para que o bot de revisão de outra aplicação também não possa acordar o nosso. Sem isto, as respostas do próprio bot chegariam como novos comentários e voltariam a acioná-lo para sempre.

O sufixo [bot] é também a razão pela qual a forma curta existe. O GitHub fixa o login de uma conta de aplicação em <slug>[bot], não oferece preenchimento automático para ele e nunca resolve @slug para a aplicação — por isso, aceitar o slug isolado é uma decisão do nosso comparador, e descobri-lo exige uma via de pesquisa de texto de comentário em bruto, em vez do índice de menções do GitHub. O custo é declarado em vez de atenuado: um utilizador humano que partilhe o slug da aplicação endereça o bot em todas as menções curtas a si próprio. Nomes de aplicação distintos tornam a colisão hipotética.

  • Sem publicação automática. Os resultados ficam no espaço de revisão; publicar no GitHub é uma ação separada e humana
  • Sem identidade difusa. O autor é resolvido para exatamente um membro ou é recusado — não existe atribuição por tentativa
  • Sem webhook da GitHub App. Esta superfície nunca regista nenhum, pelo que não há um URL de entrada para expor a comentários de PR. Os outros webhooks do produto (pipelines, sincronização de tickets) são uma configuração separada e opcional.