@payconductor/houndsman 0.12.0 → 0.14.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 (119) hide show
  1. package/README.md +23 -2
  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/doctor-command.ts +22 -0
  6. package/src/cli/commands/findings-command.ts +11 -1
  7. package/src/cli/commands/hunt-command.ts +479 -0
  8. package/src/cli/commands/review-command.ts +58 -2
  9. package/src/cli/commands/status-command.ts +3 -2
  10. package/src/cli/help.ts +20 -3
  11. package/src/cli/index.ts +20 -3
  12. package/src/cli/progress.ts +50 -0
  13. package/src/core/ai/ai-client.ts +38 -2
  14. package/src/core/ai/ai-sdk-model-provider.ts +39 -0
  15. package/src/core/ai/features/brief-enricher.ts +1 -1
  16. package/src/core/ai/features/business-analyzer.ts +61 -0
  17. package/src/core/ai/features/business-summarizer.ts +44 -0
  18. package/src/core/ai/index.ts +14 -1
  19. package/src/core/ai/prompts/brief.ts +33 -7
  20. package/src/core/ai/prompts/business.ts +76 -0
  21. package/src/core/ai/provider-capabilities.ts +12 -0
  22. package/src/core/ai/schemas.ts +70 -2
  23. package/src/core/ai/types.ts +2 -0
  24. package/src/core/ai/usage-recorder.ts +53 -1
  25. package/src/core/brief.ts +246 -12
  26. package/src/core/builtins.ts +108 -0
  27. package/src/core/business-summary.ts +583 -0
  28. package/src/core/commands/compare.ts +233 -0
  29. package/src/core/commands/context.ts +6 -2
  30. package/src/core/commands/findings.ts +38 -30
  31. package/src/core/commands/review.ts +6 -0
  32. package/src/core/commands/scaffold.ts +38 -0
  33. package/src/core/commands/status.ts +9 -4
  34. package/src/core/compare.ts +243 -0
  35. package/src/core/concurrency.ts +30 -0
  36. package/src/core/config.ts +57 -1
  37. package/src/core/defaults.ts +63 -2
  38. package/src/core/domain/budget.ts +62 -4
  39. package/src/core/domain/classification.ts +12 -2
  40. package/src/core/engine/carryover.ts +4 -0
  41. package/src/core/engine/finalize-pipeline.ts +347 -0
  42. package/src/core/engine/prepare-pipeline.ts +1294 -0
  43. package/src/core/engine/review-context.ts +51 -0
  44. package/src/core/engine/review-options.ts +47 -0
  45. package/src/core/engine/review-scope.ts +106 -26
  46. package/src/core/engine/review-session.ts +18 -16
  47. package/src/core/engine/review-workspace.ts +14 -0
  48. package/src/core/engine/run-artifacts.ts +196 -0
  49. package/src/core/engine/run-format.ts +4 -0
  50. package/src/core/env.ts +14 -0
  51. package/src/core/findings-state.ts +13 -1
  52. package/src/core/github-review.ts +5 -2
  53. package/src/core/hunt/hunt-runner.ts +418 -0
  54. package/src/core/hunt/index.ts +61 -0
  55. package/src/core/hunt/maki-install.ts +331 -0
  56. package/src/core/hunt/maki-intent-prompt.ts +50 -0
  57. package/src/core/hunt/maki-model.ts +101 -0
  58. package/src/core/hunt/maki-prompt.ts +83 -0
  59. package/src/core/hunt/maki-release.ts +104 -0
  60. package/src/core/hunt/maki-runner.ts +276 -0
  61. package/src/core/hunt/pool.ts +8 -0
  62. package/src/core/logging/index.ts +7 -0
  63. package/src/core/logging/logger.ts +19 -0
  64. package/src/core/logging/progress.ts +366 -0
  65. package/src/core/orchestrator.ts +33 -1180
  66. package/src/core/paths.ts +6 -3
  67. package/src/core/pr-context.ts +2 -4
  68. package/src/core/prepare-report.ts +61 -0
  69. package/src/core/project-config.ts +46 -1
  70. package/src/core/propagation.ts +127 -0
  71. package/src/core/registry-check.ts +60 -21
  72. package/src/core/renderers/manifest-writer.ts +13 -0
  73. package/src/core/renderers/resume-renderer.ts +151 -11
  74. package/src/core/report-builder.ts +108 -278
  75. package/src/core/storage/file/file-storage.ts +7 -3
  76. package/src/core/storage/sqlite/mappers.ts +10 -0
  77. package/src/core/storage/sqlite/schema.ts +104 -23
  78. package/src/core/storage/sqlite/sqlite-storage.ts +22 -9
  79. package/src/core/storage/types.ts +17 -4
  80. package/src/core/storage/work-area.ts +59 -1
  81. package/src/core/types.ts +31 -0
  82. package/src/core/watchdog-registry.ts +21 -3
  83. package/src/index.ts +78 -4
  84. package/src/server/client/ArtifactsPanel.tsx +4 -2
  85. package/src/server/client/FindingCard.tsx +21 -1
  86. package/src/server/client/RunsSection.tsx +5 -0
  87. package/src/server/client/utils/constants.ts +21 -11
  88. package/src/server/client/utils/markdown.ts +1 -1
  89. package/src/server/client/utils/types.ts +14 -2
  90. package/src/server/run-repository.ts +35 -14
  91. package/src/server/styles.css +2 -0
  92. package/src/skill/OUTPUT-FORMAT.md +36 -10
  93. package/src/skill/README.md +30 -14
  94. package/src/skill/SETUP.md +22 -1
  95. package/src/skill/SKILL.md +17 -4
  96. package/src/skill/example-resume.md +43 -0
  97. package/src/skill/hunt.md +181 -58
  98. package/src/tests/__snapshots__/baseline.test.ts.snap +206 -178
  99. package/src/tests/ai-core.test.ts +84 -1
  100. package/src/tests/ai-features.test.ts +95 -4
  101. package/src/tests/baseline.test.ts +29 -121
  102. package/src/tests/brief-scope.test.ts +250 -0
  103. package/src/tests/business-summary.test.ts +258 -0
  104. package/src/tests/cli.test.ts +1 -0
  105. package/src/tests/compare.test.ts +233 -0
  106. package/src/tests/fixtures/fake-model-provider.ts +2 -1
  107. package/src/tests/hunt-cli.test.ts +185 -0
  108. package/src/tests/hunt-install.test.ts +153 -0
  109. package/src/tests/hunt-maki.test.ts +525 -0
  110. package/src/tests/markdown.test.ts +3 -3
  111. package/src/tests/progress.test.ts +145 -0
  112. package/src/tests/propagation.test.ts +119 -0
  113. package/src/tests/review-resume.test.ts +60 -1
  114. package/src/tests/review-scope.test.ts +90 -19
  115. package/src/tests/review-scripts.test.ts +106 -218
  116. package/src/tests/server.test.ts +7 -4
  117. package/src/tests/storage.test.ts +194 -9
  118. package/src/core/renderers/report-renderer.ts +0 -66
  119. package/src/skill/example-review.md +0 -66
