Seat Time cresceu além do nome — e alguns merges sumiram
Nosso jogo de direção no navegador, feito com nossa equipe de agentes de programação com IA, cresceu além do nome Racing Sim. Na segunda semana de outubro de 2026, já tinha trabalhos, carteira, licenças e uma pequena cidade. Queríamos um nome que abrangesse mais do que corridas. Por trás desse crescimento, porém, parte do trabalho marcado como “Merged” nunca tinha chegado ao jogo.
A mudança de nome correu bem. Os links antigos continuaram levando ao jogo, e o progresso salvo foi preservado. O problema mais difícil era um carro ausente do seletor, apesar da integração concluída. Isso nos levou além do status tranquilizador de um pull request: a proposta que usamos para revisar e integrar código.
O simulador ganhou uma carteira e uma cidade
O jogo estava ganhando uma vida ao redor da direção. Nossos registros de desenvolvimento mostram um sistema de licenças, oficina de preparação, trabalhos de meio período, quilometragem e carteira. Planos pagos e trabalhos na cidade Miniature Rio entraram no escopo. Antes da separação, a lista também incluía um registro de créditos, inicialmente desativado, concessionária, aluguéis e missões.
“Racing Sim” descrevia a direção, mas dizia pouco sobre essas atividades. Queríamos espaço para troféus, preparação e o tempo dedicado a melhorar ao volante. Escolhemos Seat Time pela expressão do automobilismo sobre horas ao volante. O nome mantinha a direção no centro sem fazer toda atividade parecer uma corrida.
O novo nome, sozinho, não resolvia a questão do escopo. Quem chegava para correr e quem acompanhava o ciclo de trabalhos e dinheiro abria o mesmo jogo por motivos diferentes. Renomear nos deu uma identificação melhor. Ainda precisávamos decidir o que ficaria por trás dela.
Mudamos o nome sem zerar o progresso
Em 11 de outubro, renomeamos o jogo para Seat Time. A reorganização ficou em um commit só de movimentações: uma alteração registrada com 1.412 arquivos movidos. Separar essas movimentações deixou explícita a parte mecânica da mudança. Também alteramos os prefixos das mensagens traduzidas e redirecionamos os endereços antigos.
Os links antigos de /games/racing-sim redirecionam para o novo destino, preservando o idioma e os parâmetros da consulta. Usamos HTTP 308, o status de redirecionamento permanente definido na RFC 9110. A norma explica o status; preservar idioma e parâmetros foi uma escolha da nossa implementação.
Mantivemos, de propósito, as chaves dos dados salvos, as marcações de esquema e os nomes das tabelas do banco. Esses nomes ligam o jogo ao progresso já guardado no navegador ou no banco de dados. Fazer todo nome interno combinar com a nova fachada acrescentaria uma migração de dados à troca de nome. Os arquivos históricos de conteúdo publicado também mantiveram os nomes antigos.
Isso deixou uma fronteira aparentemente desarrumada dentro do projeto, mas foi intencional. O nome público mudou, enquanto os identificadores do progresso salvo ficaram estáveis. Queríamos preservar o lugar do jogador no jogo, não ganhar uma competição de buscar e substituir.
Três dias depois, separamos corrida e vida
Em 14 de outubro, dividimos o escopo entre Seat Time e Seat Life. Seat Time virou a edição de corridas, com garagem da equipe e uma progressão monomarca: 27 eventos para 24 carros de corrida. Seat Life virou o centro da economia da vida de piloto. Ambos usavam um motor e um perfil de progresso salvo.
A divisão deu um propósito mais claro a cada edição sem exigir progressos separados. As corridas ganharam uma entrada própria; o ciclo de trabalhos e economia, outra. Compartilhar o motor importava porque eram duas portas para sistemas de direção relacionados. Não tínhamos decidido reconstruir a simulação duas vezes.
Essas quantidades descrevem a divisão naquela época. E a organização no papel não mostrava se toda alteração aceita tinha chegado ao código compartilhado.
As cópias de trabalho dos agentes lotaram o disco
O trabalho em paralelo teve um custo físico antes de entendermos o problema de entrega. Por volta de 12–13 de outubro, as cópias de trabalho dos agentes ocupavam 413 GB, com 4 GB livres. Cada tarefa podia parecer pequena isoladamente. Juntas, as cópias consumiram o disco necessário para continuar desenvolvendo.
Passamos a usar worktrees com checkout esparso. Um worktree do Git oferece outro diretório de trabalho ligado ao mesmo repositório. O checkout esparso limita os arquivos rastreados presentes ali a um subconjunto escolhido. Com os dois, podíamos entregar ao agente a parte relevante do projeto sem outra cópia de trabalho completa.
As verificações automatizadas também ficaram sem espaço durante checkouts completos. Em 13 de outubro, reescrevemos o histórico do repositório para remover cerca de 1,1 GB de arquivos gerados. Isso tratava do material armazenado no histórico, um problema diferente da quantidade de arquivos necessária no diretório de cada agente.
A reescrita deixou uma consequência para nossos registros. Os primeiros 150 pull requests já não faziam parte do histórico reescrito da main. As páginas preservadas dessas propostas passaram a ser o registro principal daquele trabalho inicial. Depois disso, a ausência no histórico, sozinha, não provaria que aquelas alterações tinham se perdido.
Um carro integrado não aparecia no seletor
O Formula Club 1500 Aero deu uma forma concreta ao problema. Nosso registro de recuperação descreve um visitante sem dados anteriores vendo 24 carros, sem o Aero na lista. O pull request tinha sido integrado, mas em uma branch cujo trabalho já havia sido incorporado. A recuperação levou o histórico original à main.
Branch é uma linha separada de desenvolvimento; merge é a integração do trabalho em um destino escolhido. Main é nossa linha compartilhada de integração. As definições parecem banais até o destino estar errado. “Merged” diz que a proposta chegou à branch de destino, não que chegou à main — ou à versão aberta pelo jogador.
A proposta concluída e a lista de carros do visitante não correspondiam.
O destino ficou para trás depois que a alteração principal avançou
A armadilha estava nos pull requests empilhados. Imagine a alteração B construída sobre A, com B apontando para a branch de A. A chega à main primeiro. Se B depois entra na branch de A, o trabalho novo cai em um lugar que já encerrou seu caminho até a main. Esse merge posterior não repete automaticamente a integração anterior.
Empilhar propostas não era, por si só, prova de erro. Nossa consulta de 3 de novembro contou 106 destinos fora da main entre 516 pull requests integrados. Havia branches intencionais para trabalho em lote, além de propostas empilhadas. O problema era considerar seguro o destino depois que a proposta principal já tinha sido integrada.
A mesma consulta encontrou 13 propostas integradas em branches cujas próprias propostas já haviam chegado à main. Os intervalos iam de 1 segundo a cerca de 54 minutos. É uma contagem desse padrão de tempo, não de 13 perdas permanentes comprovadas. Parte do trabalho foi recuperada ou chegou por outro caminho; a consulta sozinha não distingue os casos.
Isso mudou a pergunta que precisávamos fazer antes de integrar. “Está pronto?” não bastava. Também precisávamos perguntar: “Para onde vai agora?”. Um destino adequado na abertura da proposta podia estar errado quando aceitávamos o trabalho.
Salto adiante: vinte segundos em 24 de outubro
Um caso posterior mostra a sequência segundo a segundo. Em 24 de outubro, a alteração principal chegou à main às 15:36:20 UTC. Uma mudança na física dos kei cars entrou na branch dessa alteração às 15:36:40 UTC. Foram vinte segundos de diferença, e a main ficou na versão 6 da física, sem receber a versão 7.
Mais tarde, levamos essa mudança de física à main. Os registros não dizem como a ausência foi descoberta. Eles mostram que a ordem dos merges bastou para deixar a main com a física antiga. Isso aconteceu depois de já termos adicionado uma verificação de entrega em 17 de outubro.
O intervalo curto torna esse caso esclarecedor. Não era preciso deixar uma branch esquecida por dias. A proposta principal podia terminar, a dependente podia vir logo depois, e ainda assim não chegar à main. Escolher o destino certo fazia parte de concluir o trabalho.
Recuperar era trazer o trabalho, não mudar um rótulo
Recuperamos mais do que o carro ausente. Uma alteração que unificava nosso publicador de implantação tinha entrado 14 segundos depois do merge da proposta principal; ela voltou em uma recuperação separada. Fluxos aceitos de conta, prática e aplicativo nativo também precisaram ser recuperados, assim como o Challenge Lab independente. Em cada caso, era necessário encontrar o trabalho e levá-lo à main.
Outro salto adiante tem data: 31 de outubro. Recuperamos Watch, o modo de demonstração do agente treinado para dirigir, que tinha entrado na branch da proposta principal 10 segundos tarde demais. A recuperação usou um merge de verdade, preservando o histórico original. Assim, a verificação de entrega podia reconhecer o trabalho recuperado na ancestralidade da main.
Nem toda entrada tinha uma recuperação para contar. A avaliação da demonstração do Hall of Fame continuava registrada como não entregue na nossa última consulta, em 3 de novembro. Ela havia aparecido na auditoria de 17 de outubro.
Uma regra e uma verificação capaz de barrar
Nossa regra ficou simples: mudar o destino de um pull request empilhado para a main antes de integrá-lo. Nunca integrá-lo em uma branch que já teve seu merge concluído. A documentação do GitHub sobre a branch de base explica essa troca. Ela também alerta que os commits exibidos e os comentários de revisão podem mudar. Portanto, trocar o destino ainda exige atenção.
A verificação de entrega adicionada em 17 de outubro pergunta se o commit final de cada proposta integrada coberta é um ancestral da main. Ancestral é uma alteração alcançável pelo histórico registrado da main. Se estiver ausente, a verificação falha, salvo uma exceção revisada que registre trabalho equivalente ou uma entrega ainda não realizada.
“Equivalente” significa que o trabalho chegou por outro caminho; “não entregue” mantém uma omissão conhecida na lista. Nenhuma dessas situações prova que o histórico original chegou à main. O histórico inicial reescrito também precisa de tratamento separado, sem transformar as primeiras 150 propostas em falsos alarmes.
A verificação pode falhar corretamente durante trabalho em lote, enquanto alterações aceitas aguardam uma branch compartilhada de integração. Precisamos concluir essa integração, em vez de ensinar a verificação a ignorar o incômodo. Nossas verificações no GitHub Actions estavam bloqueadas por cobrança, então essa barreira rodava com os testes automatizados locais.
A falha posterior na física aconteceu mesmo com a nova regra. O que mudou foi nossa definição de concluído: o status de merge precisava de um destino e de evidência de entrega. Os agentes escreveram o trabalho e ajudaram a recuperá-lo; nós orientamos o trabalho e assumimos as decisões de integração.
A próxima pergunta é o que chega ao jogador
A mudança de nome preservou os links antigos e o progresso salvo. A divisão deu lugares mais claros às corridas e à economia. Nenhuma delas podia transformar uma proposta integrada em prova de entrega. Precisávamos acompanhar o trabalho até a main, inclusive aquilo que já tínhamos chamado de concluído.
Dirija na versão atual de Seat Time.
Se “integrado” não significa “na main”, estar “na main” significa estar “no ar”?
Anterior: Chuva e o carro que se movia parado. Próximo: Cada merge é uma versão publicada.
Notas e fontes
Fatos documentados e decisões de projeto — Nossos registros de desenvolvimento documentam a mudança de nome em 11 de outubro, 1.412 arquivos movidos, identificadores de armazenamento preservados e redirecionamentos. Também documentam a divisão em 14 de outubro, seus 27 eventos e 24 carros de corrida, o motor e o perfil compartilhados. Os detalhes da expansão vêm dos títulos registrados das alterações, não de uma nova auditoria de funcionalidades. Todas as datas deste relato são de 2026.
Medições — Nossos registros apontam 413 GB de cópias de trabalho e 4 GB livres por volta de 12–13 de outubro. A reescrita de 13 de outubro removeu cerca de 1,1 GB de arquivos gerados. Nossa consulta de 3 de novembro cruzou destinos, branches de origem e horários dos merges: 106 de 516 propostas integradas tinham destinos fora da main; 13 correspondiam ao padrão de merge tardio, de 1 segundo a cerca de 54 minutos. Isso não conta funcionalidades permanentemente ausentes.
Fatos documentados — Os registros de recuperação sustentam o caso do Aero ausente, a sequência da física em 24 de outubro, as recuperações do publicador e dos fluxos, e a recuperação do Watch em 31 de outubro. As datas da perda e da recuperação do Aero são desconhecidas. A auditoria de 17 de outubro e os registros da verificação de entrega estabelecem a proteção e a pendência do Hall of Fame, consultada pela última vez em 3 de novembro. Não realizamos uma nova sessão ao volante nem uma avaliação da versão atualmente no ar para este relato.
Referências públicas — RFC 9110, 308 Permanent Redirect, Git worktree, Git sparse checkout e GitHub: mudar a branch de base de um pull request explicam os mecanismos públicos. Não verificam de forma independente nosso histórico de desenvolvimento.
Nossa interpretação — “Merged” descreve o status de uma proposta, não o conteúdo do produto. A IA auxiliou a redação e a localização deste artigo; os fatos históricos vêm dos nossos registros preservados de desenvolvimento.