@payconductor/houndsman 0.13.0 → 0.16.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 (116) hide show
  1. package/README.md +6 -1
  2. package/package.json +1 -1
  3. package/src/cli/commands/compare-command.ts +112 -0
  4. package/src/cli/commands/context-command.ts +1 -0
  5. package/src/cli/commands/findings-command.ts +11 -1
  6. package/src/cli/commands/golden-command.ts +92 -0
  7. package/src/cli/commands/hunt-command.ts +105 -4
  8. package/src/cli/commands/review-command.ts +38 -0
  9. package/src/cli/commands/status-command.ts +3 -2
  10. package/src/cli/help.ts +6 -1
  11. package/src/cli/index.ts +5 -1
  12. package/src/cli/progress.ts +7 -2
  13. package/src/core/ai/ai-client.ts +38 -2
  14. package/src/core/ai/features/brief-enricher.ts +1 -1
  15. package/src/core/ai/features/business-analyzer.ts +61 -0
  16. package/src/core/ai/features/business-summarizer.ts +44 -0
  17. package/src/core/ai/index.ts +8 -0
  18. package/src/core/ai/prompts/brief.ts +33 -7
  19. package/src/core/ai/prompts/business.ts +76 -0
  20. package/src/core/ai/provider-capabilities.ts +12 -0
  21. package/src/core/ai/schemas.ts +70 -2
  22. package/src/core/ai/usage-recorder.ts +53 -1
  23. package/src/core/brief.ts +278 -16
  24. package/src/core/builtins.ts +108 -0
  25. package/src/core/business-summary.ts +583 -0
  26. package/src/core/commands/compare.ts +266 -0
  27. package/src/core/commands/context.ts +6 -2
  28. package/src/core/commands/findings.ts +38 -30
  29. package/src/core/commands/golden.ts +176 -0
  30. package/src/core/commands/review.ts +6 -0
  31. package/src/core/commands/scaffold.ts +29 -0
  32. package/src/core/commands/status.ts +9 -4
  33. package/src/core/compare.ts +310 -0
  34. package/src/core/concurrency.ts +30 -0
  35. package/src/core/config.ts +41 -3
  36. package/src/core/defaults.ts +50 -4
  37. package/src/core/domain/budget.ts +62 -4
  38. package/src/core/domain/classification.ts +12 -2
  39. package/src/core/engine/carryover.ts +4 -0
  40. package/src/core/engine/finalize-pipeline.ts +371 -0
  41. package/src/core/engine/prepare-pipeline.ts +1294 -0
  42. package/src/core/engine/review-context.ts +51 -0
  43. package/src/core/engine/review-options.ts +47 -0
  44. package/src/core/engine/review-scope.ts +14 -1
  45. package/src/core/engine/review-session.ts +11 -13
  46. package/src/core/engine/run-artifacts.ts +196 -0
  47. package/src/core/engine/run-format.ts +4 -0
  48. package/src/core/findings-state.ts +22 -2
  49. package/src/core/github-review.ts +5 -2
  50. package/src/core/golden.ts +346 -0
  51. package/src/core/hunt/hunt-runner.ts +621 -34
  52. package/src/core/hunt/index.ts +40 -1
  53. package/src/core/hunt/maki-intent-prompt.ts +50 -0
  54. package/src/core/hunt/maki-prompt.ts +298 -5
  55. package/src/core/hunt/maki-runner.ts +93 -16
  56. package/src/core/hunt/pool.ts +4 -26
  57. package/src/core/hunt/review-checks.ts +460 -0
  58. package/src/core/logging/index.ts +6 -1
  59. package/src/core/logging/progress.ts +85 -1
  60. package/src/core/orchestrator.ts +33 -1289
  61. package/src/core/paths.ts +6 -3
  62. package/src/core/pr-context.ts +2 -4
  63. package/src/core/prepare-report.ts +61 -0
  64. package/src/core/project-config.ts +18 -1
  65. package/src/core/propagation.ts +127 -0
  66. package/src/core/registry-check.ts +90 -27
  67. package/src/core/renderers/manifest-writer.ts +13 -0
  68. package/src/core/renderers/resume-renderer.ts +151 -11
  69. package/src/core/report-builder.ts +116 -278
  70. package/src/core/severity.ts +245 -0
  71. package/src/core/storage/file/file-storage.ts +7 -3
  72. package/src/core/storage/sqlite/mappers.ts +10 -0
  73. package/src/core/storage/sqlite/schema.ts +104 -23
  74. package/src/core/storage/sqlite/sqlite-storage.ts +22 -9
  75. package/src/core/storage/types.ts +17 -4
  76. package/src/core/storage/work-area.ts +59 -1
  77. package/src/core/types.ts +31 -0
  78. package/src/core/watchdog-registry.ts +21 -3
  79. package/src/index.ts +51 -4
  80. package/src/server/client/ArtifactsPanel.tsx +4 -2
  81. package/src/server/client/FindingCard.tsx +21 -1
  82. package/src/server/client/RunsSection.tsx +5 -0
  83. package/src/server/client/utils/constants.ts +21 -11
  84. package/src/server/client/utils/markdown.ts +1 -1
  85. package/src/server/client/utils/types.ts +14 -2
  86. package/src/server/run-repository.ts +35 -14
  87. package/src/server/styles.css +2 -0
  88. package/src/skill/OUTPUT-FORMAT.md +55 -10
  89. package/src/skill/README.md +19 -14
  90. package/src/skill/SETUP.md +1 -0
  91. package/src/skill/SKILL.md +13 -4
  92. package/src/skill/example-resume.md +43 -0
  93. package/src/skill/hunt.md +205 -58
  94. package/src/skill/train.md +3 -0
  95. package/src/tests/__snapshots__/baseline.test.ts.snap +208 -184
  96. package/src/tests/ai-core.test.ts +46 -0
  97. package/src/tests/ai-features.test.ts +95 -4
  98. package/src/tests/baseline.test.ts +29 -121
  99. package/src/tests/brief-scope.test.ts +250 -0
  100. package/src/tests/business-summary.test.ts +258 -0
  101. package/src/tests/compare.test.ts +256 -0
  102. package/src/tests/findings-state.test.ts +82 -0
  103. package/src/tests/fixtures/fake-model-provider.ts +2 -1
  104. package/src/tests/golden.test.ts +195 -0
  105. package/src/tests/hunt-maki.test.ts +710 -2
  106. package/src/tests/markdown.test.ts +3 -3
  107. package/src/tests/progress.test.ts +29 -1
  108. package/src/tests/propagation.test.ts +119 -0
  109. package/src/tests/review-resume.test.ts +60 -1
  110. package/src/tests/review-scope.test.ts +38 -29
  111. package/src/tests/review-scripts.test.ts +125 -218
  112. package/src/tests/server.test.ts +7 -4
  113. package/src/tests/severity.test.ts +235 -0
  114. package/src/tests/storage.test.ts +194 -9
  115. package/src/core/renderers/report-renderer.ts +0 -66
  116. package/src/skill/example-review.md +0 -66