@@ -40,11 +40,11 @@ src/alpha/**
40
40
  - \`src/alpha/a.ts\` (modified, +3/−1)
41
41
  - \`src/alpha/b.ts\` (added, +2/−0)
42
42
 
43
- ## Fora do orçamento (NÃO revisar)
43
+ ## Fora do recorte (NÃO revisar)
44
44
 
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.
45
+ > 1 arquivo(s) do escopo ficaram fora do recorte
46
+ > (orçamento ou prioridade de fluxo). Não os leia: registre-os em \`skipped\`
47
+ > com o motivo (\`budget\` ou \`fora do fluxo\`) para que a cobertura fique honesta.
48
48
 
49
49
  - \`src/alpha/c.ts\`
50
50
 
@@ -60,111 +60,22 @@ src/alpha/**
60
60
 
61
61
  - \`src/alpha/old.ts\`
62
62
 
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
63
+ ## Orçamento de exploração
90
64
 
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\`
112
-
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;\`
117
-
118
- ## ⚠️ attention
119
-
120
- ### \`src/alpha/b.ts\`
65
+ > O diff já está no brief. Limite **neste brief**: 6 leitura(s) de arquivo
66
+ > e 6 busca(s) (grep).
67
+ > Abra arquivo só para chamador/contexto de um símbolo citado nos trechos.
68
+ > Se a prova não estiver no brief nem nesse orçamento, **não é achado** —
69
+ > registre a dúvida no campo \`action\` do finding mais próximo ou descarte.
121
70
 
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
71
+ ## Procedimento
165
72
 
166
- - \`src/alpha/c.ts\`
167
- "
73
+ 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.
74
+ 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.
75
+ 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.
76
+ 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.
77
+ 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.
78
+ 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
79
  `;
169
80
 
170
81
  exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 1`] = `
@@ -180,7 +91,7 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 1
180
91
  ".houndsman/core/skill/OUTPUT-FORMAT.md",
181
92
  ".houndsman/core/skill/README.md",
182
93
  ".houndsman/core/skill/SETUP.md",
183
- ".houndsman/core/skill/example-review.md",
94
+ ".houndsman/core/skill/example-resume.md",
184
95
  ".houndsman/core/skill/fix.md",
185
96
  ".houndsman/core/skill/hunt.md",
186
97
  ".houndsman/core/skill/train.md",
@@ -214,6 +125,11 @@ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do
214
125
  **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
215
126
  especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
216
127
 
128
+ > **Duas etapas são obrigatórias em toda revisão:** o **modelo de intenção**
129
+ > (\`business-summary.json\`) e o revisor de fluxo **\`general\`** (id reservado, sempre ativo).
130
+ > O modelo vem da IA no prepare quando há chave; sem chave, um subagente (Passo 1.5) ou o
131
+ > pré-passe maki o produz. Nenhum dos dois é configurável pelo usuário.
132
+
217
133
  ## Capabilities
218
134
 
219
135
  | Capability | Objetivo | Documento |
@@ -238,6 +154,10 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
238
154
  Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
239
155
  leia o documento correspondente em \`.houndsman/core/skill/<capability>.md\` e siga-o.
240
156
 
157
+ > **Harness local (opcional):** para rodar sem agente externo, o operador pode instalar o
158
+ > maki (\`houndsman hunt install\`) e usar \`houndsman hunt --pr 456\`. Isso não muda esta
159
+ > skill: se você é o agente, siga o fluxo normal e não rode \`houndsman hunt\`.
160
+
241
161
  ### Alvo da revisão (PR × branch)
242
162
 
243
163
  Interprete o alvo em linguagem natural **antes** de rodar o CLI:
@@ -256,12 +176,16 @@ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
256
176
  Sequência para uma PR (ex.: 456):
257
177
 
258
178
  \`\`\`bash
259
- houndsman context --pr 456
260
- houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
261
- # despache os briefs (cada um traz **Worktree:** <path>)
179
+ houndsman --pr 456 # cria/reusa o worktree, coleta o contexto e prepara
180
+ # despache os briefs em paralelo (cada um traz **Worktree:** <path>)
262
181
  houndsman --pr 456 --finalize
263
182
  \`\`\`
264
183
 
184
+ - O contexto da PR é coletado pelo próprio prepare (via \`gh\`); com IA ligada ele também é
185
+ resumido ali — não gaste um subagente nisso. Desative com \`--no-context\`.
186
+ - Para comparar duas execuções, use \`--variant <label>\` em cada uma e depois
187
+ \`houndsman compare --branch <head> --a <a> --b <b>\` (ou \`compare --list\`).
188
+
265
189
  - O worktree vive em \`<repo>/.houndsman/worktrees/<repo>/<branch>\` (detached no commit da PR)
266
190
  e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
267
191
  (e o staging também) para o agente ler/executar sem prompts de permissão.
@@ -279,7 +203,7 @@ houndsman --pr 456 --finalize
279
203
  - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
280
204
  - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
281
205
  - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
282
- - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
206
+ - \`.houndsman/core/skill/example-resume.md\` — exemplo do resumo final.
283
207
  "
284
208
  ,
285
209
  ".claude/skills/houndsman/SKILL.md":
@@ -299,6 +223,11 @@ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do
299
223
  **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
300
224
  especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
301
225
 
226
+ > **Duas etapas são obrigatórias em toda revisão:** o **modelo de intenção**
227
+ > (\`business-summary.json\`) e o revisor de fluxo **\`general\`** (id reservado, sempre ativo).
228
+ > O modelo vem da IA no prepare quando há chave; sem chave, um subagente (Passo 1.5) ou o
229
+ > pré-passe maki o produz. Nenhum dos dois é configurável pelo usuário.
230
+
302
231
  ## Capabilities
303
232
 
304
233
  | Capability | Objetivo | Documento |
@@ -323,6 +252,10 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
323
252
  Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
324
253
  leia o documento correspondente em \`.houndsman/core/skill/<capability>.md\` e siga-o.
325
254
 
255
+ > **Harness local (opcional):** para rodar sem agente externo, o operador pode instalar o
256
+ > maki (\`houndsman hunt install\`) e usar \`houndsman hunt --pr 456\`. Isso não muda esta
257
+ > skill: se você é o agente, siga o fluxo normal e não rode \`houndsman hunt\`.
258
+
326
259
  ### Alvo da revisão (PR × branch)
327
260
 
328
261
  Interprete o alvo em linguagem natural **antes** de rodar o CLI:
@@ -341,12 +274,16 @@ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
341
274
  Sequência para uma PR (ex.: 456):
342
275
 
343
276
  \`\`\`bash
344
- houndsman context --pr 456
345
- houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
346
- # despache os briefs (cada um traz **Worktree:** <path>)
277
+ houndsman --pr 456 # cria/reusa o worktree, coleta o contexto e prepara
278
+ # despache os briefs em paralelo (cada um traz **Worktree:** <path>)
347
279
  houndsman --pr 456 --finalize
348
280
  \`\`\`
349
281
 
282
+ - O contexto da PR é coletado pelo próprio prepare (via \`gh\`); com IA ligada ele também é
283
+ resumido ali — não gaste um subagente nisso. Desative com \`--no-context\`.
284
+ - Para comparar duas execuções, use \`--variant <label>\` em cada uma e depois
285
+ \`houndsman compare --branch <head> --a <a> --b <b>\` (ou \`compare --list\`).
286
+
350
287
  - O worktree vive em \`<repo>/.houndsman/worktrees/<repo>/<branch>\` (detached no commit da PR)
351
288
  e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
352
289
  (e o staging também) para o agente ler/executar sem prompts de permissão.
@@ -364,7 +301,7 @@ houndsman --pr 456 --finalize
364
301
  - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
365
302
  - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
366
303
  - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
367
- - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
304
+ - \`.houndsman/core/skill/example-resume.md\` — exemplo do resumo final.
368
305
  "
369
306
  ,
370
307
  ".houndsman/.gitignore":
@@ -489,6 +426,7 @@ export type AiProviderOptions = Record<string, Record<string, unknown>>;
489
426
  /** Features de IA do fluxo normal (todas fail-open). */
