Validação
Base atual
Os gates registados mais recentes no anfitrião de desenvolvimento Windows x64
(clang-cl e SDK do LLVM 23.1.2, /MT, _ITERATOR_DEBUG_LEVEL=0); os passos
posteriores registam os seus em .agents/00-finished.md:
| Verificação | Resultado |
|---|---|
| CTest Debug combinado a partir do zero (2026-10-14) | 299/300 aprovados; a falha é o limite conhecido de tamanho da IR em codegen_measurements; codegen_resource_cli está desativado |
check-quality-all (mesma execução) | Limpo; Lizard CCN 10 |
Testes opcionais de auditoria ao OTP (2026-10-14, pin d199a49a01a2, oráculo OTP 29.1.1) | 17/17 |
regenerate.py --corpus all --check (idem) | 19/19 corpora reproduzidos |
Executar o gate
A partir de uma shell de programador do Visual Studio x64 com
C:\Program Files\LLVM\bin no PATH (a seleção automática do SDK reutiliza
thirdparty/):
cmake --preset debug --fresh -DBUILD_TESTING=ON -G Ninja -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
cmake --build build/debug
ctest --preset debug-fast # during development
ctest --preset debug -j 16 # full mode, at feature completion
cmake --build build/debug --target check-quality # changed files, one unit per header
cmake --build build/debug --target check-quality-all # whole tree
CLAUSE_TEST_MODE=fastexecuta os corpora golden em O0 posicional mais o projeto O2 com a especialização desativada, executa as mutações uma vez e salta os testesfull_only(projetos consumidores separados comoruntime_generated_link, medições, a auditorialibrary_freshnessao OTP do anfitrião, e os fluxos de trabalho lentoslinking_lto,linking_exports,linking_compile_cache,programs_compileetransforms_cache). O modo completo (predefinido) executa todas as combinações de driver/política.- Os testes longos conduzidos por um script Python ou CMake têm um
COSTfixo no CTest: o CTest aprende o custo de um wrapper a partir do seu próprio tempo de CPU, pequeno, e iniciá-los-ia em último lugar. - Os testes sensíveis à carga (
CLAUSE_LOAD_SENSITIVE_TESTSnoCMakeLists.txtde topo:frontend_cli,codegen_examples,linking_debugger,executables_applications) só excediam o tempo limite ou perdiam corridas de temporização numa execução paralela completa. TêmDEPENDSde todos os outros testes, pelo que começam depois de terminar o resto da seleção e têm os processadores só para si; uma dependência que falhe não os faz saltar. CLAUSE_TEST_TIMEOUT_SCALE=Nmultiplica os limites por execução do executor de goldens (60 s) e do executor de casos semânticos (15 s) para compilações instrumentadas.check-quality,make formatemake-format.batabrangem os ficheiros alterados desdeHEADmais os ficheiros não seguidos;cmake/quality_scope.pyacrescenta, para cada cabeçalho alterado, uma unidade de tradução que o inclui (o seu próprio código-fonte, ou o primeiro utilizador, a partir dos dados de dependências do Ninja de qualquer configuração; os restantes dependentes do cabeçalho ficam paracheck-quality-allna verificação completa) e, para o clang-tidy, as unidades cujo comando de compilação difere do registado pela última execução aprovada (build/debug/quality/tidy-commands.json), pelo que uma edição de uma regra de compilação volta a verificar apenas as unidades que altera. As alterações a.clang-tidyou aos scripts do tidy selecionam tudo, tal como as edições de regras de compilação antes da primeira execução registada.CLAUSE_OPTIMIZED_COMPILER(por omissão ON) compila oclaue as bibliotecas do compilador otimizados também nas compilações Debug, mantendo a sua informação de depuração e os orçamentos de inferência Debug; os testes passam a maior parte do tempo noclau. Quando for preciso percorrer passo a passo uma falha do compilador, configure com-DCLAUSE_OPTIMIZED_COMPILER=OFF, recompile e volte a executar o teste que falha.- Os programas de teste não contêm informação de depuração (sem PDBs);
configure com
-DCLAUSE_TEST_DEBUG_INFO=ONpara os recompilar para um depurador. Os consumidores nativos aninhados ligam o runtime da compilação principal através deClauseRuntimeTargets.cmakeem vez de o compilar novamente; sóruntime_linkcompila o runtime de forma autónoma. - Os limiares e as supressões nunca são aumentados para passar o gate. Estão
configuradas duas exceções de terceiros (decisão do utilizador):
cmake/tidy_filter.pydescarta os relatórios do analisador estático localizados em cabeçalhos do Boost (falsos positivos do armazenamento de limbs do Boost.Multiprecision em Linux que reescrever o código chamador apenas desloca) e conta-os na saída, ebugprone-exception-escapeignorabad_array_new_length(os construtores de movimento de map/set do MSVC alocam; uma falha de alocação é, de qualquer modo, fatal). - O clang-tidy verifica os cabeçalhos do projeto em todos os anfitriões: o
filtro de cabeçalhos aceita os separadores
/e\.
Linux
O mesmo gate corre em Linux com o SDK Linux do LLVM 23.1.2 fixado como
compilador do anfitrião (CC/CXX a partir do seu bin/), a libstdc++ do
sistema, Ninja e CMake 3.28 ou mais recente. O Boost 1.90 e o toml++ 3.4.0 vêm
de pacotes instalados ou são extraídos para thirdparty/ (boost_1_90_0/,
tomlplusplus-3.4.0/); só o Windows os descarrega. O ld.lld do arquivo da
release liga a ICU 70 (Ubuntu 22.04) e o seu lldb liga o Python 3.14; em
anfitriões sem eles, linking_lto precisa da ICU 70 em LD_LIBRARY_PATH, e
linking_debugger usa o GDB.
cmake --preset debug --fresh -G Ninja -DBUILD_TESTING=ON
cmake --build build/debug
ctest --preset debug -j 16
check-quality (Lizard, clang-tidy) corre apenas no anfitrião de
desenvolvimento Windows; os outros anfitriões compilam e executam os testes
(esteve limpo em Linux uma vez, ver o histórico).
Outros alvos
Os alvos de 32 bits e ARM são verificados sem um compilador compilado para eles (não existe SDK do LLVM para esses anfitriões):
- Uma compilação só do runtime (
-DCLAUSE_BUILD_COMPILER=OFF -DBUILD_TESTING=ON) para o alvo executa aí os testes do runtime e da ABI: nativamente, num userland do alvo (chroot) ou através do emulador do anfitrião (qemu binfmt). tests/compiler/executables/cross.pyexecuta todos os goldens de executáveis e fixtures de programas com oclaudeste anfitrião,--target-triple, o arquivo do runtime dessa compilação e um--linkerque alcança as bibliotecas do alvo (run.py --target-optionpassa-os adiante).
Fixtures e proveniência
- As compilações e os testes normais não precisam do OTP nem do seu código-fonte. Os goldens foram gerados uma vez a partir do OTP e estão no repositório com hashes; as verificações de hash são executadas antes de qualquer fixture ser usada.
- Dezanove corpora de padrões/guards contêm 67 748 valores/erros nativos esperados e 106 linhas de aceitação semântica. Cada corpus nativo executa os drivers posicional e de projeto em O0/O2 com a especialização ativada e desativada, com chamadas locais e remotas.
- As entradas Erlang no repositório são de autoria local
(
tests/fixtures/patternmatch/fragments/,semantic/headers/do pré-processador);fixture_sourcesimpõe o isolamento em relação ao código-fonte do OTP. - Seis fixtures de programas finais (
tests/fixtures/programs/) contêm goldens de stdout/estado de saída do OTP e os seus diagnósticos de compilação;programs_compileverifica-os sem OTP etests/compiler/programs/regenerate.py --checkreprodu-los com o OTP (mapa das fixtures). - Os goldens de impressão de termos (
tests/fixtures/printing/) contêm o texto de~we deerlang:display/1do OTP para 9 542 valores, mais o stdout do OTP de chamadas display compiladas;tests/compiler/printing/regenerate.py --checkreprodu-los (notas das fixtures). - Os casos golden de executáveis (
tests/fixtures/executables/) são diretórios de código-fonte mais umgolden.jsoncom o stdout/estado de saída do OTP e um padrão de stderr escrito à mão;tests/compiler/executables/run.pyliga e executa cada um sob a matriz de política/driver (CTestexecutables_<case>), eregenerate.py --checkreprodu-los com o OTP (notas dos casos). - A regeneração e as auditorias em direto são explícitas:
-DCLAUSE_OTP_AUDITS=ONetests/compiler/patternmatch/regenerate.py(instruções). Nada atualiza os goldens nem o pin silenciosamente.
Conceção dos testes
O comportamento é testado através da CLI real, dos objetos emitidos, de consumidores nativos ligados e dos goldens do OTP. Os testes unitários dedicados permanecem apenas onde o código-fonte não consegue alcançar o estado, cada um com o seu propósito indicado no teste:
- Orçamentos injetados e falhas de alocação/E/S (
project_limits,project_creation_failure,codegen_limits,codegen_write_failure,runtime_lifecycle_failure, pontos de injeção de falhas em chamadas geradas). - Invariantes de posse privada, de handles inválidos/obsoletos e de reversão no analisador sintático, no grafo de tipos semântico e no backend.
- Validação de palavras em bruto e limites de termos de 32/64 bits
(
runtime_immediate,runtime_term_tag,abi_integers). - Falhas do destino de diagnósticos e o instantâneo estável dos IDs de funcionalidades.
Os casos de capacidades do sistema de ficheiros (ligações, aliases por maiúsculas/minúsculas) relatam testes saltados por caso; nunca substituem a aprovação de um teste completo.
Estado por plataforma e sanitizers
- Execução de código gerado nativo: Windows x64; Linux x86-64. Os resultados de 32 bits e ARM (testes do runtime e goldens ligados de forma cruzada) estão no histórico.
- Apple Silicon: não validado desde que o backend existe.
- ASan, UBSan e LeakSanitizer no compilador e no runtime: Linux
x86-64, uma única configuração Debug combinada
(
-fsanitize=address,undefined -fno-sanitize=vptr -fno-sanitize-recover=undefined), CTest completo comCLAUSE_TEST_TIMEOUT_SCALE=10(o código instrumentado corre várias vezes mais devagar): nenhum relatório dos sanitizers. O compilador, o runtime e os programas de teste são instrumentados; os programas que oclauliga obtêm o runtime do sanitizer a partir de um wrapperclang++noPATH, e o seu código gerado não é instrumentado. Os quatro testes de recusa injetada do anfitrião (codegen_failure_*,runtime_lifecycle_failure,runtime_memory) estão fora do âmbito do ASan: o seuoperator newaborta perante um tamanho impossível em vez de lançar uma exceção. - ThreadSanitizer: Linux x86-64, o mesmo âmbito de instrumentação com
-fsanitize=thread; o CTest completo e os testes de concorrência, cinco vezes cada, não comunicam nenhuma corrida. Também fora do âmbito: os dois testes que substituemoperator new. - Em Windows, o SDK do LLVM pré-compilado continua a entrar em conflito com o
código instrumentado (
annotate_string0 vs 1). - O ASan apenas do runtime passa em Windows com sondas Release,
/EHsc /fsanitize=address,/MT, a biblioteca de importação do ASan e o thunk de runtime estático do Clang, e a DLL do ASan noPATH. - Execuções históricas em macOS arm64 (2026-09-19/20) passaram compilações Debug completas, C++26, ASan+UBSan, apenas do compilador e apenas do runtime para as fases do analisador sintático e dos projetos; são anteriores ao backend.
Benchmarks
Comparação manual de desempenho com o Erlang/OTP. Nunca faz parte do CTest, do
gate de commit nem de check-quality, e só ela precisa de um Erlang/OTP no
anfitrião; os resultados são evidência específica do anfitrião, não resultados
do gate.
make-benchmark.bat # Windows; set JOBS=N to cap parallel builds
make-benchmark.bat --repeat 9 --only bench_gc,bench_msg
make-benchmark.bat --cpus all # unpinned set; default --cpus performance
make benchmark BENCH_ARGS="--baseline HEAD~5" # other hosts
- Ambos configuram e compilam um
claue um runtime Release embuild/benche depois executambenchmarks/run.py(--helplista as suas opções). - Programas:
benchmarks/bench_*.erlcombench_util.erl, compilados sem alterações peloerlce porclau -O2. Cada um cronometra os seus kernels comerlang:monotonic_time/1após uma chamada de aquecimento e imprimeBENCH <name> <nanoseconds>: geração de dados, processamento de dados, recolha de lixo, passagem de mensagens, E/S de ficheiros (num diretório de trabalho temporário vazio embuild/bench/runs, dentro do repositório para que uma exclusão do antivírus para o repositório o abranja), sockets de loopback e bibliotecas (libraries.qlc: transformações de consultas porqlc_pte módulos com a forma dos casos deqlc_SUITE, cronometrados em conjunto). As contagens de iterações fazem cada kernel durar 1-2 s no OTP, pelo que a resolução do temporizador e o ruído do anfitrião permanecem pequenos em comparação; os kernels de sockets aumentam o trabalho por ligação, não o número de sockets. Fora da cronometragem, o aquecimento e as chamadas cronometradas esperam, cada um, até que os processos que lançaram terminem (erroprocesses_leftapós 10 s). Cada kernel executa no seu próprio processo novo, que termina antes de o kernel seguinte começar, pelo que nenhum kernel paga pelos heaps que um anterior fez crescer. - Cada execução de programa tem o seu próprio objeto job de Windows ou sessão POSIX; a execução seguinte começa quando todos os seus processos tiverem terminado, e os restantes ainda vivos 30 s após a saída são terminados e comunicados como falha.
- CPUs: todos os processos de uma execução, tanto do OTP como do Clause,
executam no conjunto
--cpus:performance(por omissão: os núcleos daEfficiencyClassmais elevada em Windows,/sys/devices/cpu_core/cpusou a maiorcpu_capacityem Linux, pelo que são os núcleos P de um CPU híbrido e todos os CPUs nos restantes casos),all, uma lista como0-15ou2,4,6, ou uma máscara hexadecimal como0x5554. Em Windows, o objeto job da execução impõe o limite de afinidade antes de o programa retomar; em Linux, o programa define-o antes deexec; macOS não permite fixar a afinidade e executa sem ela. Tanto o OTP como o Clause iniciam um escalonador online por CPU do conjunto, sem vinculação a CPUs individuais. O cabeçalho do relatório e cada registo do histórico (cpus) indicam o conjunto; as razões de execuções em conjuntos diferentes não são comparáveis. - Sistemas, no mesmo anfitrião numa só execução, intercalados: o OTP com a sua
variante por omissão (JIT), o OTP
-emu_flavor emuquando instalado (o instalador Windows só inclui o JIT, pelo que essas colunas mostramn/a), o Clause HEAD em O2 e com--lto, e um commit anterior do Clause (por omissão: o commit mais recente com pelo menos um dia a mais do que HEAD;--baseline REV,--no-baseline) compilado num worktree em cache embuild/bench-base/<hash>que partilhathirdparty/. - Relatório: por kernel, a mediana de
--repeatexecuções (por omissão 3) em milissegundos com seis casas decimais e a sua dispersão, a variação do Clause O2 em relação a cada sistema (+N%: o Clause é mais rápido, o outro demora mais N%;-N%: o Clause demora mais N%;(Fx)a razão dos tempos) com uma média geométrica,--ltoem relação ao OTP e ao O2, os tempos totais dos programas incluindo o arranque, os tamanhos dos executáveis, as falhas e os tempos esgotados (--timeout, 600 s por execução). Uma execução por omissão mede durante cerca de 15 minutos. - Tamanhos dos executáveis, em bytes: cada programa em
-O2, com--ltoe em-O0(uma compilação adicional apenas medida, nunca executada; ambas omitidas por--no-lto) e a referência em-O2, com uma linha de total e as variações O2 vs O0,--ltovs O2,--ltovs O0 e O2 vs referência (-N%menor); eclauem HEAD e na referência. O histórico guarda-os comosizes_bytes(programs: programa → coluna → bytes,clau:head/baseline→ bytes;nullquando uma compilação falhou). - Histórico:
benchmarks/history/<host>.jsonguarda um registo por dia de execução (data da execução, hash e data do commit de HEAD, medianas do Clause, do OTP e da referência, tamanhos e razões dos tempos do Clauseotp_ratioebaseline.ratiopor kernel),benchmarks/history/reports/<host>/<day>-<hash>.txtos relatórios de texto; uma nova execução no mesmo dia substitui ambos. Os registos e os relatórios executados mais de 183 dias antes do mais recente são eliminados; uma execução com alterações de código-fonte não submetidas é comunicada mas não registada. As tabelas do histórico do relatório mostram as razões dos últimos 8 dias de execução, que continuam comparáveis quando os kernels mudam o seu trabalho; os registos anteriores ao redimensionamento para 1-2 s mantêm apenas as suas razões. O diretório do histórico é ignorado pelo git: fica no anfitrião que o executou. - Listagens: com
--listings, antes de medir, uma execução escreve as listagens--print-asme--print-irde cada programa (combench_util,--entry <program>, para que o código de biblioteca inalcançável fique de fora como no executável) ao lado dos relatórios como<program>.debug.asm/<program>.debug.ll(-O0) e<program>.release.asm/<program>.release.ll(-O2, o código que a colunaclause-o2executa), substituindo as listagens da execução anterior, incluindo com--no-historye alterações não submetidas.--print-iré a IR antes do pipeline do LLVM; os comentários do assembly citam a IR depois dele. Um programa que não compila perde as suas listagens obsoletas.
Histórico
Condensado a partir dos antigos registos por passo (originais no histórico do
Git até ao commit 2777c98). Salvo indicação em contrário: Windows x64, LLVM
23.1.2, pin 21776803ecd1, oráculo OTP 29.1.1 / ERTS 17.1. Os números de testes
são execuções completas do CTest aprovadas, com zero testes saltados.
| Data | Marco | Testes | Unidades de qualidade | Notas |
|---|---|---|---|---|
| 2026-09-19 | Phase VI do analisador sintático (macOS arm64, OTP 29.1 751f87b7, oráculo 29.0.5) | 46 | todas | 344/344 produções testemunhadas; corpus de 10 ficheiros |
| 2026-09-20 | Projetos (macOS arm64) | 64 | todas | Debug, apenas compilador, ASan+UBSan |
| 2026-09-28 | Migração dos testes para fluxos de trabalho da CLI; reparação do gate em Windows | 75 | todas | Stack overflow em parser_hardening corrigido com uma pilha de 8 MiB; Lizard + clang-tidy limpos |
| 2026-09-29 | Steps 1–46 do marco do compilador | 103 | 182 | Apenas compilador 80, apenas runtime 16, ASan do runtime 16 |
| 2026-10-01 – 10-03 | Plano de padrões/guards PG1–PG20 | 104–131 | 189–258 | Revisões 2–4 da ABI; PG15a tornou os goldens independentes do OTP (auditorias opcionais, 131 → 118 testes); encerrado com 19 corpora, 67 634 valores, 1 969 resultados semeados |
| 2026-10-03 | Auditoria do código-fonte do OTP | 125 | 258 | Ficheiros copiados do OTP substituídos por fragmentos locais; uma comparação por janelas de 60 tokens com 4 150 ficheiros Erlang e 1 190 ficheiros C/C++ do OTP não encontrou sobreposição além de um tuplo de inteiros gerado |
| 2026-10-03 | Base do plan 11 step 1 (commit b1a471f, pin 21776803ecd1, Lizard 1.24.0, clang-tidy 22.1.8) | 125 (122 rápido) | 258 | Completo 729 s em série, 85 s com -j 16; 14/14 auditorias; 19/19 corpora; objetos O0/O2 para outros alvos inspecionados em 7 alvos |
| 2026-10-03 | Steps 2, 4: fixtures de programas, impressão de termos | 126–128 | 265 | Seis goldens de programas do OTP; 9 542 goldens de ~w/display |
| 2026-10-04 | Steps 8, 8I: executor de executáveis, heap clássico (phases B, C fechadas) | 138–144 | 272–276 | Completo -j 16 235–370 s |
| 2026-10-04 – 10-05 | Steps 9–20: case, if, lançamentos, catch, try, stack traces, maybe (phase D fechada), recursão, frames e chamadas de cauda | 146–158 | 277–278 | Testes rápidos e afetados em modo completo por passo; completo -j 16 155/155 em 259 s na phase D |
| 2026-10-06 | Steps 21–28: comprehensions (phase E fechada), raízes e recolha, limites de memória e de termos (27A–27E), cópias de grafos | 159–166 | 278–281 | Completo -j 12 105–275 s; o step 27 removeu os limites de memória predefinidos |
| 2026-10-07 | Steps 29–35: records, native records (ABI 6), funs (ABI 7), closures, funs com nome, chamadas dinâmicas (ABI 8) | 167–177 | 283–290 | Completo -j 12 119–152 s |
| 2026-10-09 | Step 63 Linux x86-64 (WSL2 Ubuntu 25.04, glibc 2.41, clang do SDK LLVM 23.1.2, libstdc++ 14, GDB 16.2) | 235 | 338 | CTest completo 235/235 em 161 s; Lizard e clang-tidy limpos em Linux (7 relatórios do analisador em cabeçalhos do Boost ignorados); gate Windows 235/235 com os cabeçalhos verificados |
| 2026-10-09 | Step 64 32 bits: Windows x86 (WoW64, clang-cl) e Linux i386 (chroot Debian 13, clang 19) | 42 + 65 goldens | — | Testes do runtime/ABI 42/42 nativamente em ambos; goldens cross.py 65/65 em ambos (execuções integer_limit só de 64 bits saltadas) |
| 2026-10-09 | Step 65 Linux arm64 e armhf (sysroots Debian 13, qemu-user 9.2) | 42 + 65 goldens | — | Testes do runtime/ABI 42/42 em cada; goldens 64/65 em cada (port_spawn enoent: lacuna do posix_spawn no qemu), limite de execução 900 s |
| 2026-10-10 | Step 67 ASan + UBSan + LeakSanitizer (Linux x86-64) | 235 | — | Nenhum relatório dos sanitizers; quatro testes de recusa injetada do anfitrião fora do âmbito do ASan; CLAUSE_TEST_TIMEOUT_SCALE=10 |
| 2026-10-10 | Step 68 ThreadSanitizer (Linux x86-64) | 233 | — | Uma inversão da ordem de bloqueios corrigida (Executor::clear); depois nenhum relatório no CTest completo nem em 15 testes de concorrência x5 |
| 2026-10-10 | Steps 65A–65C: behaviours, module_info/0,1, imports | 234–236 rápido | 342–344 | Os goldens de lint e de executáveis reproduzem-se com o OTP 29.1.1 |
| 2026-10-11 | Steps 73A–73G parse transforms | 242/243 rápido | — | Falha conhecida de codegen_resource_cli, entretanto desativado |
| 2026-10-12 | Steps 62D1–62E diretório de compilação e caches | 263/264 | todas | CTest completo, falha conhecida de codegen_resource_cli; check-quality-all limpo |
| 2026-10-13 | Steps 58U–58W cache de inferência | 278/279 | todas | CTest completo, falha conhecida de codegen_measurements; check-quality-all limpo |
| 2026-10-14 | Step 41S prim_eval e a nova execução do luerl (H3 fechado) | 299/300 | todas | Ver a base atual |
| 2026-10-17 | Plan 20 OPTM.2 (Term de uma palavra, termos persistentes no local e recuperados) e OPTM.3 (acessores sem verificações) | 330/332 | todas | CTest completo: falha conhecida de codegen_measurements, e library_freshness (OTP do anfitrião) ainda espera os corpos de stub not_implemented que b0e62a38 substituiu; check-quality-all limpo |
| 2026-10-19 | Plan 21 LIB10F ThreadSanitizer (Linux x86-64): goldens de ETS e digraph, runtime_concurrency | 10 | — | Nenhum relatório; ets_portions num só worker revelou uma eliminação libertada em duas porções, corrigida atribuindo a um objeto libertado o custo de um percorrido |
PG = passo do plano de padrões/guards; os registos dos passos do plano 11 estão
arquivados em .agents/00-finished.md.
Clause