@@ -27,8 +27,14 @@ src/alpha/**
27
27
 
28
28
  ## Regras (por severidade)
29
29
 
30
- - ❌ **blocking** — Nunca usar \`any\`.
31
- - ⚠️ **attention** — Promover: validar a entrada.
30
+ - 1. ❌ **blocking** — Nunca usar \`any\`.
31
+ - 2. ⚠️ **attention** — Promover: validar a entrada.
32
+
33
+ ## Como declarar a severidade
34
+
35
+ - **Finding de regra:** copie \`rule\` exatamente como no brief. A severidade é a **declarada na regra** — outro valor é ignorado e corrigido pelo motor.
36
+ - **Finding emergente** (\`Lógica:\`/\`Domínio:\`): preencha \`impactClass\` — \`flow-break\` (fluxo/capacidade não honrada), \`contract-drift\` (contrato/estado divergente), \`degradation\` (borda/erro frágil) ou \`cosmetic\`.
37
+ - \`blocking\` fora de regra continua exigindo \`scenario\` + \`evidence\`; sem os dois, o motor rebaixa para \`attention\`.
32
38
 
33
39
  ## Docs de contexto (carregar sob demanda)
34
40
 
@@ -40,11 +46,11 @@ src/alpha/**
40
46
  - \`src/alpha/a.ts\` (modified, +3/−1)
41
47
  - \`src/alpha/b.ts\` (added, +2/−0)
42
48
 
43
- ## Fora do orçamento (NÃO revisar)
49
+ ## Fora do recorte (NÃO revisar)
44
50
 
45
- > 1 arquivo(s) do seu domínio ficaram fora do orçamento
46
- > (menor churn). Não os leia: registre-os em \`skipped\` com o motivo
47
- > "budget" para que a cobertura do relatório fique honesta.
51
+ > 1 arquivo(s) do escopo ficaram fora do recorte
52
+ > (orçamento ou prioridade de fluxo). Não os leia: registre-os em \`skipped\`
53
+ > com o motivo (\`budget\` ou \`fora do fluxo\`) para que a cobertura fique honesta.
48
54
 
49
55
  - \`src/alpha/c.ts\`
50
56
 
@@ -60,111 +66,22 @@ src/alpha/**
60
66
 
61
67
  - \`src/alpha/old.ts\`
62
68
 
63
- ## Procedimento
64
-
65
- 1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
66
- 2. **READ SCOPE** — carregue apenas as faixas alteradas em *Escopo do diff*; o restante do arquivo é só contexto.
67
- 3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas.
68
- 4. **DEEP-READ** — aprofunde apenas as faixas com suspeita de violação dentro do escopo.
69
- 5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido e \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre."
70
- `;
71
-
72
- exports[`baseline — relatório renderReport consolidado 1`] = `
73
- "# PR Review — feature/x
74
-
75
- **Data:** <date>
76
- **Watchdogs ativos:** alpha, beta
77
- **Achados:** 1 bloqueantes · 1 atenção · 0 sugestões · 0 nits
78
-
79
- ## Contexto da PR
80
-
81
- **PR:** #42 Entrega X — https://example.test/pull/42
82
- **Branch:** \`feature/x\` → \`main\`
83
- **Objetivo:** Entregar X
84
- **Motivação:** Reduzir Y
85
-
86
- **Resumo das alterações:**
87
-
88
- - Faz A
89
- - Remove B
90
-
91
- ## Relatórios por domínio
92
-
93
- | Watchdog | Achados | Revisados | Relatório |
94
- |---|---|---|---|
95
- | Alpha | 2 | 2/2 | [\`review.alpha.md\`](review.alpha.md) |
96
-
97
- ## Cobertura
98
-
99
- | Watchdog | Arquivos revisados | Findings |
100
- |---|---|---|
101
- | Alpha | 2 | 2 |
102
- | Beta | 1 | 0 |
103
-
104
- ## Conclusão
105
-
106
- **Status:** ❌ Mudanças Necessárias
107
- **Resumo:** 1 violações bloqueantes, 1 pontos de atenção, 0 sugestões e 0 nits.
108
-
109
- ## ❌ blocking
110
-
111
- ### \`src/alpha/a.ts\`
69
+ ## Orçamento de exploração
112
70
 
113
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`id-alpha\`
114
- any detectado
115
- **Ação:** tipar
116
- **Evidência:** \`export const a: any = 1;\`
71
+ > O diff já está no brief. Limite **neste brief**: 6 leitura(s) de arquivo
72
+ > e 6 busca(s) (grep).
73
+ > Abra arquivo só para chamador/contexto de um símbolo citado nos trechos.
74
+ > Se a prova não estiver no brief nem nesse orçamento, **não é achado** —
75
+ > registre a dúvida no campo \`action\` do finding mais próximo ou descarte.
117
76
 
118
- ## ⚠️ attention
119
-
120
- ### \`src/alpha/b.ts\`
121
-
122
- - **Promover: validar a entrada.** — \`src/alpha/b.ts:2\` · _Alpha, Beta_ · \`id-beta\`
123
- sem validação
124
- **Ação:** adicionar schema
125
- "
126
- `;
127
-
128
- exports[`baseline — relatório renderDomainReport isolado 1`] = `
129
- "# Review — Alpha (\`alpha\`) — feature/x
130
-
131
- **Data:** <date>
132
- **Arquivos revisados:** 2/2
133
- **Achados:** 2
134
-
135
- ## Contexto da PR
136
-
137
- **PR:** #42 Entrega X — https://example.test/pull/42
138
- **Branch:** \`feature/x\` → \`main\`
139
- **Objetivo:** Entregar X
140
- **Motivação:** Reduzir Y
141
-
142
- **Resumo das alterações:**
143
-
144
- - Faz A
145
- - Remove B
146
-
147
- ## ❌ blocking
148
-
149
- ### \`src/alpha/a.ts\`
150
-
151
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`id-alpha\`
152
- any detectado
153
- **Ação:** tipar
154
- **Evidência:** \`export const a: any = 1;\`
155
-
156
- ## ⚠️ attention
157
-
158
- ### \`src/alpha/b.ts\`
159
-
160
- - **Promover: validar a entrada.** — \`src/alpha/b.ts:2\` · _Alpha, Beta_ · \`id-beta\`
161
- sem validação
162
- **Ação:** adicionar schema
163
-
164
- ## Não revisados
77
+ ## Procedimento
165
78
 
166
- - \`src/alpha/c.ts\`
167
- "
79
+ 1. **RECONSTRUCT** — leia o recorte do *Modelo de intenção (negócio)* e diga para si mesmo o que a mudança DEVE entregar (fluxos, invariantes, contratos). Sem modelo, derive do contexto da PR.
80
+ 2. **SCOPE** — os *Trechos alterados (diff)* já estão no brief: **não releia o arquivo inteiro** para vê-los. Trecho com o marcador \`… [trecho truncado]\` pode ser aberto, uma vez, para o restante.
81
+ 3. **TRACE** — siga cada símbolo alterado até seus chamadores, adapters e tipos compartilhados **dentro do seu domínio** (use os importadores do AST), **dentro do orçamento de exploração** (seção acima). Priorize os arquivos de maior churn.
82
+ 4. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas, **dentro do orçamento**. Pare quando tiver a prova: repetir busca não aumenta certeza.
83
+ 5. **PROVE** — para cada suspeita, descreva gatilho → comportamento observado → invariante/regra violada. Sem prova, não é achado. Trecho com o marcador de truncamento só sustenta achado depois de abrir o arquivo para ver o restante.
84
+ 6. **CONCLUDE** — grave o JSON no caminho de output. \`reviewedFiles\` é um subconjunto de \`## Arquivos do seu domínio\` (só o que você revisou; **não** liste chamadores/importadores nem arquivos de outros domínios) e o que ficou de fora entra em \`skipped\` ("budget", "truncated" ou "fora do fluxo"). Máximo de 20 achados: priorize severidade e agrupe ocorrências idênticas. \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre."
168
85
  `;
169
86
 
170
87
  exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 1`] = `
@@ -180,7 +97,7 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 1
180
97
  ".houndsman/core/skill/OUTPUT-FORMAT.md",
181
98
  ".houndsman/core/skill/README.md",
182
99
  ".houndsman/core/skill/SETUP.md",
183
- ".houndsman/core/skill/example-review.md",
100
+ ".houndsman/core/skill/example-resume.md",
184
101
  ".houndsman/core/skill/fix.md",
185
102
  ".houndsman/core/skill/hunt.md",
186
103
  ".houndsman/core/skill/train.md",
@@ -214,6 +131,11 @@ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do
214
131
  **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
215
132
  especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
216
133
 
134
+ > **Duas etapas são obrigatórias em toda revisão:** o **modelo de intenção**
135
+ > (\`business-summary.json\`) e o revisor de fluxo **\`general\`** (id reservado, sempre ativo).
136
+ > O modelo vem da IA no prepare quando há chave; sem chave, um subagente (Passo 1.5) ou o
137
+ > pré-passe maki o produz. Nenhum dos dois é configurável pelo usuário.
138
+
217
139
  ## Capabilities
218
140
 
219
141
  | Capability | Objetivo | Documento |
@@ -260,12 +182,16 @@ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
260
182
  Sequência para uma PR (ex.: 456):
261
183
 
262
184
  \`\`\`bash
263
- houndsman context --pr 456
264
- houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
265
- # despache os briefs (cada um traz **Worktree:** <path>)
185
+ houndsman --pr 456 # cria/reusa o worktree, coleta o contexto e prepara
186
+ # despache os briefs em paralelo (cada um traz **Worktree:** <path>)
266
187
  houndsman --pr 456 --finalize
267
188
  \`\`\`
268
189
 
190
+ - O contexto da PR é coletado pelo próprio prepare (via \`gh\`); com IA ligada ele também é
191
+ resumido ali — não gaste um subagente nisso. Desative com \`--no-context\`.
192
+ - Para comparar duas execuções, use \`--variant <label>\` em cada uma e depois
193
+ \`houndsman compare --branch <head> --a <a> --b <b>\` (ou \`compare --list\`).
194
+
269
195
  - O worktree vive em \`<repo>/.houndsman/worktrees/<repo>/<branch>\` (detached no commit da PR)
270
196
  e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
271
197
  (e o staging também) para o agente ler/executar sem prompts de permissão.
@@ -283,7 +209,7 @@ houndsman --pr 456 --finalize
283
209
  - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
284
210
  - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
285
211
  - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
286
- - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
212
+ - \`.houndsman/core/skill/example-resume.md\` — exemplo do resumo final.
287
213
  "
288
214
  ,
289
215
  ".claude/skills/houndsman/SKILL.md":
@@ -303,6 +229,11 @@ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do
303
229
  **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
304
230
  especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
305
231
 
232
+ > **Duas etapas são obrigatórias em toda revisão:** o **modelo de intenção**
233
+ > (\`business-summary.json\`) e o revisor de fluxo **\`general\`** (id reservado, sempre ativo).
234
+ > O modelo vem da IA no prepare quando há chave; sem chave, um subagente (Passo 1.5) ou o
235
+ > pré-passe maki o produz. Nenhum dos dois é configurável pelo usuário.
236
+
306
237
  ## Capabilities
307
238
 
308
239
  | Capability | Objetivo | Documento |
@@ -349,12 +280,16 @@ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
349
280
  Sequência para uma PR (ex.: 456):
350
281
 
351
282
  \`\`\`bash
352
- houndsman context --pr 456
353
- houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
354
- # despache os briefs (cada um traz **Worktree:** <path>)
283
+ houndsman --pr 456 # cria/reusa o worktree, coleta o contexto e prepara
284
+ # despache os briefs em paralelo (cada um traz **Worktree:** <path>)
355
285
  houndsman --pr 456 --finalize
356
286
  \`\`\`
357
287
 
288
+ - O contexto da PR é coletado pelo próprio prepare (via \`gh\`); com IA ligada ele também é
289
+ resumido ali — não gaste um subagente nisso. Desative com \`--no-context\`.
290
+ - Para comparar duas execuções, use \`--variant <label>\` em cada uma e depois
291
+ \`houndsman compare --branch <head> --a <a> --b <b>\` (ou \`compare --list\`).
292
+
358
293
  - O worktree vive em \`<repo>/.houndsman/worktrees/<repo>/<branch>\` (detached no commit da PR)
359
294
  e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
360
295
  (e o staging também) para o agente ler/executar sem prompts de permissão.
@@ -372,16 +307,18 @@ houndsman --pr 456 --finalize
372
307
  - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
373
308
  - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
374
309
  - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
375
- - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
310
+ - \`.houndsman/core/skill/example-resume.md\` — exemplo do resumo final.
376
311
  "
377
312
  ,
378
313
  ".houndsman/.gitignore":
379
314
  "# Diretórios gerados pelo houndsman — \`core/\` é regenerado por \`houndsman update\`.
380
315
  # \`work/\` e \`worktrees/\` são runtime de revisão (staging e worktrees).
316
+ # \`golden/\` é massa de avaliação local (defeitos congelados por commit).
381
317
  core/
382
318
  .runs/
383
319
  work/
384
320
  worktrees/
321
+ golden/
385
322
  "
386
323
  ,
387
324
  ".houndsman/core/types.ts":
@@ -497,6 +434,7 @@ export type AiProviderOptions = Record<string, Record<string, unknown>>;
497
434
  /** Features de IA do fluxo normal (todas fail-open). */
