@payconductor/houndsman 0.13.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 (106) 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/hunt-command.ts +20 -3
  7. package/src/cli/commands/review-command.ts +38 -0
  8. package/src/cli/commands/status-command.ts +3 -2
  9. package/src/cli/help.ts +3 -1
  10. package/src/cli/index.ts +3 -1
  11. package/src/cli/progress.ts +7 -2
  12. package/src/core/ai/ai-client.ts +38 -2
  13. package/src/core/ai/features/brief-enricher.ts +1 -1
  14. package/src/core/ai/features/business-analyzer.ts +61 -0
  15. package/src/core/ai/features/business-summarizer.ts +44 -0
  16. package/src/core/ai/index.ts +8 -0
  17. package/src/core/ai/prompts/brief.ts +33 -7
  18. package/src/core/ai/prompts/business.ts +76 -0
  19. package/src/core/ai/provider-capabilities.ts +12 -0
  20. package/src/core/ai/schemas.ts +70 -2
  21. package/src/core/ai/usage-recorder.ts +53 -1
  22. package/src/core/brief.ts +246 -12
  23. package/src/core/builtins.ts +108 -0
  24. package/src/core/business-summary.ts +583 -0
  25. package/src/core/commands/compare.ts +233 -0
  26. package/src/core/commands/context.ts +6 -2
  27. package/src/core/commands/findings.ts +38 -30
  28. package/src/core/commands/review.ts +6 -0
  29. package/src/core/commands/scaffold.ts +27 -0
  30. package/src/core/commands/status.ts +9 -4
  31. package/src/core/compare.ts +243 -0
  32. package/src/core/concurrency.ts +30 -0
  33. package/src/core/config.ts +31 -3
  34. package/src/core/defaults.ts +50 -4
  35. package/src/core/domain/budget.ts +62 -4
  36. package/src/core/domain/classification.ts +12 -2
  37. package/src/core/engine/carryover.ts +4 -0
  38. package/src/core/engine/finalize-pipeline.ts +347 -0
  39. package/src/core/engine/prepare-pipeline.ts +1294 -0
  40. package/src/core/engine/review-context.ts +51 -0
  41. package/src/core/engine/review-options.ts +47 -0
  42. package/src/core/engine/review-scope.ts +14 -1
  43. package/src/core/engine/review-session.ts +11 -13
  44. package/src/core/engine/run-artifacts.ts +196 -0
  45. package/src/core/engine/run-format.ts +4 -0
  46. package/src/core/findings-state.ts +13 -1
  47. package/src/core/github-review.ts +5 -2
  48. package/src/core/hunt/hunt-runner.ts +90 -0
  49. package/src/core/hunt/index.ts +2 -0
  50. package/src/core/hunt/maki-intent-prompt.ts +50 -0
  51. package/src/core/hunt/maki-prompt.ts +13 -1
  52. package/src/core/hunt/pool.ts +4 -26
  53. package/src/core/logging/index.ts +6 -1
  54. package/src/core/logging/progress.ts +85 -1
  55. package/src/core/orchestrator.ts +33 -1289
  56. package/src/core/paths.ts +6 -3
  57. package/src/core/pr-context.ts +2 -4
  58. package/src/core/prepare-report.ts +61 -0
  59. package/src/core/project-config.ts +8 -1
  60. package/src/core/propagation.ts +127 -0
  61. package/src/core/registry-check.ts +60 -21
  62. package/src/core/renderers/manifest-writer.ts +13 -0
  63. package/src/core/renderers/resume-renderer.ts +151 -11
  64. package/src/core/report-builder.ts +108 -278
  65. package/src/core/storage/file/file-storage.ts +7 -3
  66. package/src/core/storage/sqlite/mappers.ts +10 -0
  67. package/src/core/storage/sqlite/schema.ts +104 -23
  68. package/src/core/storage/sqlite/sqlite-storage.ts +22 -9
  69. package/src/core/storage/types.ts +16 -4
  70. package/src/core/storage/work-area.ts +59 -1
  71. package/src/core/types.ts +31 -0
  72. package/src/core/watchdog-registry.ts +21 -3
  73. package/src/index.ts +29 -4
  74. package/src/server/client/ArtifactsPanel.tsx +4 -2
  75. package/src/server/client/FindingCard.tsx +21 -1
  76. package/src/server/client/RunsSection.tsx +5 -0
  77. package/src/server/client/utils/constants.ts +21 -11
  78. package/src/server/client/utils/markdown.ts +1 -1
  79. package/src/server/client/utils/types.ts +14 -2
  80. package/src/server/run-repository.ts +35 -14
  81. package/src/server/styles.css +2 -0
  82. package/src/skill/OUTPUT-FORMAT.md +36 -10
  83. package/src/skill/README.md +18 -14
  84. package/src/skill/SETUP.md +1 -0
  85. package/src/skill/SKILL.md +13 -4
  86. package/src/skill/example-resume.md +43 -0
  87. package/src/skill/hunt.md +145 -58
  88. package/src/tests/__snapshots__/baseline.test.ts.snap +187 -178
  89. package/src/tests/ai-core.test.ts +46 -0
  90. package/src/tests/ai-features.test.ts +95 -4
  91. package/src/tests/baseline.test.ts +29 -121
  92. package/src/tests/brief-scope.test.ts +250 -0
  93. package/src/tests/business-summary.test.ts +258 -0
  94. package/src/tests/compare.test.ts +233 -0
  95. package/src/tests/fixtures/fake-model-provider.ts +2 -1
  96. package/src/tests/hunt-maki.test.ts +58 -0
  97. package/src/tests/markdown.test.ts +3 -3
  98. package/src/tests/progress.test.ts +29 -1
  99. package/src/tests/propagation.test.ts +119 -0
  100. package/src/tests/review-resume.test.ts +60 -1
  101. package/src/tests/review-scope.test.ts +38 -29
  102. package/src/tests/review-scripts.test.ts +106 -218
  103. package/src/tests/server.test.ts +7 -4
  104. package/src/tests/storage.test.ts +194 -9
  105. package/src/core/renderers/report-renderer.ts +0 -66
  106. package/src/skill/example-review.md +0 -66
