@payconductor/houndsman 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -3
  3. package/assets/houndsman.png +0 -0
  4. package/package.json +63 -5
  5. package/src/cli/index.ts +210 -0
  6. package/src/core/assets.ts +20 -0
  7. package/src/core/brief.ts +162 -0
  8. package/src/core/commands/context.ts +39 -0
  9. package/src/core/commands/review.ts +50 -0
  10. package/src/core/commands/scaffold.ts +373 -0
  11. package/src/core/commands/setup.ts +75 -0
  12. package/src/core/commands/test.ts +20 -0
  13. package/src/core/commands/update.ts +30 -0
  14. package/src/core/commands/watchdog.ts +105 -0
  15. package/src/core/config-loader.ts +87 -0
  16. package/src/core/config.ts +59 -0
  17. package/src/core/doc-discoverer.ts +33 -0
  18. package/src/core/file-classifier.ts +247 -0
  19. package/src/core/jev/index.ts +12 -0
  20. package/src/core/jev/jev-candidates.ts +105 -0
  21. package/src/core/jev/jev-client.ts +99 -0
  22. package/src/core/jev/jev-detector.ts +203 -0
  23. package/src/core/jev/jev-questions.ts +92 -0
  24. package/src/core/jev/jev-types.ts +91 -0
  25. package/src/core/orchestrator.ts +444 -0
  26. package/src/core/paths.ts +30 -0
  27. package/src/core/pr-context.ts +271 -0
  28. package/src/core/registry-check.ts +145 -0
  29. package/src/core/report-builder.ts +357 -0
  30. package/src/core/types.ts +137 -0
  31. package/src/core/watchdog-registry.ts +43 -0
  32. package/src/index.ts +56 -0
  33. package/src/skill/AUDIT-PROTOCOL.md +96 -0
  34. package/src/skill/OUTPUT-FORMAT.md +70 -0
  35. package/src/skill/README.md +116 -0
  36. package/src/skill/SETUP.md +99 -0
  37. package/src/skill/example-review.md +58 -0
  38. package/src/skill/houndsman-update.md +251 -0
  39. package/src/skill/houndsman.md +239 -0
  40. package/src/tests/fixtures/fake-project.ts +64 -0
  41. package/src/tests/review-scripts.test.ts +851 -0
