Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
83a5a69
feat(deploy): manifesto declara as unidades executáveis e o que exigem
GabrielAderaldo Oct 7, 2026
cb156d8
fix(deploy): o gate do manifesto deixa de ser tautologia e passa a pe…
GabrielAderaldo Oct 7, 2026
d58a96f
Merge pull request #1051 from ERP-Bem-Comum/feat/manifesto-de-workloads
GabrielAderaldo Oct 8, 2026
6976c2f
docs(financial): o ADR-0075 registra a VAN em produção, e quatro arte…
GabrielAderaldo Oct 14, 2026
a7b070d
chore(doc): o repositório deixa de mentir sobre como ele roda — trasl…
GabrielAderaldo Oct 14, 2026
2b251d2
Merge pull request #1058 from ERP-Bem-Comum/chore/registro-deixa-de-m…
GabrielAderaldo Oct 14, 2026
7ba383b
feat(deploy): o template de env e a doc de variáveis passam a ser GER…
GabrielAderaldo Oct 14, 2026
9ef5c4b
feat(deploy): o ambiente de um adapter pertence ao ADAPTER, não à uni…
GabrielAderaldo Oct 14, 2026
d7c1213
fix(deploy): a mensagem de boot nomeia a variável, e a porta deixa de…
GabrielAderaldo Oct 14, 2026
107cf5a
docs(deploy): o ciclo E2E local vira ferramental versionado, com as s…
GabrielAderaldo Oct 15, 2026
8669cfb
Merge pull request #1060 from ERP-Bem-Comum/feat/env-derivado-do-mani…
GabrielAderaldo Oct 15, 2026
ad77fcb
docs(harness): a rule que faltava para `src/deploy/`, e a da suíte de…
GabrielAderaldo Oct 15, 2026
81bbf76
Merge pull request #1061 from ERP-Bem-Comum/docs/rules-do-deploy-e-da…
GabrielAderaldo Oct 15, 2026
55a126f
Merge branch 'main' into dev
GabrielAderaldo Oct 15, 2026
824f064
feat(ci): issue fecha ao entrar na dev, e deixa de depender da branch…
GabrielAderaldo Oct 15, 2026
6456023
Merge pull request #1064 from ERP-Bem-Comum/feat/fecha-issue-ao-entra…
GabrielAderaldo Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 0 additions & 293 deletions .claude/agents/bruno-api-client-expert.md

This file was deleted.

