Buscar/Altere uma grande base de código de runtime multilíngue sem quebrar o comportamento existente

Altere uma grande base de código de runtime multilíngue sem quebrar o comportamento existente

Para um grande projeto de runtime nativo e de scripts com dependências vendorizadas e com patches. A IA lê primeiro o guia mais próximo, usa os atalhos de build e teste, segue os tipos próprios e as proibições, e coloca mudanças atrás de sinalizadores de compatibilidade.

Para usar estas regras de IA
## Leia o guia mais próximo do código e verifique se há um projeto pai As orientações neste tipo de repositório são organizadas em camadas. Um guia na raiz oferece a orientação de alto nível; os guias dentro dos subdiretórios trazem o contexto específico de cada componente, como classes principais, tabelas de "onde procurar", convenções locais e antipadrões. Leia sempre o guia mais próximo do código que você está prestes a modificar, além do guia da raiz. - Determine sempre se o repositório foi clonado de forma independente ou se está aninhado como componente de um projeto pai maior. Se estiver aninhado, há documentação importante na raiz do projeto pai que não é visível daqui; leia o readme do projeto pai, o guia do projeto pai e os demais documentos de nível superior antes de supor qualquer coisa. - Investigue e leia à vontade, mas reúna esse contexto antes de propor ou fazer edições. - Quando descobrir informações duradouras de alto nível que estejam ausentes dos guias, sugira acrescentá-las em vez de deixá-las apenas na conversa. ## Faça build e teste com os atalhos do projeto, sem comandos improvisados O projeto tem um único sistema de build oficial, além de uma camada fina de atalhos no executor de tarefas. Use os atalhos no trabalho do dia a dia e recorra à ferramenta de build subjacente apenas quando um atalho não expuser a opção de que você precisa. Não invente comandos de compilação improvisados. Atalhos típicos que você deve procurar e reaproveitar: compilar, executar todos os testes, formatar, verificar o estilo dos fontes de script, verificar o estilo dos fontes nativos, verificar o estilo dos pacotes da linguagem de sistemas, transmitir a saída dos testes para depuração, executar uma única suíte de compatibilidade ou de conformidade, criar a estrutura de um novo teste, gerar definições de tipos, gerar o banco de dados de índice do editor, compilar e testar com o sanitizador de endereços, produzir um relatório de cobertura e observar os diretórios de código-fonte para reexecutar um comando a cada alteração. ## Encontre o alvo de teste certo e suas variantes geradas automaticamente Várias famílias de testes coexistem e cada uma tem seu próprio ponto de entrada: - Testes de integração orientados por configuração: um arquivo de configuração serializado que declara um serviço com módulos de script embutidos, uma data de compatibilidade, sinalizadores de recursos e vínculos como vínculos de serviço, dados estruturados, armazenamentos de chave-valor e namespaces de objetos com estado. - Testes unitários nativos construídos por uma macro dedicada, com um sufixo de teste hifenizado no nome do arquivo. - Suítes de compatibilidade do runtime e suítes de conformidade com os padrões da web, cada uma executada pelo nome. - Benchmarks, executados pelo caminho. Tanto o comando de build quanto o de teste aceitam alvos explícitos e, por padrão, abrangem toda a árvore. Os nomes dos alvos carregam um marcador de sufixo obrigatório, e as macros de build geram automaticamente várias variantes por teste: uma variante padrão fixada na linha de base de compatibilidade mais antiga, uma variante na data mais recente com todos os sinalizadores ativados e uma variante com todos os gates temporários ativados. Para encontrar o alvo correto de um arquivo, leia o arquivo de build no mesmo diretório ou consulte o sistema de build para listar todos os alvos daquele pacote. ## Conheça as áreas principais do código e siga uma implementação parecida Construa um mapa mental antes de editar e, para qualquer trabalho novo, encontre uma implementação existente semelhante e siga o padrão dela. - APIs do runtime: implementações nativas das interfaces expostas aos scripts, mais a camada de compatibilidade da biblioteca padrão e seus testes. - Subsistema de E/S: armazenamento e cache de objetos com estado, rastreamento de requisições, limites de recursos, threads e ciclo de vida dos workers. Um objeto de contexto por requisição amarra a requisição inteira. - Camada de ligação: vínculos com o motor, wrappers de tipos, tratamento de promessas, gerenciamento de memória e o sistema de módulos. - Camada de servidor: o ponto de entrada do binário e o tratamento da configuração, usando um modelo de segurança baseado em capacidades descrito por um arquivo de esquema. - Árvores específicas de cada linguagem para a camada de compatibilidade, um runtime de script alternativo e os componentes de integração com a linguagem de sistemas. As camadas de compatibilidade são duplas: a metade nativa fica em uma árvore e a metade de script em outra, e os novos módulos precisam ser registrados na tabela de módulos designada. As definições de tipos são derivadas das informações de tipo nativas somadas a declarações escritas à mão e são regeradas, nunca editadas manualmente. ## Siga o guia de estilo e faça commits pequenos que passem nos testes Siga o guia de estilo interno referenciado, incluindo suas exceções documentadas; onde o projeto se desvia deliberadamente desse guia, o desvio é a regra. - Respeite exatamente o padrão fixo da linguagem, as extensões incomuns de arquivo de código-fonte do projeto e o sufixo hifenizado dos arquivos de teste. - Um único comando de formatação executa todos os formatadores em todas as linguagens. Execute-o, e também o comando completo de testes, antes de enviar uma alteração. - Uma verificação de pré-commit bloqueia macros de impressão de depuração no código em stage e reexecuta a checagem de formatação. Não contorne essa verificação. - Divida as alterações em commits pequenos; cada commit deve compilar e passar nos testes por conta própria. Não deixe commits de correção pendentes. - Os fontes do lado de script são estritamente tipados: semântica exata de propriedades opcionais, sintaxe de campos privados e tipos de retorno explícitos são obrigatórios. ## Use os tipos da biblioteca base própria em vez dos tipos padrão A base de código usa deliberadamente sua própria biblioteca básica em vez da biblioteca padrão da linguagem para a maioria dos tipos. Acompanhe o estilo do arquivo ao redor em vez de recorrer aos contêineres padrão. Substituições a aplicar: string com posse e visão de string sem posse em vez da string padrão; array de tamanho fixo e vetor expansível em vez do vetor padrão; handles de posse única, com contagem de referências, com contagem de referências segura para threads e de referência fraca em vez dos ponteiros inteligentes padrão; um tipo "talvez" em vez do opcional; um wrapper chamável em vez do objeto de função padrão; uma união marcada em vez da variante; uma fatia de array em vez de spans brutos; o tipo de exceção da biblioteca; e a promessa da biblioteca e a promessa bifurcada em vez dos futuros padrão. Por segurança, prefira uma fatia de array a um ponteiro bruto, e um handle vinculado ao tempo de vida a uma referência nua quando a referência estiver atrelada ao tempo de vida do proprietário. Para erros, use a macro dedicada para desembrulhar um tipo "talvez", as macros de requisito voltadas ao script quando a falha precisar aparecer como exceção de script com o tipo de exceção adequado, e as macros nativas de asserção e de pré-condição para invariantes internas. ## Evite os padrões proibidos que causam vazamentos e danos ocultos Estas regras são absolutas; violá-las produz corrupção sutil, vazamentos ou quebras de compatibilidade. - Nunca coloque handles locais ou globais do motor em declarações de struct do tipo valor; use os wrappers de referência fornecidos. - Nunca coloque handles do motor dentro de tipos de promessa e nunca passe o lock do motor para corrotinas assíncronas. - Nunca mantenha referências do heap de script para objetos de E/S sem o wrapper proprietário; um guarda de escopo impõe essa regra. - Prefira propriedades de protótipo a propriedades de instância, que anulam a otimização da coleta de lixo. - Nunca congele profundamente conteúdo fornecido pelo usuário, o que é inseguro para valores cíclicos. - Nunca adicione métodos a uma interface que despacha nomes desconhecidos remotamente sem protegê-los por um sinalizador de compatibilidade, e nunca altere valores de enumeração serializados. - Prefira a chamada aditiva de registro de tarefas ao acessor bruto da lista de tarefas, e evite parâmetros booleanos em favor de tipos booleanos fortes. - Qualquer referência armazenada em um objeto nativo alcançável a partir do heap de script deve implementar a visitação da coleta de lixo; ciclos de referência nativos nunca são coletados. Uma verificação de estilo dedicada valida isso. - Erros de uso indevido do banco de dados embutido sempre lançam exceção e nunca são suprimidos; transações não são permitidas no banco de dados de objetos com estado. - A avaliação de módulos nunca deve ocorrer dentro de um contexto de requisição, e E/S assíncrona no escopo global é proibida. - Em arquivos compartilhados de declaração de tipos, nunca use nomes genéricos de tipos ambientes; sempre prefixe-os com o nome do produto ou do recurso. Nunca use um objeto sem tipo como tipo; declare uma interface adequada com campos conhecidos, estendendo opcionalmente um registro aberto para compatibilidade futura. - Nunca edite manualmente snapshots gerados. Corrija a camada de origem e regenere. ## Coloque mudanças de comportamento atrás de sinalizadores de compatibilidade ou gates temporários O projeto assume um forte compromisso de compatibilidade retroativa: uma vez que um comportamento é implantado, ele não pode ser removido nem alterado silenciosamente. Por isso, mudanças de comportamento precisam ser introduzidas atrás de um gate, e você escolhe o gate conforme a permanência dele. - Os sinalizadores de compatibilidade orientados por data são definidos por instância, são permanentes e ficam declarados em um esquema cujas anotações carregam o nome do sinalizador e a data de ativação. Todo sinalizador deve estar documentado antes que sua data de ativação chegue. - Os gates temporários no nível do processo são orientados por configuração e destinam-se a lançamentos arriscados com ativação condicional. Eles são definidos como uma enumeração mais um mapa de strings, e os dois precisam permanecer sincronizados. Mantenha um critério exigente para interfaces fora do padrão; prefira implementar padrões publicados a inventar comportamentos específicos do projeto. ## Atualize as dependências vendorizadas sem perder os patches locais As dependências de terceiros são incorporadas a um diretório externo pelo mecanismo de módulos do sistema de build. A integração fica no manifesto de módulos e em um diretório de build de dependências; um arquivo de workspace legado ainda pode existir, mas já não é o mecanismo principal. Consulte diretamente os fontes da biblioteca básica incorporada para tirar dúvidas sobre seus cabeçalhos e namespaces, em vez de adivinhar. Várias dependências carregam conjuntos de patches mantidos localmente e aplicados durante o build. Esses patches introduzem personalizações específicas do projeto e novas interfaces, portanto revise-os e atualize-os sempre que a dependência for atualizada. Observe também que o projeto usa um alocador de memória alternativo, cujo comportamento difere do padrão; qualquer análise de memória precisa levar isso em conta. Para uma atualização importante do motor ou de uma dependência: pergunte qual é a versão exata desejada e quais patches ou personalizações precisam ser preservados antes de começar, e então siga as etapas documentadas de sincronização, aplicação de patches, rebase, regeneração de patches e incremento de versão. Conflitos de merge são comuns e quase sempre exigem julgamento humano para manter intactas as mudanças específicas do projeto; nunca os resolva automaticamente sem revisão humana. Confirme que a suíte de testes completa passa e comunique quaisquer novas depreciações que encontrar. ## Encontre a documentação espalhada e proponha correções quando estiver errada A documentação é distribuída, não centralizada. Um diretório de documentos cobre temas transversais, como configuração do ambiente, diretrizes para adicionar novas interfaces e procedimentos de atualização de dependências, enquanto os diretórios de código-fonte individuais costumam trazer seu próprio readme ou guia com detalhes profundos do subsistema. Procure esses materiais de forma proativa ao trabalhar em uma área desconhecida, antes de adivinhar ou perguntar. Quando a documentação estiver faltando, imprecisa ou desatualizada, proponha uma atualização em vez de ficar em silêncio. Verifique os fatos primeiro e não faça commit de edições de documentação sem confirmar a exatidão delas com um mantenedor.