490
427
  export type HoundsmanAiFeatures = {
491
428
  context?: boolean;
429
+ business?: boolean;
492
430
  brief?: boolean;
493
431
  technical?: boolean;
494
432
  classification?: boolean;
@@ -516,6 +454,28 @@ export type HoundsmanAi = {
516
454
  watchdogs?: Record<string, HoundsmanAiWatchdog>;
517
455
  };
518
456
 
457
+ /** Harness local da capability \`hunt\` (\`houndsman hunt\`) — opcional. */
458
+ export type HoundsmanHunt = {
459
+ enabled?: boolean;
460
+ model?: string;
461
+ concurrency?: number;
462
+ timeoutMs?: number;
463
+ retries?: number;
464
+ binaryPath?: string;
465
+ };
466
+
467
+ /**
468
+ * Prioridade por caminho.
469
+ *
470
+ * \`bonus\` promove (linhas de churn equivalentes) e \`maxRiskFromChurn\` satura o
471
+ * superchurn de caminhos de baixa criticidade.
472
+ */
473
+ export type HoundsmanPriority = {
474
+ pattern: RegExp;
475
+ bonus?: number;
476
+ maxRiskFromChurn?: number;
477
+ };
478
+
519
479
  /** Contrato de configuração do motor. */
520
480
  export type HoundsmanConfig<TId extends string = string> = {
521
481
  projectName: string;
@@ -524,11 +484,14 @@ export type HoundsmanConfig<TId extends string = string> = {
524
484
  watchdogs: Record<TId, WatchdogDefinition>;
525
485
  exclusions: readonly RegExp[];
526
486
  docMappings: readonly (readonly [RegExp, readonly string[]])[];
487
+ /** Prioridade por caminho (opcional; a primeira regra que casar vence). */
488
+ priorities?: readonly HoundsmanPriority[];
527
489
  alwaysIncludeDocs?: readonly string[];
528
490
  budgets?: HoundsmanBudgets;
529
491
  concurrency?: HoundsmanConcurrency;
530
492
  ast?: HoundsmanAst;
531
493
  ai?: HoundsmanAi;
494
+ hunt?: HoundsmanHunt;
532
495
  };
533
496
 
534
497
  /** Helper de autoria (identidade) — apenas tipagem. */
@@ -607,6 +570,9 @@ import { exampleWatchdog } from "./example";
607
570
  /**
608
571
  * Definições dos watchdogs — as chaves definem o union \`WatchdogId\`.
609
572
  * Adicionar um watchdog = criar \`<id>.ts\` e registrá-lo aqui.
573
+ *
574
+ * NÃO declare um watchdog com id \`general\`: ele é reservado pelo motor
575
+ * (revisor de fluxo obrigatório) e é injetado em todo ciclo.
610
576
  */
611
577
  export const WATCHDOG_DEFINITIONS = {
612
578
  default: defaultWatchdog,
@@ -634,6 +600,15 @@ export const houndsmanConfig = {
634
600
  watchdogs: WATCHDOG_DEFINITIONS,
635
601
  exclusions: EXCLUSION_PATTERNS,
636
602
  docMappings: DOC_MAPPINGS,
603
+ // Prioridade por caminho (opcional): "linhas de churn equivalentes".
604
+ // \`bonus\` promove caminho crítico; \`maxRiskFromChurn\` satura o superchurn de
605
+ // caminho de baixa criticidade (risco = min(churn, teto) + bonus).
606
+ // A primeira regra que casar vence; sem regra, o risco é o churn puro.
607
+ // priorities: [
608
+ // { pattern: /^src\\/(db|repositories)\\//, bonus: 300 },
609
+ // { pattern: /^src\\/(services|domain)\\//, bonus: 200 },
610
+ // { pattern: /^src\\/(components|styles)\\//, maxRiskFromChurn: 120 },
611
+ // ],
637
612
  } satisfies HoundsmanConfig;
638
613
 
639
614
  export default houndsmanConfig;
@@ -650,19 +625,19 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
650
625
  },
651
626
  {
652
627
  "file": ".houndsman/core/skill/OUTPUT-FORMAT.md",
653
- "sha256": "a78ed16d4d211889",
628
+ "sha256": "49d36854d10f795c",
654
629
  },
655
630
  {
656
631
  "file": ".houndsman/core/skill/README.md",
657
- "sha256": "9aadf51b48c7f304",
632
+ "sha256": "4d200cf9e5c1d748",
658
633
  },
659
634
  {
660
635
  "file": ".houndsman/core/skill/SETUP.md",
661
- "sha256": "5e5335870f493aba",
636
+ "sha256": "e7f587d1c8e459d1",
662
637
  },
663
638
  {
664
- "file": ".houndsman/core/skill/example-review.md",
665
- "sha256": "d9e75054cc9811dc",
639
+ "file": ".houndsman/core/skill/example-resume.md",
640
+ "sha256": "4993f56afdf2ffd1",
666
641
  },
667
642
  {
668
643
  "file": ".houndsman/core/skill/fix.md",
@@ -670,7 +645,7 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
670
645
  },
671
646
  {
672
647
  "file": ".houndsman/core/skill/hunt.md",
673
- "sha256": "dfaec1a665d7ee65",
648
+ "sha256": "0a81003a5b39b84a",
674
649
  },
675
650
  {
676
651
  "file": ".houndsman/core/skill/train.md",
@@ -683,25 +658,31 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
683
658
  ]
684
659
  `;
685
660
 
686
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 1`] = `
687
- "Discovery: 1 watchdog(s) ativado(s), 3 arquivo(s), 1 deletado(s).
661
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state 1`] = `
662
+ "Discovery: 1 watchdog(s) de domínio + revisor general, 3 arquivo(s), 1 deletado(s).
688
663
  Briefs: <cwd>/.home/work/<uuid>/briefs/
689
664
  Deletado (breaking change): src/alpha/old.ts
690
665
  Escopo: 2 arquivo(s), 0 símbolo(s) em 2 faixa(s) alterada(s).
666
+ Escopo: 2 arquivo(s) em mais de um domínio (máx. 2) — cada domínio revisa o arquivo com o seu recorte.
691
667
  Jev: pulado (desativado (--no-jev)).
692
668
  AST: desabilitado ou sem grammar compatível.
693
669
  Sem contexto da PR (rode \`bun run houndsman context\` antes, se houver PR).
670
+ Intenção da PR determinística (1 fluxo(s)) — enriquecida no passo de intenção (<cwd>/.home/work/<uuid>/business-brief.md).
694
671
 
695
672
  Próximo passo: despachar os sub-agentes (um por brief em <cwd>/.home/work/<uuid>/briefs/).
696
673
  Quando os findings estiverem gravados: bun run houndsman --finalize"
697
674
  `;
