@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.
- package/README.md +6 -1
- package/package.json +1 -1
- package/src/cli/commands/compare-command.ts +112 -0
- package/src/cli/commands/context-command.ts +1 -0
- package/src/cli/commands/findings-command.ts +11 -1
- package/src/cli/commands/hunt-command.ts +20 -3
- package/src/cli/commands/review-command.ts +38 -0
- package/src/cli/commands/status-command.ts +3 -2
- package/src/cli/help.ts +3 -1
- package/src/cli/index.ts +3 -1
- package/src/cli/progress.ts +7 -2
- package/src/core/ai/ai-client.ts +38 -2
- package/src/core/ai/features/brief-enricher.ts +1 -1
- package/src/core/ai/features/business-analyzer.ts +61 -0
- package/src/core/ai/features/business-summarizer.ts +44 -0
- package/src/core/ai/index.ts +8 -0
- package/src/core/ai/prompts/brief.ts +33 -7
- package/src/core/ai/prompts/business.ts +76 -0
- package/src/core/ai/provider-capabilities.ts +12 -0
- package/src/core/ai/schemas.ts +70 -2
- package/src/core/ai/usage-recorder.ts +53 -1
- package/src/core/brief.ts +246 -12
- package/src/core/builtins.ts +108 -0
- package/src/core/business-summary.ts +583 -0
- package/src/core/commands/compare.ts +233 -0
- package/src/core/commands/context.ts +6 -2
- package/src/core/commands/findings.ts +38 -30
- package/src/core/commands/review.ts +6 -0
- package/src/core/commands/scaffold.ts +27 -0
- package/src/core/commands/status.ts +9 -4
- package/src/core/compare.ts +243 -0
- package/src/core/concurrency.ts +30 -0
- package/src/core/config.ts +31 -3
- package/src/core/defaults.ts +50 -4
- package/src/core/domain/budget.ts +62 -4
- package/src/core/domain/classification.ts +12 -2
- package/src/core/engine/carryover.ts +4 -0
- package/src/core/engine/finalize-pipeline.ts +347 -0
- package/src/core/engine/prepare-pipeline.ts +1294 -0
- package/src/core/engine/review-context.ts +51 -0
- package/src/core/engine/review-options.ts +47 -0
- package/src/core/engine/review-scope.ts +14 -1
- package/src/core/engine/review-session.ts +11 -13
- package/src/core/engine/run-artifacts.ts +196 -0
- package/src/core/engine/run-format.ts +4 -0
- package/src/core/findings-state.ts +13 -1
- package/src/core/github-review.ts +5 -2
- package/src/core/hunt/hunt-runner.ts +90 -0
- package/src/core/hunt/index.ts +2 -0
- package/src/core/hunt/maki-intent-prompt.ts +50 -0
- package/src/core/hunt/maki-prompt.ts +13 -1
- package/src/core/hunt/pool.ts +4 -26
- package/src/core/logging/index.ts +6 -1
- package/src/core/logging/progress.ts +85 -1
- package/src/core/orchestrator.ts +33 -1289
- package/src/core/paths.ts +6 -3
- package/src/core/pr-context.ts +2 -4
- package/src/core/prepare-report.ts +61 -0
- package/src/core/project-config.ts +8 -1
- package/src/core/propagation.ts +127 -0
- package/src/core/registry-check.ts +60 -21
- package/src/core/renderers/manifest-writer.ts +13 -0
- package/src/core/renderers/resume-renderer.ts +151 -11
- package/src/core/report-builder.ts +108 -278
- package/src/core/storage/file/file-storage.ts +7 -3
- package/src/core/storage/sqlite/mappers.ts +10 -0
- package/src/core/storage/sqlite/schema.ts +104 -23
- package/src/core/storage/sqlite/sqlite-storage.ts +22 -9
- package/src/core/storage/types.ts +16 -4
- package/src/core/storage/work-area.ts +59 -1
- package/src/core/types.ts +31 -0
- package/src/core/watchdog-registry.ts +21 -3
- package/src/index.ts +29 -4
- package/src/server/client/ArtifactsPanel.tsx +4 -2
- package/src/server/client/FindingCard.tsx +21 -1
- package/src/server/client/RunsSection.tsx +5 -0
- package/src/server/client/utils/constants.ts +21 -11
- package/src/server/client/utils/markdown.ts +1 -1
- package/src/server/client/utils/types.ts +14 -2
- package/src/server/run-repository.ts +35 -14
- package/src/server/styles.css +2 -0
- package/src/skill/OUTPUT-FORMAT.md +36 -10
- package/src/skill/README.md +18 -14
- package/src/skill/SETUP.md +1 -0
- package/src/skill/SKILL.md +13 -4
- package/src/skill/example-resume.md +43 -0
- package/src/skill/hunt.md +145 -58
- package/src/tests/__snapshots__/baseline.test.ts.snap +187 -178
- package/src/tests/ai-core.test.ts +46 -0
- package/src/tests/ai-features.test.ts +95 -4
- package/src/tests/baseline.test.ts +29 -121
- package/src/tests/brief-scope.test.ts +250 -0
- package/src/tests/business-summary.test.ts +258 -0
- package/src/tests/compare.test.ts +233 -0
- package/src/tests/fixtures/fake-model-provider.ts +2 -1
- package/src/tests/hunt-maki.test.ts +58 -0
- package/src/tests/markdown.test.ts +3 -3
- package/src/tests/progress.test.ts +29 -1
- package/src/tests/propagation.test.ts +119 -0
- package/src/tests/review-resume.test.ts +60 -1
- package/src/tests/review-scope.test.ts +38 -29
- package/src/tests/review-scripts.test.ts +106 -218
- package/src/tests/server.test.ts +7 -4
- package/src/tests/storage.test.ts +194 -9
- package/src/core/renderers/report-renderer.ts +0 -66
- 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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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,
|
package/src/server/styles.css
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 (
|
|
95
|
+
## Findings emergentes (obrigatórios no `general`)
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
89
|
-
|
|
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`.
|
package/src/skill/README.md
CHANGED
|
@@ -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 | `
|
|
49
|
-
| 1. Preparar | `bun run houndsman` | skill | `classification.json` + `candidates.json` + `briefs/` + `manifest.json` |
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
>
|
|
55
|
-
>
|
|
56
|
-
>
|
|
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` |
|
|
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 —
|
|
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
|
-
| `
|
|
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`
|
|
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
|
package/src/skill/SETUP.md
CHANGED
|
@@ -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`). |
|
package/src/skill/SKILL.md
CHANGED
|
@@ -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
|
|
64
|
-
|
|
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-
|
|
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.
|