Steven
Steven6 min de leitura

Porque É Que o Seu Notetaker com IA Para de Gravar a Meio da Reunião

A nossa própria app terminou duas das nossas reuniões com a outra parte a meio de uma frase. O rasto forense levou a um temporizador de inatividade bem-intencionado que só o ouvia a si — e a um segundo bug que podia bloquear todo o desktop. Ambos corrigidos no GeekBye v2.0.9.

Fiabilidade
Reuniões
Engenharia
Lançamentos GeekBye
Porque É Que o Seu Notetaker com IA Para de Gravar a Meio da Reunião

A 2 de julho, o GeekBye terminou por conta própria a gravação de uma reunião. A linha na base de dados diz tudo: ended_reason = 'idle', duração de 519 segundos, 99 entradas de transcript — a última escrita dois segundos antes de a app decidir que não estava lá ninguém.

O outro participante estava a meio de uma explicação. A última linha do transcript é literalmente um fragmento de frase: "...executes it or turns it on or so—".

Não era a primeira vez. Na noite anterior, outra sessão tinha terminado da mesma forma. Duas reuniões, mortas pela nossa própria funcionalidade de fiabilidade. Aqui fica o diagnóstico e a correção que saiu no GeekBye v2.0.9 — mais um segundo bug, mais assustador, que corrigimos no mesmo lançamento.

Um temporizador bem-intencionado que só o ouvia a si

O fecho automático por inatividade existe por uma boa razão. As pessoas esquecem-se de gravações a correr durante a noite; um separador de reunião deixado aberto continua a pingar áudio para sempre. Por isso o GeekBye vigia a inatividade: após 60 segundos sem atividade de voz mostra um pequeno aviso "Still recording?" ("Ainda a gravar?") e, 30 segundos depois, sem resposta, termina a sessão — a guardar tudo, com delicadeza.

A falha estava numa palavra: voz. O relógio de atividade contava apenas energia sustentada do microfone. Foi uma decisão de design deliberada, e não uma decisão tola — contar a energia bruta do áudio do sistema permitiria que um separador silenciado mas barulhento mantivesse viva uma sessão morta indefinidamente, que é exatamente a falha que a funcionalidade existe para prevenir. As reuniões em que sobretudo ouve deviam estar cobertas pela deteção de janelas de reunião.

Só que a deteção de reuniões não consegue ver todas as reuniões. Separadores do browser, clientes invulgares, uma apresentação que está a ver — não detetados. E numa reunião não detetada em que ouve durante 90 segundos — uma coisa completamente normal enquanto alguém explica o seu pipeline de Databricks — é, para o relógio de inatividade, indistinguível de uma sala vazia.

Veja a cronologia da sessão morta: o último transcript do nosso microfone chegou 68 segundos antes do fim. Depois, 60 segundos da outra pessoa a falar (transcritos na perfeição, ignorados pelo relógio), o aviso que passou despercebido, a contagem decrescente de 30 segundos e o corte — 2 segundos depois das últimas palavras dela.

A correção: um transcript é prova de vida

A correção é quase embaraçosa em retrospetiva: um transcript que chega é a evidência mais forte possível de que a sessão não está inativa. Não importa quem falou. O modelo de voz acabou de reconhecer palavras — isso é a reunião.

Assim, a v2.0.9 carimba o relógio de atividade com cada transcript que chega, de qualquer um dos lados. A energia bruta do áudio do sistema continua a não contar — música, tons de espera e o zumbido do ar condicionado continuam sem conseguir imortalizar uma sessão morta, e o limite máximo de gravação continua a servir de rede de segurança para tudo. Só a fala reconhecida mantém uma sessão viva, que é precisamente a fronteira certa.

Um detalhe da code review que vale a pena passar: a primeira versão da correção carimbava o relógio dentro do caminho de atribuição de orador — que um subconjunto de transcripts pode legitimamente saltar. A revisão apanhou que uma alteração futura podia reintroduzir o bug em silêncio precisamente para os transcripts que importam (os do outro orador). O carimbo é agora incondicional, antes de qualquer ramificação, com um teste que falha se alguém o mover.

O mesmo lançamento corrigiu algo mais assustador

Enquanto testávamos estas correções, batemos noutro bug da pior maneira: um crash no processo da interface deixou todo o desktop sem responder a cliques.

O overlay do GeekBye é uma janela transparente, sempre em primeiro plano, que cobre o ecrã. Por omissão deixa passar os cliques; a interface torna-a interativa quando está a usar um painel. Essas comutações vêm do processo da interface — por isso, quando esse processo crashou com um painel aberto, a janela invisível ficou em modo interativo sem qualquer UI viva por trás. Cada clique no desktop aterrava num painel morto e invisível. A única saída era forçar o encerramento da app.

O gestor de crashes da v2.0.9 restaura agora imediatamente a passagem de cliques e recarrega a interface — com um limite de três recargas por minuto para que um loop de crashes não possa girar para sempre (ultrapassado o limite, a app desiste de recarregar, mas o desktop continua utilizável, que é a parte que importa). A code review também apurou esta correção: a recuperação está circunscrita especificamente à janela do overlay, porque aplicar a passagem de cliques indiscriminadamente a uma janela normal em crash — digamos, o diálogo de atualização — teria criado o bloqueio oposto.

Pode verificar esta correção por si mesmo, de forma brutal: abra um painel do GeekBye, force o fecho do processo "GeekBye Helper (Renderer)" no Monitor de Atividade e veja a app recuperar o seu desktop em menos de um segundo.

O que este par de bugs nos ensinou

  1. Todo o proxy para "o utilizador está aqui?" falha nalgum lado. A energia do microfone falha para quem ouve. A deteção de janelas falha para os browsers. Os transcripts reconhecidos falham para... nada que tenhamos encontrado até agora, porque não são um proxy — são o próprio produto.
  2. Tudo o que é conduzido pelo renderer precisa de uma história de crash. Se um processo de UI morto pode deixar para trás estado ao nível do sistema operativo (captura do rato, sempre em primeiro plano, proteção de conteúdo), o processo principal tem de ser o dono do reset.
  3. Ser o próprio utilizador mais intensivo é uma estratégia para encontrar bugs. Ambos os bugs nos atingiram em reuniões reais antes de mais do que uma mão-cheia de clientes reparar. A coluna ended_reason que tínhamos adicionado meses antes por observabilidade foi o que transformou o diagnóstico numa query à base de dados em vez de um palpite.

Ambas as correções foram do diagnóstico a um lançamento publicado e notarizado em menos de um dia, cada uma levada por um PR revisto com testes de regressão. Se está no GeekBye v2, tem-nas desde a v2.0.9 via atualização automática.

Para o resto da história deste lançamento, veja o vizinho da série porque a transcrição com IA ouve mal os termos técnicos (v2.0.11), as fundações de fiabilidade em porque é que o seu notetaker com IA para com Wi-Fi mau e como o overlay se mantém invisível durante a partilha de ecrã sem lhe roubar os cliques.