
Construí uma IA para superar o solucionador na recuperação de tripulação aérea. Ela perdeu — e essa derrota virou o produto.
O benchmark que construí para vencer — e perdi
Construí a primeira versão do StormCrew para superar o solucionador. Era essa a proposta inteira na minha cabeça. O controle de operações aéreas roda em motores de otimização de décadas, então se eu conseguisse treinar algo mais inteligente, teria uma história que valesse a pena contar. Passei semanas nisso. Então comparei meu motor de recuperação com o CBC, um solucionador maduro de programação inteira mista e de código aberto, testado em batalha desde antes de eu conseguir escrever um for-loop — e o CBC venceu. Não por um erro de arredondamento.
Lembro de ficar olhando as duas colunas de números e sentir aquele vazio específico que você sente quando o experimento que desenhou para provar que estava certo prova, em vez disso, que você estava errado. O solucionador foi mais rápido. Seus planos eram mais baratos. Ele nunca devolveu um cronograma inviável. Minha versão esperta perdeu nos três.
Então fiz a única coisa honesta que me ocorreu. Mudei a tese, não os números.
Construí a IA para superar o solucionador. O solucionador venceu. A parte interessante acabou sendo tudo o que aquela disputa escondia.
Essa reversão é a espinha do que o StormCrew de fato se tornou, e acho que é a história mais útil do que a que eu tinha saído para contar. Você pode rodar tudo você mesmo em veriprajna.com/pt-BR/demos/stormcrew-recuperacao-de-tripulacao-irops-em-segundos-legal-por-construcao, mas deixe-me percorrer o que mudou minha opinião, porque o pivô é o ponto.
O que de fato quebra quando uma tempestade fecha um hub?
Voltei a ler as autópsias dos colapsos depois que o CBC me humilhou, e quase nenhuma das falhas era "a matemática ficou um pouco subótima." Operações irregulares, o que o setor chama de IROPS, custam às companhias aéreas cerca de US$ 60 bilhões por ano (IATA). O desastre canônico, a Southwest em dezembro de 2022, ficou em torno de US$ 1,2 bilhão, com cerca de 16.900 cancelamentos e aproximadamente 2 milhões de passageiros encalhados. Quando tracei como aqueles dias de fato se desenrolam, o otimizador nunca foi o vilão.
Três coisas quebram em vez disso. A recuperação é lenta demais: quando uma tempestade fecha um hub, remanejar a tripulação da cascata a jusante ainda é em grande parte uma corrida manual de 4 a 12 horas (um benchmark com fonte, não um número que inventei). É arriscada demais: cada remanejamento de tripulação precisa respeitar a FAA Part 117 — limites de serviço e descanso — e um CBA sindical por companhia, e uma única violação é um evento de conformidade, não uma nota de rodapé. E é opaca demais: a cascata de voos a jusante que acabaram de perder a tripulação fica invisível até que esses voos já estejam cancelando.
Esse último ponto é o que as ferramentas legadas perdem, e é a primeira coisa que fiz o demo mostrar. Injete uma tempestade no hub mais movimentado e o app destaca o raio de impacto: os voos aterrados mais os voos a jusante de um salto que perdem a tripulação pela rotação. No cenário semeado são 53 voos em risco na rede.

Desde a regra de reembolso automático do DOT (out. 2024), cada atraso em cascata de 3 horas ou mais também é agora um impacto financeiro automático. Então o custo de ser lento, ilegal ou cego subiu exatamente enquanto as ferramentas permaneceram as mesmas. Nenhuma dessas três falhas se corrige com uma função-objetivo melhor. Eu estava otimizando a única coisa que já estava bem.
Por que parei de tentar superar o CBC e comecei a alimentá-lo?
Fiz as pazes com a derrota para o CBC dando a ele um trabalho diferente. Em vez de competir com o solucionador, eu o envolvi. O pipeline é todo código real, determinístico e semeado: uma rede aérea sintética e estado de tripulação, um injetor de disrupção que calcula o raio de impacto por alcançabilidade em grafo sobre a rotação, um gerador de jornadas, depois o CBC como motor que escolhe o plano, depois uma comparação-sombra contra não fazer nada, depois um certificado assinado.
Quando rodo no cenário de tempestade semeado, o gerador produz 1.762 jornadas legais de recuperação (52 delas reposicionamentos deadhead para mover tripulação até onde é necessária), mais 53 fallbacks de cancelamento, totalizando 1.815 colunas candidatas no total. O CBC resolve a partição de conjuntos de custo mínimo com 1.815 variáveis e 115 restrições até OPTIMAL e devolve um plano em cerca de 0,11 segundos. Resultado nesse cenário: 52 de 53 voos remanejados (98 por cento), 1 cancelamento, 34 tripulações usadas (25 de linha e 9 de reserva).

