@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.
- package/LICENSE +21 -0
- package/README.md +195 -3
- package/assets/houndsman.png +0 -0
- package/package.json +63 -5
- package/src/cli/index.ts +210 -0
- package/src/core/assets.ts +20 -0
- package/src/core/brief.ts +162 -0
- package/src/core/commands/context.ts +39 -0
- package/src/core/commands/review.ts +50 -0
- package/src/core/commands/scaffold.ts +373 -0
- package/src/core/commands/setup.ts +75 -0
- package/src/core/commands/test.ts +20 -0
- package/src/core/commands/update.ts +30 -0
- package/src/core/commands/watchdog.ts +105 -0
- package/src/core/config-loader.ts +87 -0
- package/src/core/config.ts +59 -0
- package/src/core/doc-discoverer.ts +33 -0
- package/src/core/file-classifier.ts +247 -0
- package/src/core/jev/index.ts +12 -0
- package/src/core/jev/jev-candidates.ts +105 -0
- package/src/core/jev/jev-client.ts +99 -0
- package/src/core/jev/jev-detector.ts +203 -0
- package/src/core/jev/jev-questions.ts +92 -0
- package/src/core/jev/jev-types.ts +91 -0
- package/src/core/orchestrator.ts +444 -0
- package/src/core/paths.ts +30 -0
- package/src/core/pr-context.ts +271 -0
- package/src/core/registry-check.ts +145 -0
- package/src/core/report-builder.ts +357 -0
- package/src/core/types.ts +137 -0
- package/src/core/watchdog-registry.ts +43 -0
- package/src/index.ts +56 -0
- package/src/skill/AUDIT-PROTOCOL.md +96 -0
- package/src/skill/OUTPUT-FORMAT.md +70 -0
- package/src/skill/README.md +116 -0
- package/src/skill/SETUP.md +99 -0
- package/src/skill/example-review.md +58 -0
- package/src/skill/houndsman-update.md +251 -0
- package/src/skill/houndsman.md +239 -0
- package/src/tests/fixtures/fake-project.ts +64 -0
- 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
|
+
```
|