@@ -48,6 +48,8 @@ import { fetchPrComments, type PrCommentsResponse } from "./pr-comments";
48
48
  export type RunListItem = {
49
49
  slug: string;
50
50
  branch: string;
51
+ /** Variante A/B (ausente = run principal da branch). */
52
+ variant?: string;
51
53
  /** Worktree onde a run foi executada (ausente = clone principal). */
52
54
  worktreePath?: string;
53
55
  /** PR revisada (quando iniciada via `--pr`). */
@@ -63,6 +65,8 @@ export type RunListItem = {
63
65
  export type RunDetail = {
64
66
  slug: string;
65
67
  branch: string;
68
+ /** Variante A/B (ausente = run principal da branch). */
69
+ variant?: string;
66
70
  /** Worktree onde a run foi executada (ausente = clone principal). */
67
71
  worktreePath?: string;
68
72
  /** PR revisada (quando iniciada via `--pr`). */
@@ -129,6 +133,7 @@ export class RunRepository {
129
133
  return this.storage.listReviews(this.repo.key).map((review) => {
130
134
  const state = this.storage.readFindings(review.id);
131
135
  return {
136
+ variant: review.variant,
132
137
  slug: review.slug,
133
138
  branch: review.branch,
134
139
  worktreePath: review.worktreePath,
@@ -144,11 +149,11 @@ export class RunRepository {
144
149
 
145
150
  /** Mapa branch → slug das runs (usado para casar PRs com execuções). */
146
151
  branchIndex(): Map<string, string> {
147
- return new Map(
148
- this.storage
149
- .listReviews(this.repo.key)
150
- .map((review) => [review.branch, review.slug]),
151
- );
152
+ const index = new Map<string, string>();
153
+ for (const review of this.reviewsForBranchLinks()) {
154
+ if (!index.has(review.branch)) index.set(review.branch, review.slug);
155
+ }
156
+ return index;
152
157
  }
153
158
 
154
159
  /** Mapa branch → run + worktree (sidebar de PRs). */
@@ -156,15 +161,30 @@ export class RunRepository {
156
161
  string,
157
162
  { slug: string; worktreePath?: string; prNumber?: number }
158
163
  > {
159
- return new Map(
160
- this.storage.listReviews(this.repo.key).map((review) => [
161
- review.branch,
162
- {
163
- slug: review.slug,
164
- worktreePath: review.worktreePath,
165
- prNumber: review.prNumber,
166
- },
167
- ]),
164
+ const index = new Map<
165
+ string,
166
+ { slug: string; worktreePath?: string; prNumber?: number }
167
+ >();
168
+ for (const review of this.reviewsForBranchLinks()) {
169
+ if (index.has(review.branch)) continue;
170
+ index.set(review.branch, {
171
+ slug: review.slug,
172
+ worktreePath: review.worktreePath,
173
+ prNumber: review.prNumber,
174
+ });
175
+ }
176
+ return index;
177
+ }
178
+
179
+ /**
180
+ * Runs ordenadas para links de PR: a principal da branch primeiro (uma
181
+ * variante A/B não deve "roubar" o atalho da PR), depois as mais recentes.
182
+ */
183
+ private reviewsForBranchLinks(): ReviewRecord[] {
184
+ return [...this.storage.listReviews(this.repo.key)].sort(
185
+ (a, b) =>
186
+ Number(Boolean(a.variant)) - Number(Boolean(b.variant)) ||
187
+ b.updatedAt.localeCompare(a.updatedAt),
168
188
  );
169
189
  }
170
190
 
@@ -180,6 +200,7 @@ export class RunRepository {
180
200
  }>(review, "classification.json");
181
201
  return {
182
202
  slug: review.slug,
203
+ variant: review.variant,
183
204
  branch: review.branch,
184
205
  worktreePath: review.worktreePath,
185
206
  prNumber: review.prNumber,
@@ -77,6 +77,8 @@ body.resizing-sidebar { cursor:col-resize; user-select:none; }
77
77
  .run-icon { flex:none; margin-top:2px; color:var(--muted-2); }
78
78
  .run.active .run-icon { color:var(--accent); }
79
79
  .run-branch { font-size:12.5px; font-weight:600; line-height:1.35; word-break:break-word; }
80
+ .run-variant { flex:none; align-self:flex-start; padding:1px 6px; border-radius:999px; font-family:var(--font-mono);
81
+ font-size:9.5px; color:var(--accent); background:var(--accent-soft); border:1px solid var(--accent-line); }
80
82
  .run-meta { display:flex; align-items:center; gap:10px; font-family:var(--font-mono); font-size:10.5px; color:var(--muted); }
81
83
  .run-when { display:inline-flex; align-items:center; gap:6px; }
82
84
  .run-count { margin-left:auto; color:var(--muted-2); }
@@ -1,7 +1,8 @@
1
1
  # Formato de Saída dos Watchdogs
2
2
 
3
3
  Todo watchdog DEVE gravar **um arquivo JSON** com seus achados. O `report-builder.ts`
4
- consolida os JSONs no artefato `review.md` do storage global.
4
+ valida e deduplica os JSONs; o `--finalize` grava a triagem no storage e o
5
+ `review-resume.md` com a cobertura por domínio.
5
6
 
6
7
  > **Não** escrever markdown livre no chat. O único output consumido pelo pipeline é o JSON.
7
8
 
@@ -33,7 +34,11 @@ staging global da review:
33
34
  "line": 5,
34
35
  "message": "Arquivo de rota importa `db` e executa query inline.",
35
36
  "action": "Mover a query para o service correspondente.",
36
- "evidence": "import { db } from '../db'"
37
+ "evidence": "import { db } from '../db'",
38
+ "scenario": "request autenticada em /orders executa a query na rota",
39
+ "impact": "acoplamento e bypass das regras do service",
40
+ "confidence": 0.9,
41
+ "basis": "logic"
37
42
  }
38
43
  ]
39
44
  }
@@ -44,7 +49,7 @@ staging global da review:
44
49
  | Campo | Tipo | Obrigatório | Descrição |
45
50
  |---|---|---|---|
46
51
  | `watchdogId` | string | ✅ | Id do watchdog (deve casar com uma chave de `.houndsman/watchdogs/index.ts`) |
47
- | `reviewedFiles` | string[] | ✅ | Arquivos efetivamente inspecionados |
52
+ | `reviewedFiles` | string[] | ✅ | Arquivos **do seu domínio** efetivamente revisados (subconjunto de `## Arquivos do seu domínio`; não inclua chamadores/importadores nem arquivos de outros domínios) |
48
53
  | `skipped` | string[] | ✅ | Arquivos do domínio que NÃO foram lidos + motivo |
49
54
  | `findings` | object[] | ✅ | Achados (vazio se nada encontrado) |
50
55
  | `findings[].rule` | string | ✅ | Regra violada (conforme o brief do watchdog) |
@@ -54,6 +59,10 @@ staging global da review:
54
59
  | `findings[].message` | string | ✅ | O que está errado (curto, específico) |
55
60
  | `findings[].action` | string | ✅ | O que fazer |
56
61
  | `findings[].evidence` | string | — | Trecho que comprova o achado |
62
+ | `findings[].scenario` | string | — | Gatilho concreto que expõe o gap (ex.: "renovação de assinatura Pix sem split") |
63
+ | `findings[].impact` | string | — | Consequência observável (ex.: "cobrança recriada sem o split configurado") |
64
+ | `findings[].confidence` | number | — | Confiança do revisor (0–1) |
65
+ | `findings[].basis` | `"rule" \| "logic" \| "domain"` | — | Origem do achado; inferida pelo prefixo `Lógica:`/`Domínio:` |
57
66
 
58
67
  ## Severidade
59
68
 
@@ -68,7 +77,14 @@ staging global da review:
68
77
 
69
78
  - Sem achados → `"findings": []` (arquivo **obrigatório**).
70
79
  - Um achado por regra violada; não agrupar regras diferentes.
80
+ - **Teto de 20 achados por watchdog.** Se houver mais, mantenha os de maior severidade e
81
+ agrupe ocorrências idênticas (mesmo trecho + mesma regra) em um único item. O JSON precisa
82
+ caber inteiro — relatório cortado perde achados.
83
+ - `reviewedFiles ∪ skipped` deve cobrir **todo** o escopo do brief. O que não foi revisado
84
+ entra em `skipped` com o motivo (`budget`, `truncated`, `fora do fluxo`).
71
85
  - `file:line` sempre que possível; `evidence` quando o achado não é óbvio.
86
+ - **Trecho truncado** (`… [trecho truncado]`): sem abrir o arquivo para ver o restante, não
87
+ afirme violação sobre ele — reduza a `confidence` ou não reporte.
72
88
  - **Escopo do diff:** a `line` deve cair dentro das faixas listadas em
73
89
  *Escopo do diff (símbolos alterados)* no brief. Código fora delas é contexto — não é
74
90
  achado desta revisão. Se a alteração quebra código não alterado, ancore o finding na
@@ -76,14 +92,24 @@ staging global da review:
76
92
  - Achado **sem linha** só quando for inerente à alteração (vira comentário de arquivo).
77
93
  - Não inventar achados — se não houver violação, o array fica vazio.
78
94
 
79
- ## Findings emergentes (opt-in)
95
+ ## Findings emergentes (obrigatórios no `general`)
80
96
 
81
- Quando o watchdog declara `allowEmergentFindings: true`, você pode reportar falhas de
82
- **lógica** ou **domínio** que não correspondem a uma regra explícita usando os prefixos
83
- reservados:
97
+ O watchdog `general` (id reservado, sempre ativo) **deve** reportar gaps de lógica e domínio
98
+ que não correspondem a uma regra explícita, usando os prefixos reservados:
84
99
 
85
100
  - `Lógica: <descrição>` — nome/contrato vs comportamento, fluxos, estados, bordas.
86
- - `Domínio: <descrição>` — transições, idempotência, invariantes, arredondamento, timezone.
101
+ - `Domínio: <descrição>` — transições, idempotência, invariantes, arredondamento, timezone,
102
+ paridade de capacidade, propagação de credencial.
87
103
 
88
- Esses findings continuam exigindo `evidence` e têm severidade máxima `attention`. Sem o
89
- opt-in, todo finding precisa citar uma regra existente.
104
+ Demonstre o gap em três partes:
105
+
106
+ 1. `scenario` — o gatilho concreto (ex.: "`AsaasSplit` recebe `RenewAutomaticPix`").
107
+ 2. `message` — o comportamento observado e o invariante/regra violado.
108
+ 3. `evidence` — o trecho que comprova.
109
+
110
+ **Severidade:** fora de regra, `blocking` só é aceito com `scenario` **e** `evidence`. Sem os
111
+ dois, o motor rebaixa para `attention` (e registra um aviso). Regras explícitas mantêm a
112
+ severidade declarada pelo watchdog.
113
+
114
+ Os demais watchdogs podem usar os mesmos prefixos apenas quando declararem
115
+ `allowEmergentFindings: true`.
@@ -45,25 +45,28 @@ O CLI só substitui o despacho manual dos subagentes por processos maki headless
45
45
 
46
46
  | Passo | Comando | Quem roda | Resultado |
47
47
  |---|---|---|---|
48
- | 0. Contexto | `bun run houndsman context` | subagente | `context.json` + `context-brief.md` → `context-summary.json` |
49
- | 1. Preparar | `bun run houndsman` | skill | `classification.json` + `candidates.json` + `briefs/` + `manifest.json` |
50
- | 2. Revisar | *(subagentes)* | skill | `findings/<watchdog>.json` (um por watchdog) |
51
- | 3. Finalizar | `bun run houndsman --finalize` | skill | `review.md` |
52
-
53
- > **Alvo = PR** (ex.: “revise a PR 456”): troque os passos por `houndsman context --pr 456`,
54
- > `houndsman --pr 456` e `houndsman --pr 456 --finalize`. O prepare cria um **worktree**
55
- > detached em `<repo>/.houndsman/worktrees/<repo>/<branch>`; os briefs trazem
56
- > `**Worktree:**` e os subagentes devem ler essa árvore (nunca o clone principal).
48
+ | 0. Contexto | `houndsman --pr` (via `gh`) | prepare | `context.json` + `context-brief.md` → `context-summary.json` (IA; sem IA, subagente) |
49
+ | 1. Preparar | `bun run houndsman` | skill | `classification.json` + `candidates.json` + `business-summary.json` + `briefs/` + `manifest.json` |
50
+ | 1.5. Intenção | *(subagente)* | skill, só sem IA | `business-summary.json` enriquecido (só quando não veio da IA) |
51
+ | 2. Revisar | *(subagentes)* | skill | `findings/<watchdog>.json` (inclui o `general`, sempre ativo) |
52
+ | 3. Finalizar | `bun run houndsman --finalize` | skill | `review-resume.md` + triagem no storage |
53
+
54
+ > **Alvo = PR** (ex.: “revise a PR 456”): use `houndsman --pr 456` e
55
+ > `houndsman --pr 456 --finalize`. O prepare coleta o contexto via `gh`, cria um **worktree**
56
+ > detached em `<repo>/.houndsman/worktrees/<repo>/<branch>` e resume o contexto com IA;
57
+ > os briefs trazem `**Worktree:**` e os subagentes devem ler essa árvore (nunca o clone
58
+ > principal). Despache os briefs em paralelo (mesmo bloco de tool calls).
57
59
 
58
60
  ## Comandos
59
61
 
60
62
  | Comando | Função |
61
63
  |---|---|
62
- | `houndsman context` | Passo 0 — contexto da PR via `gh` (`--pr <n>`/`--worktree <path>`) |
64
+ | `houndsman context` | Contexto da PR via `gh` (`--pr <n>`/`--worktree <path>`) — o prepare já coleta com `--pr` |
63
65
  | `houndsman` | Passo 1 — preparar (gera os briefs) |
64
66
  | `houndsman --pr <n>` | Passo 1 em worktree dedicado (revisões paralelas) |
65
- | `houndsman --finalize` | Passo 3 — gerar o relatório (`--pr <n>` reusa o worktree) |
67
+ | `houndsman --finalize` | Passo 3 — gravar a triagem e o resumo final (`--pr <n>` reusa o worktree) |
66
68
  | `houndsman hunt [--pr <n>]` | Harness local opcional (maki): prepare → watchdogs → finalize |
69
+ | `houndsman compare` | Compara duas runs/variantes (`--list`, `--a`, `--b` ou dois slugs) |
67
70
  | `houndsman hunt install` | Baixa o maki fixado para `<HOUNDSMAN_HOME>/tools/maki` |
68
71
  | `houndsman worktree <ação>` | `list`/`add`/`remove`/`prune`/`path` dos worktrees |
69
72
  | `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
@@ -90,9 +93,10 @@ Runs, findings e artefatos vivem no **storage global** (SQLite em `<HOUNDSMAN_HO
90
93
  | findings | Decisão/execução + fingerprint + âncora + histórico + vínculo com o GitHub |
91
94
  | `classification.json` | Watchdogs ativados + status (A/M/D/R) + churn |
92
95
  | `candidates.json` | Candidatos da pré-análise Jev |
93
- | `manifest.json` | Resumo (watchdogs, arquivos, deletados, contexto, orçamento, churn) |
96
+ | `business-summary.json` / `business-brief.md` | Modelo de intenção da PR e o brief do passo |
97
+ | `manifest.json` | Resumo (watchdogs, arquivos, deletados, contexto, intenção, orçamento, churn) |
94
98
  | `briefs/<watchdog>.md` | Brief enviado a cada sub-agente (auditoria) |
95
- | `review.md` / `review.<watchdog>.md` | Relatório consolidado e por domínio |
99
+ | `review-resume.md` | Resumo final: negócio, pontos técnicos, cobertura por domínio e conclusão |
96
100
  | `verify.md` | Relatório do `findings verify` |
97
101
  | `context.json` / `context-brief.md` / `context-summary.json` | Contexto da PR |
98
102
 
@@ -121,7 +125,7 @@ src/
121
125
  │ ├── paths.ts # layout fixo da camada (.houndsman/) + relFromRoot
122
126
  │ ├── types.ts # Severity, Rule, WatchdogDefinition, defineWatchdog
123
127
  │ ├── watchdog-registry.ts # getWatchdog/findWatchdog/getWatchdogContext(config)
124
- │ ├── orchestrator.ts # preparar/finalizar
128
+ │ ├── orchestrator.ts # fachada: preparar/finalizar (pipelines em engine/)
125
129
  │ ├── brief.ts # defaultRenderBrief + PROCEDURE
126
130
  │ ├── pr-context.ts # contexto da PR via gh
127
131
  │ ├── file-classifier.ts # classificação (via `classify` dos watchdogs) + churn
@@ -106,6 +106,7 @@ Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.
106
106
  | `watchdogs` | Definições dos watchdogs (incluem `classify`); os **ids são derivados** das chaves. |
107
107
  | `exclusions` | Arquivos que nunca entram na revisão. |
108
108
  | `docMappings` | Path → documentação de contexto. |
109
+ | `priorities` | **Opcional** — prioridade por caminho `[{ pattern: RegExp, bonus?: number, maxRiskFromChurn?: number }]`. Risco = `min(churn, maxRiskFromChurn) + bonus`: `bonus` promove caminho crítico e o teto impede que superchurn de caminho de baixa criticidade escale. A primeira regra que casar vence. Ordena o orçamento, o rateio do diff e o recorte do `general`. Sem config: churn puro. |
109
110
  | `alwaysIncludeDocs` | Docs sempre presentes nos briefs (default `["AGENTS.md"]`). |
110
111
  | `budgets` | **Opcional** — teto de arquivos por brief (`maxFilesPerBrief`, default `40`); o excedente vira "fora do orçamento" (registrar em `skipped`). |
111
112
  | `concurrency` | **Opcional** — chamadas Jev simultâneas (`jev`, default `5`). |
@@ -14,6 +14,11 @@ consolida tudo num relatório. O motor é o CLI **`houndsman`**; as regras do pr
14
14
  **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
15
15
  especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
16
16
 
17
+ > **Duas etapas são obrigatórias em toda revisão:** o **modelo de intenção**
18
+ > (`business-summary.json`) e o revisor de fluxo **`general`** (id reservado, sempre ativo).
19
+ > O modelo vem da IA no prepare quando há chave; sem chave, um subagente (Passo 1.5) ou o
20
+ > pré-passe maki o produz. Nenhum dos dois é configurável pelo usuário.
21
+
17
22
  ## Capabilities
18
23
 
19
24
  | Capability | Objetivo | Documento |
@@ -60,12 +65,16 @@ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
60
65
  Sequência para uma PR (ex.: 456):
61
66
 
62
67
  ```bash
63
- houndsman context --pr 456
64
- houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
65
- # despache os briefs (cada um traz **Worktree:** <path>)
68
+ houndsman --pr 456 # cria/reusa o worktree, coleta o contexto e prepara
69
+ # despache os briefs em paralelo (cada um traz **Worktree:** <path>)
66
70
  houndsman --pr 456 --finalize
67
71
  ```
68
72
 
73
+ - O contexto da PR é coletado pelo próprio prepare (via `gh`); com IA ligada ele também é
74
+ resumido ali — não gaste um subagente nisso. Desative com `--no-context`.
75
+ - Para comparar duas execuções, use `--variant <label>` em cada uma e depois
76
+ `houndsman compare --branch <head> --a <a> --b <b>` (ou `compare --list`).
77
+
69
78
  - O worktree vive em `<repo>/.houndsman/worktrees/<repo>/<branch>` (detached no commit da PR)
70
79
  e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
71
80
  (e o staging também) para o agente ler/executar sem prompts de permissão.
@@ -83,4 +92,4 @@ houndsman --pr 456 --finalize
83
92
  - `.houndsman/core/skill/OUTPUT-FORMAT.md` — schema do JSON de saída dos watchdogs.
84
93
  - `.houndsman/core/skill/AUDIT-PROTOCOL.md` — taxonomia da auditoria de regras (Modo B do `train`).
85
94
  - `.houndsman/core/skill/SETUP.md` · `.houndsman/core/skill/README.md` — configuração e visão geral.
86
- - `.houndsman/core/skill/example-review.md` — exemplo de relatório.
95
+ - `.houndsman/core/skill/example-resume.md` — exemplo do resumo final.
@@ -0,0 +1,43 @@
1
+ # Resumo da revisão — feature/add-webhook-retry
2
+
3
+ **Data:** 2026-04-20 · **Status:** ❌ Mudanças Necessárias
4
+
5
+ ## Resumo de negócio
6
+
7
+ Tornar o envio de webhooks resiliente a falhas temporárias do destinatário, sem perda de
8
+ eventos e sem reenvio manual.
9
+
10
+ **Invariantes:**
11
+ - Todo evento entregue tem no máximo uma tentativa `in_flight` por destinatário.
12
+ - O retry nunca duplica o `eventId` já aceito pelo integrador.
13
+
14
+ **Fluxos (2):**
15
+ - **Retry de webhook** — disparo: resposta não-2xx/timeout — esperado: reagendamento com
16
+ backoff exponencial e registro da tentativa.
17
+
18
+ ## Pontos técnicos
19
+
20
+ - **Contratos** — `WebhookRetryPolicy`, `RetryAttempt` (`src/webhooks/types.ts`).
21
+ - **Implementações** — `WebhookDispatcher` (`src/webhooks/dispatcher.ts`).
22
+ - **Novas dependências** — `p-retry`.
23
+
24
+ ## Cobertura por domínio
25
+
26
+ | Domínio | Achados | Revisados | Faltam |
27
+ |---|---|---|---|
28
+ | Arquitetura Backend | 2 | 3/3 | — |
29
+ | Pagamentos & Integrações | 1 | 4/4 | — |
30
+ | Acquirer Integrations | 2 | 3/4 | 1 |
31
+
32
+ ## Candidatos não verificados (1)
33
+
34
+ > Indícios da pré-análise que nenhum watchdog confirmou. Não bloqueiam.
35
+
36
+ - `src/webhooks/queue.ts` · attention · Fila sem limite de tentativas.
37
+
38
+ ## Conclusão
39
+
40
+ **Resumo:** 2 bloqueantes · 1 atenção · 1 sugestões · 1 nits.
41
+
42
+ > Achados individuais (com `id` de triagem) vivem na UI (`Findings`) e em
43
+ > `houndsman findings list --json` — o resumo não os duplica.