Trabalho · App construída com agentes · 2026
Seis erros que as verificações estáticas não viam
Uma app de transporte com dois lados, escrita com agentes de código, passou o analisador e a verificação do esquema. Conduzir a build de produção contra o backend real encontrou seis erros que teriam parado os primeiros vinte motoristas.
1. O ponto de partida
Uma app de passageiro e uma app de motorista em Flutter, um Postgres alojado com PostGIS e segurança por linha por trás, ofertas e estado da viagem conduzidos por triggers na base de dados, e um mapa ao vivo. A maior parte do código foi escrita com agentes em poucos dias. O analisador estático estava limpo, e um script de verificação exercitava a máquina de estados da viagem em SQL e passava.
Antes de os primeiros motoristas lhe tocarem, as duas apps foram compiladas como builds web de produção, apontadas ao backend real e conduzidas com um browser em ecrã de telemóvel, com a localização simulada numa rua real da cidade. A regra da sessão foi que uma captura de ecrã decide, e uma asserção em código é uma pista.
2. O que as verificações não viam
Seis defeitos teriam ido para produção. Nenhum é exótico, e cada um vivia numa fronteira que o analisador e a verificação em SQL não atravessam.
| Sintoma | Causa | Porque escapou |
|---|---|---|
| Um motorista fica online e nunca recebe uma viagem | O stream de posição só emite quando o carro se move, por isso a última posição nunca se atualizava e o emparelhamento tratava o motorista como inativo | Código correto; a falha é um carro parado |
| Nada atualiza ao vivo | Duas tabelas nunca foram adicionadas à publicação realtime, por isso cada ecrã parecia vivo só por leituras únicas | Configuração, e a verificação lê as tabelas diretamente |
| Nenhum motorista conseguia aceitar uma viagem | A segurança por linha só deixava o motorista ler a viagem depois de a aceitar, e o botão de aceitar estava dentro da leitura que falhava | A verificação corria como service role, que ignora a segurança por linha |
| Todas as leituras da tabela de viagens falhavam com recursão infinita | A correção da linha anterior referenciava uma tabela cuja política referenciava a tabela de viagens de volta | As políticas são avaliadas pela base de dados, e só com a chave anónima |
| Todos os ecrãs de mapa caíam num retângulo cinzento | A API serializa colunas de geografia como binário hexadecimal, e o cliente esperava GeoJSON | Tipos corretos dos dois lados, errado no fio |
| Nenhum botão que mudava o estado da viagem fazia nada | A biblioteca cliente devolve futures preguiçosos; um handler que criava um sem o esperar não enviava pedido nem registava erro | Compila, corre, e falha em silêncio |
3. A falha que veio depois
Uma semana depois do lançamento a app do motorista mostrava um motorista online enquanto o socket por trás estava morto. O stream realtime tinha ficado em silêncio, e silêncio não é um erro, por isso nada disparou. No wifi do escritório o estado nunca ocorre. Numa rede móvel urbana é rotina.
A correção foi um heartbeat com uma faixa de offline visível, e o teste precisou de uma janela maior do que o intervalo de 25 segundos do heartbeat, porque qualquer teste mais curto dá um falso positivo. A build web também não expunha o texto da faixa à árvore de acessibilidade, por isso a asserção dizia ausente enquanto a captura a mostrava. As capturas continuaram a ser a fonte de verdade.
4. O que levar daqui
- 1
Uma base de código escrita por agentes que passa o analisador diz que o código está bem formado. Não diz nada sobre as fronteiras: políticas, publicações, serialização e a rede.
- 2
Leia a base de dados como o utilizador anónimo. Uma verificação que corre como service role não consegue ver um único defeito de segurança por linha.
- 3
Conduza a build de produção contra o backend real em ecrã de telemóvel antes do primeiro utilizador real. Seis erros bloqueantes numa tarde é o rendimento normal.