O problema da companhia aérea nunca foi o solucionador ser fraco demais. Foi a recuperação ser lenta demais, arriscada demais e invisível até ser tarde demais.
Note a honestidade dessa captura de tela. O motor de recuperação é o CBC, nomeado no painel. A tese durável não é que meu código supera um solucionador. É que o plano chega bem em menos de um segundo onde o processo manual com fonte leva de 4 a 12 horas, e o app mede essa lacuna à vista de todos. Quero ser preciso sobre o escopo, porque isto é um demo e me recuso a lavá-lo para parecer mais do que é: esses números exatos são resultados de uma rede sintética semeada, não uma garantia de mundo aberto. A tese velocidade versus manual é a que viaja.
A garantia de legalidade pertence ao código, não ao julgamento de um modelo
Tenho uma opinião forte que só conquistei construindo isto, então deixe-me dizer com clareza. Uma garantia de legalidade não pode viver no julgamento de um modelo. Tem de viver em código determinístico, por construção. O jeito de impedir que uma jornada ilegal de tripulação seja alguma vez recomendada não é treinar um modelo para evitá-la, nem adicionar um termo de penalidade à função-objetivo e torcer para o otimizador contorná-la. É tornar a jornada ilegal impossível de gerar desde o início.
Então as restrições são aplicadas na hora da geração, não pontuadas depois. A Part 117 limita um período de serviço a 780 minutos, o tempo de voo a 480 minutos, e exige um sit mínimo de 30 minutos; o CBA de exemplo limita uma jornada a 4 segmentos. Só jornadas que satisfazem tudo isso se tornam colunas candidatas. Isso é mascaramento de ação. Uma atribuição ilegal não é penalizada — ela é irrepresentável. O que quer que o CBC faça com as colunas que recebe, e o que quer que o copiloto opcional diga depois sobre o plano, nenhum dos dois pode ressuscitar uma jornada ilegal, porque ela nunca esteve no conjunto.
Isso me dá um invariante em vez de uma pontuação: 0 atribuições ilegais, jamais, testadas em unidade (a suíte de testes está 3/3 passando, verificando que o raio de impacto não está vazio, que só colunas legais são geradas e que o plano recuperado é uma partição legal). Uma pontuação você pode regredir. Um invariante você pode prometer.

É também por isso que não acho mais convincentes os pitches de "ops de IA autônoma" quando a história de segurança é "o modelo aprendeu a não fazer." Confiei em um modelo para respeitar uma regra dura exatamente uma vez durante esta construção, cedo, e esteve bem até a única entrada em que não esteve. Em um domínio em que uma única violação é um evento regulatório, "geralmente legal" é o mesmo que "não legal." Prefiro apagar a possibilidade a supervisioná-la.
O que acontece no pior dia do ano?
Quase lancei uma versão que autoaprovaria qualquer coisa, e fico feliz que um cenário me impediu. Alterne o demo para severe, em que o evento é grave o bastante para esgotar as reservas e restarem apenas cerca de 30 por cento das tripulações. O CBC ainda encontra um plano totalmente legal, em cerca de 0,05 segundos, ainda com 0 ilegal. Mas esse plano cancelaria 20 de 53 voos, o que é 38 por cento do raio, bem acima do limiar de autoaprovação do OCC de 15 por cento.
A atitude certa ali não é carimbar em silêncio um plano que cancela mais de um terço da rede afetada. Então o status muda para ESCALATE, assinatura humana obrigatória, com o motivo exibido. O plano ainda é calculado, ainda é legal, ainda é apresentado ao controlador (33 voos recuperados, 62 por cento do raio). Só não é autoaprovado.