14 changes: 9 additions & 5 deletions .claude/agents/cnab240-bradesco.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,15 @@ bonito. Fora do escopo atual, use a skill [`issue-report`](../skills/issue-repor
convênio é barrado por `tests/cleanup/bank-fixture-masking.test.ts` (reservados `000000` e
`999999`); **os demais dependem do seu julgamento**. E não escreva o valor no commit, no assert
nem na issue — explicar a correção citando o dado a repete.
- **Não há ambiente de homologação para remessa de pagamento.** A única conexão é produção, no
convênio real, onde arquivo de teste vira pagamento de verdade
([ADR-0061](../../handbook/architecture/adr/0061-van-bucket-contract-supersedes-0060-pendencies.md)).
Validar a **forma** é o mais longe que dá para ir sem mover dinheiro. Nunca transmita para
"testar".
- **A transmissão está em produção desde 06/09/2026** — TED, crédito em conta e boleto no piloto; o
**Pix** entrou depois, com a forma arbitrada por laudo escrito do banco em 05/09/2026 e a operação
liberada pelo próprio Bradesco
([ADR-0075](../../handbook/architecture/adr/0075-van-transmission-exercised-supersedes-0061-pilot-pending.md),
que supersede o estado da integração do ADR-0061). ⚠️ **Isso não afrouxa nada — a razão só muda de
lugar.** Gravar objeto no prefixo de saída **é enfileirar pagamento**, e quem transmite é o
**cliente, sobre título real, por decisão da P.O.** Você nunca aciona transmissão para "ver o que
acontece", e isso não depende de existir homologação: depende de o arquivo ser dinheiro. Validar a
**forma** segue sendo o mais longe que dá para ir sem mover dinheiro.
- **Idioma:** código e identificadores em **EN**; comentário, doc, commit e resposta em **PT-BR com
acentuação**. Erro interno é union de string `'kebab-case'` em EN.
- **Commit** leva `Assisted-by: AGENT_NAME:MODEL_VERSION`. **Nunca** `Signed-off-by`.
Expand Down
17 changes: 16 additions & 1 deletion .claude/rules/api-collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@ Suíte da borda HTTP em **Hurl** — normativo: **[ADR-0074](../../handbook/arch

- **A suíte convertida está `.gitignore`d, e isso não é descuido.** `api-collections-hurl/` (241 requests em 23 arquivos sob `casos/`) e `api-collections-http/` são uso interno enquanto o seed E2E não existir. O `.hurl` **nasce sem segredo** (variável vem de `--variables-file`), então é versionável no dia em que virar gate; o `.http` **não é** — ele só funciona com o token colado dentro do arquivo.

- **Ainda não há gate E2E da borda, e isso é anterior à troca de ferramenta.** O `bruno-all.sh` caiu em 05/10 e nada o substituiu: medido em 06/10, **82 de 241** requests executam, o resto para em variável indefinida — 8 perfis de token que exigem o **seed E2E** (nenhum e-mail do environment existe no banco de dev) e IDs criados em outro arquivo. Não citar um `.hurl` daqui como prova de que uma rota funciona sem ter rodado.
- **Ainda não há gate E2E da borda, e isso é anterior à troca de ferramenta.** O `bruno-all.sh` caiu em 05/10 e nada o substituiu. Não citar um `.hurl` daqui como prova de que uma rota funciona sem ter rodado.

**Estado medido em 14/10/2026** (antes: 82/241, em 06/10 — o salto veio do seed E2E e do banco limpo, não de mudança na suíte): **191 de 241 requests enviados**, 6 arquivos verdes, **zero erro 500** e **zero defeito de aplicação**. Reprodutível com `swift scripts/debug/macos/local-e2e.swift --reset`, que semeia os 8 perfis e recria o banco. O que impede os 50 restantes, por natureza:

| Causa | Nº | Resolve com |
| :--- | ---: | :--- |
| `[Captures]` não cruzam arquivos | 48 | juntar arquivos ou pré-criar e injetar IDs — **nenhuma env resolve** |
| Asserts de `403` | **24** | **a [#634](https://github.com/ERP-Bem-Comum/core-api/issues/634)** — ver abaixo |
| Assert de `409` | 1 | a asserção supõe resíduo; `--reset` a invalida |
| `jsonpath "$.meta" exists` | 2 | a conversão perdeu a condicionalidade do `.bru` |

🚨 **A suíte NÃO pode passar enquanto o `AUTH_RBAC_MODE` estiver em bypass.** Os 24 casos verificam *"autenticado sem permissão → 403"*, e sob bypass todo autenticado é super-usuário; o modo está **fixado por código** (`src/server.ts`, duas linhas marcadas `← religar`). Ao ver esses 24 vermelhos, **não os conserte na suíte e não os trate como defeito** — eles voltam ao verde religando o RBAC. Hoje quem olha a suíte não distingue "RBAC desligado" de "autorização quebrada".

⚠️ Os 24 só ficaram visíveis **depois** de semear os perfis: antes o `bareToken` era variável indefinida e os casos nem eram enviados. Destravar o seed não criou o problema; revelou uma camada de verificação de segurança que ninguém exercia.

- **Três detalhes de invocação que o README da suíte não traz, medidos em 14/10:** `--file-root .` é **obrigatório** — sem ele os `PUT …/photo` morrem com `unauthorized access to file ../../tests/fixtures/…`; o **access token expira em minutos**, então gere-o imediatamente antes de rodar (um token de poucos minutos antes devolveu 401 em `/api/v1/me`, e o mesmo fluxo com token fresco passou 3/3); e `api-collections-hurl/` **é gitignored**, logo existe só no checkout principal — de dentro de uma worktree, resolva o caminho com `git rev-parse --path-format=absolute --git-common-dir`, nunca contando níveis de `..`.

- **`[Captures]` não cruzam arquivos** (medido: capture em `a.hurl` + uso em `b.hurl`, mesmo comando, `--jobs 1` → `you must set the variable`). Então ou o arquivo é autocontido (login → ações), ou o token vem de `--variables-file`. **`--jobs 1` é obrigatório**: `--test` paraleliza por default e o rate limit de login (5/min) é compartilhado — dois arquivos logando se auto-envenenam com `429`. **`--continue-on-error`** em CI, porque o Hurl para no primeiro assert que falha dentro do arquivo.

Expand Down
6 changes: 5 additions & 1 deletion .claude/rules/cnab.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ Emissor e parser do CNAB 240 Multipag Bradesco. É **ACL** ([ADR-0006](../../han

- **O Validador Universal trava em dois casos, e travar esconde defeito.** CEP inexistente e crítica em lote **não-primeiro** fazem a página não devolver relatório — medido por eliminação na inquiry-0033. **"Quebrou" nunca significa "arquivo válido"**, e o relatório dele é prosa sem código G059: repete a crítica por registro afetado, então contar linhas não é contar defeitos. Três das cinco críticas daquele dia **não têm código na G059** — a tabela não cobre o que o validador cobra.

- **Não há ambiente de homologação para remessa de pagamento**: a única conexão é produção, no convênio real, onde arquivo de teste vira pagamento de verdade ([ADR-0061](../../handbook/architecture/adr/0061-van-bucket-contract-supersedes-0060-pendencies.md)). O validador confere **forma** e é o mais longe que se vai sem mover dinheiro — **nunca transmita para "testar"**.
- **A transmissão está em produção nas quatro formas, e as datas são duas** — **TED, crédito em conta e boleto desde 06/09/2026** (o piloto); o **Pix depois disso**, com a forma arbitrada por laudo escrito do banco em 05/09/2026 e a operação confirmada pela P.O. em 14/10/2026. Em todas, arquivo gerado por este código, transmitido pela VAN e **lido pelo banco do cedente**, conferido pelo cliente ([ADR-0075](../../handbook/architecture/adr/0075-van-transmission-exercised-supersedes-0061-pilot-pending.md), que supersede o estado da integração do 0061). O Pix foi destravado por **habilitação do banco**, não por mudança nossa. Falta exercitar **as demais contas-cedente** — o piloto usou a conta em produção.

⚠️ **Nada disso afrouxa a proibição; ela só muda de razão.** Gravar objeto no prefixo de saída **é enfileirar pagamento** ([ADR-0060](../../handbook/architecture/adr/0060-van-transport-via-s3-bucket-supersedes-0008-relay.md)): `sandbox/` existe apenas no bucket de homologação, e errar o destino exige trocar o **nome do bucket**, não o prefixo. Quem transmite é **o cliente, sobre título real, por decisão da P.O.** — a validação em produção é cerimônia conduzida, não teste. **Nenhum agente aciona transmissão por iniciativa própria para ver o que acontece**, e isso não depende de existir homologação: depende de o arquivo ser dinheiro. O validador confere **forma**, e para o Pix o laudo escrito do banco (05/09/2026, [inquiry-0037](../../handbook/inquiries/0037-laudo-multipag-pix-e-validador-cego.md)) arbitra acima dele — nenhum dos dois diz nada sobre o transporte.

⚠️ **Afirmação sobre o estado da operação, nesta rule, carrega data e fonte** — este repositório **registra** o estado da VAN e não o **mede**: não há sonda nem `/health` que responda por ela. A alínea anterior dizia que a transmissão nunca havia ocorrido e sobreviveu **cinco semanas** ao primeiro pagamento real; nesse intervalo, duas vezes, um agente a citou para recusar operação legítima e argumentar contra a P.O. ([#993](https://github.com/ERP-Bem-Comum/core-api/issues/993)). Texto sem data é lembrança apresentada como norma.

- ⚠️ **Fixture de CNAB não recebe dado real de cadastro.** Convênio, agência, conta, CPF, CNPJ, endereço de parceiro. Os repositórios são **públicos**, e fixture é o caminho por onde esse dado entra — um convênio copiado de arquivo recebido do banco já viveu aqui em 16 ocorrências. `tests/cleanup/bank-fixture-masking.test.ts` barra o convênio (reservados `000000` e `999999`); **o resto depende de julgamento**. E o valor não vai na mensagem de commit, no assert nem na issue — explicar a correção citando o dado a repete.

Expand Down
58 changes: 58 additions & 0 deletions .claude/rules/deploy-manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
paths:
- 'src/deploy/**/*.ts'
- 'scripts/deploy/**/*.ts'
- 'scripts/debug/**'
verify:
- claim: 'o `.env.example` é GERADO — editá-lo à mão é desfeito pelo gerador e acusado pelo gate'
root: 'scripts/deploy'
pattern: 'ARQUIVO GERADO'
expect:
- 'scripts/deploy/generate-env-artifacts.ts'
- claim: 'a descrição de cada variável vive no catálogo, uma vez, indexada pela VARIÁVEL'
root: 'src/deploy'
pattern: 'export const ENV_CATALOG'
expect:
- 'src/deploy/env-catalog.ts'
- claim: 'o ambiente de um adapter pertence ao adapter, não à unidade que declara a capacidade'
root: 'src/deploy'
pattern: 'CAPABILITY_ADAPTERS'
expect:
- 'src/deploy/capability-adapters.ts'
---

`src/deploy/workloads.ts` é a fonte auto-contida do que este repositório sabe executar — `command`, regime, capacidades e as três listas de env. Que ele case com o código é cobrado por `tests/cleanup/workloads-manifest.test.ts`; a bijeção com o catálogo e a volta `código → manifesto`, por `tests/cleanup/env-catalog.test.ts`. Nada disso se repete aqui.

- **O `.env.example` e a doc de variáveis são DERIVADOS — não se editam à mão.** Saem de `env-catalog.ts` + `workloads.ts` por `pnpm run env:generate`, e `tests/cleanup/env-artifacts-generated.test.ts` exige que o disco seja **idêntico** ao gerado, na forma do `format:check` contra o Prettier. Editar à mão é desfeito na próxima geração; o gate acusa antes.

**Gerar, e não conferir, é decisão medida** ([ADR-0073](../../handbook/architecture/adr/0073-nvmrc-single-source-supersedes-0058-partial.md)): o gate da versão do Node cobrava só o major, e a divergência de minor (`24.16.0` contra `24.15`) sobreviveu **verde**. Igualdade byte a byte não tem essa fenda. O defeito que originou isto: o template não declarava `VAN_S3_REGION`/`VAN_S3_BUCKET`, e `cp .env.example .env && pnpm run dev` não subia nem o `http` ([#1059](https://github.com/ERP-Bem-Comum/core-api/issues/1059)).

- **Três lugares possíveis para uma variável, e a escolha diz o que ela É.** Lista da unidade em `workloads.ts` = *o processo exige sempre*. `capability-adapters.ts` = *só o adapter que a usa exige, quando ele é o escolhido*. `notComposed` no catálogo = *existe código que a lê, fora do caminho de boot de qualquer unidade*. O gate recusa a mesma variável em dois lugares: a lista da unidade e o adapter fazem afirmações incompatíveis, e as duas juntas garantem que uma mente.

⚠️ **Não crie constraint condicional de valor** (`required-when EMAIL_PROVIDER=smtp`). Ela acopla o manifesto ao **valor string** de outra variável — renomear o provider quebra a declaração sem nada acusar. O vínculo correto é estrutural: a unidade declara `requires: [{ kind: 'smtp' }]`, e o adapter declara o que precisa. Adapter novo não toca o manifesto, porque a capacidade já está declarada. `selectedBy` ausente significa adapter **fixo** da capacidade — e então o ambiente dele pertence à unidade, como as `S3_*`.

- 🚨 **Precedência de env tem TRÊS camadas, e o mecanismo define a sintaxe aceita.** Medido em 14/10/2026; custou três ciclos de diagnóstico e **nenhum produziu erro no boot**.

```bash
X_TESTE=do-ambiente node --env-file=arq.env -e 'console.log(process.env.X_TESTE)'
# → do-ambiente
```

| Mecanismo | Sintaxe | Vence env de processo? |
| :--- | :--- | :--- |
| overmind lendo `.env` | dotenv | injeta **como** env de processo |
| `--env-file` do Node | valor cru | **não** |
| `set -a; . arquivo` | quoting de **shell** | **sim** |
| inline no Procfile | shell | **sim** |

Como o template declara `AUTH_SEED_JSON=""` e `CORE_API_E2E="false"` — corretos para ele —, um `--env-file` com o valor real **nunca vence**: a guarda lê string vazia, devolve `undefined` (o caminho **certo** de produção) e o sintoma aparece oito requests depois. E trocar para `source` sem requotar fez o shell comer as aspas duplas de um JSON: **2255 caracteres viraram 1999**, exatamente as 256 aspas, e o valor chegou presente e corrompido. Para sobrescrever o que o `.env` declara, use `source` (molde: `scripts/debug/run-http-with-e2e-env.sh`) ou inline — nunca `--env-file`.

- **Variável comparada como string literal não aceita sinônimo.** `CORE_API_E2E` passa a guarda só com `'1'`: `true`, `yes` ou `on` deixam o seed **inerte, sem aviso**. Ao declarar flag nova no catálogo, escreva na `description` **qual valor liga** — "booleano" não basta quando a comparação é literal.

- **Dois rate limits independentes, e subir um não afeta o outro.** `AUTH_LOGIN_RATE_LIMIT_MAX` (5/min) é defesa contra força bruta; `RATE_LIMIT_MAX` (100/janela), contra abuso de uso. A separação é deliberada. Medido: resolvido o de login, a suíte disparou 185 requests em ~1 s e **142 de 347** voltaram 429 no geral.

- **`example` vai para arquivo versionado, e os repositórios são públicos.** Só valor de desenvolvimento (`localhost`, `dev`) ou placeholder. Nunca credencial, endpoint de produção, nome real de bucket, convênio, agência, conta ou documento de parceiro — o mesmo cuidado que `tests/cleanup/bank-fixture-masking.test.ts` cobra para fixture de CNAB. Chave privada **nunca**: deixe a instrução de gerar, não o valor.

- **Mensagem de erro de configuração NOMEIA o campo.** O [ADR-0068](../../handbook/architecture/adr/0068-env-fail-fast-every-environment.md) justifica o fail-fast assim: *"o processo não sobe **e diz qual campo falta** — é o único [modo de falha] que chega a quem tem a mão no problema"*. Formatar só o `tag` do erro cumpre metade: `config de e-mail inválida (invalid-provider-config)` custou dois boots e uma sonda, com o `field` disponível e descartado. O molde é `describeEmailConfigError` / `describeVanS3ConfigError` — e `raw` de campo sensível não entra na mensagem (CWE-532), nem valor sem passar por `echoEnvValue` (CWE-117).

Ciclo local completo, com as sete armadilhas medidas: [`handbook/runbooks/local-stack-setup.md`](../../handbook/runbooks/local-stack-setup.md) §9 · catálogo gerado: [`handbook/infrastructure/14-environment-variables.md`](../../handbook/infrastructure/14-environment-variables.md) · ferramental de debug: [`scripts/debug/README.md`](../../scripts/debug/README.md).
Loading
Loading