698
675
 
699
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: classification.json 1`] = `
676
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: classification.json 1`] = `
700
677
  "{
701
678
  "watchdogs": {
702
679
  "alpha": [
703
680
  "src/alpha/a.ts",
704
681
  "src/alpha/b.ts"
682
+ ],
683
+ "general": [
684
+ "src/alpha/a.ts",
685
+ "src/alpha/b.ts"
705
686
  ]
706
687
  },
707
688
  "files": {
@@ -735,7 +716,8 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
735
716
  "src/alpha/old.ts"
736
717
  ],
737
718
  "stats": {
738
- "alpha": 2
719
+ "alpha": 2,
720
+ "general": 2
739
721
  },
740
722
  "excludedCount": 0,
741
723
  "headSha": "<sha>",
@@ -766,7 +748,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
766
748
  "
767
749
  `;
768
750
 
769
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: manifest.json 1`] = `
751
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: manifest.json 1`] = `
770
752
  "{
771
753
  "branch": "main",
772
754
  "slug": "main",
@@ -795,12 +777,31 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
795
777
  "brief": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\briefs\\\\alpha.md",
796
778
  "findings": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\findings\\\\alpha.json",
797
779
  "status": "pending"
780
+ },
781
+ {
782
+ "id": "general",
783
+ "name": "Lógica e domínio (fluxo)",
784
+ "files": [
785
+ "src/alpha/a.ts",
786
+ "src/alpha/b.ts"
787
+ ],
788
+ "overflow": 0,
789
+ "brief": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\briefs\\\\general.md",
790
+ "findings": "<cwd>\\\\.home\\\\work\\\\<uuid>\\\\findings\\\\general.json",
791
+ "status": "pending"
798
792
  }
799
793
  ],
800
794
  "context": {
801
795
  "summarized": false,
802
796
  "source": null
803
797
  },
798
+ "business": {
799
+ "source": "deterministic",
800
+ "flows": 1,
801
+ "invariants": 0,
802
+ "contracts": 0,
803
+ "states": 0
804
+ },
804
805
  "jev": {
805
806
  "available": false,
806
807
  "reason": "desativado (--no-jev)"
@@ -824,7 +825,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
824
825
  "
825
826
  `;
