Um sistema que ingere logs de chat privado, raspa a web e grava arquivos que um agente nomeia precisa ser paranoico por construção. A ADR-0011 define quatro restrições permanentes — fail-closed em tudo, redação de PII antes de um byte sair da máquina, isolamento de um corpus de prompts vazado e uma regra de clean-room — e elas não são slogans: aparecem como guardas reais no código que você já conheceu. Esta lição conecta a política à implementação: a fronteira Zod, a defesa realpath/path-traversal no SkillStore, o fail-closed DEFAULT_TIER = T4, e a redação de PII antes da chamada de modelo.
DEFAULT_TIER = T4 (trabalho não classificado estaciona) e o contrato de nunca-lança (uma falha não tratada vira uma negação tipada, não um passe silencioso).| # | Restrição (ADR-0011) | Onde vive no código |
|---|---|---|
| 1 | Fail-closed em tudo relevante à segurança — guardas realpath, webhooks HMAC, comparações de tempo constante, Zod em toda fronteira | Segurança de caminhos do SkillStore; DEFAULT_TIER = T4; safeParse de todo subsistema |
| 2 | Redação de PII antes de egressar — antes da chamada de modelo, não meramente antes de emitir | O funil reda sinais de canal privado pré-chamada (mapa §3) |
| 3 | Isolamento CL4R1T4S — o corpus de prompts de vendor vazado é dado para analisar, nunca um comando a seguir | Excluído da ingestão-como-instrução; tratado como dado inerte |
| 4 | Clean-room do tac — padrões reimplementados do zero, zero código/prompts literais, source nunca publicado | A fusão inteira é TS do zero, não source copiado |
Você viu o SkillStore na Lição 12. Sua espinha de segurança é validateSupportPath — uma função pura que recusa qualquer caminho relativo que pudesse escapar do diretório da skill. Ela espelha o has_traversal_component + _resolve_skill_target do Hermes e é o validador fail-closed de manual: lista o que permite e nega todo o resto.
// packages/hermes/src/skills/skill-store.ts:404-433 (condensado) const validateSupportPath = (relPath: string): Result<string, Error> => { if (relPath.length === 0) return err(new Error('file path is required.')); if (relPath.includes('\\')) return err(…'use forward slashes.'); // sem truques de backslash if (relPath.startsWith('/')) return err(…'must be relative.'); // sem caminhos absolutos const segments = relPath.split('/').filter((s) => s.length > 0); for (const segment of segments) { if (segment === '..' || segment === '.') // sem segmentos de traversal return err(…'path traversal is not allowed.'); } const first = segments[0]; if (first === undefined || !isSupportDir(first)) // deve ser um subdir PERMITIDO return err(…'first segment must be one of …'); return ok(normalized); // só agora: um caminho relativo vetado e confinado };
Note a forma: todo ramo é uma negação exceto o ok final. Um ../../etc/passwd controlado por atacante é rejeitado na checagem de ..; um sorrateiro references/../../secret também é rejeitado. A função é pura e nunca lança, então compõe limpa no mundo Result — falhas de segurança surgem como erros tipados, fail-closed (ADR-0011 §1, "não passes silenciosos").
A expressão mais profunda de fail-closed não é uma guarda que você chama — é o padrão. DEFAULT_TIER = T4 significa que qualquer trabalho não explicitamente classificado como autônomo é estacionado, esperando um humano (Lição 24, ADR-0005). A ADR traça a linha ela mesma: "é também por isso que DEFAULT_TIER = T4" — o caso desconhecido nega. Autonomia não classificada é impossível por construção, não por lembrar de checar.
A palavra sutil é egressar. Seria fácil redar PII só antes de mostrar um resultado a um usuário. A ADR-0011 exige mais: um Signal derivado de um canal privado (WhatsApp, Discord, Skool, Circle) é "redado de PII antes de sair da máquina local — antes da chamada de modelo, não meramente antes de emitir". O modelo de ameaça assume que o próprio endpoint do modelo está fora da fronteira de confiança, então dado privado bruto nunca pode estar num payload de requisição.
As duas últimas são sobre disciplina, não checagens em runtime. Isolamento CL4R1T4S: um corpus vazado de prompts de vendor (e seu README de payload de injeção) "é isolado e nunca ingerido como instrução; é dado para analisar, nunca um comando a seguir". É defesa contra prompt-injection na camada de ingestão — o corpus é texto inerte, nunca executado. Clean-room do tac: o tac é um blueprint de licença educacional, então "seus padrões são reimplementados do zero, com zero código ou prompts literais, e seu source nunca é publicado". A fusão inteira do @alembic/hermes é uma reimplementação TypeScript do zero precisamente por causa dessa regra — que é também por que as lições citam o source do próprio Alembic, nunca o Python do Hermes.
A regra de orquestração do CLAUDE.md "SEMPRE cite a fonte" e os stores content-addressed (SHA-256 sobre JSON canônico, Lição 28) significam que todo fato ingerido carrega uma fonte, uma data e um hash. Proveniência não é uma feature separada — é o que permite ao sistema saber se um dado é confiável (um Learning vetado) ou suspeito (um payload CL4R1T4S). Fail-closed + proveniência são a mesma postura por dois ângulos: negue o desconhecido, e sempre saiba de onde uma coisa veio.
validateSupportPath rejeita .., caminhos absolutos e backslashes, permitindo só caminhos sob um subdir aprovado. Qual padrão de design é esse?err tipados. É allow-listing / fail-closed — a mesma postura de DEFAULT_TIER = T4.