@@ -0,0 +1,70 @@
1
+ # Formato de Saída dos Watchdogs
2
+
3
+ Todo watchdog DEVE gravar **um arquivo JSON** com seus achados. O `report-builder.ts`
4
+ consolida os JSONs em `.houndsman/.runs/<branch-slug>/review.md`.
5
+
6
+ > **Não** escrever markdown livre no chat. O único output consumido pelo pipeline é o JSON.
7
+
8
+ ## Caminho do arquivo
9
+
10
+ O caminho exato é informado no brief do watchdog (gerado por `houndsman`):
11
+
12
+ ```
13
+ .houndsman/.runs/<branch-slug>/findings/<watchdogId>.json
14
+ ```
15
+
16
+ - `<branch-slug>`: branch com `/` substituído por `-` (ex.: `feature/x` → `feature-x`).
17
+ - `<watchdogId>`: id do watchdog (ex.: `backend-architecture`).
18
+
19
+ ## Schema
20
+
21
+ ```json
22
+ {
23
+ "watchdogId": "backend-architecture",
24
+ "reviewedFiles": ["src/services/order/order-service.ts"],
25
+ "skipped": [],
26
+ "findings": [
27
+ {
28
+ "rule": "Route acessando db",
29
+ "severity": "blocking",
30
+ "file": "src/routes/order-route.ts",
31
+ "line": 5,
32
+ "message": "Arquivo de rota importa `db` e executa query inline.",
33
+ "action": "Mover a query para o service correspondente.",
34
+ "evidence": "import { db } from '../db'"
35
+ }
36
+ ]
37
+ }
38
+ ```
39
+
40
+ ### Campos
41
+
42
+ | Campo | Tipo | Obrigatório | Descrição |
43
+ |---|---|---|---|
44
+ | `watchdogId` | string | ✅ | Id do watchdog (deve casar com uma chave de `.houndsman/watchdogs/index.ts`) |
45
+ | `reviewedFiles` | string[] | ✅ | Arquivos efetivamente inspecionados |
46
+ | `skipped` | string[] | ✅ | Arquivos do domínio que NÃO foram lidos + motivo |
47
+ | `findings` | object[] | ✅ | Achados (vazio se nada encontrado) |
48
+ | `findings[].rule` | string | ✅ | Regra violada (conforme o brief do watchdog) |
49
+ | `findings[].severity` | `"blocking" \| "attention" \| "suggestion" \| "nit"` | ✅ | Severidade |
50
+ | `findings[].file` | string | ✅ | Caminho relativo à raiz |
51
+ | `findings[].line` | number | — | Linha do achado |
52
+ | `findings[].message` | string | ✅ | O que está errado (curto, específico) |
53
+ | `findings[].action` | string | ✅ | O que fazer |
54
+ | `findings[].evidence` | string | — | Trecho que comprova o achado |
55
+
56
+ ## Severidade
57
+
58
+ | Severidade | Emoji | Bloqueia merge? |
59
+ |---|---|---|
60
+ | `blocking` | ❌ | Sim |
61
+ | `attention` | ⚠️ | Não (requer atenção) |
62
+ | `suggestion` | 💡 | Não |
63
+ | `nit` | 🔎 | Não (detalhe/observação) |
64
+
65
+ ## Regras
66
+
67
+ - Sem achados → `"findings": []` (arquivo **obrigatório**).
68
+ - Um achado por regra violada; não agrupar regras diferentes.
69
+ - `file:line` sempre que possível; `evidence` quando o achado não é óbvio.
70
+ - Não inventar achados — se não houver violação, o array fica vazio.
@@ -0,0 +1,116 @@
1
+ # houndsman — skill
2
+
3
+ Revisão automatizada de Pull Requests — CLI independente + camada de configuração do projeto.
4
+
5
+ ## Terminologia
6
+
7
+ - **houndsman** — o orquestrador/treinador (CLI + motor).
8
+ - **watchdog** — cada agente especialista por domínio que audita o diff.
9
+ - **review/revisão** — o processo de revisão.
10
+
11
+ ## Quem executa o quê
12
+
13
+ - **Você** só invoca o skill: `/houndsman`. Não roda script à mão.
14
+ - **O skill** orquestra: executa o CLI `bun run houndsman` e despacha os subagentes.
15
+ - **O CLI** tem passos distintos — um comando cada:
16
+
17
+ | Passo | Comando | Quem roda | Resultado |
18
+ |---|---|---|---|
19
+ | 0. Contexto | `bun run houndsman context` | subagente | `context.json` + `context-brief.md` → `context-summary.json` |
20
+ | 1. Preparar | `bun run houndsman` | skill | `classification.json` + `candidates.json` + `briefs/` + `manifest.json` |
21
+ | 2. Revisar | *(subagentes)* | skill | `findings/<watchdog>.json` (um por watchdog) |
22
+ | 3. Finalizar | `bun run houndsman --finalize` | skill | `review.md` |
23
+
24
+ ## Comandos
25
+
26
+ | Comando | Função |
27
+ |---|---|
28
+ | `houndsman context` | Passo 0 — contexto da PR via `gh` |
29
+ | `houndsman` | Passo 1 — preparar (gera os briefs) |
30
+ | `houndsman --finalize` | Passo 3 — gerar o relatório |
31
+ | `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
32
+ | `houndsman setup` | Cria a configuração inicial do projeto |
33
+ | `houndsman update` | Sincroniza os arquivos auto-gerados (`.houndsman/core`) |
34
+ | `houndsman doctor` | Valida a configuração e o ambiente (anti-drift) |
35
+ | `houndsman test` | Roda a suíte de testes da lib |
36
+
37
+ ### Flags
38
+
39
+ `--config <path>` · `--base <branch>` (default `main`) · `--head <ref>` (default `HEAD`) ·
40
+ `--branch <nome>` · `--dir <dir>` · `--clean` · `--no-jev` · `--fail-on-blocking` (no `--finalize`).
41
+
42
+ ## Artefatos
43
+
44
+ Tudo em `.houndsman/.runs/<branch-slug>/` (default do `artifactDir`, `.houndsman/.runs`):
45
+
46
+ | Arquivo | Conteúdo |
47
+ |---|---|
48
+ | `classification.json` | Watchdogs ativados + status (A/M/D/R) |
49
+ | `candidates.json` | Candidatos da pré-análise Jev |
50
+ | `context.json` | Payload bruto da PR via `gh` (ou marcador de indisponível) |
51
+ | `context-summary.json` | Resumo do subagente (objetivo/motivação/alterações) |
52
+ | `briefs/<watchdog>.md` | Instruções prontas para cada sub-agente |
53
+ | `manifest.json` | Resumo (watchdogs, arquivos, deletados, status, contexto) |
54
+ | `findings/<watchdog>.json` | Saída dos sub-agentes (schema `OUTPUT-FORMAT.md`) |
55
+ | `review.md` | Relatório final |
56
+
57
+ ## Estrutura
58
+
59
+ ### Pacote (motor)
60
+
61
+ ```
62
+ src/
63
+ ├── index.ts # API pública (defineWatchdog, defineHoundsmanConfig, tipos)
64
+ ├── cli/index.ts # CLI ÚNICO (bin `houndsman`)
65
+ ├── core/ # bibliotecas genéricas
66
+ │ ├── config.ts # contrato HoundsmanConfig + defineHoundsmanConfig
67
+ │ ├── config-loader.ts # descoberta/carregamento de houndsman.config.ts
68
+ │ ├── assets.ts # assets embarcados (src/skill/) — usados para gerar a camada
69
+ │ ├── paths.ts # layout fixo da camada (.houndsman/) + relFromRoot
70
+ │ ├── types.ts # Severity, Rule, WatchdogDefinition, defineWatchdog
71
+ │ ├── watchdog-registry.ts # getWatchdog/findWatchdog/getWatchdogContext(config)
72
+ │ ├── orchestrator.ts # preparar/finalizar
73
+ │ ├── brief.ts # defaultRenderBrief + PROCEDURE
74
+ │ ├── pr-context.ts # contexto da PR via gh
75
+ │ ├── file-classifier.ts # classificação (via `classify` dos watchdogs)
76
+ │ ├── doc-discoverer.ts # descoberta de docs
77
+ │ ├── report-builder.ts # dedupe/render do relatório
78
+ │ ├── registry-check.ts # validações anti-drift (config-driven)
79
+ │ ├── commands/ # context · review · watchdog · setup · update · test
80
+ │ └── jev/ # subsistema Jev (Passo 1.5)
81
+ ├── skill/*.md # assets markdown (embarcados no pacote)
82
+ └── tests/ # suíte da lib (project-agnóstica, "project fake")
83
+ ```
84
+
85
+ ### Projeto (consumidor — gerado por `houndsman setup`)
86
+
87
+ ```
88
+ houndsman.config.ts # HoundsmanConfig (dados; descoberto em runtime)
89
+ .houndsman/
90
+ ├── .gitignore # AUTO — ignora core/ e .runs/
91
+ ├── core/ # AUTO — sincronizado por `houndsman update`
92
+ │ ├── types.ts # snapshot dos tipos + helpers (autocontido)
93
+ │ └── skill/*.md # documentação do skill
94
+ ├── watchdogs/ # USUÁRIO — 1 módulo .ts por watchdog
95
+ │ └── index.ts # WATCHDOG_DEFINITIONS + type WatchdogId
96
+ ├── exclusions.ts # USUÁRIO
97
+ └── doc-mappings.ts # USUÁRIO
98
+ ```
99
+
100
+ > Os `SKILL.md` em `.agents/skills/houndsman/` e `.claude/skills/houndsman/` são
101
+ > ponteiros para `.houndsman/core/skill/houndsman.md`.
102
+
103
+ ## Manutenção
104
+
105
+ > As regras devem refletir os padrões **aplicados hoje**. Antes de adicionar uma regra,
106
+ > prove que o padrão existe no código (regra negativa: prove que o anti-padrão **não** existe).
107
+ > Regras devem ser **gerais/reutilizáveis** no domínio e declarar a **polaridade** no texto
108
+ > (`Promover:` = deve acontecer; `Evitar:`/`Não`/`Nunca` = não deve acontecer).
109
+
110
+ 1. Novas regras/watchdogs → editar `.houndsman/watchdogs/<id>.ts` (regras + escopo +
111
+ `classify`) ou `doc-mappings.ts`/`exclusions.ts`. Um watchdog novo exige só o módulo em
112
+ `.houndsman/watchdogs/<id>.ts` + entrada em `.houndsman/watchdogs/index.ts`.
113
+ 2. Rodar `bun run houndsman doctor` — valida a config (definições, classificação, specs Jev).
114
+
115
+ > Para qualquer alteração de regra (pontual ou auditoria completa), use o skill
116
+ > **`houndsman-update`**: `.houndsman/core/skill/houndsman-update.md`.
@@ -0,0 +1,99 @@
1
+ # Setup — usar o houndsman no seu projeto
2
+
3
+ O **houndsman** é um CLI instalado **globalmente**. A camada de configuração que ele gera
4
+ no seu projeto é **autocontida** — não exige nenhuma dependência local do pacote.
5
+
6
+ ## Pré-requisitos
7
+
8
+ - **Bun** — o CLI e o motor usam a runtime Bun (execução de TS, `Bun.spawnSync`).
9
+ - **git** — o diff usa `git diff <base>...<head> --name-status`.
10
+ - Opcional: **`gh`** (contexto da PR) e **`TYPESAFE_API_KEY`** (pré-análise Jev). Ambos são
11
+ **falha-aberto** — sem eles o pipeline segue normalmente.
12
+
13
+ ## Instalação (global)
14
+
15
+ ```bash
16
+ bun add -g @payconductor/houndsman
17
+ ```
18
+
19
+ O comando `houndsman` fica disponível em qualquer diretório.
20
+
21
+ ## Configuração
22
+
23
+ Na raiz do seu projeto:
24
+
25
+ ```bash
26
+ bun run houndsman setup
27
+ ```
28
+
29
+ Isso cria:
30
+
31
+ A camada separa o que é **auto-gerado** do que é **do usuário**:
32
+
33
+ | Caminho | Dono | O que é |
34
+ |---|---|---|
35
+ | `houndsman.config.ts` | usuário | Configuração — um objeto de dados (sem imports do pacote) |
36
+ | `.houndsman/watchdogs/example.ts` + `index.ts` | usuário | Comece com **1 watchdog de exemplo** |
37
+ | `.houndsman/exclusions.ts` | usuário | Arquivos que nunca entram na revisão |
38
+ | `.houndsman/doc-mappings.ts` | usuário | path → documentação de contexto |
39
+ | `.houndsman/core/types.ts` | **auto** | Snapshot dos tipos + helpers (tipagem sem install) |
40
+ | `.houndsman/core/skill/*.md` | **auto** | Documentação do skill |
41
+ | `.houndsman/.gitignore` | **auto** | Ignora `core/` e `.runs/` (gerados/temporários) |
42
+ | `.agents/skills/houndsman/SKILL.md` etc. | **auto** | Ponteiros de skill dos harnesses |
43
+
44
+ Além disso, adiciona o script `"houndsman": "houndsman"` ao `package.json` — assim
45
+ `bun run houndsman [...]` funciona na raiz do projeto. Os artefatos ficam em
46
+ `.houndsman/.runs/<branch-slug>/` (auto-ignorados).
47
+
48
+ Flags: `--name <projeto>` · `--harness agents,claude|both|none` · `--force` (sobrescreve só os
49
+ arquivos do usuário). É **idempotente** — arquivos do usuário existentes são mantidos.
50
+
51
+ ## Atualizar (auto-gerados)
52
+
53
+ Depois de atualizar a lib, sincronize os arquivos auto-gerados **sem tocar** nas suas regras:
54
+
55
+ ```bash
56
+ bun run houndsman update # reescreve .houndsman/core/** e .houndsman/.gitignore
57
+ ```
58
+
59
+ ## Verificar
60
+
61
+ ```bash
62
+ bun run houndsman doctor # valida config + ambiente (git/gh/Jev)
63
+ bun run houndsman test # suíte da lib (project-agnóstica)
64
+ bun run houndsman --base main # prepara briefs do diff atual
65
+ ```
66
+
67
+ ## Contrato do motor (`HoundsmanConfig`)
68
+
69
+ Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.ts` (gerado):
70
+
71
+ | Campo | Descrição |
72
+ |---|---|
73
+ | `projectName` | Nome legível (prompts/docs). |
74
+ | `artifactDir` | **Opcional** — onde gravar os artefatos (default `.houndsman/.runs`). |
75
+ | `watchdogs` | Definições dos watchdogs (incluem `classify`); os **ids são derivados** das chaves. |
76
+ | `exclusions` | Arquivos que nunca entram na revisão. |
77
+ | `docMappings` | Path → documentação de contexto. |
78
+ | `alwaysIncludeDocs` | Docs sempre presentes nos briefs (default `["AGENTS.md"]`). |
79
+
80
+ > O motor **não contém** ids, paths ou regras do projeto — tudo chega por `HoundsmanConfig`,
81
+ > carregado em runtime a partir de `houndsman.config.ts` (ou `--config <path>`).
82
+
83
+ ## Estrutura do pacote (motor)
84
+
85
+ ```
86
+ houndsman/
87
+ ├── package.json
88
+ └── src/
89
+ ├── index.ts # API pública (defineWatchdog, defineHoundsmanConfig, tipos)
90
+ ├── cli/index.ts # CLI único — bin `houndsman`
91
+ ├── core/ # bibliotecas genéricas (config, orchestrator, brief, jev/, …)
92
+ ├── skill/*.md # assets markdown (embarcados no pacote)
93
+ └── tests/ # suíte da lib (project-agnóstica, "project fake")
94
+ ```
95
+
96
+ ## Desenvolvimento da lib
97
+
98
+ - Scripts: `bun run test`, `bun run typecheck`, `bun run ci`.
99
+ - O motor é 100% agnóstico ao consumidor: nenhuma regra, path ou nome de projeto vive aqui.
@@ -0,0 +1,58 @@
1
+ # PR Review — feature/add-webhook-retry
2
+
3
+ **Data:** 2026-04-20
4
+ **Watchdogs ativos:** api-contracts, backend-architecture, payments-integrations, acquirer-integrations
5
+ **Achados:** 2 bloqueantes · 1 atenção · 1 sugestões · 1 nit
6
+
7
+ ## Contexto da PR
8
+ **PR:** #482 Adicionar retry de webhooks — https://github.com/org/repo/pull/482
9
+ **Branch:** `feature/add-webhook-retry` → `main`
10
+ **Objetivo:** Tornar o envio de webhooks resiliente a falhas temporárias do destinatário.
11
+ **Motivação:** Webhooks com falha exigiam reenvio manual e causavam perda de eventos em integradores.
12
+ **Resumo das alterações:**
13
+ - Nova fila de retry para webhooks que falharam.
14
+ - Novo endpoint interno para reprocessar eventos manualmente.
15
+ - Registro de tentativas no handler de envio.
16
+
17
+ ## ❌ blocking
18
+
19
+ - **Webhook handler sem verifySignature** — `server/src/services/integrations/acquirer/webhook/handle-charge-event.ts:15` · _Acquirer Integrations, Pagamentos & Integrações_
20
+ Payload processado antes de validar a assinatura do provider.
21
+ **Ação:** Validar `verifyWebhookSignature(payload, signature, secret)` antes de qualquer efeito.
22
+ **Evidência:** `const event = JSON.parse(body)`
23
+
24
+ - **Promise não aguardada** — `server/src/services/webhook/webhook-retry-service.ts:92` · _Pagamentos & Integrações_
25
+ `updateWebhookStatus(id, 'failed')` sem `await` — status pode não persistir antes do retorno.
26
+ **Ação:** Adicionar `await`.
27
+
28
+ ## ⚠️ attention
29
+
30
+ - **Retry sem backoff** — `server/src/services/webhook/webhook-retry-service.ts:55` · _Acquirer Integrations_
31
+ Retry com intervalo fixo de 1s.
32
+ **Ação:** Usar exponential backoff com jitter.
33
+
34
+ ## 💡 suggestion
35
+
36
+ - **Complexidade** — `server/src/services/webhook/webhook-retry-service.ts:45-78` · _Arquitetura Backend_
37
+ `retryWithBackoff` com 6 níveis de indentação.
38
+ **Ação:** Extrair `calculateBackoffDelay(attempt, config)` e usar early returns.
39
+
40
+ ## 🔎 nit
41
+
42
+ - **Ordem de membros** — `server/src/services/webhook/webhook-retry-service.ts:12` · _Arquitetura Backend_
43
+ Campo privado declarado antes do construtor público.
44
+ **Ação:** Reordenar membros (públicos primeiro).
45
+
46
+ ## Cobertura
47
+
48
+ | Watchdog | Arquivos revisados | Findings |
49
+ |---|---|---|
50
+ | API & Contratos | 2 | 0 |
51
+ | Arquitetura Backend | 3 | 1 |
52
+ | Pagamentos & Integrações | 4 | 2 |
53
+ | Acquirer Integrations | 3/4 (faltam 1) | 2 |
54
+
55
+ ## Conclusão
56
+
57
+ **Status:** ❌ Mudanças Necessárias
58
+ **Resumo:** 2 violações bloqueantes, 1 ponto de atenção, 1 sugestão.
@@ -0,0 +1,251 @@
1
+ # Atualização de Lógicas do houndsman
2
+
3
+ > **Documento canônico do skill `/houndsman-update`.** Os `SKILL.md` de cada harness
4
+ > (`.agents/skills/houndsman-update/` e `.claude/skills/houndsman-update/`) são apenas ponteiros para cá.
5
+
6
+ > **Propósito:** manter os watchdogs do skill `houndsman` alinhados ao que o
7
+ > projeto **realmente aplica** — seja para adicionar/ajustar uma regra a pedido do
8
+ > usuário, seja para uma auditoria geral após mudanças de padrão no código.
9
+
10
+ Este skill é o **mantenedor** do `houndsman`. Ele não revisa PRs; ele atualiza as regras
11
+ que o `houndsman` usa.
12
+
13
+ ---
14
+
15
+ ## Princípio Fundamental (Regra de Ouro)
16
+
17
+ > Só é regra o que o projeto **aplica hoje**. Como provar depende da **polaridade** da regra
18
+ > (ver Convenções de escrita, abaixo):
19
+ >
20
+ > - Regra **afirmativa** (`Promover:`): exige a **presença** de um padrão. Ele deve existir no
21
+ > código; se não existe em lugar nenhum, é `UTOPIAN` (remover/rebaixar).
22
+ > - Regra **negativa** (`Evitar:`, `Não`, `Nunca`): exige a **ausência** de um anti-padrão.
23
+ > **Zero ocorrências = regra seguida** → **manter**. Nunca remover uma regra negativa só
24
+ > porque não há ocorrências.
25
+
26
+ Toda regra nova ou alterada deve vir com **evidência**: `arquivo:linha` (regra afirmativa) ou
27
+ `0 ocorrências via grep X` do anti-padrão (regra negativa). Regra sem evidência é rejeitada ou
28
+ vira `suggestion` explicitamente aprovada pelo usuário.
29
+
30
+ Ver `AUDIT-PROTOCOL.md` para a taxonomia completa.
31
+
32
+ ---
33
+
34
+ ## Convenções de escrita das regras
35
+
36
+ Rubrica única — o texto da regra é renderizado **literalmente** no brief do subagente
37
+ (`renderBrief` em `src/core/brief.ts`), então toda ambiguidade vira ruído na revisão.
38
+ Toda regra (nova ou alterada) deve passar por **todos** os itens:
39
+
40
+ > **Prefixo de polaridade (obrigatório).** Toda regra começa com o sentido do que se espera:
41
+ > `Promover:` → algo que **DEVE** acontecer (a presença do padrão); `Evitar:` → algo que
42
+ > **NÃO DEVE** acontecer (a ausência do anti-padrão); `Não` e `Nunca` no início são
43
+ > equivalentes aceitos de `Evitar:`. Regra sem prefixo explícito é ambígua e o
44
+ > `houndsman doctor` emite um aviso. O prefixo define **um único sentido** por regra —
45
+ > ver *Unipolar* (item 8).
46
+
47
+ 1. **Sujeito explícito** — diz qual artefato é verificado; sem pronome órfão ("o antigo", "isso").
48
+ 2. **Condição inequívoca** — duas IAs chegam à mesma conclusão sobre o que é violação.
49
+ 3. **Critério concreto** — limite/prazo/lista explícito ou referência a símbolo real do código.
50
+ 4. **Geral e reutilizável** — descreve um padrão do **domínio**, não uma regra de negócio pontual
51
+ que só existe dentro de uma classe/use-case. Regra amarrada a um único ponto do código não é
52
+ replicável em outros contextos — isso é papel de **teste automatizado**, não do watchdog.
53
+ - ❌ `Promover: cálculo de taxa deve usar toDecimals` (o cálculo de taxa vive atrás de um único
54
+ use-case — a regra não se aplica em nenhum outro contexto).
55
+ 5. **Sem jargão abreviado ou vago** — sigla/termo/apelido deve estar definido ou ancorado num
56
+ símbolo/path real do código; nunca um apelido interno sem referência.
57
+ - ❌ `Evitar que o flow faça parte do grupo` (não se sabe o que é "flow" nem "grupo").
58
+ 6. **Sem qualificador vago** — proibido: "apenas por compatibilidade", "período de depreciação",
59
+ "conjunto real", "completos e corretos", "só faz sentido", "indefinidamente".
60
+ 7. **Polaridade explícita** — a regra começa com o sentido inequívoco:
61
+ - `Promover:` → algo que **DEVE** acontecer (ex.: `Promover: rotas validam a entrada com o schema do Elysia`).
62
+ - `Evitar:` → algo que **NÃO DEVE** acontecer; `Não` / `Nunca` no início são **equivalentes aceitos** de `Evitar:`.
63
+ 8. **Unipolar (um só sentido)** — a regra expressa **uma única direção**, a mesma do prefixo:
64
+ só afirmações de **promover** ou só afirmações de **evitar**. Não combine "faça X" **e**
65
+ "não faça Y" na mesma regra — são dois juízos independentes, com veredito e evidência
66
+ próprios. Regra que precisa dos dois sentidos **vira duas regras**: uma `Promover:` e
67
+ outra `Evitar:`.
68
+ - ❌ `Evitar: o handler valida a entrada e não acessa o banco direto` (afirmação + negação).
69
+ - ✅ `Promover: o handler valida a entrada com o schema do Elysia` **+**
70
+ `Evitar: o handler acessa o banco direto`.
71
+ - Exceção **aceitável**: quando os dois sentidos são **inseparáveis** (a negação é condição
72
+ direta da afirmação). Aí o prefixo lidera o sentido dominante e o outro entra como oração
73
+ subordinada — nunca como segundo juízo coordenado.
74
+ 9. **Escopo coerente** — a regra pertence ao domínio do watchdog.
75
+ 10. **Sem duplicata** — nenhuma regra repetida literalmente no mesmo watchdog.
76
+
77
+ > O `houndsman doctor` emite um **aviso** (não bloqueante) para regra sem polaridade explícita
78
+ > (`Promover:`, `Evitar:`, `Não` ou `Nunca`).
79
+
80
+ ---
81
+
82
+ ## Quando Usar
83
+
84
+ - Usuário pede para **adicionar / alterar / remover** uma regra de revisão.
85
+ - Um watchdog está gerando **falso positivo** (cobra padrão não aplicado).
86
+ - O projeto mudou de padrão (ex.: passou a usar uma lib, mudou autenticação, etc.).
87
+ - **Auditoria completa** dos watchdogs após revisão geral do código.
88
+ - **Regra confusa/ambígua** (humano ou IA não entende) — ver Modo C.
89
+ - O usuário invoca `/houndsman-update`.
90
+
91
+ ---
92
+
93
+ ## Arquivos que definem a revisão
94
+
95
+ > A primeira parte é a **camada de projeto** (muda por consumidor); a segunda é o **motor**
96
+ > (o pacote `@payconductor/houndsman`).
97
+
98
+ | Arquivo | Papel |
99
+ |---|---|
100
+ | `.houndsman/watchdogs/<id>.ts` | **Fonte de verdade**: `defineWatchdog` com `rules` (severidade + texto), `scope`, `description`, `reviewFocus`, `exclude`, `breakingChange`, `contextFiles`, `classify` |
101
+ | `.houndsman/watchdogs/index.ts` | `WATCHDOG_DEFINITIONS` — as **chaves definem os ids** (`WatchdogId`); `watchdogIds` é derivado |
102
+ | `houndsman.config.ts` | `houndsmanConfig` do projeto — `projectName`, `artifactDir`, `watchdogs`, `exclusions`, `docMappings` (descoberto em runtime) |
103
+ | `.houndsman/exclusions.ts` | `EXCLUSION_PATTERNS` + `isExcluded` |
104
+ | `.houndsman/doc-mappings.ts` | `DOC_MAPPINGS` (path → docs) |
105
+ | `.houndsman/core/types.ts` | Snapshot gerado dos tipos + helpers (autocontido) |
106
+ | `src/core/types.ts` | Tipos genéricos: `Severity`, `Rule`, `WatchdogDefinition`, `defineWatchdog` |
107
+ | `src/core/config.ts` | `HoundsmanConfig<TId>` + `defineHoundsmanConfig` (contrato do motor) |
108
+ | `src/core/config-loader.ts` | Descoberta/carregamento de `houndsman.config.ts` |
109
+ | `src/core/brief.ts` | Render do brief: `defaultRenderBrief` + `PROCEDURE` |
110
+ | `src/core/registry-check.ts` | Validação anti-drift (config-driven) |
111
+ | `src/skill/houndsman.md` | Orquestração + tabela de watchdogs |
112
+ | `src/tests/**` | Suíte da lib (project-agnóstica; usa `fixtures/fake-project.ts`) |
113
+ | `src/cli/index.ts` | **CLI único** — `houndsman [context, setup, doctor, test, watchdog, --finalize]` |
114
+
115
+ > Todo o markdown canônico vive em `src/skill/` (fonte única). Os `SKILL.md` de cada harness
116
+ > são apenas ponteiros — não duplicar conteúdo.
117
+
118
+ ---
119
+
120
+ ## Severidade
121
+
122
+ | Severidade | Quando usar |
123
+ |---|---|
124
+ | `blocking` | Violação que quebra contrato, segurança ou integridade — e o projeto **já faz** do jeito certo em todos os lugares |
125
+ | `attention` | Boa prática aplicada na maior parte do código, com exceções aceitáveis |
126
+ | `suggestion` | Recomendação aplicada parcialmente; nunca bloqueia |
127
+ | `nit` | Detalhe cosmético/observação; ruído, nunca bloqueia |
128
+
129
+ > Severidade não é aspiração: se o projeto só aplica o padrão em 15/72 lugares, é `suggestion`.
130
+
131
+ ---
132
+
133
+ ## Pré-análise Jev (opcional)
134
+
135
+ Regra que deve ser verificada automaticamente antes da revisão declara `jev`. É sempre um
136
+ **objeto** com `kind` obrigatório — a presença de `jev` não é um liga/desliga do Jev:
137
+
138
+ | Campo | Obrigatório | Uso |
139
+ |---|---|---|
140
+ | `kind` | ✅ | `noul` (a violação ocorre?), `choice` (opções) ou `score` (rubrica) |
141
+ | `instructions` | — | Pergunta customizada; omitida, é derivada do texto da regra |
142
+ | `criteria` | em `choice`/`score` | Objeto `{ valor: rótulo }` para `choice`; lista de rótulos para `score` |
143
+
144
+ ```ts
145
+ { severity: "blocking", text: "Import de TypeBox direto", jev: { kind: "noul" } }
146
+ { severity: "attention", text: "Repository com lógica", jev: { kind: "noul", instructions: "O repository tem lógica de negócio?" } }
147
+ ```
148
+
149
+ Não anotar todas as regras: o Jev custa uma chamada por arquivo. Reservar para as regras
150
+ verificáveis por leitura local. Candidatos não confirmados pelo watchdog **não bloqueiam**.
151
+
152
+ ---
153
+
154
+ ## Modo A — Ajuste pontual (pedido do usuário)
155
+
156
+ 1. **Interpretar o pedido** — extrair: qual regra, qual watchdog, adicionar/alterar/remover.
157
+ 2. **Identificar o watchdog** pelos paths de `classify` da camada de projeto. Em dúvida, perguntar.
158
+ 3. **Provar no código** (Regra de Ouro):
159
+ - `grep_search` pelo padrão real e pelo anti-padrão.
160
+ - Determinar a **polaridade**: afirmativa (`Promover:` → exige presença; ausência = `UTOPIAN`) ou
161
+ negativa (`Evitar:`/`Não`/`Nunca` → exige ausência; **0 ocorrências do anti-padrão = `ALIGNED`**).
162
+ - Classificar: `ALIGNED`, `UTOPIAN`, `OUTDATED`, `MISCALIBRATED` ou `DEAD-PATH`.
163
+ - Coletar a evidência (`file:line` afirmativa; `0 ocorrências via grep X` negativa).
164
+ 4. **Editar `.houndsman/watchdogs/<id>.ts`** (`WATCHDOG_DEFINITIONS[<id>]`):
165
+ - `rules`: uma entrada `{ severity, text }` por regra — o texto começa com `Promover:` (DEVE) ou
166
+ `Evitar:`/`Não`/`Nunca` (NÃO DEVE), conforme as Convenções de escrita.
167
+ - Regra que mistura afirmação e negação (dois sentidos) → dividir em **duas entradas** (*Unipolar*, item 8).
168
+ - `jev` (opcional): `{ kind: "noul" }`, com `instructions` e/ou `criteria` — ver seção acima.
169
+ - Ajustar `scope` / `description` / `reviewFocus` / `exclude` / `contextFiles` se necessário.
170
+ - Se a regra muda para outro domínio (paths), ajustar o `classify` do watchdog.
171
+ 5. **Watchdog novo?** criar `.houndsman/watchdogs/<id>.ts` e registrar em `.houndsman/watchdogs/index.ts` (o id é derivado das chaves).
172
+ 6. **Atualizar `src/skill/houndsman.md`/`README.md`** se escopo/regra visível mudou (no motor).
173
+ 7. **Atualizar a suíte da lib** se o comportamento do MOTOR mudou (a suíte é project-agnóstica).
174
+ 8. **Verificar** (seção abaixo).
175
+
176
+ ---
177
+
178
+ ## Modo B — Auditoria completa (revisão geral do código)
179
+
180
+ Para alinhar **todos** os watchdogs de uma vez.
181
+
182
+ 1. **Fase 0 — Preparação.** Criar `.houndsman-audit/<slug>/` e copiar/adequar `AUDIT-PROTOCOL.md`.
183
+ 2. **Fase 1 — Auditoria por watchdog (subagentes, 1 por watchdog, em ondas paralelas).**
184
+ Cada subagente recebe: `WATCHDOG_DEFINITIONS[<id>]` + `src/core/brief.ts` (`PROCEDURE`) +
185
+ fontes ground-truth do projeto (ex.: `AGENTS.md`, docs de arquitetura) + código real.
186
+ Saída: `<slug>/<id>.md` com ground-truth do domínio + tabela regra × veredito × evidência × ação.
187
+ 3. **Fase 2 — Consolidação.** Merge em `audit-summary.md`; agrupar temas transversais; resolver
188
+ regras duplicadas entre watchdogs.
189
+ 4. **Fase 3 — Alinhamento com o usuário.** Apresentar remoções/correções borderline e obter
190
+ aprovação **antes** de editar (regra utópica → remover; parcial → `suggestion`).
191
+ 5. **Fase 4 — Aplicar.** Editar `.houndsman/watchdogs/*.ts` + `.houndsman/**` + `src/skill/**` + testes.
192
+ 6. **Fase 5 — Verificar** (seção abaixo).
193
+
194
+ > Detalhes de taxonomia, formato de relatório e evidência: `AUDIT-PROTOCOL.md`.
195
+
196
+ ---
197
+
198
+ ## Modo C — Revisão de clareza das regras
199
+
200
+ Alinha o **texto** das regras (não a semântica) para que humano e IA interpretem igual.
201
+ As regras são renderizadas **literalmente** nos briefs dos subagentes (`renderBrief` em
202
+ `src/core/brief.ts`) — o texto da regra é exatamente o que a IA lê.
203
+
204
+ A rubrica é a seção **Convenções de escrita das regras** (acima). Toda regra deve passar por
205
+ todos os itens — em especial: **geral/reutilizável** (não regra de negócio pontual),
206
+ **sem jargão abreviado**, **polaridade explícita** (`Promover:` / `Evitar:`/`Não`/`Nunca`) e
207
+ **unipolar** (um só sentido por regra — sem afirmar e negar no mesmo texto).
208
+
209
+ ### Passos
210
+
211
+ 1. Inventariar todas as regras (`rules`) dos watchdogs alvo.
212
+ 2. Marcar cada regra contra a rubrica; propor reescrita **preservando semântica e severidade**.
213
+ Regra que mistura os dois sentidos → **dividir** em afirmativa e negativa (*Unipolar*, item 8).
214
+ 3. Se for regra **afirmativa** ambígua **e não houver evidência de aplicação** no código,
215
+ tratá-la como `UTOPIAN`/`OUTDATED` (remover/rebaixar) conforme a Regra de Ouro.
216
+ Para regra **negativa**, a ausência de ocorrências é o **esperado** — não remover por isso.
217
+ 4. Aplicar em `.houndsman/watchdogs/<id>.ts`; corrigir duplicatas/sobreposições.
218
+ 5. Se o termo citado for do procedimento, ajustar `PROCEDURE`/`reviewFocus`/`exclude` em
219
+ `src/core/brief.ts` ou no watchdog.
220
+ 6. Conferir que o `renderBrief` continua renderizando o texto da regra (dry-run abaixo).
221
+ 7. Verificar (seção abaixo).
222
+
223
+ ---
224
+
225
+ ## Verificação (obrigatória)
226
+
227
+ ```bash
228
+ bun run houndsman doctor # config sem drift + ambiente
229
+ bun run houndsman test # suíte da lib (project-agnóstica)
230
+ bun run ci:fix # formatação/imports/lint (no repo da lib)
231
+ bun run ci:check # tipagem (no repo da lib)
232
+ ```
233
+
234
+ Checklist final:
235
+
236
+ - [ ] `bun run houndsman doctor` → sem problemas reportados.
237
+ - [ ] `bun run houndsman test` → **0 fail**.
238
+ - [ ] `ci:fix` + `ci:check` → exit 0 (warnings pré-existentes não contam).
239
+ - [ ] `WATCHDOG_DEFINITIONS[<id>].id` bate com a chave e `description` não vazio.
240
+ - [ ] `src/skill/houndsman.md` continua consistente com os watchdogs do projeto.
241
+ - [ ] Toda regra nova/alterada tem **evidência** registrada no PR/relatório
242
+ (`file:line` se afirmativa; `0 ocorrências do anti-padrão` se negativa).
243
+ - [ ] Nenhuma regra **negativa** foi removida por "0 ocorrências" (Regra de Ouro).
244
+ - [ ] Brief de amostra não contém regra removida (dry-run abaixo).
245
+ - [ ] Toda regra passa nas convenções de escrita (geral/reutilizável, sem jargão abreviado,
246
+ sem qualificador vago, com polaridade explícita e **unipolar**) — conferir via grep.
247
+
248
+ ```bash
249
+ # Dry-run: gerar briefs e conferir ausência de regras removidas
250
+ bun -e "import { renderBrief } from 'houndsman'; import { WATCHDOG_DEFINITIONS } from './.houndsman/watchdogs'; const base={files:['x.ts'],branch:'t',outputPath:'o.json',docs:[],statuses:{},deleted:[]}; for (const id of Object.keys(WATCHDOG_DEFINITIONS)) console.log(id, /verifySignature|circuit|saldo/i.test(renderBrief(WATCHDOG_DEFINITIONS[id],{...base,watchdogId:id})) ? 'FOUND' : 'OK');"
251
+ ```