498
435
  export type HoundsmanAiFeatures = {
499
436
  context?: boolean;
437
+ business?: boolean;
500
438
  brief?: boolean;
501
439
  technical?: boolean;
502
440
  classification?: boolean;
@@ -534,6 +472,18 @@ export type HoundsmanHunt = {
534
472
  binaryPath?: string;
535
473
  };
536
474
 
475
+ /**
476
+ * Prioridade por caminho.
477
+ *
478
+ * \`bonus\` promove (linhas de churn equivalentes) e \`maxRiskFromChurn\` satura o
479
+ * superchurn de caminhos de baixa criticidade.
480
+ */
481
+ export type HoundsmanPriority = {
482
+ pattern: RegExp;
483
+ bonus?: number;
484
+ maxRiskFromChurn?: number;
485
+ };
486
+
537
487
  /** Contrato de configuração do motor. */
538
488
  export type HoundsmanConfig<TId extends string = string> = {
539
489
  projectName: string;
@@ -542,6 +492,8 @@ export type HoundsmanConfig<TId extends string = string> = {
542
492
  watchdogs: Record<TId, WatchdogDefinition>;
543
493
  exclusions: readonly RegExp[];
544
494
  docMappings: readonly (readonly [RegExp, readonly string[]])[];
495
+ /** Prioridade por caminho (opcional; a primeira regra que casar vence). */
496
+ priorities?: readonly HoundsmanPriority[];
545
497
  alwaysIncludeDocs?: readonly string[];
546
498
  budgets?: HoundsmanBudgets;
547
499
  concurrency?: HoundsmanConcurrency;
@@ -626,6 +578,9 @@ import { exampleWatchdog } from "./example";
626
578
  /**
627
579
  * Definições dos watchdogs — as chaves definem o union \`WatchdogId\`.
628
580
  * Adicionar um watchdog = criar \`<id>.ts\` e registrá-lo aqui.
581
+ *
582
+ * NÃO declare um watchdog com id \`general\`: ele é reservado pelo motor
583
+ * (revisor de fluxo obrigatório) e é injetado em todo ciclo.
629
584
  */
630
585
  export const WATCHDOG_DEFINITIONS = {
631
586
  default: defaultWatchdog,
@@ -653,6 +608,15 @@ export const houndsmanConfig = {
653
608
  watchdogs: WATCHDOG_DEFINITIONS,
654
609
  exclusions: EXCLUSION_PATTERNS,
655
610
  docMappings: DOC_MAPPINGS,
611
+ // Prioridade por caminho (opcional): "linhas de churn equivalentes".
612
+ // \`bonus\` promove caminho crítico; \`maxRiskFromChurn\` satura o superchurn de
613
+ // caminho de baixa criticidade (risco = min(churn, teto) + bonus).
614
+ // A primeira regra que casar vence; sem regra, o risco é o churn puro.
615
+ // priorities: [
616
+ // { pattern: /^src\\/(db|repositories)\\//, bonus: 300 },
617
+ // { pattern: /^src\\/(services|domain)\\//, bonus: 200 },
618
+ // { pattern: /^src\\/(components|styles)\\//, maxRiskFromChurn: 120 },
619
+ // ],
656
620
  } satisfies HoundsmanConfig;
657
621
 
658
622
  export default houndsmanConfig;
@@ -669,19 +633,19 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
669
633
  },
670
634
  {
671
635
  "file": ".houndsman/core/skill/OUTPUT-FORMAT.md",
672
- "sha256": "a78ed16d4d211889",
636
+ "sha256": "8754e8faaf66c4f9",
673
637
  },
674
638
  {
675
639
  "file": ".houndsman/core/skill/README.md",
676
- "sha256": "2ecf43f34a624011",
640
+ "sha256": "b9d5725a87365c06",
677
641
  },
678
642
  {
679
643
  "file": ".houndsman/core/skill/SETUP.md",
680
- "sha256": "5720c48ede6c84ea",
644
+ "sha256": "e7f587d1c8e459d1",
681
645
  },
682
646
  {
683
- "file": ".houndsman/core/skill/example-review.md",
684
- "sha256": "d9e75054cc9811dc",
647
+ "file": ".houndsman/core/skill/example-resume.md",
648
+ "sha256": "4993f56afdf2ffd1",
685
649
  },
686
650
  {
687
651
  "file": ".houndsman/core/skill/fix.md",
@@ -689,11 +653,11 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
689
653
  },
690
654
  {
691
655
  "file": ".houndsman/core/skill/hunt.md",
692
- "sha256": "d31198580d894427",
656
+ "sha256": "10ecf846c3b6880e",
693
657
  },
694
658
  {
695
659
  "file": ".houndsman/core/skill/train.md",
696
- "sha256": "d774215c68d15159",
660
+ "sha256": "e2742937c6f943a5",
697
661
  },
698
662
  {
699
663
  "file": ".houndsman/core/skill/verify.md",
@@ -702,25 +666,31 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
702
666
  ]
703
667
  `;
704
668
 
705
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 1`] = `
706
- "Discovery: 1 watchdog(s) ativado(s), 3 arquivo(s), 1 deletado(s).
669
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state 1`] = `
670
+ "Discovery: 1 watchdog(s) de domínio + revisor general, 3 arquivo(s), 1 deletado(s).
707
671
  Briefs: <cwd>/.home/work/<uuid>/briefs/
708
672
  Deletado (breaking change): src/alpha/old.ts
709
673
  Escopo: 2 arquivo(s), 0 símbolo(s) em 2 faixa(s) alterada(s).
674
+ Escopo: 2 arquivo(s) em mais de um domínio (máx. 2) — cada domínio revisa o arquivo com o seu recorte.
710
675
  Jev: pulado (desativado (--no-jev)).
711
676
  AST: desabilitado ou sem grammar compatível.
712
677
  Sem contexto da PR (rode \`bun run houndsman context\` antes, se houver PR).
678
+ Intenção da PR determinística (1 fluxo(s)) — enriquecida no passo de intenção (<cwd>/.home/work/<uuid>/business-brief.md).
713
679
 
714
680
  Próximo passo: despachar os sub-agentes (um por brief em <cwd>/.home/work/<uuid>/briefs/).
715
681
  Quando os findings estiverem gravados: bun run houndsman --finalize"
716
682
  `;
717
683
 
718
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: classification.json 1`] = `
684
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: classification.json 1`] = `
719
685
  "{
720
686
  "watchdogs": {
721
687
  "alpha": [
722
688
  "src/alpha/a.ts",
723
689
  "src/alpha/b.ts"
690
+ ],
691
+ "general": [
692
+ "src/alpha/a.ts",
693
+ "src/alpha/b.ts"
724
694
  ]
725
695
  },
726
696
  "files": {
@@ -754,7 +724,8 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
754
724
  "src/alpha/old.ts"
755
725
  ],
756
726
  "stats": {
757
- "alpha": 2
727
+ "alpha": 2,
728
+ "general": 2
758
729
  },
759
730
  "excludedCount": 0,
760
731
  "headSha": "<sha>",
@@ -785,7 +756,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
785
756
  "
786
757
  `;
787
758
 
788
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: manifest.json 1`] = `
759
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: manifest.json 1`] = `
789
760
  "{
790
761
  "branch": "main",
791
762
  "slug": "main",
@@ -814,12 +785,31 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
814
785
  "brief": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\briefs\\\\alpha.md",
815
786
  "findings": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\findings\\\\alpha.json",
816
787
  "status": "pending"
788
+ },
789
+ {
790
+ "id": "general",
791
+ "name": "Lógica e domínio (fluxo)",
792
+ "files": [
793
+ "src/alpha/a.ts",
794
+ "src/alpha/b.ts"
795
+ ],
796
+ "overflow": 0,
797
+ "brief": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\briefs\\\\general.md",
798
+ "findings": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\findings\\\\general.json",
799
+ "status": "pending"
817
800
  }
818
801
  ],
819
802
  "context": {
820
803
  "summarized": false,
821
804
  "source": null
822
805
  },
806
+ "business": {
807
+ "source": "deterministic",
808
+ "flows": 1,
809
+ "invariants": 0,
810
+ "contracts": 0,
811
+ "states": 0
812
+ },
823
813
  "jev": {
824
814
  "available": false,
825
815
  "reason": "desativado (--no-jev)"
@@ -843,7 +833,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
843
833
  "
844
834
  `;
