Kit de conformidade do DCP-AI¶
Tradução informativa da versão em inglês, atualizada em 02/11/2026. Em caso de divergência, prevalece a versão em inglês. Identificadores, comandos e blocos de código são mantidos sem tradução.
tools/conformance.js executa as suítes declaradas em catalog.json contra os fixtures e
vetores do repositório. O catálogo é versionado (kit_version) e fixa, para cada suíte, os IDs exatos dos
casos que ela deve produzir. O kit só lê fixtures: não gera chaves nem fixtures no checkout e não altera a
canonicalização, as assinaturas, os perfis, os esquemas nem os vetores.
Comandos¶
npm run conformance # every suite (same as node tools/conformance.js)
node tools/conformance.js --list # suites, pinned case counts and inventory
node tools/conformance.js --suite v1.integrity --suite v2.hashes
node tools/conformance.js --report /tmp/conformance.json
node --test tools/conformance/conformance.test.mjs # runner self-tests (temporary copies only)
Os caminhos de fixtures, esquemas e catálogo são resolvidos a partir do script, não do diretório atual.
Execute os comandos acima a partir da raiz do repositório; a partir de outro diretório, invoque o script pelo
caminho absoluto (node /path/to/dcp-ai/tools/conformance.js). --root <dir> aponta o kit para outra cópia
dos fixtures (os autotestes o usam com cópias temporárias).
Contrato¶
| Saída | Significado |
|---|---|
| 0 | Todos os casos selecionados passaram |
| 1 | Pelo menos uma discrepância (um valor ou veredito difere da sua expectativa) |
| 2 | Erro de uso: argumento desconhecido, ID de suíte desconhecido, duplicado ou vazio, --list com --report |
| 3 | Erro de infraestrutura: fixture ausente ou malformado, expectativa malformada, kind de configuração desconhecido, catálogo ausente ou malformado, exceção, um caso fixado que não foi produzido ou um não fixado que foi produzido, ou nenhuma verificação executada |
- Um caso faltante ou sobrando é um erro, então remover um vetor de uma coleção que ainda tem outros não pode reduzir a cobertura silenciosamente. Uma suíte que lança uma exceção falha mesmo depois de ter produzido todos os casos fixados.
- Com
--report, um marcadorincompleteé gravado antes da execução e substituído pelo relatório final; um erro de uso ou de catálogo também substitui o arquivo. Isso vale para os erros que o kit trata e um caminho de relatório gravável: se o Node não iniciar ou o arquivo não puder ser gravado, um arquivo anterior pode permanecer, então quem o consome deve verificar o código de saída e os camposrun.idestatusdo relatório em vez de confiar em um arquivo existente. - O relatório traz
kit(nome, versão, SHA-256 do catálogo),run(uuid, carimbos de tempo, raiz, versão do Node),selection,status,totals(cases,executed,pass,fail,error), cada suíte com sua afirmação, limites e casos (status, ekind:discrepancy,fixture,expectation,exceptionoucatalog), o inventário e os limites globais.
Suítes de teste¶
| Suíte | Casos | Especificação | Esquemas / vetores | O que um resultado aprovado prova |
|---|---|---|---|---|
v1.schema |
7 | DCP-01, DCP-02, DCP-03, BUNDLE.md |
schemas/v1, tests/conformance/examples/*.json |
Apenas validade de esquema |
v1.integrity |
9 | VERIFICATION.md (V1), DCP-03 |
citizenship_bundle.signed.json, keys/public_key.txt, golden_vectors.json#v1_bundle_verification |
Assinatura Ed25519, hash do bundle, raiz de Merkle, hash da intenção, hashes das entradas e cadeia prev_hash de um fixture, comparados com os valores golden; metadados de chave coerentes |
v2.canonicalization |
11 | CANONICALIZATION_PROFILE.md |
golden_vectors.json#canonicalization, #v2_canonicalization, interop_vectors.json#canonicalization |
Bytes dcp-jcs-v1 do canonicalizador de referência |
v2.hashes |
9 | DCP-AI-v2.0 §2.3, §10.3 | golden_vectors.json#hash_vectors, #dual_hash_vectors |
Valores SHA-256 / SHA3-256, hashes duplos e raízes de Merkle duplas |
v2.signed_bundle |
10 | VERIFICATION.md (V2) |
lib/verify.js, bundle construído em memória |
Vereditos do verificador de referência para bundles válidos e adulterados; verificado não é admissão |
v2.secondary_sha3 |
51 | VERIFICATION.md V2-11 e sua errata |
secondary_sha3_vectors.json, lib/verify.js |
Vereditos do verificador de referência sobre os campos secundários SHA3-256 presentes, com um controle por caso rejeitado; não uma cadeia secundária completa |
v2.schema |
4 | DCP-AI-v2.0 | schemas/v2, exemplos *_v2.json |
Apenas validade de esquema |
ext.dcp05_09.schema |
18 | DCP-05 a DCP-09 | schemas/v2, exemplos <record>_v2.json |
Apenas validade de esquema |
ext.dcp05_09.wire |
28 | DCP-05, DCP-08, DCP-09, V2-WIRE-COMPATIBILITY.md |
schemas/v2, registros assinados em memória, interop_vectors.json#domain_separation_all_contexts |
Representação, validade de esquema e assinatura destes registros como camadas separadas; não conformidade funcional |
admission.strict_v1 |
117 | spec/profiles/admission |
admission_vectors.json |
Resultado de admissão e códigos de erro esperados; action_authorized é sempre false |
Limites¶
- Passar em um subconjunto certifica essas verificações sobre estes fixtures e nada mais: não uma implementação completa do DCP, outro SDK nem uma implantação. As suítes de esquema provam apenas validade de esquema; a suíte de esquemas V2 não faz uma implementação V2 sem as suítes de canonicalização, hashes e assinaturas.
verifiedeadmittednunca autorizam uma ação.- Os adaptadores (Express, FastAPI, OpenClaw, o servidor de verificação) não fazem parte do kit.
- Pontos do protocolo, segundo
spec/V2-WIRE-COMPATIBILITY.md: o campo de expiração do DCP-09 (valid_until) e os contextos de assinatura do DCP-05, DCP-08 e DCP-09 estão corrigidos por erratas e são testados porext.dcp05_09.wire. Continuam pendentes de um projeto explícito e versionado, e o kit não os decide: as métricas fracionárias devitality_reportdo DCP-05 (comdcp-jcs-v1só 0 e 1 são representáveis), os direitos em notação de domínio reverso do DCP-08 §4.3 (recusados pelo enumright_type) e os segundos signatários ou confirmações (DCP-05 §4.4, DCP-09 §3.3 e §6.3). Os exemplos do DCP-04, DCP-06 e DCP-07 ficam fora destas erratas.
Inventário¶
Aparece em --list e no relatório, fora dos totais: o kit não o executa, e sua presença não é um teste
aprovado. Os vetores de ataque, os casos-limite de canonicalização e as demais categorias de
interop_vectors.json e os vetores de bundles e mandatos rodam nas suítes de teste dos SDKs.
tests/nist-kat/ contém vetores de resposta conhecida e testes de propriedades, cada um com seu próprio
escopo (veja seu README); eles também rodam nas suítes dos SDKs. O candidato dcp-jcs-v2 é experimental, fica fora do dcp-jcs-v1 e tem sua própria suíte
(tests/interop/candidate/).
Implementações externas¶
tools/conformance-external.js executa um catálogo separado, external-catalog.json
(contrato dcp-ai-conformance-external/1), contra uma implementação que você indica como argv depois de --. A
implementação pode ser escrita em qualquer linguagem: ela lê uma requisição JSON pelo stdin e escreve uma resposta
JSON pelo stdout. O runner precisa do Node 20 ou posterior e usa apenas módulos nativos. O comando, o catálogo e o
relatório acima não mudam.
node tools/conformance-external.js --list
node tools/conformance-external.js --report /tmp/external.json -- node tools/conformance/wrappers/ts-sdk.mjs
node tools/conformance-external.js -- /path/to/python -I tools/conformance/wrappers/python_sdk.py
node tools/conformance-external.js --suite external.digest -- ./my-implementation --its-own-flag
node --test tools/conformance/external.test.mjs
DCP_EXTERNAL_PYTHON=/path/to/python DCP_EXTERNAL_REQUIRE_PYTHON=1 node --test tools/conformance/external.test.mjs
Sem DCP_EXTERNAL_PYTHON, node --test pula o wrapper de Python e informa isso; com
DCP_EXTERNAL_REQUIRE_PYTHON=1, a falta do interpretador é uma falha. O último comando executa todos os testes.
| Suíte | Casos | Vetores |
|---|---|---|
external.dcp-jcs-v1.canonicalize |
30 | golden_vectors.json#canonicalization, #v2_canonicalization; interop_vectors.json#canonicalization e seus 19 edge_cases, 3 dos quais devem ser rejeitados |
external.digest |
8 | golden_vectors.json#hash_vectors; #dual_hash_vectors raw e intent, SHA-256 e SHA3-256 |
Uma troca mínima, o SHA-256 de zero bytes, que você pode executar contra o wrapper de TypeScript:
printf '%s' '{"contract":"dcp-ai-conformance-external/1","run_id":"00000000-0000-4000-8000-000000000000","nonce":"00000000000000000000000000000000","cases":[{"id":"c1","op":"digest","alg":"sha256","input_b64":""}]}' | node tools/conformance/wrappers/ts-sdk.mjs
Uma resposta válida para essa requisição (o wrapper também adiciona resolved_from e runtime):
{"contract":"dcp-ai-conformance-external/1","run_id":"00000000-0000-4000-8000-000000000000","nonce":"00000000000000000000000000000000","implementation":{"name":"example","version":"0.0.1"},"results":[{"id":"c1","status":"ok","hex":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}]}
- Envelopes: a requisição e a resposta são JSON em UTF-8. A resposta é exatamente um documento JSON no stdout, e o processo termina com código 0.
- Requisição:
contract,run_id,nonceecases, cada um comid,op(canonicalizecomprofiledcp-jcs-v1, oudigestcomalgsha256ousha3-256) einput_b64. Os IDs são aleatórios a cada execução e nenhuma expectativa é enviada. A entrada de canonicalize é texto JSON: um vetorinput_jsonexatamente como está no repositório, e um valorinputcomoJSON.stringifyo escreve. - Resposta: os mesmos
contract,run_idenonce;implementation(name,version, e opcionalmenteresolved_fromeruntime, todos declarados pela implementação); eresults, um array com exatamente um objeto por caso, cada um com oiddesse caso e umstatus:okcomoutput_b64(os bytes canônicos) ouhex,rejectedcomcodeparseouprofile,errorcommessage, ouunsupported. Nenhum outro campo é aceito. - Codificações:
input_b64eoutput_b64são base64 RFC 4648 com o alfabeto padrão, padding e sem quebras de linha, na forma canônica;hextem exatamente 64 caracteres hexadecimais minúsculos. - Avaliação: os bytes são comparados exatamente, e um vetor que deve ser rejeitado só passa se for rejeitado. Um
resultado
errorouunsupported, um resultado malformado, ausente, duplicado ou extra, umrun_idounonceobsoleto, uma saída inválida, um código de saída diferente de zero ou um sinal, um timeout e um stdout acima de 4 MiB são erros, nunca um sucesso. Os códigos de saída são os do contrato. - Processo: iniciado sem shell, em seu próprio grupo de processos em POSIX. Um único prazo (
--timeout-ms, padrão 30 000) é medido com um relógio monotônico; depois, SIGTERM, SIGKILL 2 s depois e uma espera limitada de 2 s pelo fechamento dos pipes (senão,cleanup_incomplete). O stderr é mantido até 64 KiB e nunca é interpretado. - O catálogo e os fixtures são validados antes: IDs únicos, ponteiros existentes, expectativas coerentes com os vetores, e cada membro de cada coleção fixado uma vez por operação e algoritmo. Um defeito dá exit 3. O relatório registra os hashes do catálogo, dos fixtures e da requisição, e a identidade declarada pela implementação separada do que o runner observou.
- Relatório: um valor de
--reportausente, que pareça uma opção ou repetido é um erro de uso (exit 2) e nenhum relatório é escrito, porque o caminho é ambíguo. Como no comando acima, um relatório antigo também pode permanecer se o Node não iniciar, o relatório não puder ser escrito ou o runner for encerrado. Verifique sempre o código de saída e, depois, orun.ide ostatusdo relatório. - Wrappers:
wrappers/ts-sdk.mjs(@dcp-ai/sdk;--sdk <path>é opcional) ewrappers/python_sdk.py(odcp_aiinstalado; execute-o com-I). Cada um chama o canonicalizador real uma vez e só informarejected/profilepara a rejeição de números não inteiros documentada do SDK. Os SDKs não têm códigos de erro estáveis, então ela é reconhecida pelo tipo e pela mensagem: se mudarem, uma rejeição correta aparece como erro, nunca como sucesso. A CI executa os dois wrappers. - Limites: um sucesso mostra que o argv executado passa nestes 38 casos, através do parser que ele usa; não é uma
implementação completa de
dcp-jcs-v1nem conformidade DCP, e a identidade é declarada pela implementação. Não é um sandbox: a implementação roda com seus privilégios e seu ambiente, descendentes que saem do grupo de processos (setsid) não são vistos, e no Windows só o filho direto é encerrado.
Wrappers de Go, Rust e WASM¶
Mais três wrappers executam os mesmos 38 casos e o mesmo contrato contra o SDK de Go, o SDK de Rust e a
compilação WASM do SDK de Rust, todos deste checkout. build.mjs os compila em tools/conformance/wrappers/.build/
(ignorado pelo Git); precisa do Go 1.25 ou posterior, do Cargo e do wasm-pack com o target
wasm32-unknown-unknown. Não instala nem publica nenhum pacote de DCP nem muda manifests ou lockfiles do SDK. Sem
--offline, o Cargo e o wasm-pack podem baixar ferramentas de compilação e as dependências fixadas para seus
caches; --offline usa GOPROXY=off, Cargo --offline e wasm-pack --mode no-install, e precisa desses caches
já preenchidos.
node tools/conformance/wrappers/build.mjs all
node tools/conformance/wrappers/build.mjs --offline go rust wasm
node tools/conformance-external.js -- tools/conformance/wrappers/.build/go-wrapper
node tools/conformance-external.js -- tools/conformance/wrappers/.build/rust-target/debug/dcp-ai-conformance-wrapper
node tools/conformance-external.js -- node tools/conformance/wrappers/wasm.mjs
DCP_EXTERNAL_REQUIRE_NATIVE=1 node --test tools/conformance/external-native.test.mjs
- Compilação: o Go compila com
-mod=readonlycontra ogo.mode ogo.sumdo wrapper, cujas versões são um subconjunto das do próprio SDK; o Cargo compila com--locked, o wrapper nativo com seuCargo.lock(uma cópia do lock do SDK, resolvida sem rede, com as mesmas versões fixadas) e o artefato WASM com oCargo.lockdo SDK.--offlineusa apenas os caches locais. Nenhum manifest ou lockfile do SDK muda. - Go (
wrappers/go): a entrada deve ser UTF-8 (verificado primeiro, porqueencoding/jsonsubstituiria os bytes inválidos), depoisjson.Unmarshaleminterface{}, como faz o próprio teste de interop do SDK, e uma única chamada av2.CanonicalizeV2; só a rejeição documentada (non-integer float at,non-finite float at) érejected/profile. Digests:v2.SHA256Hex,v2.SHA3256Hex. A versão é informada como o checkout local. - Rust (
wrappers/rust): decodificação UTF-8 fatal,serde_json::from_stre uma única chamada adcp_ai::v2::canonicalize::canonicalize_v2; só a rejeição documentada (Non-integer number in V2 canonical form:,Non-finite number in V2 canonical form:, após prefixos de caminho) érejected/profile. Digests:sha256_hex,sha3_256_hex. A versão éDCP_SDK_VERSION. - WASM (
wrappers/wasm.mjs): carrega o.wasmreal que owasm-packcompilou a partir desdks/rustcom a featurewasm(--target web) e informa seu SHA-256. O texto JSON cru vai para uma única chamada dewasm_canonicalize_v2, semJSON.parsenemJSON.stringifyem JavaScript antes da chamada; depois, a entrada e a saída só são inspecionadas para marcar a ambiguidade, sem recalcular bytes. Essa exportação informa os erros dentro do próprio resultado como{"error": "…"}, que uma entrada válida também pode produzir, então um resultado{"error": string}de uma única chave é umerrorambíguo quando a entrada é ela mesma um objeto raiz cuja única chave éerror(qualquer que seja seu valor), e caso contrário só é uma rejeição para as mensagens documentadas. As exportações de digest recebem texto: as 8 entradas de digest são texto, e bytes que não são UTF-8 são umerror, nunca substituídos. - Erros: nos três, uma requisição com um tipo errado (por exemplo
input_b64numérico ounull, oucasesque não é um array) é inválida e o wrapper termina com 2; qualquer erro diferente da rejeição documentada éerror. Em Rust e WASM, a rejeição documentada de números é reconhecida em uma única passada linear, sem expressões regulares com backtracking; uma mensagem de mais de 1 MiB em UTF-8 é umerror, nunca uma rejeição (o limite se aplica a esse classificador, não aos erros de parse). SemDCP_EXTERNAL_REQUIRE_NATIVE=1,node --testpula o que não está compilado e informa isso; com ela, a falta de uma ferramenta ou de um artefato é uma falha. A CI compila os três wrappers a partir do checkout e executa os 38 casos com cada um, então lá os cinco wrappers são obrigatórios. - Limites: o wrapper WASM chama as exportações cruas do wasm-bindgen hospedadas no Node: não cobre a API
JavaScript do pacote
@dcp-ai/wasm(comoDcpClient) nem um navegador. A classificação das rejeições depende do texto das mensagens, porque os SDKs não têm códigos de erro estáveis, e, via WASM, uma entrada raiz{"error": …}de uma única chave só é um erro ambíguo quando a exportação devolve o envelope{"error": string}({"error":5}continuaok). Um sucesso mostra que estes 38 casos passam com cada wrapper, nada mais.
Catálogo de evidência: Merkle e verificação de assinaturas¶
--catalog evidence seleciona um catálogo opcional, external-evidence-catalog.json
(contrato dcp-ai-conformance-external/2, 241 casos), executado contra o mesmo tipo de argv. O catálogo padrão,
o contrato /1 e seus 38 casos não mudam; o contract do catálogo decide como ele é carregado e julgado. Os
cinco wrappers aceitam os dois contratos e respondem com o contrato da requisição. Só são usados fixtures
públicos versionados: nenhuma chave é gerada e nada é assinado.
node tools/conformance-external.js --catalog evidence --list
node tools/conformance-external.js --catalog evidence --assessment verdict --report /tmp/evidence-ts.json -- node tools/conformance/wrappers/ts-sdk.mjs --sdk sdks/typescript/dist/index.js
node tools/conformance-external.js --catalog evidence --assessment verdict -- /path/to/python -I tools/conformance/wrappers/python_sdk.py
node tools/conformance-external.js --catalog evidence --assessment verdict -- tools/conformance/wrappers/.build/go-wrapper
node tools/conformance-external.js --catalog evidence --assessment verdict -- tools/conformance/wrappers/.build/rust-target/debug/dcp-ai-conformance-wrapper
node tools/conformance-external.js --catalog evidence --assessment verdict -- node tools/conformance/wrappers/wasm.mjs
DCP_EXTERNAL_PYTHON=/path/to/python DCP_EXTERNAL_REQUIRE_PYTHON=1 DCP_EXTERNAL_REQUIRE_NATIVE=1 node --test tools/conformance/external-evidence.test.mjs
| Suíte | Casos | Vetores |
|---|---|---|
external.merkle.dual_root |
6 | tests/conformance/v2/merkle_vectors.json: 1, 2, 3 e 5 folhas e folhas reordenadas (spec/VERIFICATION.md V2-11), geradas offline com a biblioteca padrão do Python |
external.signature.composite |
24 | interop_vectors.json: assinaturas compostas e só clássicas, seus ataques versionados e alterações determinísticas de cada positivo |
external.v2.bundle_vectors |
131 | bundle_vectors.json: o bundle assinado, suas 38 mutações versionadas, 9 bundles aceitos e 79 rejeitados construídos à parte, o bundle de rotina só clássico em 4 modos |
external.v2.secondary_sha3 |
80 | secondary_sha3_vectors.json: casos aceitos e rejeitados e o controle versionado de cada caso rejeitado |
- Operações:
dual_merkle_rootrecebeleaves, um array não vazio de{sha256, sha3_256}com strings hexadecimais de 64 caracteres em minúsculas, e respondeokcomsha256esha3_256(64 hex em minúsculas).composite_verifyrecebecontext,payload_b64(os bytes canônicos do payload),composite_sigcomo está versionada,classical_public_key_b64epq_public_key_b64(ounull), e respondeokcomvalideclassical_valid(booleanos) epq_valid(booleano ounull).verify_signed_bundle_v2recebebundle_b64(o JSON do bundle assinado),policy(um objeto de política do verificador) everification_time(RFC 3339 comZou um deslocamento), e respondeokcomverified(booleano) eerrors(um array de strings). Uma requisição com formato errado (uma folha vazia ou em maiúsculas, uma folha que não é string, um horário sem fuso, um campo desconhecido) faz o wrapper sair com 2. - Julgamento: os casos compostos comparam só os campos que o fixture fixa; o veredito de um bundle deve
coincidir, e uma rejeição deve conter o
error_containsversionado (sem diferenciar maiúsculas, sobre os erros unidos).verified: truecom erros é um errocontradictory_result.rejectedcomcodeparsefalha, porque toda entrada versionada pode ser analisada;erroreunsupportednunca são um sucesso. - Controles: um caso negativo só conta se seu controle passou; caso contrário, é
control_failed, um erro. O bundle assinado base controla suas 38 mutações; o positivo do mesmo payload controla suas alterações e os ataques versionados; um modo válido do bundle só clássico controla seus modos que rejeitam; cada caso secundário rejeitado tem seu controle versionado. Os 79must_reject_bundlesnão têm controle por caso: só contam se a base e os 9 bundles aceitos passam (um controle no nível da suíte, uma garantia mais fraca) e são julgados pelo seuerror_containsversionado. O relatório dá para cada caso seusource, seuinput_sha256e seuscontrols. - Assinatura PQ ausente: diante de uma assinatura
pq_over_classicalsem parte PQ,composite_verifydo Rust devolve um erro e a exportação WASM o erro em bandaSignature error: pq_over_classical binding requires PQ signature. Esses dois wrappers o reportam comorejectedcomcodemissing_pq_signature, só para esse erro exato e só quando a entrada tem esse binding epq: null. O runner só o aceita onde o fixture fixa apenasvalid: false(stripping_pq_removal) e seu controle positivo passou; o mesmo código diante de uma assinatura válida ou de qualquer outro negativo falha. TypeScript, Python e Go respondem a esse caso com booleanos. - As alterações do payload mudam o último caractere do primeiro valor string do payload canônico, de modo que o payload continua sendo JSON canônico válido (a exportação WASM recebe o JSON do payload) e um erro do analisador nunca é contado como uma falha criptográfica.
- Horário: cada caso de bundle envia
verification_time: 2026-10-22T00:00:00Z, dentro da janela de validade do bundle base e de cada bundle que deve ser verificado (alguns negativos estão expirados ou ainda não são válidos nesse instante de propósito), ou o horário versionado dos vetores secundários. TypeScript passa{ now }, Pythonnow_ms, GoVerifySignedBundleV2Ate Rustverify_signed_bundle_v2_at. A exportação WASM lêDate.now, então o wrapper WASM substituiDate.nowpor esse instante só durante a chamada síncrona e o restaura emfinally, também quando a chamada lança uma exceção; seuruntimeinforma isso. Os self-tests mostram que cada wrapper rejeita o bundle base em 2020-01-01, o aceita em 2026-10-22 e o rejeita em 2100-01-01, e a restauração após uma exceção. - Merkle via WASM: o wrapper usa o
wasm_dual_merkle_rootcompilado a partir deste checkout, que delega ao núcleo de Rust; o helper publicado no@dcp-ai/wasm2.1.1 e anteriores falha nos casos de várias folhas (veja o CHANGELOG). - V2-2 e a redação comprometida: os verificadores dos SDKs na
mainexecutam a V2-2 primeiro, então 16 das 146 rejeições que trazem umerror_contains(7 linhasmust_rejectde codificação de assinaturas e 9must_reject_bundles) agora recebem um diagnóstico de esquema em vez da redação da verificação mais profunda. Comlegacy, cada wrapper de SDK passa portanto em 225 casos e falha nesses 16 como discrepâncias de redação com o veredito correto, o que não é um sucesso; comverdictos 241 passam, 130 com redaçãomatchede esses 16 comdiffers. A CI avalia os cinco wrappers de SDK comverdict. Os fixtures, suas stringserror_containse a avaliação padrão não mudam. - Self-tests:
external-evidence.test.mjsexecuta os 241 casos com os cinco wrappers, a prova do relógio, requisições malformadas e uma implementação falsa construída a partir das respostas reais do wrapper de TypeScript: verificar tudo, rejeitar tudo, resultados contraditórios, um texto de erro errado, uma redução Merkle que ignora a ordem ou que faz o hash do texto hexadecimal, uma base que falha,missing_pq_signatureno lugar certo e fora dele, e erros ouunsupportednos negativos. Fixtures e catálogos adulterados são erros de infraestrutura (saída 3). O tempo limite padrão deste catálogo é de 300 000 ms (--timeout-ms). Com as duas variáveisREQUIRE, um wrapper ausente falha em vez de ser pulado; a CI executa os cinco. Em cada execução com os wrappers as duas avaliações são verificadas:legacydeve falhar exatamente as 16 linhas acima como discrepâncias de redação, everdictdeve passar nas 241. - Limites: um sucesso mostra que o argv executado passa nestes 241 casos, nada mais. A política é
default_verifier_policycom osverifier_policy_overridesversionados de cada caso, mais os 4 modos do bundle só clássico; nenhuma outra política é testada.composite_verifyé uma primitiva com o binding e as chaves dados, e o veredito de um bundle não é admissão, confiança no principal nem autorização de uma ação.stripping_pq_with_downgradeé julgado porclassical_validepq_valid; rejeitá-lo cabe a uma políticahybrid_required. Os campos secundários são verificados onde estão presentes, então um sucesso não mostra uma cadeia secundária completa. Via WASM, o horário é o relógio do host substituído. As stringserror_containssão a redação de diagnóstico dos SDKs, não são normativas:spec/VERIFICATION.mdnão define códigos de erro. Um sucesso nesses 146 casos mostra concordância com essa redação; um verificador com os mesmos veredictos e outras mensagens falha neles, e essa falha por si só não mostra um veredito errado. A avaliação por veredito julga esses casos apenas pelo veredito.
Avaliação por veredito¶
spec/VERIFICATION.md define quando um bundle não é verificado, não a redação dos seus erros. --assessment verdict
julga este catálogo apenas pelos vereditos, para implementações com mensagens próprias. Sem a opção, ou com
--assessment legacy, o julgamento, o relatório e os códigos de saída são exatamente os descritos acima. A opção só
se aplica a um catálogo /2, o versionado ou um arquivo próprio; com o catálogo /1 ou /3 é um erro de uso,
inclusive legacy, porque seus códigos fazem parte do contrato ou são normativos.
node tools/conformance-external.js --catalog evidence --assessment verdict --list
node tools/conformance-external.js --catalog evidence --assessment verdict --report /tmp/evidence-verdict.json -- ./my-implementation
DCP_EXTERNAL_PYTHON=/path/to/python DCP_EXTERNAL_REQUIRE_PYTHON=1 DCP_EXTERNAL_REQUIRE_NATIVE=1 node --test tools/conformance/external-evidence-assessment.test.mjs
- O que muda: apenas as 146 rejeições que trazem um
error_contains(38 mutações, 79 bundles construídos à parte e 29 casos secundários). Cada uma passa quando seu resultado éok, bem formado e não contraditório, dizverified: falsee seus controles passaram na mesma execução; as mensagens não são julgadas. Todas as demais regras são as do julgamento anterior, controles incluídos. Com as mesmas respostas, um caso que passa comlegacypassa comverdict, e todo caso fora dessas 146 recebe o mesmo status e o mesmo tipo. - Âncoras e premissas: cada um desses casos indica seu passo de
spec/VERIFICATION.md(anchor): ospec_stepdos vetores de bundle (V2-1 a V2-14), ou V2-11 e o campo da errata do grupo secundário (audit_merkle_root_secondary,prev_hash_secondaryouintent_hash_secondary). Todo controle deve ser um positivo simples: espera-se que verifique (ou que seja válido), semerror_containse sem controles próprios, de modo que a avaliação nunca muda o resultado de um controle. Ambas as coisas são verificadas antes da execução; um plano que não as cumpre dá saída 3 comverdict(comlegacyainda pode passar, por exemplo com um--rootpróprio), e a propriedade acima só vale para planos válidos nas duas avaliações. - Diagnóstico: a redação de uma rejeição que passa é informada como
matched(contém oerror_containsversionado),differsouno_message(errors: []). Qualquer outro resultado énot_evaluated, com seureason:run_error,missing,duplicate,malformed_result,implementation,unsupported,rejected,contradictory_result,wrong_verdictoucontrol_failed. Um veredito errado nunca passa, qualquer que seja sua mensagem, e a redação nunca muda um status, um total nem o código de saída. - Relatório:
kit.contractcontinua/2; o relatório acrescentaassessment(seuschemaédcp-ai-conformance-assessment/1, à parte do contrato do wire) ediagnostic_totals. Seusclaimelimitsindicam o que esta avaliação verifica, definidos pelo runner para cada suite independentemente da prosa do catálogo; essa prosa é mantida literal emcatalog_claimecatalog_limitse não é um resultado verificado. Cada um dos 146 casos mostraexpect: {"verified": false}, suaanchore seudiagnostic. Um relatório legacy não tem nenhum dos campos novos (assessment,diagnostic_totals,catalog_claim,catalog_limits,anchor,diagnostic), e seusclaim,limitseexpect(comerror_contains) ficam como estavam.--listcom--assessmentindica o modo; sem ela, sua saída não muda. - Códigos de saída e atualização: os do contrato. Só o status
pass(saída 0) significa que a execução passou: os diagnósticos de uma execução com statusfailouerror, por exemplo com um resultado a mais, são detalhe parcial, nunca conformidade. Todo erro de--assessment(um valor desconhecido, repetido ou ausente, um catálogo/1ou/3, uma âncora ausente) vem depois do marcador, então substitui um relatório anterior por um erro novo com umrun.idnovo; só as exceções descritas para o comando não deixam relatório. - Self-tests:
external-evidence-assessment.test.mjsexecuta nas duas avaliações um fake construído com as respostas reais do wrapper de TypeScript: vereditos corretos com a mensagem esperada, uma neutra ou nenhuma; vereditos errados com a mensagem esperada; verificar ou rejeitar tudo; resultados com erro,unsupported, ausentes, duplicados, malformados, rejeitados e a mais; controles com falha, uma execução com falha e um timeout; cada suite selecionada sozinha; a propriedade acima em todos os modos, incluídos um Merkle que ignora a ordem, a antiga promoção do nó ímpar emissing_pq_signatureno lugar certo e fora dele; âncoras e premissas; relatórios atualizados sobre um sucesso anterior; formas do relatório e--list. Também executa os 241 casos com os cinco wrappers comverdict; a CI o executa com todos os wrappers obrigatórios. - Limites: um sucesso com
verdictmostra vereditos corretos nesses casos, com a argv executada e com as mesmas políticas; não avalia se as mensagens são exatas ou úteis. O contrato do wire/2, o catálogo, os fixtures e os wrappers não mudam.
Diagnóstico do limite de esquemas (opcional)¶
O catálogo separado external-schema-catalog.json usa o contrato /2 para 15 casos do novo corpus de fechamento de esquemas. Preserva a expectativa normativa V2-2: um membro desconhecido em um objeto fechado deve ser rejeitado mesmo quando seus hashes e assinaturas continuam válidos. A base e as extensões permitidas são controles positivos; uma extensão assinada desatualizada é um negativo distinto de integridade. Este diagnóstico não altera os 241 casos do catálogo de evidências padrão.
node tools/conformance-external.js --catalog tools/conformance/external-schema-catalog.json --assessment verdict --list
node tools/conformance-external.js --catalog tools/conformance/external-schema-catalog.json --assessment verdict --report /tmp/schema-diagnostic.json -- ./my-implementation
node --test tools/conformance/external-schema.test.mjs
Os verificadores dos SDKs na main executam a V2-2, e os cinco wrappers de SDK passam nesses 15 casos; uma implementação que falha continua sendo uma falha, nunca uma exceção aceita. schema-boundary.js relata separadamente a validação de esquemas de referência, uma verificação de integridade limitada a este corpus finito e a composição de esquema com SDK TypeScript no instante do corpus. A composição passar não prova que o SDK sozinho aplica V2-2; também não é a API de referência executada com relógio injetado. O helper de integridade não é um verificador normativo geral. Os autotestes exercitam o diagnóstico, seus controles e expectativas; sua aprovação não certifica a conformidade dos SDKs. Veja o mapa de cobertura e o guia do implementador.
Catálogo de validação de esquemas (V2-2, opt-in)¶
external-schema-validation-catalog.json usa o contrato /2 para os 57 casos assinados de wiring_cases.json, cada um fixado por ID: 13 positivos e 44 negativos. Cada negativo só conta quando o caso base é verificado na mesma execução, e cada caso indica seu passo de spec/VERIFICATION.md (de V2-1 a V2-14). Um caso guardado como texto é enviado exatamente com esses bytes. Só os vereditos são julgados: nenhum caso traz um error_contains, então legacy e verdict os julgam igual. Os catálogos padrão não mudam.
node tools/conformance-external.js --catalog tools/conformance/external-schema-validation-catalog.json --assessment verdict --list
node tools/conformance-external.js --catalog tools/conformance/external-schema-validation-catalog.json --assessment verdict --report /tmp/schema-validation.json -- ./my-implementation
node --test tools/conformance/external-schema-validation.test.mjs
Os autotestes verificam que o kit constrói o mesmo plano que o leitor do corpus de tools/schema-ir/, a integridade do catálogo e do corpus (um ID ausente, sobrando ou duplicado, um caso dado nas duas formas, uma base que não é positiva) e os controles do executor: aceitar tudo falha exatamente nos 44 negativos, rejeitar tudo não conta nenhum, um verificador que ignora uma restrição falha exatamente naquele caso, e resultados ausentes, duplicados ou malformados são erros. A CI executa os autotestes e o catálogo com os cinco wrappers de SDK, todos obrigatórios. Passar cobre estes 57 casos com sua política e instante de verificação; não é a conformidade V2 completa.
Catálogo de políticas do verificador (opt-in)¶
external-policy-catalog.json usa o contrato /2 para 74 casos com instante fixo: 10 controles positivos, 24 casos de PQ presente inválida em quatro modos solicitados, 14 casos de listas de algoritmos e advisories e 26 casos de tier. O catálogo de evidências padrão permanece inalterado. Cada negativo exige que seu controle positivo passe; a redação do diagnóstico não é avaliada.
node tools/conformance-external.js --catalog tools/conformance/external-policy-catalog.json --assessment verdict --list
node tools/conformance-external.js --catalog tools/conformance/external-policy-catalog.json --assessment verdict --report /tmp/policy-conformance.json -- ./my-implementation
node --test tools/conformance/external-policy.test.mjs
O positivo híbrido routine alcança classical_only efetivo; o positivo standard eleva essa solicitação a hybrid_preferred. A derivação registrada de tier e modo é explicativa, não uma avaliação dos campos do resultado. Os casos de tier usam bundles versionados assinados separadamente, não pares de alteração única. As exclusões de algoritmos clássicos sob pq_only continuam omitidas sem veredicto esperado até esclarecer a interpretação. Veja as perguntas do corpus e o mapa de cobertura para os limites restantes. CI executa os autotestes do corpus e runner e o catálogo pelos cinco wrappers SDK; passar comprova somente esses casos.
Catálogo estrutural (opt-in)¶
external-structural-catalog.json executa 16 casos com tempo fixo por meio de /2 e hybrid_preferred efetivo: dois controles positivos e 14 negativos estruturais. Cada negativo depende do controle base, e o caso de sessão invertida também depende de seu gêmeo positivo. Os catálogos padrão permanecem iguais.
node tools/conformance-external.js --catalog tools/conformance/external-structural-catalog.json --assessment verdict --list
node tools/conformance-external.js --catalog tools/conformance/external-structural-catalog.json --assessment verdict --report /tmp/structural-conformance.json -- ./my-implementation
node --test tools/conformance/external-structural.test.mjs
Apenas os veredictos são avaliados. O corpus registra a procedência das assinaturas e os limites de isolamento, especialmente a evidência obsoleta do payload com fração e a inexistência de raiz válida para um intervalo invertido. A CI executa os autotestes do corpus e runner e os cinco wrappers SDK. A aprovação se limita a esses casos e a essa política; não comprova conformidade V2 completa.
Catálogo de admissão: admissão strict-v1¶
--catalog admission seleciona um segundo catálogo opt-in, external-admission-catalog.json
(contrato dcp-ai-conformance-external/3, 140 casos), executado contra o mesmo tipo de argv. Ele julga a decisão de
admissão de spec/profiles/admission sobre o
admission_vectors.json versionado, que o catálogo fixa por SHA-256
junto com bundle_vectors.json. Os contratos /1 e /2 e seus catálogos não mudam. Os wrappers de TypeScript, Python,
Go e Rust respondem a /3 por meio do seu SDK; o build WASM não tem API de admissão, então o seu wrapper recusa /3
(exit 2) e nada o emula.
node tools/conformance-external.js --catalog admission --list
node tools/conformance-external.js --catalog admission --report /tmp/admission-ts.json -- node tools/conformance/wrappers/ts-sdk.mjs --sdk sdks/typescript/dist/index.js
node tools/conformance-external.js --catalog admission -- /path/to/python -I tools/conformance/wrappers/python_sdk.py
node tools/conformance-external.js --catalog admission -- tools/conformance/wrappers/.build/go-wrapper
node tools/conformance-external.js --catalog admission -- tools/conformance/wrappers/.build/rust-target/debug/dcp-ai-conformance-wrapper
node --test tools/conformance/external-admission.test.mjs
DCP_EXTERNAL_PYTHON=/path/to/python DCP_EXTERNAL_REQUIRE_PYTHON=1 DCP_EXTERNAL_REQUIRE_NATIVE=1 node --test tools/conformance/external-admission-wrappers.test.mjs
| Suíte | Casos | Origem |
|---|---|---|
external.admission.outcomes |
65 | Os vetores de resultado de admission_vectors.json |
external.admission.config |
71 | As suas 49 configurações rejeitadas, os seus 2 perfis aceitos com seus máximos, e o carregamento dos 14 conjuntos de confiança e 6 perfis que os vetores usam |
external.admission.composed |
4 | Escritos no catálogo a partir das entradas dos vetores: um perfil sem conjunto de confiança, um perfil com uma política de verificador de quem chama, e duas composições cujos códigos uma ordem alfabética deslocaria |
- Operações:
admit_signed_bundle_v2recebebundle_b64,now,profile,trust_set,verifier_policyerevocation, sempre os seis;load_admission_configrecebekind(trust_setouprofile) econfig. nowé exatamenteYYYY-MM-DDTHH:mm:ss.sssZ, uma data real dos anos 0001 a 9999. É só o intervalo deste transporte: não muda nenhum timestamp do protocolo.revocationénullsem perfil,{"state": "unavailable"}(sem snapshot, R1) ou{"state": "snapshot", "snapshot": {…}}com um objeto, completo ou não, que o SDK julga. Ela é dada exatamente quando há perfil.profile,trust_seteverifier_policysão objetos ounull. O conjunto de confiança e o perfil são a configuração do operador, dada fora de banda na requisição, nunca tirada do bundle. Sem perfil, a requisição leva uma política de verificador completa: os 14 campos dedefault_verifier_policy, maisrequire_session_expiry: false,require_audience_binding: falseemax_session_duration_seconds: 0. Com perfil não leva nenhuma, exceto no caso que verifica a sua recusa.- Uma requisição de outra forma faz o wrapper sair com 2 antes de chamar o SDK.
- Respostas:
okcom exatamenteverified,principal_trust,profile,profile_compliance,admitted,action_authorized,recorded_decision,trust_set_version,codes(os códigos deerrors, na ordem emitida, com as repetições) everification_verified; para uma configuração,accepted: true, e para um perfil os seus dois máximos.rejectedleva um códigoCONFIG_*, somente quando o SDK lançou o seu erro de configuração tipado.erroreunsupportednunca são um sucesso. - Julgamento, nesta ordem:
- os tipos dos campos (
malformed_result); - as regras que decorrem de spec/profiles/admission (
contradictory_result):action_authorizedéfalse;admittedvale exatamente quando nenhum código foi acrescentado; a confiança no principal só é avaliada com um conjunto de confiança e um bundle verificado; - os campos exatos e o conjunto de códigos;
- a ordem da sequência bruta pelas fases dos §5.1 e §5.2, com as paradas de P1, T1, R1 e R2 (
order); - as repetições (
cardinality): só P4, T2, R4 e R5, que se aplicam a vários componentes ou sujeitos, podem repetir o seu código.
Uma configuração rejeitada passa com um dos seus allowed_codes: o seu próprio código, ou qualquer um dos dois
aplicáveis nos três conjuntos de confiança com dois problemas (§2.2). Os perfis são julgados pelos seus máximos
efetivos (§4.1).
- Controles: um negativo só conta se os seus controles passaram, de forma transitiva; caso contrário é
control_failed, um erro.
- 29 negativos de resultado são controlados pelo positivo do seu próprio bundle.
- 19 não têm positivo no seu bundle e são controlados no nível da suíte, uma garantia mais fraca.
- As rejeições de configuração são controladas pelo carregamento de um conjunto de confiança ou de um perfil válido.
- Os casos compostos são controlados pelos vetores que compõem.
--suite executa também os controles de que um caso selecionado precisa e os informa (controls_included,
included_for_controls).
- Processo e erros: como em /1 e /2 (run id, nonce, ids de caso aleatórios, grupo de processos e limites); o
timeout padrão deste catálogo é de 300 000 ms. Uma falha ao iniciar, um exit diferente de zero, um sinal, um timeout,
ids obsoletos, ou um resultado malformado, ausente, duplicado ou extra é um erro, nunca uma rejeição nem um “não
admitido”. O catálogo e as suas fixtures são validados ao carregar (hashes fixados, chaves e tipos exatos, cada
expectativa coerente com o texto); um defeito é exit 3.
- Wrappers: uma chamada por caso à função combinada ou aos carregadores do SDK, com o now da requisição, nunca o
relógio do sistema: admitSignedBundleV2, createPrincipalTrustStore e resolveStrictV1Profile (TypeScript);
admit_signed_bundle_v2, create_principal_trust_store e resolve_strict_v1_profile (Python);
AdmitSignedBundleV2, NewPrincipalTrustStore e ResolveStrictV1Profile (Go); admit_signed_bundle_v2,
PrincipalTrustStore::from_json e resolve_strict_v1_profile (Rust), com os provedores Ed25519 e ML-DSA-65. Só o erro
tipado é uma rejeição: AdmissionConfigError (TypeScript, Python, Rust) ou *AdmissionConfigError por meio de
errors.As (Go). DCP_CONFORMANCE_WRAPPER_FAULT serve só aos autotestes e só pode transformar uma resposta em erro.
- Autotestes:
- external-admission.test.mjs julga respostas sintéticas construídas a partir das expectativas do próprio catálogo,
sem SDK: decisões erradas, ordem, cardinalidade, códigos de configuração, falhas de infraestrutura, e catálogos e
fixtures adulterados.
- external-admission-wrappers.test.mjs executa os quatro wrappers com os seus SDKs: os 140 casos de cada um, o
relógio da requisição (um caso em três instantes), requisições malformadas, falhas injetadas, uma implementação que
não consegue carregar, a recusa do WASM, e um SDK que tira a confiança do bundle, por meio do TypeScript.
A CI executa os dois, com os quatro wrappers obrigatórios.
- Limites:
- O que um sucesso mostra. O argv executado passa nestes 140 casos, nada mais. A admissão nunca é uma autorização:
action_authorized é sempre false.
- Uma projeção. A resposta é uma projeção do resultado de admissão. A verificação incluída (os seus erros, avisos,
detalhes, signer_keys, modo e nível) não é julgada; verification_verified é informado pela própria implementação.
- Erros tipados. Uma rejeição é julgada pelo seu código. Se ela veio do erro tipado do SDK, quem vê é o wrapper,
não o runner.
- Garantias mais fracas. Os 19 controles no nível da suíte, e as 4 expectativas compostas, que estão escritas no
catálogo e não nos vetores.
- Fora deste catálogo. Os adaptadores, as fontes de confiança e de revogação, TLS, os inquilinos, o cache e o uso
único. O corpus são os vetores versionados e estas quatro composições, não qualquer entrada.
Linha de base de desempenho¶
tools/conformance-perf.js mede o verificador V2 normativo dos cinco SDKs deste checkout com os mesmos bytes de
entrada, a mesma política e o mesmo instante de verificação (contrato dcp-ai-perf/1). É uma linha de base local,
pequena e reproduzível; não é um benchmark deste harness, nem um ranking de segurança, nem um requisito de velocidade:
a CI nunca verifica uma velocidade.
node tools/conformance-perf.js --list
node tools/conformance-perf.js --offline --warmup 5 --samples 20 --rounds 1 --python /path/to/python --report /tmp/perf-sanity.json
node tools/conformance-perf.js --no-build --warmup 20 --samples 100 --rounds 3 --python /path/to/python --report /tmp/perf.json
DCP_PERF_PYTHON=/path/to/python DCP_EXTERNAL_REQUIRE_PYTHON=1 DCP_EXTERNAL_REQUIRE_NATIVE=1 node --test tools/conformance/perf.test.mjs
- Cargas: seis bundles versionados, lidos e nunca assinados de novo, com
default_verifier_policyem 2026-10-22T00:00:00Z:hybrid_ok,classical_sig_invalid(a assinatura Ed25519 do RPR),pq_sig_invalid(a assinatura ML-DSA-65 do bundle),secondary_root_ok,secondary_root_wrongesecondary_all_ok. O par secundário compartilha os artefatos base e as entradas, e difere emaudit_merkle_root_secondarydo manifest e na assinatura do bundle que o cobre (manifest_hash, os dois valores de assinatura,signature.hash_alg): não é um experimento que isole o custo de um único campo. - O que é medido, por chamada, em um processo por SDK, sem iniciar um processo por amostra: TypeScript
JSON.parseeawait verifySignedBundleV2(odistlocal, não um pacote publicado); Pythonjson.loadseawait verify_signed_bundle_v2em um único loopasynciopersistente (odcp_aido checkout); GoVerifySignedBundleV2At, cuja API de bytes inclui o parsing; Rustserde_json::from_sliceeverify_signed_bundle_v2_at(um example em release); WASM a decodificação,wasm_verify_signed_bundle_v2eJSON.parsedo seu resultado, comDate.nowsubstituído pelo instante de verificação durante a chamada, com os custos da fronteira pública incluídos e nomeados. Os registries e as políticas são preparados uma vez; nenhum resultado é guardado em cache. - Verificações: as chamadas de aquecimento e as medidas rodam em round-robin sobre as cargas, e cada chamada é
verificada: o veredito esperado, nenhum erro em um positivo, erros em um negativo. Uma verificação que falha
interrompe esse filho: ele responde
check_failedsem tempos e termina com saída 0, e o runner informa a execução como falha (sua saída 1). O relatório mantém os resultados dos demais filhos e então não é uma linha de base (baseline: false); nunca se apresenta nenhum tempo do filho que falhou. Um filho responde ou um sucesso com todas as amostras ou essa falha; o runner verifica o contrato, a identidade da execução, o SDK e a entrada, as contagens, e que cada amostra seja um inteiro seguro positivo de nanossegundos. - Estatísticas: todas as amostras são mantidas, em ordem; por SDK e carga,
n,min, a mediana (a média dos dois valores centrais para umnpar), p90 e p99 por posto mais próximo,maxe o IQR. Sem ranking e sem porcentagens atribuídas; um negativo pode parar na sua primeira verificação que falha, e seuerrors_firsté só diagnóstico. - Procedência: por padrão a ferramenta compila o que mede (o
distde TypeScript, o filho Go com-osob.build, o example de Rust e o WASM em release, o WASM na sua própria pasta) sob um único prazo de build limitado. Depois registra, para cada SDK selecionado, as árvores de fonte, manifests e locks, filhos, hashes de artefatos (todo odist, o.wasme seu glue JS, os binários), versões de ferramentas e opções de build, e não mede nada se faltar algum.--no-buildrecalcula tudo isso para os SDKs pedidos e rejeita qualquer diferença ou lacuna; a hora, o commit e o indicador dirty são informativos. Cada filho informa o que carregou (TypeScript: cada import resolvido a partir dedist, com seu manifest de pacote e seu hash; Python: odcp_aido checkout e os módulos realmente importados). O record liga os artefatos a este checkout; não certifica a cadeia de suprimentos. - Processos e relatório: cada filho roda sob o runner do kit externo (prazo, grupo de processos, limites de saída).
O relatório recebe primeiro um marcador
incompletee é substituído em todos os casos; um--reportambíguo (ausente, com forma de opção ou repetido) não escreve nada. Códigos de saída do runner: 0 passa, 1 uma verificação que falhou, 2 uso, 3 infraestrutura, build ou procedência.--child-argvsubstitui um filho só para testar o harness; esse relatório nunca é uma linha de base. - Self-tests:
perf.test.mjsexecuta um smoke obrigatório dos cinco filhos (W=1, N=2, R=1); filhos falsos (resultados ausentes, duplicados ou desconhecidos, contagens erradas, amostras malformadas ou não seguras, uma identidade errada, contradições, accept-all, falhas no aquecimento e nas amostras, uma falha malformada, uma saída válida seguida de um exit diferente de zero, um travamento); um filho real com um positivo esperado errado; relatórios novos sobre um sucesso anterior; procedência falsificada, desatualizada e incompleta; uma seleção em uma árvore temporária; e um passo de build que ignora SIGTERM. A CI os executa no job nativo com todos os filhos obrigatórios. - Limites: uma única máquina e uma amostra pequena: a frequência, o estado térmico e de energia e a carga de fundo não são controlados (a CPU e o SO são registrados). Cada SDK é medido como está, com suas próprias bibliotecas criptográficas; o perfil de Rust é o release padrão. Os resultados ficam locais: esta seção documenta o método, não números.