Repository navigation
chore(toolchain): lint vira oxlint type-aware e o TypeScript 7 entra sem side-by-side (ADR-0072) - #1035
Conversation
…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
…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
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
Sincronizado com a
|
| Arquivo | Tipo | Resolução |
|---|---|---|
scripts/e2e/bruno-all.sh |
delete/modify | remoção aceita — o Bruno saiu pelo ADR-0074 |
eslint.config.js |
delete/modify invertido | remoção aceita (ADR-0072) + .tmp/** portado para .oxlintrc.json |
package.json |
conteúdo | união das duas remoções |
pnpm-lock.yaml |
conteúdo | lado da dev + pnpm install |
handbook/architecture/adr/README.md |
conteúdo | aditivo — 0072, 0073 e 0074 preservados |
O eslint.config.js merece nota: a branch deletou o arquivo e a dev o modificou, acrescentando .tmp/** aos ignores. Aceitar a remoção sem mais nada perderia essa correção em silêncio — o ignorePatterns do oxlint não tinha a entrada. Ela foi portada para junto dos irmãos de mesma categoria (tools/bugs-scripts/**, tests/reports/**): descartável, gitignored, fora de qualquer tsconfig.
No manifesto, cada lado removera coisa diferente: saíram test:integration:all e @usebruno/cli (dev) e @typescript/native-preview (branch). O lock passa a conter o toolchain e o que a dev trouxe — fastify@5.12.5, nodemailer@10.0.15, zero usebruno, zero typescript-eslint, zero native-preview.
O audit (produção — blocking) deve virar verde
Ele falhava porque a branch, aberta antes do #1037, ainda carregava fastify@5.12.1 e nodemailer@9.1.1. Medido após o merge: pnpm audit --prod --audit-level=high → No known vulnerabilities found.
Achados do code-review tratados
Nenhum defeito de correção no fonte de produção. Dois gates aprovavam por vacuidade:
node-version-single-source— o padrãoRUNS_NODEvarria sórun:em linha própria. Não casava nem- run: pnpm install, a forma mais comum, nemrun: |com o comando na linha seguinte. Passa a cobrir as quatro formas, provado invertido contra caso sintético; os 9 workflows recebem o mesmo veredito nas duas versões, então o buraco era latente.lint-gaps— a guarda erascanned > 1500, um limiar: com 2041 arquivos, dezenas escapariam sem derrubar o número. Passa a afirmar a propriedade — nenhum.tsversionado fora do programa — e lista quais, quando houver.
Mais três correções de consistência: integration.yml recuperou --enable-source-maps (que não é redundante no Node 24, ao contrário de --experimental-strip-types e --no-warnings); o comentário do compose.yaml afirmava "Sem NODE_OPTIONS" enquanto o Dockerfile:128 a define; e INVOCATION_POINTS ganhou três hooks que executam o runtime.
Para a revisão da borda
.meta({ example }) → .meta({ examples: [...] }) muda o OpenAPI publicado em 4 pontos (auth ×3, budget-plans ×1). É o keyword correto para 3.1.1 e está declarado no ADR-0072 §D6, mas consumidor que leia schema.example perde o valor — vale conferir do lado do BFF.
Gate
typecheck ✅ · format:check ✅ · lint ✅ (1017 arquivos, 154 regras, 0 erros) · 11964 testes, fail 0, 20 skipped.
Assisted-by: Claude-Code:claude-opus-5
Resumo
Troca o lint de ESLint + typescript-eslint para oxlint type-aware e leva o TypeScript 7 ao gate sem side-by-side — implementa o ADR-0072 (aceito em 05/10), que supersede a decisão de linter da Inquiry-0029 e o D2 do ADR-0067, e com isso tira do papel o D1 e o D3 do ADR-0067 (aceitos em 25/08, nunca implementados).
Por que agora, se a Inquiry-0029 decidiu ficar no ESLint: ela escolheu ESLint +
--cachepela velocidade. Medido hoje:--cachedá falso verde — mudar só o tipo de retorno ema.tsdeixa umno-floating-promisesemb.tspassar com cache (exit 0) e falhar sem (exit 1); a FAQ do typescript-eslint confirma que o cache não acompanha dependência entre arquivos;Cache not found for input keys) — o passoLintleva 39–62 s.Commits
fix(lint).meta({ example })→examples: [...]chore(toolchain)enforced_by, skillsdocs(toolchain)docs(adr)superseded, agenttypescript-language-expertfix(toolchain)typescriptestava em^7.0.2; fixado e cobrado por asserção no gateComo a paridade foi provada (não presumida)
.oxlintrc.jsongerado doeslint --print-configdos cinco contextos: 154 das 158 regras com a mesma severidade, opções e exceções por pasta; todas as categorias do oxlint desligadas.eslint-disabledesligadas nos dois, 222 de 224 violações reais achadas no mesmo arquivo e linha; as 2 restantes sãonaming-convention.max: 4— o default do oxlint é 3).no-octalotscrecusa (TS1121);class,naming-conventionemember-orderingviram gate de AST emtests/cleanup/lint-gaps.test.ts(APItypescript/unstable/*, concentrada emtests/support/ts-ast.ts). Conferido contra o ESLint: 46 de 46 nomes idênticos em 2036 arquivos; fixtures 15 de 15; prova invertida reprova as três.typecheck·format:check·lint(2,3 s) ·test— 11.904 pass, 0 fail, 20 skip.Riscos declarados
unstable/do TS 7 — por isso otypescripté exato, e agora o gate cobra isso.nurseryno oxlint (no-unnecessary-condition,prefer-optional-chain,no-useless-assignment).tscdo projeto passa a ser o TS 7 (typecheck ~1,9 s contra ~7,2 s no TS 6, ambos verdes).fix(lint)(writer.integration,renumber-by-vigencia.drizzle-mysql) — só a asserção muda; o CI de integração os cobre.Fora do escopo, registrado
ADR-0006-C4dizenforced_by: [], mas omodule-boundary.test.tsjá garante a alegação.eslint.config.jsnunca as cobriu).O Prettier fica; a troca para
oxfmtvem em PR próprio, com ADR.