Repository navigation
chore(release): promove a 1.0.0-rc.4 para a main — PF, Silo, ciclo de QA da borda e o toolchain - #1031
Conversation
… sem razão social Fecha #1022. O cadastro de Fornecedor aceita pessoa física (CPF), pagos por RPA. - Domínio: `SupplierDocument` (CPF | CNPJ, no módulo, não no kernel) e identidade PF × PJ como union discriminada — na PF razão social e nome fantasia não existem no tipo. O tipo de pessoa é derivado do documento, nunca gravado. PF com os campos preenchidos é recusada (`supplier-*-not-allowed-for-pf`); branco conta como ausente. - Persistência: migration 0020 (`cnpj` → `document`, índice `par_suppliers_document_idx`, `corporate_name`/`fantasy_name` nullable com CHECK amarrado ao tamanho do documento). Ausência é NULL só na borda; sem valor sentinela (ADR-0070). - HTTP v1 aditivo: `document` + `personType`; `cnpj` segue como alias deprecated por um ciclo, na entrada e na resposta. Códigos `invalid-supplier-document` e `*-document-duplicate`. - Busca por CPF, CSV "CPF/CNPJ", leitura de nota resolve CPF (`findSupplierIdByDocument`), ETL aceita CPF na coluna legada. - Testes de favorecido CPF no CNAB (transferência, J-52, Pix); sem mudança de código lá. - ADR-0070 supersede parcialmente o ADR-0031. Assisted-by: Claude-Code:claude-opus-5-5
Os 20 comandos de hook do `.claude/settings.json` eram `${CLAUDE_PROJECT_DIR}/...` sem
aspas: num clone em "Área de trabalho" o `/bin/sh` partia o caminho no espaço e todo hook
falhava como "non-blocking" — Prettier pós-edição, bloqueios de Bash e o gate do Stop
deixavam de rodar em silêncio. Agora `"\"${CLAUDE_PROJECT_DIR}\"/..."`, a forma da doc.
Com os hooks de volta, apareceram mais três defeitos da mesma família:
- `pre-commit-typecheck.sh` guardava `pnpm --dir=${CORE_API_DIR}` numa string e a expandia
sem aspas: os quatro gates do pre-commit morriam com `ENOENT ... lstat '/home/.../Área'`.
Agora a chamada é direta, com `--dir` entre aspas.
- `stop-quality-gate.sh` reportava `pnpm: comando não encontrado` como QUATRO vermelhos.
Shell de hook não carrega o nvm; ausência do pnpm agora é diagnóstico próprio ("gate
não rodou"), que continua bloqueando, mas com a causa verdadeira.
- O fixture do `gate-blocker` montava `typecheck: <caminho do tsc> --noEmit` sem aspas no
package.json temporário; o cenário GREEN falhava por ambiente, não por gate.
Assisted-by: Claude-Code:claude-opus-5-5
- `rehydrate` aplica só a regra do CHECK (PF ⟺ nomes NULL). Exigir nome não-branco na LEITURA derrubava o `list()` inteiro por uma PJ gravada com razão social `''` por fora do domínio — o CHECK aceita, e essa linha sempre reidratou. - Borda: documento só alfanumérico. Só o tamanho deixava um CPF mascarado (14 caracteres) passar como CNPJ sem máscara, enquanto o CNPJ mascarado caía em 400. - ETL: CPF ambíguo (os 11 dígitos com zeros à esquerda também formam CNPJ válido — CNPJ legado que perdeu os zeros) vai para quarentena, não para PF; e documento inválido volta a juntar o erro de razão social na mesma quarentena. - `companyNamesOf` no domínio substitui o mesmo `switch` repetido em DTO, CSV, mapper e busca; tamanhos de CPF/CNPJ têm fonte única em `SupplierDocument`. - Reverte a edição da linha de status do ADR-0031: ADR aceito não se edita; a supersessão fica registrada no ADR-0070. ADR-0070 registra o risco aceito do OCR resolver CPF. - Diagnóstico de duplicatas e textos de teste apontam `par_suppliers.document`. Assisted-by: Claude-Code:claude-opus-5-5
Os 20 comandos de hook do `.claude/settings.json` eram `${CLAUDE_PROJECT_DIR}/...` sem
aspas: num clone em "Área de trabalho" o `/bin/sh` partia o caminho no espaço e todo hook
falhava como "non-blocking" — Prettier pós-edição, bloqueios de Bash e o gate do Stop
deixavam de rodar em silêncio. Agora `"\"${CLAUDE_PROJECT_DIR}\"/..."`, a forma da doc.
Com os hooks de volta, apareceram mais três defeitos da mesma família:
- `pre-commit-typecheck.sh` guardava `pnpm --dir=${CORE_API_DIR}` numa string e a expandia
sem aspas: os quatro gates do pre-commit morriam com `ENOENT ... lstat '/home/.../Área'`.
Agora a chamada é direta, com `--dir` entre aspas.
- `stop-quality-gate.sh` reportava `pnpm: comando não encontrado` como QUATRO vermelhos.
Shell de hook não carrega o nvm; ausência do pnpm agora é diagnóstico próprio ("gate
não rodou"), que continua bloqueando, mas com a causa verdadeira.
- O fixture do `gate-blocker` montava `typecheck: <caminho do tsc> --noEmit` sem aspas no
package.json temporário; o cenário GREEN falhava por ambiente, não por gate.
Assisted-by: Claude-Code:claude-opus-5-5
… Docker Hub Fecha #1026. A MinIO apagou `minio/minio` e `minio/mc` do Docker Hub em 2026-09-11 e o espelho quay.io/minio exige login: nenhuma tag nem digest do oficial baixa sem conta. O `integration` falhava todo dia na main desde 2026-09-12 (storage, logo, photo → gate). O compose passa a `pgsty/silo` + `pgsty/mc`, pinados por digest multi-arch. Fork mantido, AGPLv3 como o MinIO, e drop-in: envs `MINIO_*`, secrets `*_FILE`, rotas `/minio/*`, healthcheck e bootstrap inalterados. Escolhido entre seis hipóteses testadas em container isolado contra as quatro suítes reais do CI (registro na #1026); ADR-0071 supersede parcialmente o ADR-0019 só na fonte da imagem. Assisted-by: Claude-Code:claude-opus-5-5
- compose.yaml volta ao MESMO número de linhas: os comentários novos deslocavam tudo abaixo do serviço `minio` e deixavam erradas as citações `compose.yaml:N` em integration.yml, ADR-0014.yaml, ADR-0064 e spec 033. O detalhe da troca vive no ADR-0071. - Inventário do ADR-0019: C5 passa a `contradicted` na letra (a imagem não é mais a oficial minio/minio, por decisão do ADR-0071) e os `verify` voltam a achar as linhas; índice de ADRs anota "imagem superseded por 0071" na linha da 0019. - Doc de paridade local: o comando de criar bucket usava `minio/mc`, que sumiu; passa ao `pgsty/mc` pinado, com `--entrypoint /bin/sh` (o entrypoint da imagem é `mc`). - gate-blocker: fixture com espaço no caminho — prova inversa medida: sem as aspas do `--dir` o cenário GREEN quebra. Antes, a regressão voltaria sem teste vermelho. - Gate do Stop sem pnpm: mensagem neutra quanto ao gerenciador de versão e manda escalar ao humano em vez de alterar a home; PATH só no log. Título "fallback npx" do pre-commit corrigido (não há fallback: falha fechado). - Nome do teste de infra e exemplo do docker-compose-expert deixam de citar minio/mc e de usar placeholder inválido. Fora do escopo, registrado: #1027 (gate do Stop pula com .ts de nome com espaço). Assisted-by: Claude-Code:claude-opus-5-5
fix(infra): S3 de dev/teste passa ao fork Silo — minio/minio sumiu do Docker Hub
…-fisica # Conflicts: # .claude/hooks/stop-quality-gate.sh # handbook/architecture/adr/README.md
…sica feat(partners): fornecedor pessoa física (CPF) — SupplierDocument, PF sem Razão Social/Nome Fantasia
|
…a passar
Medidos ao rodar o oxlint em paridade 1:1 com o ESLint (ADR-0072): o código que
o ESLint aprova tinha 16 violações que só o oxlint enxerga. Nenhuma muda
comportamento, exceto a primeira.
- 4× no-deprecated: `.meta({ example })` do Zod, depreciado pelo zod-openapi,
vira `examples: [...]`. ⚠️ Muda o OpenAPI gerado (`example` → `examples`,
o formato do OpenAPI 3.1). Nenhum teste dependia do campo.
- 7× prefer-optional-chain: `x !== null && x.campo === v` → `x?.campo === v`;
o compilador segue estreitando `x` para não nulo depois da comparação.
- 3× no-unnecessary-type-parameters: genérico usado uma vez vira `unknown` ou
`never` — `TableRead<T>` é todo readonly, então a troca é covariante e segura.
- 2× prefer-readonly-parameter-types e 1× consistent-generic-constructors.
Os dois testes de integração alterados (writer.integration e
renumber-by-vigencia.drizzle-mysql) mudam só a asserção; ficam para o CI, que
roda contra MySQL.
Assisted-by: Claude-Code:claude-opus-5-5
…tra sem side-by-side Implementa o ADR-0072 (que supersede a decisão de linter da Inquiry-0029 e o D2 do ADR-0067) e, com ele, o D1 e o D3 do ADR-0067, aceitos em 25/08 e nunca levados ao código. Lint: - `oxlint 1.86.0` + `oxlint-tsgolint 7.0.2003`, versões exatas; `pnpm run lint` é `oxlint`, sem cache — 2036 arquivos com type-aware em ~2,3 s (o ESLint levava 30–32 s sem cache e 39–62 s no CI, onde o cache nunca era restaurado). - `.oxlintrc.json` GERADO do `eslint --print-config` dos cinco contextos: 154 das 158 regras com a mesma severidade, opções e exceções por pasta; todas as categorias do oxlint desligadas. Paridade provada por diferencial (222 de 224 violações reais no mesmo arquivo e linha) e por 36 de 36 sondas de opção. - As 4 sem equivalente: `no-octal` o compilador já recusa (TS1121); `class`, `naming-convention` e `member-ordering` viram gate de AST em `tests/cleanup/lint-gaps.test.ts`, sobre a API `typescript/unstable/*` concentrada em `tests/support/ts-ast.ts`. Conferido contra o ESLint: 46 de 46 nomes idênticos em 2036 arquivos; fixtures do autoteste 15 de 15; prova invertida reprova as três. As exceções `__brand` e `__nonZeroMoney` saem das diretivas `eslint-disable` para a allowlist do gate, com motivo. TypeScript: - `typescript` 7.0.2, versão exata (os gates usam a API `unstable/`). Saem `eslint`, `typescript-eslint`, `eslint-config-prettier`, `@eslint/js` e `@typescript/native-preview`; sai o `eslint.config.js`. O Prettier fica. Harness e registros que dependiam do arquivo removido: - Hooks Stop e pre-commit apontam para o `.oxlintrc.json`; o CI perde o passo de cache do ESLint; ignores atualizados. - `enforced_by` dos registros de decisão apontam o mecanismo REAL: ADR-0009 e ADR-0011 → `.oxlintrc.json`; ADR-0045 e ADR-0051 → `module-boundary.test.ts`; ADR-0037 e ADR-0047 → `[]`, porque o `eslint.config.js` nunca cobriu a fronteira que eles afirmavam. - Skills que linkavam `eslint.config.js` passam a linkar o mecanismo atual. Assisted-by: Claude-Code:claude-opus-5-5
…nismo
CLAUDE.md, seis rules, o README, o SCHEMA dos registros de decisão, docblocks de
gates e comentários de código afirmavam que o ESLint barrava `class`, casing e
libs proibidas. Depois do ADR-0072 quem barra é o oxlint ou o gate de AST
`tests/cleanup/lint-gaps.test.ts`, e cada texto passa a nomear o mecanismo real.
Uma afirmação já era falsa antes da troca e foi corrigida, não só renomeada: a
`domain.md` dizia que `class`/`this` eram barrados pelo `no-restricted-syntax`,
mas a config só tinha seletores de `class` — `this` nunca foi barrado.
Nos comentários de código ("o ESLint recusa X"), a regra citada é uma das 154
portadas para o oxlint; a afirmação continua verdadeira e só a ferramenta muda.
Assisted-by: Claude-Code:claude-opus-5-5
Aceito pelo Tech Lead em 2026-10-05. Supersede a decisão de linter da Inquiry-0029 (§6, ESLint + `--cache`) e o D2 do ADR-0067 (alias do TS 6); o D1, D3–D6 do 0067 seguem vigentes e agora implementados. O que derrubou a 0029 foi medido, não opinado: o `--cache` do ESLint dá falso verde em regra type-aware (mudar só o tipo de retorno em `a.ts` deixa um `no-floating-promises` em `b.ts` passar com cache e falhar sem; a doc do typescript-eslint confirma que o cache não acompanha dependência entre arquivos) e nunca era restaurado no CI (`Cache not found`, lint de 39–62 s). - O ADR registra decisões, provas (diferencial, sondas, nomes 46/46, fixtures, prova invertida), custos — gates sobre API `unstable/`, três regras `nursery`, a mudança no OpenAPI — e quando reavaliar. - Índice de ADRs: linha do 0072; o 0067 vira "Accepted (D2 superseded por 0072)", sem editar o ADR aceito. - Inquiry-0029 → `superseded`, com aviso no topo; o corpo, que registra as medições de 2026-08-06, fica intacto. Índices regerados por `docs:index`. - O agent typescript-language-expert deixa de se apresentar como TS 6 com roadmap via `native-preview`. Assisted-by: Claude-Code:claude-opus-5-5
Achado da revisão do PR: o ADR-0072 (D4) e o cabeçalho de `tests/support/ts-ast.ts` afirmam que o `typescript` está em versão exata — porque os gates de `lint-gaps` leem a AST pela API `typescript/unstable/*` —, mas o manifesto dizia `^7.0.2`. O `pnpm add --save-exact` manteve o estilo de faixa da entrada que já existia, e nada conferia a afirmação. O valor é corrigido e a afirmação vira asserção em `tests/cleanup/lint-gaps.test.ts`: uma faixa no `typescript` reprova o gate (prova invertida feita — `^7.0.2` acusa "fixar a versão exata"). Assisted-by: Claude-Code:claude-opus-5-5
O scripts/e2e/bruno-all.sh era o unico lugar que chamava bru run e estava muito desatualizado; foi substituido pela abordagem de QA + pen-test por arquivos .rest. Remove o script e todas as referencias: o npm-script test:integration:all, os READMEs, a rule api-collections.md (verify block + enforced_by), as clausulas do ADR-0038.yaml que apontavam para o script (enforced_by -> []), e os dois testes que o citavam (migrate-boot-inversion e block-bash-file-io). Assisted-by: Claude-Code:claude-opus-4-8
…m contracts/:id) z.uuid() do Zod v4 aceitava UUID bem-formado nao-v4 (nil, max, v1/v3/v5); o dominio rejeita via isUuidV4, e o handler de contracts nao mapeava contract-id-invalid, caindo no default 500 (viola a invariante nunca-500). Introduz um schema uuidV4() compartilhado em src/shared/http (z.uuidv4 estrito, com teste de paridade com o isUuidV4 do dominio) e troca as 11 ocorrencias de z.uuid() da borda, preservando os modificadores. Defesa em profundidade: mapeia contract-id-invalid / amendment-id-invalid / document-id-invalid para 400 no contracts. Efeito medido: UUID nao-v4 passa a devolver 400 uniforme em toda rota :id. Assisted-by: Claude-Code:claude-opus-4-8
O upload de logo (POST /api/v1/programs/:id/logo) confiava no Content-Type declarado e nao conferia os bytes reais — aceitava conteudo arbitrario rotulado como imagem (provado ao vivo: HTML como image/png -> 200). As rotas-irmas (foto de usuario, documentos fiscais) ja checavam magic-byte; o logo ficou de fora. Adiciona imageMagicBytesMatch (jpeg/png/webp) inline no use case uploadProgramLogo, retornando logo-content-mismatch -> 422, consistente com o photo-content-mismatch da foto. Assisted-by: Claude-Code:claude-opus-4-8
…e a 24.21.0 O repositório declarava a versão do Node em cinco lugares e rodava três versões diferentes: `.nvmrc` e `devEngines` em 24.16.0, `FROM`/`LABEL` em 24.15, e quatro workflows em `node-version: '24'` — presos a nenhum dos dois e flutuando a cada release upstream. O gate existente passava verde porque cobrava apenas o major, e a divergência era de minor; o próprio ADR-0058:41 registrara a divergência em 05/08 como "observação, não norma". O `.nvmrc` passa a ser a fonte única por ser o único arquivo que o `fnm` (no `cd`) e o `actions/setup-node` (`node-version-file`) leem sem tradução humana. As seis derivadas são conferidas por gate, cada uma na granularidade que o alvo permite. - ADR-0073, que supersede PARCIALMENTE o ADR-0058 (§2 e §4). A §1 — acompanhar o LTS recomendado — e a §3 — troca de tecnologia por inquiry — seguem vigentes; o corpo do ADR aceito não foi editado, só o status no índice. - `tests/cleanup/node-version-single-source.test.ts` refeito: de 3 pontos por major para 6 por derivação, com guarda contra verde por vacuidade. Foi essa guarda, na versão anterior, que acusou a troca de `node-version` por `node-version-file`. - Versão alinhada em 24.21.0 (ponta da linha 24). O digest da imagem base foi recalculado. O `pnpm-lock.yaml` acompanha porque o pnpm registra o runtime do `devEngines` — sem isso o `--frozen-lockfile` do CI recusaria. - Os workflows deixam de declarar `node-version` e passam a ler o `.nvmrc`. Medido em 06/10/2026 contra `nodejs/Release/schedule.json`: a linha 24 entra em maintenance em 20/10/2026 e a 26 vira Active LTS em 28/10/2026. O salto ao 26 é PR próprio, deliberadamente fora daqui — rodar Current em produção, e empilhar um major de runtime sobre a migração de toolchain desta branch, são duas coisas que este commit não faz. Refs #1035 Assisted-by: Claude-Code:claude-opus-5
…antes 45 dos 64 scripts do `package.json` carregavam `--experimental-strip-types --enable-source-maps --no-warnings`, e as três foram medidas no runtime do `devEngines` (24.21.0) em 06/10/2026 — nenhuma fazia diferença: - `--experimental-strip-types`: o stripping é DEFAULT desde o Node 23.6 (backport na 22.18). A prova verificável é `--no-strip-types` existir como negação no `--help`. O repositório tem zero `enum` e zero `namespace` (garantido por `erasableSyntaxOnly`), então nada aqui precisaria de `--experimental-transform-types` no lugar. - `--enable-source-maps`: o stripping troca tipo por espaço em branco, então a posição no `.ts` é preservada e o stack trace sai idêntico com e sem a flag (medido: mesmo `arquivo.ts:27:9`). E nenhuma das 10 dependências de produção publica `.js.map` — a flag não tinha alvo algum neste repositório. - `--no-warnings`: existia para calar o `ExperimentalWarning` do stripping, que não é mais emitido. Sem ela, script real e `node --test` emitem zero linha em stderr. A terceira é a que justifica o commit. As duas primeiras eram inertes; `--no-warnings` estava ENGOLINDO `DeprecationWarning` em 45 comandos — o canal pelo qual o Node anuncia o que quebra na próxima major, e a informação que torna acionável a disciplina de subida de runtime do ADR-0073. Em produção o mesmo valia por `NODE_NO_WARNINGS=1` no Dockerfile, que sai junto: o aviso passa a chegar ao stderr do contêiner, logo ao log do ECS. `tests/cleanup/node-flags-not-redundant.test.ts` impede o retorno, que aconteceria por imitação do script vizinho — foi assim que chegou a 45. Um gate quase quebrou em silêncio: `migrate-boot-inversion.test.ts` ancorava em `'--no-warnings src/server.ts'` para distinguir a invocação real do `pkill -f` do cleanup. Sem a flag, os dois `indexOf` iriam a -1. A âncora passa a ser `node` no início da linha, que o `pkill` não casa. Uma flag sem função sustentava a asserção. Fora do escopo, de propósito: ~70 citações em `handbook/specs/` e `handbook/interviews/` ficam intactas — é acervo datado, e reescrever registro histórico é falsificá-lo. Refs #1035 Assisted-by: Claude-Code:claude-opus-5
…ndante A flag removida do código voltaria pela porta da frente: `.claude/` tinha 43 ocorrências das três flags em 16 arquivos, e é ela que o agente lê ANTES de olhar o repositório. O mapa de propagação estava visível em `git grep -c` ordenado — `package.json:45` → `nodejs-runtime-expert.md:8` → `Procfile:6`: o manifesto espalhou para a instrução, que ensinava a espalhar de novo. O achado mais caro não eram os comandos, e sim duas afirmações FALSAS do `nodejs-runtime-expert`, que numa sessão futura teriam me feito recusar esta limpeza: - "`--experimental-strip-types` está em Active development em Node 24 (não Stable)" — é default desde a 23.6, e produção já dependia disso (o ENTRYPOINT da imagem não passa flag alguma). - `@types/node` declarado como `^22.10.0`, quando o manifesto diz `^24.0.0`. As duas foram corrigidas e o agente ganhou um bloco explícito proibindo as três flags, com a razão medida de cada uma. Também atualizados: `rules/testing.md` (carrega por path em todo teste), as skills `nodejs-fs-scripter`, `nodejs-process-runner`, `ts-domain-modeler`, `tdd-strategist`, `tdd-theorist`, `tdd-tutor`, `test-pyramid-engineer`, `ts-quality-checker` e os agentes `cnab240-bradesco` e `docker-compose-expert`. Preservado de propósito: o gatilho de ativação do `nodejs-runtime-expert` (alguém ainda pode PERGUNTAR sobre a flag), `--enable-source-maps` na lista de flags de diagnóstico do Node, e os ponteiros para `handbook/reference/nodejs/`, que descrevem a doc oficial — ela documenta essas flags, e o ponteiro não é instrução de uso. Refs #1035 Assisted-by: Claude-Code:claude-opus-5
… um minor fixo) O `Dockerfile` declarava `# syntax=docker/dockerfile:1.10` e a ponta estável é `1.27.1` (medida em 06/10/2026 no Docker Hub) — 17 minors atrás, sem receber correção desde que a `1.11` saiu, e sem nada no repositório capaz de apontar isso. A doc oficial é explícita, e é a fonte aqui: "docker/dockerfile:1 - kept updated with the latest 1.x.x minor and patch release. (…) If a specific version is used, such as 1.2 or 1.2.1, the Dockerfile needs to be updated manually to continue receiving bugfixes and new features." — https://docs.docker.com/build/buildkit/frontend/ Um minor fixo é a pior das três posições possíveis: não é imutável (recebe patches `1.10.x`) nem atualizado (congelou na `1.11`). A doc só oferece duas coerentes — `:1` ou uma versão exata com digest. Por que isto NÃO contraria o digest pin do ADR-0011: o frontend do `# syntax` é baixado em tempo de BUILD e não entra na imagem final; ele não afeta a reprodutibilidade do que roda em produção, que é o que aquele ADR protege. A imagem base segue pinada por `@sha256`. A distinção está registrada em comentário no próprio Dockerfile, porque é o tipo de coisa que alguém "corrige" de volta por coerência aparente. O repositório tinha TRÊS versões divergentes do mesmo directive: `Dockerfile` em `1.10`, `.claude/agents/docker-compose-expert.md` em `1.7` — instrução viva, mais velha que o código — e `handbook/reference/docker/` em `:1`, que já era a cópia correta da doc oficial. As duas primeiras foram alinhadas; a reference não foi tocada. O agente ganhou a regra com o link, para o número não voltar. Refs #1035 Assisted-by: Claude-Code:claude-opus-5
…u não seguia o symlink do pnpm Achado da revisão do PR. O commit 95abe48 removeu as três flags afirmando que "nenhuma das 10 dependências de produção publica .js.map". **Era falso, e por erro de medição:** o `find` rodou sem `-L`, e `node_modules/<dep>` é SYMLINK sob pnpm — a varredura nunca desceu no alvo e devolveu zero para tudo. Remedido com `find -L`: `drizzle-orm` publica **444** arquivos `.js.map` e `fast-xml-parser` mais 4. O efeito é reproduzível num erro lançado dentro da lib: sem a flag: at getTableColumns (…/drizzle-orm/utils.js:109:15) com a flag: at getTableColumns (…/drizzle-orm/src/utils.ts:208:9) O raciocínio original — "o stripping preserva a posição no `.ts`" — está correto para o código DESTE repositório, e é por isso que enganou: a flag nunca serviu a ele. Serve às dependências que publicam mapa, e `drizzle-orm` é a mais usada do projeto (183 imports). Perder isso degradaria o stack trace de `serve`, dos workers e dos jobs em produção. A flag volta a todos os pontos de invocação: `package.json` (45 scripts), `Procfile`, `NODE_OPTIONS` do Dockerfile, `scripts/e2e/*.sh`, o spawn de `test-integration.ts` e os 4 testes que spawnam processo. As outras duas seguem removidas — a medição delas não dependia de `node_modules` e foi reproduzida. Os outros três achados da revisão, todos de alcance de gate: - `node-flags-not-redundant` cobria só o `package.json`, enquanto a `rules/testing.md` prometia por escrito "todos os comandos do repositório". Passa a varrer os 12 pontos de invocação, com caso que falha se um caminho da lista deixar de existir.⚠️ Na primeira execução ampliada ele acusou `Dockerfile` e `test-integration.ts`, que apenas DOCUMENTAM as flags em comentário — a armadilha uso × menção. Agora ignora linha de comentário (`#`, `//`, `*`). Prova invertida: `--no-warnings` injetado numa linha de código do `Procfile` é acusado. - `node-version-single-source` só enxergava workflow que JÁ usava `setup-node`. `audit.yml` executava `corepack enable` + `pnpm audit` sem declarar runtime, caindo no Node pré-instalado do runner — o "CI escolhe sozinho" que o ADR-0073 §2 encerra. O gate passa a cobrar por QUEM RODA Node, e o `audit.yml` ganhou o passo. - `migrate-boot-inversion` ancorava em `^\s*node src/…`, que a volta da flag quebraria. A âncora aceita as flags que houver entre `node` e o caminho. Textos que repetiam a premissa errada foram corrigidos, não só renomeados: `rules/testing.md`, `agents/nodejs-runtime-expert.md` e o comentário do Dockerfile. O agente ganhou a regra operacional que faltava: **ao medir dentro de `node_modules` sob pnpm, usar `find -L`**. Refs #1035 Assisted-by: Claude-Code:claude-opus-5
…movida ADR-0074, que supersede o ADR-0034 (adocao do @usebruno/cli) e o ADR-0038 (Bruno obrigatorio via CLI + autoria .bru). O gatilho foi o critério do proprio ADR-0038: "um .bru escrito e nao executado e cobertura ilusoria". Quando o runner unico (scripts/e2e/bruno-all.sh) caiu em 05/10 por estar desatualizado, nada o substituiu — e os 266 .bru viraram exatamente o que aquele ADR proibia. Somado a isso, o formato guarda o encadeamento em JavaScript (bru.setVar) e as assercoes em chai, o que exige o runtime do Bruno para saber se o arquivo esta correto. Hurl 8.0.1 resolve os dois pontos: [Captures] nativo (sem JavaScript), --variables-file (o arquivo nasce SEM segredo), --report-junit para CI e `hurlfmt --check` como gate de sintaxe que roda sem servidor. A colecao foi convertida: 241 requests em 23 arquivos, 24 [Captures] e 77 [Asserts] traduzidos do JS, hurlfmt verde nos 23. BREAKING CHANGE: api-collections/ (266 .bru) e @usebruno/cli saem do repositorio. A remocao da devDependency levou 317 pacotes, e com eles as DUAS excecoes de supply-chain que o Bruno exigia (protobufjs em allowBuilds, semver@5.7.2||6.3.1 em trustPolicyExclude) — removidas depois de `pnpm why` provar que nenhuma outra cadeia as trazia. Excecao de politica sobrevive a dependencia que a justificou se ninguem varrer. Os fixtures binarios de upload (sample.jpg/pdf) migram de api-collections/ para tests/fixtures/http-edge/, versionado e neutro: as pastas de saida da conversao sao gitignored e guardar fixture dentro delas tiraria o arquivo do git. Limites medidos, nao supostos: [Captures] NAO cruzam arquivos (capture em a.hurl + uso em b.hurl, mesmo comando e --jobs 1, falha); a suite exige o seed E2E (8 perfis) e hoje roda 82/241, o resto parando em variavel indefinida; --jobs 1 e obrigatorio porque --test paraleliza por default e o rate limit de login e compartilhado. Zero 500 nos 82 requests executados. As colecoes convertidas ficam fora do git por ora (uso interno): o .hurl e versionavel quando virar gate, porque nao carrega segredo; o .http, nao, porque so funciona com o token colado dentro do arquivo. O .gitignore tambem passa a cobrir .cockpit/ (estado de workspace da IDE). Registro historico (handbook/specs, tickets, CHANGELOG) NAO foi reescrito (ADR-0057 §5) e ainda descreve o Bruno: era verdade quando foi escrito. Assisted-by: Claude-Code:claude-opus-5
O ciclo de QA de 05/10 provou que dois usuarios podiam ser criados com o MESMO cpf e e-mails diferentes — ambos 201. Como cpf e documento, isso e duplicacao de identidade: `auth_user` tinha uniqueIndex em email e legacy_id, nenhum em cpf, e `createUserByAdmin` so checava findByEmail. A garantia passa a viver no banco (`auth_user_cpf_idx`, migration 0010). cpf segue nullable e o InnoDB permite multiplos NULL num UNIQUE, entao quem nasce sem perfil (register/OIDC) nao colide — propriedade coberta por teste. Os DOIS adapters que inserem em auth_user distinguem o 1062 pelo nome do indice na sqlMessage: `user-repository.drizzle` devolve `cpf-already-registered` (409 na borda, em create e update) e `provisioned-user-store.drizzle` idem, para a ETL poder tratar. Sem a distincao, dado duplicado se disfarcaria de falha de infra (`provisioned-user-store-unavailable`) e o usuario legado NAO seria migrado — defeito que a propria migration criava. Em `provisionLegacyUser`, cpf duplicado DEGRADA para null + warning e re-tenta, a mesma politica que ja valia para cpf invalido (Evans p.82, reconstituicao): um campo de perfil opcional nao vale o registro inteiro. O id e gerado uma vez e reusado no retry — reconstruir nao troca identidade. Testes: o contrato do port ganha CA7 (duplicado -> erro nomeado), CA8 (dois NULL coexistem) e CA9 (upsert do proprio registro nao e conflito), valendo para as duas implementacoes; CA7 provado invertido (removida a checagem, acusa). O gate de schema varre TODAS as migrations, nao a 0000, porque o indice nasceu na 0010. `user-repository.drizzle.test` passa a honrar AUTH_DATABASE_URL com fallback no helper canonico, como contracts e financial ja faziam. Efeito colateral medido e corrigido: 18 testes de rota ficaram vermelhos (`409 !== 201`) porque as fixtures reusavam um cpf fixo para criar N usuarios. A correcao e a fixture respeitar o invariante novo, nunca afrouxar o assert: `tests/support/synthetic-cpf.ts` deriva cpf valido por modulo 11 de um seed. Gerar em vez de listar numeros e deliberado — fixture e o caminho por onde dado de cadastro real entra num repositorio publico. Verificado contra MySQL 8.4 real (nao so fake): replay das 7 migrations em banco limpo, e o contrato do UserRepository com MYSQL_INTEGRATION=1 passando 11/11. Assisted-by: Claude-Code:claude-opus-5
`.tmp/` e onde script de medicao/conversao tem de viver: no scratchpad da sessao o ESM resolve pelo path do ARQUIVO e os imports do projeto dao MODULE_NOT_FOUND. Mas o diretorio nao entra em tsconfig algum, e o projectService type-aware do ESLint reprova com `was not found by the project service` — qualquer script ad-hoc ali travava o `lint` e, com ele, o gate do hook Stop. A regua ja existia para os irmaos da mesma categoria (descartavel, gitignored, fora de tsconfig): `tools/bugs-scripts/**` e `tests/reports/**` ja estavam na lista de ignores, com esse motivo escrito. `.tmp/` ficou de fora — existia num lugar e faltava no outro. Assisted-by: Claude-Code:claude-opus-5
… 3a UNIQUE da ETL Tres correcoes em `src/` apontadas pela revisao da branch. 1. O nome do indice era string magica em tres arquivos. `AUTH_USER_UNIQUE_INDEX` (schemas/mysql.ts) passa a ser a fonte unica dos tres nomes, e os dois adapters a consomem. Nao e cosmetica: o errno 1062 nao diz QUAL unicidade quebrou — quem distingue e o nome do indice dentro da sqlMessage, e e por ele que o adapter escolhe entre erro nomeado, idempotencia e falha de infra. Com o nome escrito a mao em cada lugar, um `drizzle-kit generate` que o renomeasse passava no gate e quebrava a traducao EM SILENCIO: o 409 do cpf duplicado viraria 500 e a ETL leria dado duplicado como banco indisponivel. O gate novo (schema-hardening, CA10) cobra a PROPRIEDADE, nao a contagem: cada valor da constante existe em alguma migration, nenhum adapter repete o literal, e os adapters de fato consomem a constante (guarda contra verde por vacuidade). A assercao que fecha e a NEGATIVA, e ela foi provada invertida — reintroduzido o literal, o gate acusa. 2. `provisioned-user-store` tratava DUAS das tres UNIQUE que o INSERT alcanca. O `auth_user_email_idx` caia em `provisioned-user-store-unavailable`: dado duplicado disfarcado de falha de infra, o mesmo defeito que o commit anterior corrigiu para o cpf. Agora devolve `email-already-registered`, que PROPAGA (email nao se degrada — e obrigatorio e e a identidade do login), diferente do cpf, que o use case anula e re-tenta. O comentario do arquivo dizia "as duas de auth_user"; eram tres. 3. `upload-program-logo`: o `default` do switch de magic-byte passa a ser fail-CLOSED. Hoje e inalcancavel (a allowlist roda antes), mas protege o dia em que um MIME novo entrar na allowlist sem a assinatura — com `return true` aquele MIME aceitaria conteudo falsificado em silencio (CWE-434), que e o defeito que a funcao veio corrigir.⚠️ A funcao irma em `auth/adapters/http/photo-upload.ts` FICA fail-open, de proposito: lá o magic-byte roda na BORDA e a allowlist so no use case, entao fechar o default trocaria `photo-type-unsupported` por `photo-content-mismatch` — mudanca de contrato observavel, nao endurecimento. A assimetria esta documentada nos dois arquivos; e ela a razao de as duas copias NAO terem sido fundidas num modulo compartilhado nesta passada: unificar exige alinhar a ORDEM primeiro. Nao mexido, com motivo medido: `uuidV4()` em response schema. A revisao sugeriu que contrariava o principio do proprio arquivo, mas o `git blame` mostra o oposto — o comentario de `financial/.../schemas.ts` JA dizia "IDs proprios seguem z.uuid()" antes, e o commit anterior so trocou por `uuidV4()`. A politica (refs estrangeiras nao revalidam, ids proprios revalidam) e pre-existente e deliberada. Risco residual medido: toda fonte de id e `randomUUID()`, os 16 UUID de seed das migrations sao v4 e o banco local tem zero nao-v4. Assisted-by: Claude-Code:claude-opus-5
… verde O `audit (produção — blocking)` estava vermelho com 16 vulnerabilidades (10 high) em quatro pacotes. Nao era regressao deste PR: toda a mudanca anterior em package.json foi a REMOCAO de uma devDependency. O audit so nao rodava na dev desde 10/09, e as advisories sairam nesse intervalo — este PR foi o primeiro run depois delas, e revelou o estado em vez de causa-lo. - `fastify` 5.12.1 -> 5.12.5 (patch, dentro do major 5). - `nodemailer` 9.1.1 -> 10.0.15 (major). O unico breaking do 10.0.0 e exigir Node.js >= 20; estamos em 24. `createTransport`, `sendMail` e `verify()` nao mudaram de assinatura, e e toda a superficie que o adapter usa. - `fast-uri` piso 3.1.6 -> 3.1.7 (resolve 3.1.8) e `brace-expansion` 5.0.9 -> 5.0.11 (resolve 5.0.12), nos overrides. Os dois overrides eram a parte interessante: eles estavam SEGURANDO a versao vulneravel, nao excluindo-a. O comentario do proprio pnpm-workspace.yaml previa isso por escrito — "o piso fixado para a advisory do dia vira o teto quando sai a proxima" — e se cumpriu pela QUINTA vez no fast-uri e pela QUARTA no brace-expansion. Faixa (`>=X <4`) nao empurra ninguem: o piso e ele proprio uma versao aceitavel, entao `@fastify/ajv-compiler` seguia resolvendo 3.1.6 mesmo com o fastify em 5.12.5. Expulsar exige SUBIR o piso acima da vulneravel. O historico de reincidencia fica no comentario; o piso vigente e o novo. Verificacao, com a ressalva de onde ela alcanca: - `pnpm run audit` -> "No known vulnerabilities found" (era 16). - Gate completo verde: 11931 testes, fail 0. - O boot do Fastify esta exercitado de verdade: 190 arquivos de teste montam o app por `fastify.inject`. O `createTransport` real do nodemailer 10 roda em `nodemailer-require-tls.test.ts`, nos dois branches (pool e nao-pool). - NAO houve boot contra SMTP real (o OrbStack estava desligado e subir container exige OK do dono): o envio de ponta a ponta segue coberto so por fake.⚠️ `@types/nodemailer` FICA em `^8`: nao existe `@types/nodemailer@10` — a ultima publicada e 8.0.2. O nodemailer 10 migrou para TypeScript mas declara `types: null` e manteve, de proposito, compatibilidade com o layout do @types (esta no changelog do 10.0.0). Quem tentar "alinhar" os majors nao vai achar o pacote.⚠️ Divida registrada, nao corrigida aqui: o adapter importa subpath profundo (`nodemailer/lib/smtp-pool/index.js`). Esse caminho NAO existe mais no v10 — o pacote publica so `dist/`, e o `exports` mapeia `./lib/*`. Funciona hoje porque sao `import type`, apagados em runtime, e o tipo vem do @types. Virar import de valor quebraria. Trocar para o especificador do `exports` e assunto proprio. Assisted-by: Claude-Code:claude-opus-5
Ciclo de QA/pen-test da borda HTTP (05-06/10): fecha os tres achados no codigo e troca a ferramenta da suite de colecoes. - fix(auth): unicidade de CPF em auth_user (F7). UNIQUE auth_user_cpf_idx na migration 0010; os dois adapters que inserem em auth_user distinguem as TRES unicidades pelo nome do indice no errno 1062 — legacy_id (idempotencia), cpf (409 na borda; a ETL degrada e re-tenta) e email (propaga). Nome do indice em fonte unica (AUTH_USER_UNIQUE_INDEX), com gate que cobra a ausencia do literal nos adapters. - fix(http): uuidV4 estrito na borda. z.uuid() do Zod v4 aceitava UUID nao-v4 e o dominio rejeitava, caindo no default 500 — violacao da invariante "nunca 500". Schema compartilhado em src/shared/http com teste de paridade contra o VO; 400 uniforme em toda rota :id. - fix(programs): magic-byte no upload de logo (CWE-434). O default do switch e fail-closed aqui porque a allowlist roda antes; a funcao irma do auth FICA fail-open de proposito — la a ordem e inversa, e fechar trocaria o codigo de erro da API. - feat(api-collections)!: Hurl substitui o Bruno (ADR-0074, supersede 0034 e 0038). api-collections/ (266 .bru) e @usebruno/cli removidos: -317 pacotes e as duas excecoes de supply-chain que o Bruno exigia. 241 requests convertidos em 23 arquivos. - fix(deps): audit de producao zerado. fastify 5.12.1->5.12.5, nodemailer 9.1.1->10.0.15, e os pisos dos overrides de fast-uri e brace-expansion subidos — eles SEGURAVAM a versao vulneravel em vez de exclui-la, exatamente como o comentario do pnpm-workspace.yaml previa. Verificacao: 20/20 checks verdes. Gate completo (11931 testes, fail 0) em cada commit, pelo hook de pre-commit. Contra MySQL 8.4 real: replay das 7 migrations em banco limpo e o contrato do UserRepository com MYSQL_INTEGRATION=1 (11/11), inclusive a propriedade de multiplos NULL no UNIQUE que um fake so imita. /security-review: zero vulnerabilidades novas. Limites declarados: a suite Hurl NAO e gate (exige o seed E2E; roda 82/241) — a borda esta sem gate E2E desde 05/10, quando o runner do Bruno caiu, e isso e anterior a troca de ferramenta. A migration 0010 aborta se houver CPF duplicado pre-existente, e o replay em banco limpo e cego para isso: pre-voo necessario em ambiente com dado, risco assumido pelo dono. Registro historico (handbook/specs, tickets, CHANGELOG) nao foi reescrito (ADR-0057 §5). Follow-up: #1036 (ETL degrada CPF duplicado sem quarentenar).
A branch do toolchain estava parada à espera da dev. Merge, não rebase: ela está publicada e tem o PR #1035 aberto. Cinco conflitos, dos treze arquivos que os dois lados tocaram: - `scripts/e2e/bruno-all.sh` (delete/modify) — remoção aceita. O Bruno saiu do projeto inteiro pelo ADR-0074, e o runner não se ressuscita. - `eslint.config.js` (delete/modify, invertido) — remoção aceita. A branch retira o ESLint pelo ADR-0072; a dev havia acrescentado `.tmp/**` aos ignores. A entrada foi portada para `ignorePatterns` do `.oxlintrc.json`, ao lado dos irmãos de mesma categoria (`tools/bugs-scripts/**`, `tests/reports/**`): descartável, gitignored, fora de qualquer tsconfig. Sem ela, script ad-hoc em `.tmp/` volta a travar o lint. - `package.json` — os dois lados removeram coisas diferentes e a união remove ambas: sai `test:integration:all` (dev, apontava para o runner do Bruno) e sai `@usebruno/cli` (dev), sai `@typescript/native-preview` (branch, ADR-0072). Preservadas as flags que o TS 7 tornou redundantes, já retiradas pela branch. - `pnpm-lock.yaml` — lado da dev aceito e regenerado com `pnpm install`, como manda o lockfile. Coexistem as deps do toolchain (oxlint, oxlint-tsgolint, typescript 7.0.2) e o que a dev trouxe: fastify 5.12.5, nodemailer 10.0.15, zero `usebruno`, zero `typescript-eslint`, zero `native-preview`. - `handbook/architecture/adr/README.md` — conflito aditivo: 0072 e 0073 da branch, 0074 da dev. Os três preservados em ordem; 0034 e 0038 seguem `Superseded by 0074`. Um vermelho veio do merge e foi corrigido aqui: `node-flags-not-redundant.test.ts` listava `scripts/e2e/bruno-all.sh` em `INVOCATION_POINTS`, e o arquivo deixou de existir. As três falhas tinham essa causa única — o `readSource` estourando ENOENT derrubava junto os dois testes que apenas iteram a mesma lista, que é exatamente o cenário descrito no docstring do gate. Nenhum dos dois lados produz esse vermelho sozinho: a lista é artefato do ADR-0072, o arquivo foi removido pelo ADR-0074. Gate verde: typecheck, format:check, lint (1017 arquivos, 154 regras, 0 erros) e 11963 testes com fail 0, 20 skipped. Assisted-by: Claude-Code:claude-opus-5
… vacuidade Nenhum defeito de correção no fonte de produção. O que a revisão achou foram duas guardas que passariam vazias e duas inconsistências de registro. `node-version-single-source`: o padrão `RUNS_NODE` varria uma única forma de invocação — `run:` em linha própria. Medido em 06/10, ele não casava nem `- run: pnpm install`, que é a forma mais comum em YAML, nem `run: |` com o comando na linha seguinte; `audit.yml` só foi pego porque, além dos três blocos escalares, tinha um `run: corepack enable` numa linha. Passa a cobrir as quatro formas. Provado invertido contra caso sintético: o padrão antigo deixa passar três das quatro, o novo acusa as quatro e segue ignorando comentário YAML, `uses:` e menção em prosa. Os 9 workflows de hoje recebem o mesmo veredito nas duas versões — o buraco era latente, e o próximo workflow escrito com bloco escalar o tornaria vivo com o gate verde. `lint-gaps`: a guarda contra vacuidade era `scanned > 1500`, um limiar. Com 2041 arquivos, dezenas poderiam escapar sem derrubar o número — e escapam de verdade os `.ts` versionados que caem fora dos globs de `include` do tsconfig, porque `trackedTs()` lista `src tests scripts db` enquanto o programa só entrega `db/drizzle/**`. Contagem não é a propriedade: passa a afirmar que nenhum arquivo versionado fica de fora, listando quais quando houver. A guarda contra lista vazia do git virou caso próprio, senão a comparação de conjuntos vazios passaria sozinha. `integration.yml`: a remoção das flags redundantes levou junto `--enable-source-maps`, que não é redundante no Node 24 — as redundantes eram `--experimental-strip-types` e `--no-warnings`. Todos os outros pontos de invocação a mantêm. Sem ela, um stack trace do próprio runner de integração aponta posição no `.js` empacotado. `compose.yaml`: o comentário afirmava "Sem NODE_OPTIONS" enquanto o `Dockerfile:128` define `NODE_OPTIONS="--enable-source-maps"`, herdado por todos aqueles serviços. Registro que descreve o contrário do código. `node-flags-not-redundant`: `INVOCATION_POINTS` não listava três hooks que executam o runtime (`pre-commit-typecheck.sh`, `stop-quality-gate.sh`, `prettier-write.sh`), onde as flags poderiam voltar sem vermelho. O critério de entrada é executar, não citar: `block-npm.sh` e `block-inline-interpreter.sh` mencionam `node` e `pnpm` dezenas de vezes no texto de ajuda e não invocam nada. Fica registrado no docstring que a lista é manual e que nada guarda contra entrada ausente — só contra entrada morta. Gate: typecheck, format:check e lint verdes; 11964 testes, fail 0, 20 skipped. Assisted-by: Claude-Code:claude-opus-5
chore(toolchain): lint vira oxlint type-aware e o TypeScript 7 entra sem side-by-side (ADR-0072)
…hain Traslado do #1030 para branch limpa, partindo da `dev`. A branch anterior recebia a `dev` por merge, e é isso que produzia o CHANGELOG defasado: o gerador percorre `git log --first-parent`, e numa branch que MERGEIA a `dev` ela é o segundo pai — tudo que ela acumulou fica invisível, escondido atrás de um merge commit que o gerador classifica como "não classificado". Medido em 06/10: a partir da branch antiga o `--first-parent` achava 2 PRs; a partir da `dev`, acha os 4. `update-branch` no #1030 teria piorado, porque também é merge. A branch de release precisa ser descendente LINEAR da `dev`. `release-notes`: entrega consolidada escreve as mudanças como bullets convencionais, e o `CONVENTIONAL` exige o tipo no início da linha — o `- ` o empurrava e o merge inteiro era descartado. O #1037 tem cinco bullets, entre elas um `feat(api-collections)!`: a rc.4 omitia uma quebra de contrato. `parseEntry` passa a devolver uma LISTA e emite uma entrada por bullet; sem bullets, segue valendo um merge, uma entrada. O marcador de lista é obrigatório no padrão novo, senão todo merge comum renderia duas vezes — coberto por caso próprio. Efeito medido: de 3 entradas e 1 não classificado para **8 entradas e 0 não classificados**, com o breaking em seção própria.⚠️ O gerador reescreve o CHANGELOG inteiro com a versão corrente e apaga as anteriores (#940). As seções rc.3, rc.2 e rc.1 foram recolocadas à mão depois de cada geração. O defeito continua aberto — aqui ele foi contornado, não corrigido. Gate: typecheck, format:check e lint verdes; 11966 testes, fail 0, 20 skipped. Assisted-by: Claude-Code:claude-opus-5
…from-dev chore(release): 1.0.0-rc.4 — PF, Silo, ciclo de QA da borda e o toolchain
…payload O `typecheck + format + lint + test` do #1031 ficou vermelho em `post-compact-rules-reminder.test.ts:201` com `spawnSync bash EPIPE`, e o processo tinha saído com `status: 0`. Parecia flake de CI — não era. Causa: quem invoca o hook escreve o payload JSON no stdin dele. O `post-compact-rules-reminder.sh` tinha o `exit 0` da falta do log ANTES do `payload=$(cat)`: ele saía sem consumir o stdin, e o escritor levava EPIPE. O sintoma é intermitente porque o buffer do pipe (64 KB) absorve a escrita quando o payload é pequeno e o processo sai rápido. Medido em 06/10: | payload | resultado | | --- | --- | | ~60 B e ~1 KB | 5 de 5 OK | | ~70 KB e ~500 KB | 5 de 5 EPIPE | O CI falhou com ~60 bytes porque o runner deixou o script sair primeiro. Era corrida, não aleatoriedade — e foi isso que a disfarçou de vermelho de infraestrutura. A régua não estava num lugar só: dos 4 hooks que leem stdin, **3** saíam antes de drenar (`post-compact-rules-reminder.sh`, `logbook.sh`, `log-instructions-loaded.sh`). Nos três, a leitura passa para antes de qualquer `exit` — inclusive antes do `cd`, que também pode falhar e sair. Varredura depois da correção: nenhum. O gate que trava a propriedade é `tests/cleanup/hooks-drain-stdin.test.ts`, com payload de 128 KB — acima do buffer, que é o que o torna determinístico. Payload pequeno aprovaria os hooks defeituosos, exatamente como o teste existente fazia.⚠️ A PRIMEIRA versão deste gate passou 4 de 4 com o `logbook.sh` revertido ao padrão defeituoso: ela usava só um cenário — `CLAUDE_PROJECT_DIR` num diretório vazio —, e nele o `cd` do `logbook.sh` FUNCIONA, então o hook não sai cedo e o defeito não aparece. Media a fronteira errada para dois dos três. O gate roda dois cenários: | cenário | `cd` | post-compact | logbook · log-instructions | | --- | --- | --- | --- | | diretório vazio | funciona | EPIPE | ok (não sai cedo) | | diretório inexistente | falha | EPIPE | EPIPE | Provado invertido com o segundo cenário no lugar: revertendo o `logbook.sh`, o gate acusa `logbook.sh — projeto inexistente`, e só esse caso. Gate: typecheck, format:check e lint verdes; 11973 testes, fail 0, 20 skipped. Assisted-by: Claude-Code:claude-opus-5
fix(harness): hook que sai cedo deixa de dar EPIPE em quem escreve o payload
|
⏸️ Aguardando aprovação da P.O. — não mergear. Decisão do dono em 06/10: os PRs param na Estado técnico, para quando a aprovação vier:
Depois do merge, falta marcar a tag Assisted-by: Claude-Code:claude-opus-5 |
|
Front: o web-app#420 entrou na 🤖 Generated with Claude Code |
Promove a
dev(1.0.0-rc.4) para amain— que é produção neste repositório.O que vai ao ar
api-collections/(266.bru) e@usebruno/cliremovidos — −317 pacotes (fix(auth,http,programs): ciclo de QA da borda — unicidade de CPF, uuidV4 estrito, magic-byte no logo; Hurl substitui o Bruno (ADR-0074) #1037)Adicionado
Corrigido
auth_user(fix(auth,http,programs): ciclo de QA da borda — unicidade de CPF, uuidV4 estrito, magic-byte no logo; Hurl substitui o Bruno (ADR-0074) #1037)uuidV4estrito na borda — fim do 500 emcontracts/:id(fix(auth,http,programs): ciclo de QA da borda — unicidade de CPF, uuidV4 estrito, magic-byte no logo; Hurl substitui o Bruno (ADR-0074) #1037)fastify5.12.5,nodemailer10.0.15 (fix(auth,http,programs): ciclo de QA da borda — unicidade de CPF, uuidV4 estrito, magic-byte no logo; Hurl substitui o Bruno (ADR-0074) #1037)Alterado
oxlinttype-aware e o TypeScript 7 entra sem side-by-side (ADR-0072);.nvmrcvira fonte única do runtime (ADR-0073) (chore(toolchain): lint vira oxlint type-aware e o TypeScript 7 entra sem side-by-side (ADR-0072) #1035)Por que isto importa agora
A
mainestá em1.0.0-rc.3, comfastify@5.12.1enodemailer@9.1.1— o GitHub acusa 2 vulnerabilidadeshighna branch default. As correções existem desde o #1037 e só chegam à produção por aqui.Medições
dev..main= 0 depois doupdate-branch: amainé ancestral dadev, nada de conteúdo existe só nela.update-branchalterou 0 arquivos — trouxe apenas o nó de merge da promoção anterior (a16e1deb), exigido porque a proteção damaintemstrict: true.dev: 4 seções de versão (rc.4, rc.3, rc.2, rc.1), com a rc.4 gerada do histórico porpnpm release:notes.Depois do merge
Marcar a tag
v1.0.0-rc.4namain, conforme o rito.Assisted-by: Claude-Code:claude-opus-5