845
835
 
846
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: briefs/alpha.md 1`] = `
836
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: briefs/alpha.md 1`] = `
847
837
  "# Brief — Alpha (\`alpha\`)
848
838
 
849
839
  **Branch:** main
@@ -868,10 +858,57 @@ src/alpha/**
868
858
  - \`src/alpha/a.ts\` — linhas 1-2 _(faixas do diff)_
869
859
  - \`src/alpha/b.ts\` — linhas 1 _(faixas do diff)_
870
860
 
861
+ ## Modelo de intenção (negócio)
862
+
863
+ > Fonte: determinístico. Use para saber o que a mudança **deve** entregar; não é achado.
864
+
865
+ > Recorte do seu domínio: fluxos/arquivos de outros domínios pertencem a outros watchdogs — não os investigue.
866
+
867
+ **Fluxos (1):**
868
+ - **Alpha**
869
+ arquivos: src/alpha/a.ts, src/alpha/b.ts
870
+
871
+ ## Trechos alterados (diff)
872
+
873
+ > Trechos já extraídos do diff (\`-U0\`, só linhas alteradas). Eles bastam
874
+ > para achar violações: **não abra os arquivos apenas para reler o que já
875
+ > está aqui**. Use o arquivo só para contexto adjacente ou chamadores.
876
+
877
+ ### \`src/alpha/a.ts\`
878
+
879
+ \`\`\`diff
880
+ diff --git a/src/alpha/a.ts b/src/alpha/a.ts
881
+ index cc798ff..bc84e2e 100644
882
+ --- a/src/alpha/a.ts
883
+ +++ b/src/alpha/a.ts
884
+ @@ -1 +1,2 @@
885
+ -export const a = 1;
886
+ +export const a: any = 1;
887
+ +export const b = 2;
888
+ \`\`\`
889
+
890
+ ### \`src/alpha/b.ts\`
891
+
892
+ \`\`\`diff
893
+ diff --git a/src/alpha/b.ts b/src/alpha/b.ts
894
+ new file mode 100644
895
+ index 0000000..f4082f0
896
+ --- /dev/null
897
+ +++ b/src/alpha/b.ts
898
+ @@ -0,0 +1 @@
899
+ +export const b = 3;
900
+ \`\`\`
901
+
871
902
  ## Regras (por severidade)
872
903
 
873
- - ❌ **blocking** — Nunca usar \`any\`.
874
- - ⚠️ **attention** — Promover: validar a entrada.
904
+ - 1. ❌ **blocking** — Nunca usar \`any\`.
905
+ - 2. ⚠️ **attention** — Promover: validar a entrada.
906
+
907
+ ## Como declarar a severidade
908
+
909
+ - **Finding de regra:** copie \`rule\` exatamente como no brief. A severidade é a **declarada na regra** — outro valor é ignorado e corrigido pelo motor.
910
+ - **Finding emergente** (\`Lógica:\`/\`Domínio:\`): preencha \`impactClass\` — \`flow-break\` (fluxo/capacidade não honrada), \`contract-drift\` (contrato/estado divergente), \`degradation\` (borda/erro frágil) ou \`cosmetic\`.
911
+ - \`blocking\` fora de regra continua exigindo \`scenario\` + \`evidence\`; sem os dois, o motor rebaixa para \`attention\`.
875
912
 
876
913
  ## Docs de contexto (carregar sob demanda)
877
914
 
@@ -886,77 +923,63 @@ src/alpha/**
886
923
 
887
924
  - \`src/alpha/old.ts\`
888
925
 
926
+ ## Orçamento de exploração
927
+
928
+ > O diff já está no brief. Limite **neste brief**: 6 leitura(s) de arquivo
929
+ > e 6 busca(s) (grep).
930
+ > Abra arquivo só para chamador/contexto de um símbolo citado nos trechos.
931
+ > Se a prova não estiver no brief nem nesse orçamento, **não é achado** —
932
+ > registre a dúvida no campo \`action\` do finding mais próximo ou descarte.
933
+
889
934
  ## Procedimento
890
935
 
891
- 1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
892
- 2. **READ SCOPE** — carregue apenas as faixas alteradas em *Escopo do diff*; o restante do arquivo é só contexto.
893
- 3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas.
894
- 4. **DEEP-READ** — aprofunde apenas as faixas com suspeita de violação dentro do escopo.
895
- 5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido e \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre.
936
+ 1. **RECONSTRUCT** — leia o recorte do *Modelo de intenção (negócio)* e diga para si mesmo o que a mudança DEVE entregar (fluxos, invariantes, contratos). Sem modelo, derive do contexto da PR.
937
+ 2. **SCOPE** — os *Trechos alterados (diff)* já estão no brief: **não releia o arquivo inteiro** para vê-los. Trecho com o marcador \`… [trecho truncado]\` pode ser aberto, uma vez, para o restante.
938
+ 3. **TRACE** — siga cada símbolo alterado até seus chamadores, adapters e tipos compartilhados **dentro do seu domínio** (use os importadores do AST), **dentro do orçamento de exploração** (seção acima). Priorize os arquivos de maior churn.
939
+ 4. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas, **dentro do orçamento**. Pare quando tiver a prova: repetir busca não aumenta certeza.
940
+ 5. **PROVE** — para cada suspeita, descreva gatilho → comportamento observado → invariante/regra violada. Sem prova, não é achado. Trecho com o marcador de truncamento só sustenta achado depois de abrir o arquivo para ver o restante.
941
+ 6. **CONCLUDE** — grave o JSON no caminho de output. \`reviewedFiles\` é um subconjunto de \`## Arquivos do seu domínio\` (só o que você revisou; **não** liste chamadores/importadores nem arquivos de outros domínios) e o que ficou de fora entra em \`skipped\` ("budget", "truncated" ou "fora do fluxo"). Máximo de 20 achados: priorize severidade e agrupe ocorrências idênticas. \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre.
896
942
  "
897
943
  `;
898
944
 
899
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 2`] = `
900
- "Triagem: sqlite:<cwd>\\houndsman.db#<uuid> — 1 finding(s).
901
- Relatório: sqlite:<cwd>\\houndsman.db#<uuid> — 1 bloqueante(s), 0 atenção."
945
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state 2`] = `
946
+ "Severidade: 1 pela regra.
947
+ Triagem: sqlite:<cwd>\\houndsman.db#<uuid> — 1 finding(s).
948
+ Resumo: sqlite:<cwd>\\houndsman.db#<uuid> (review-resume.md) — 1 bloqueante(s), 0 atenção."
902
949
  `;
903
950
 
904
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.md 1`] = `
905
- "# PR Review — main
951
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: review-resume.md 1`] = `
952
+ "# Resumo da revisão — main
906
953
 
907
- **Data:** <date>
908
- **Watchdogs ativos:** alpha
909
- **Achados:** 1 bloqueantes · 0 atenção · 0 sugestões · 0 nits
954
+ **Data:** <date> · **Status:** ❌ Mudanças necessárias
910
955
 
911
- ## Relatórios por domínio
956
+ ## Resumo de negócio
912
957
 
913
- | Watchdog | Achados | Revisados | Relatório |
914
- |---|---|---|---|
915
- | Alpha | 1 | 2/2 | [\`review.alpha.md\`](review.alpha.md) |
958
+ **Fluxos (1):**
959
+ - **Alpha**
960
+ arquivos: src/alpha/a.ts, src/alpha/b.ts
916
961
 
917
- ## Cobertura
962
+ ## Pontos técnicos
918
963
 
919
- | Watchdog | Arquivos revisados | Findings |
920
- |---|---|---|
921
- | Alpha | 2 | 1 |
964
+ - **Estrutura** — Novo diretório \`src/alpha\` com 1 arquivo(s).
965
+ - **Remoções** — \`src/alpha/old.ts\`
922
966
 
923
- ## Conclusão
924
-
925
- **Status:** ❌ Mudanças Necessárias
926
- **Resumo:** 1 violações bloqueantes, 0 pontos de atenção, 0 sugestões e 0 nits.
967
+ ## Cobertura por domínio
927
968
 
928
- ## ❌ blocking
929
-
930
- ### \`src/alpha/a.ts\`
969
+ | Domínio | Achados | Revisados | Fora do recorte | Faltam |
970
+ |---|---|---|---|---|
971
+ | Alpha | 1 | 2/2 | — | — |
972
+ | Lógica e domínio (fluxo) | 0 | 2/2 | — | — |
931
973
 
932
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`<id>\`
933
- any detectado
934
- **Ação:** tipar
935
- **Evidência:** \`export const a: any = 1;\`
936
-
937
- "
938
- `;
974
+ > \`Faltam\` = arquivos do escopo sem revisão e sem declaração em \`skipped\`.
939
975
 
940
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.alpha.md 1`] = `
941
- "# Review — Alpha (\`alpha\`) — main
942
-
943
- **Data:** <date>
944
- **Arquivos revisados:** 2/2
945
- **Achados:** 1
946
-
947
- ## ❌ blocking
948
-
949
- ### \`src/alpha/a.ts\`
950
-
951
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_
952
- any detectado
953
- **Ação:** tipar
954
- **Evidência:** \`export const a: any = 1;\`
976
+ ## Conclusão
955
977
 
978
+ **Resumo:** 1 bloqueantes · 0 atenção · 0 sugestões · 0 nits.
956
979
  "
957
980
  `;
958
981
 
959
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: state.json 1`] = `
982
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: state.json 1`] = `
960
983
  "{
961
984
  "version": 2,
962
985
  "branch": "main",
@@ -979,6 +1002,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
979
1002
  "message": "any detectado",
980
1003
  "action": "tipar",
981
1004
  "evidence": "export const a: any = 1;",
1005
+ "basis": "rule",
982
1006
  "anchor": {
983
1007
  "snippet": "export const a: any = 1;",
984
1008
  "line": 1,
@@ -1001,7 +1025,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
1001
1025
  }"
1002
1026
  `;
1003
1027
 
1004
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: run.json 1`] = `
1028
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: run.json 1`] = `
1005
1029
  "{
1006
1030
  "id": "<uuid>",
1007
1031
  "repoKey": "path:<cwd>",