A parte que a maioria dos pitches "autônomos" pula é saber quando a ação correta é não agir e entregar o dia a um humano.
Construir esse portão mudou como me sinto em relação à categoria inteira. Escalonar não é o sistema falhando. É o sistema sendo honesto sobre um dia ruim. Um conselheiro que sempre devolve uma resposta confiante é fácil de demonstrar e perigoso de confiar. Aquele que de vez em quando diz "este está acima da sua linha, você decide" é o que eu realmente colocaria ao lado de um controlador às 3h da manhã.
O artefato que eu quereria se fosse o controlador
Fiquei me perguntando o que um controlador de operações precisaria na manhã seguinte, e a resposta não era um painel — era um registro. Então cada recuperação se sela em um recovery_plan.json assinado: a disrupção, o plano escolhido ação a ação com tripulação e voo, a cláusula específica da Part 117 e do CBA checada por ação contra seu teto, o tempo decorrido da recuperação e as cifras de economia. É o registro de auditoria do OCC sobre por que esta recuperação foi recomendada, exportável com um clique.

Há também um copiloto de plano opcional, e quero deixar claro onde ele fica. É um adaptador fino a um LLM (Claude por padrão, provedor trocável, ou uma ponte local sem chave) que explica o plano em linguagem simples. Ele se abstém por completo sem uma chave, todo o resto roda offline e sem chave, e ele vive fora do núcleo de decisão. A máscara determinística, o CBC e o portão de escalonamento decidem. O modelo só narra depois do fato. Coloquei-o ali de propósito, porque no momento em que o modelo de linguagem influencia se uma jornada é legal, eu perdi a garantia que passei a construção inteira conquistando.
Sobre as economias, a mesma disciplina se aplica. No cenário normal a comparação-sombra mostra 52 cancelamentos evitados e cerca de US$ 2,37 milhões de exposição a reembolso do DOT evitados (um modelo de US$ 300 por passageiro) versus não fazer nada. Esse é o enquadramento mais lisonjeiro possível, porque a linha de base é deixar encalhado o raio de impacto inteiro, e está rotulado como ilustrativo daquele único cenário. Não é manchete, e certamente não é prova de que meu código supera qualquer coisa. Perdi esse argumento para o CBC no primeiro dia. Não vou reconquistá-lo em silêncio com um número de marketing.
Então o que "aumentar, não substituir" realmente significa?
Eu costumava achar que aumento era a escolha tímida, a coisa que se diz quando não se consegue construir a coisa ousada. Agora penso o contrário. O comprador aqui já possui uma boa pilha de solucionadores, Jeppesen ou IBS, e não tolera rip-and-replace, lock-in, nem uma recomendação inexplicada no pior dia do ano. Dizer a esse comprador "jogue fora pelo meu modelo mais inteligente" não é ousado — é uma tese que eu já refutei a mim mesmo com um benchmark.
O que posso oferecer com honestidade é a camada operacional em torno do solucionador em que eles já confiam. Tornar a cascata visível antes que morda. Tornar movimentos ilegais impossíveis de gerar em vez de apenas desencorajados. Colapsar horas em segundos. E saber quando o dia está ruim o bastante para a resposta certa ser escalonar, não autoaprovar. Tudo no demo é sintético e semeado — a rede, as tripulações, a disrupção, as cifras em dólares —, nenhum dado real de companhia aérea em lugar nenhum. O que é real é o mecanismo, e você pode vê-lo rodar de ponta a ponta em veriprajna.com/pt-BR/demos/stormcrew-recuperacao-de-tripulacao-irops-em-segundos-legal-por-construcao.
E se preferir ver a ler minha descrição, aqui está a coisa inteira rodando de ponta a ponta.
Aqui está a pergunta que não parei de revolver desde que o CBC me venceu. Quando o solucionador com o qual você compete já é bom, e o comprador já o possui, o que resta construir não é uma resposta melhor. É uma relação melhor com a resposta: mais rápida, comprovadamente legal, visível e humilde o bastante para escalonar. Então quanto da IA que estão te vendendo este ano está de fato resolvendo a parte difícil, e quanto está resolvendo de novo a parte que nunca esteve quebrada?