826
827
 
827
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: briefs/alpha.md 1`] = `
828
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: briefs/alpha.md 1`] = `
828
829
  "# Brief — Alpha (\`alpha\`)
829
830
 
830
831
  **Branch:** main
@@ -849,6 +850,47 @@ src/alpha/**
849
850
  - \`src/alpha/a.ts\` — linhas 1-2 _(faixas do diff)_
850
851
  - \`src/alpha/b.ts\` — linhas 1 _(faixas do diff)_
851
852
 
853
+ ## Modelo de intenção (negócio)
854
+
855
+ > Fonte: determinístico. Use para saber o que a mudança **deve** entregar; não é achado.
856
+
857
+ > Recorte do seu domínio: fluxos/arquivos de outros domínios pertencem a outros watchdogs — não os investigue.
858
+
859
+ **Fluxos (1):**
860
+ - **Alpha**
861
+ arquivos: src/alpha/a.ts, src/alpha/b.ts
862
+
863
+ ## Trechos alterados (diff)
864
+
865
+ > Trechos já extraídos do diff (\`-U0\`, só linhas alteradas). Eles bastam
866
+ > para achar violações: **não abra os arquivos apenas para reler o que já
867
+ > está aqui**. Use o arquivo só para contexto adjacente ou chamadores.
868
+
869
+ ### \`src/alpha/a.ts\`
870
+
871
+ \`\`\`diff
872
+ diff --git a/src/alpha/a.ts b/src/alpha/a.ts
873
+ index cc798ff..bc84e2e 100644
874
+ --- a/src/alpha/a.ts
875
+ +++ b/src/alpha/a.ts
876
+ @@ -1 +1,2 @@
877
+ -export const a = 1;
878
+ +export const a: any = 1;
879
+ +export const b = 2;
880
+ \`\`\`
881
+
882
+ ### \`src/alpha/b.ts\`
883
+
884
+ \`\`\`diff
885
+ diff --git a/src/alpha/b.ts b/src/alpha/b.ts
886
+ new file mode 100644
887
+ index 0000000..f4082f0
888
+ --- /dev/null
889
+ +++ b/src/alpha/b.ts
890
+ @@ -0,0 +1 @@
891
+ +export const b = 3;
892
+ \`\`\`
893
+
852
894
  ## Regras (por severidade)
853
895
 
854
896
  - ❌ **blocking** — Nunca usar \`any\`.
@@ -867,77 +909,62 @@ src/alpha/**
867
909
 
868
910
  - \`src/alpha/old.ts\`
869
911
 
912
+ ## Orçamento de exploração
913
+
914
+ > O diff já está no brief. Limite **neste brief**: 6 leitura(s) de arquivo
915
+ > e 6 busca(s) (grep).
916
+ > Abra arquivo só para chamador/contexto de um símbolo citado nos trechos.
917
+ > Se a prova não estiver no brief nem nesse orçamento, **não é achado** —
918
+ > registre a dúvida no campo \`action\` do finding mais próximo ou descarte.
919
+
870
920
  ## Procedimento
871
921
 
872
- 1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
873
- 2. **READ SCOPE** — carregue apenas as faixas alteradas em *Escopo do diff*; o restante do arquivo é só contexto.
874
- 3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas.
875
- 4. **DEEP-READ** — aprofunde apenas as faixas com suspeita de violação dentro do escopo.
876
- 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.
922
+ 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.
923
+ 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.
924
+ 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.
925
+ 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.
926
+ 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.
927
+ 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.
877
928
  "
878
929
  `;
879
930
 
880
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 2`] = `
931
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state 2`] = `
881
932
  "Triagem: sqlite:<cwd>\\houndsman.db#<uuid> — 1 finding(s).
882
- Relatório: sqlite:<cwd>\\houndsman.db#<uuid> — 1 bloqueante(s), 0 atenção."
933
+ Resumo: sqlite:<cwd>\\houndsman.db#<uuid> (review-resume.md) — 1 bloqueante(s), 0 atenção."
883
934
  `;
884
935
 
885
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.md 1`] = `
886
- "# PR Review — main
936
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: review-resume.md 1`] = `
937
+ "# Resumo da revisão — main
887
938
 
888
- **Data:** <date>
889
- **Watchdogs ativos:** alpha
890
- **Achados:** 1 bloqueantes · 0 atenção · 0 sugestões · 0 nits
939
+ **Data:** <date> · **Status:** ❌ Mudanças necessárias
891
940
 
892
- ## Relatórios por domínio
941
+ ## Resumo de negócio
893
942
 
894
- | Watchdog | Achados | Revisados | Relatório |
895
- |---|---|---|---|
896
- | Alpha | 1 | 2/2 | [\`review.alpha.md\`](review.alpha.md) |
943
+ **Fluxos (1):**
944
+ - **Alpha**
945
+ arquivos: src/alpha/a.ts, src/alpha/b.ts
897
946
 
898
- ## Cobertura
947
+ ## Pontos técnicos
899
948
 
900
- | Watchdog | Arquivos revisados | Findings |
901
- |---|---|---|
902
- | Alpha | 2 | 1 |
903
-
904
- ## Conclusão
905
-
906
- **Status:** ❌ Mudanças Necessárias
907
- **Resumo:** 1 violações bloqueantes, 0 pontos de atenção, 0 sugestões e 0 nits.
908
-
909
- ## ❌ blocking
910
-
911
- ### \`src/alpha/a.ts\`
949
+ - **Estrutura** — Novo diretório \`src/alpha\` com 1 arquivo(s).
950
+ - **Remoções** — \`src/alpha/old.ts\`
912
951
 
913
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`<id>\`
914
- any detectado
915
- **Ação:** tipar
916
- **Evidência:** \`export const a: any = 1;\`
952
+ ## Cobertura por domínio
917
953
 
918
- "
919
- `;
920
-
921
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.alpha.md 1`] = `
922
- "# Review — Alpha (\`alpha\`) — main
923
-
924
- **Data:** <date>
925
- **Arquivos revisados:** 2/2
926
- **Achados:** 1
954
+ | Domínio | Achados | Revisados | Fora do recorte | Faltam |
955
+ |---|---|---|---|---|
956
+ | Alpha | 1 | 2/2 | — | — |
957
+ | Lógica e domínio (fluxo) | 0 | 2/2 | — | — |
927
958
 
928
- ## ❌ blocking
959
+ > \`Faltam\` = arquivos do escopo sem revisão e sem declaração em \`skipped\`.
929
960
 
930
- ### \`src/alpha/a.ts\`
931
-
932
- - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_
933
- any detectado
934
- **Ação:** tipar
935
- **Evidência:** \`export const a: any = 1;\`
961
+ ## Conclusão
936
962
 
963
+ **Resumo:** 1 bloqueantes · 0 atenção · 0 sugestões · 0 nits.
937
964
  "
938
965
  `;
939
966
 
940
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: state.json 1`] = `
967
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: state.json 1`] = `
941
968
  "{
942
969
  "version": 2,
943
970
  "branch": "main",
@@ -960,6 +987,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
960
987
  "message": "any detectado",
961
988
  "action": "tipar",
962
989
  "evidence": "export const a: any = 1;",
990
+ "basis": "rule",
963
991
  "anchor": {
964
992
  "snippet": "export const a: any = 1;",
965
993
  "line": 1,
@@ -982,7 +1010,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
982
1010
  }"
983
1011
  `;
984
1012
 
985
- exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: run.json 1`] = `
1013
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, resumo e state: run.json 1`] = `
986
1014
  "{
987
1015
  "id": "<uuid>",
988
1016
  "repoKey": "path:<cwd>",