@payconductor/houndsman 0.1.1 → 0.1.3

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 (42) hide show
  1. package/README.md +32 -14
  2. package/package.json +1 -1
  3. package/src/cli/index.ts +22 -11
  4. package/src/core/assets.ts +3 -0
  5. package/src/core/brief.ts +2 -3
  6. package/src/core/commands/findings.ts +232 -4
  7. package/src/core/commands/review.ts +2 -0
  8. package/src/core/commands/scaffold.ts +13 -44
  9. package/src/core/diff-source.ts +4 -4
  10. package/src/core/findings-state.ts +20 -2
  11. package/src/core/fix-batch.ts +236 -0
  12. package/src/core/git-revision.ts +105 -0
  13. package/src/core/jev/index.ts +1 -0
  14. package/src/core/jev/jev-detector.ts +2 -2
  15. package/src/core/jev/jev-verify.ts +178 -0
  16. package/src/core/orchestrator.ts +202 -15
  17. package/src/core/paths.ts +6 -0
  18. package/src/core/report-builder.ts +5 -0
  19. package/src/core/run-status.ts +123 -0
  20. package/src/core/verify.ts +175 -0
  21. package/src/core/watchdog-registry.ts +1 -2
  22. package/src/index.ts +1 -1
  23. package/src/server/artifacts.ts +1 -0
  24. package/src/server/client/RunList.tsx +22 -13
  25. package/src/server/client/constants.ts +32 -1
  26. package/src/server/client/types.ts +4 -0
  27. package/src/server/index.ts +12 -1
  28. package/src/skill/AUDIT-PROTOCOL.md +2 -2
  29. package/src/skill/README.md +29 -5
  30. package/src/skill/SETUP.md +11 -1
  31. package/src/skill/SKILL.md +48 -0
  32. package/src/skill/fix.md +206 -0
  33. package/src/skill/{houndsman.md → hunt.md} +41 -68
  34. package/src/skill/{houndsman-update.md → train.md} +11 -11
  35. package/src/skill/verify.md +70 -0
  36. package/src/tests/findings-commands.test.ts +252 -2
  37. package/src/tests/findings-state.test.ts +52 -1
  38. package/src/tests/fix-batch.test.ts +257 -0
  39. package/src/tests/run-status.test.ts +147 -0
  40. package/src/tests/scaffold.test.ts +59 -0
  41. package/src/tests/server.test.ts +30 -0
  42. package/src/tests/verify.test.ts +170 -0
@@ -2,6 +2,7 @@
2
2
  * Sidebar: logo do houndsman + lista de runs (branch e nº de findings).
3
3
  */
4
4
 
5
+ import { describeRunStatus } from "./constants";
5
6
  import type { RunSummary } from "./types";
6
7
 
7
8
  export function RunList({
@@ -24,19 +25,27 @@ export function RunList({
24
25
  </div>
25
26
  <nav class="runs">
26
27
  {runs.length === 0 && <p class="empty">Nenhuma run encontrada.</p>}
27
- {runs.map((run) => (
28
- <button
29
- type="button"
30
- title={`Abrir a run da branch ${run.branch}`}
31
- class={`run${run.slug === slug ? " active" : ""}`}
32
- onClick={() => onSelect(run.slug)}
33
- >
34
- <span class="run-branch">{run.branch}</span>
35
- <span class="run-meta">
36
- {run.summary.present}/{run.summary.total} presentes
37
- </span>
38
- </button>
39
- ))}
28
+ {runs.map((run) => {
29
+ const status = describeRunStatus(run);
30
+ return (
31
+ <button
32
+ type="button"
33
+ title={`Abrir a run da branch ${run.branch}`}
34
+ class={`run${run.slug === slug ? " active" : ""}`}
35
+ onClick={() => onSelect(run.slug)}
36
+ >
37
+ <span class="run-branch">{run.branch}</span>
38
+ <span class="run-meta">
39
+ {run.summary.present}/{run.summary.total} presentes
40
+ </span>
41
+ {status && (
42
+ <span class={`run-status status-${status.kind}`}>
43
+ {status.label}
44
+ </span>
45
+ )}
46
+ </button>
47
+ );
48
+ })}
40
49
  </nav>
41
50
  </aside>
42
51
  );
@@ -2,7 +2,7 @@
2
2
  * Constantes de apresentação do cliente (labels, ordem, emojis).
3
3
  */
4
4
 
5
- import type { Decision, ExecState, Severity } from "./types";
5
+ import type { Decision, ExecState, RunStatus, RunSummary, Severity } from "./types";
6
6
 
7
7
  export const SEVERITY_EMOJI: Record<Severity, string> = {
8
8
  blocking: "❌",
@@ -30,6 +30,37 @@ export const EXEC_LABELS: Record<ExecState, string> = {
30
30
  stale: "exec: stale",
31
31
  };
32
32
 
33
+ export const RUN_STATUS_LABELS: Record<RunStatus, string> = {
34
+ reviewing: "Revisando",
35
+ review_done: "Revisão pronta",
36
+ fixing: "Corrigindo",
37
+ fix_done: "Correção pronta",
38
+ };
39
+
40
+ /** Limiar de inatividade para exibir timeout (display-only; não é status). */
41
+ export const STATUS_TIMEOUT_MS = 10 * 60 * 1000;
42
+
43
+ export type RunStatusView = { kind: string; label: string; timeout: boolean };
44
+
45
+ /** View do status de uma run — label; vira timeout quando ativo e sem ping recente. */
46
+ export function describeRunStatus(
47
+ run: RunSummary,
48
+ now: number = Date.now(),
49
+ ): RunStatusView | null {
50
+ const status = run.status;
51
+ if (!status) return null;
52
+ const active = status === "reviewing" || status === "fixing";
53
+ const updated = run.updatedAt ? Date.parse(run.updatedAt) : Number.NaN;
54
+ if (active && Number.isFinite(updated) && now - updated > STATUS_TIMEOUT_MS) {
55
+ return {
56
+ kind: "timeout",
57
+ label: status === "reviewing" ? "Timeout na revisão" : "Timeout na correção",
58
+ timeout: true,
59
+ };
60
+ }
61
+ return { kind: status, label: RUN_STATUS_LABELS[status], timeout: false };
62
+ }
63
+
33
64
  /** Artefatos que podem ser lidos na aba "Artefatos". */
34
65
  export const ARTIFACTS = [
35
66
  "manifest.json",
@@ -9,6 +9,9 @@ export type Severity = "blocking" | "attention" | "suggestion" | "nit";
9
9
  export type Decision = "pending" | "execute" | "ignore";
10
10
  export type ExecState = "pending" | "in_progress" | "done" | "stale";
11
11
 
12
+ /** Estados de execução de uma run (espelham `core/run-status.ts`). */
13
+ export type RunStatus = "reviewing" | "review_done" | "fixing" | "fix_done";
14
+
12
15
  export type Finding = {
13
16
  id: string;
14
17
  rule: string;
@@ -38,6 +41,7 @@ export type RunSummary = {
38
41
  slug: string;
39
42
  branch: string;
40
43
  updatedAt?: string;
44
+ status?: RunStatus | null;
41
45
  summary: Summary;
42
46
  };
43
47
 
@@ -27,6 +27,7 @@ import {
27
27
  syncState,
28
28
  } from "../core/findings-state";
29
29
  import { STATE_FILE } from "../core/paths";
30
+ import { pingFindingsStatus, readRunStatus } from "../core/run-status";
30
31
  import type { Severity } from "../core/types";
31
32
  import { listRunSlugs, readRunFile, readRunJson, runDirForSlug } from "./artifacts";
32
33
  import { buildClientBundle } from "./client-build";
@@ -95,10 +96,12 @@ function listRuns(artifactDir: string): unknown[] {
95
96
  dir,
96
97
  "manifest.json",
97
98
  );
99
+ const status = readRunStatus(dir);
98
100
  return {
99
101
  slug,
100
102
  branch: state.branch || manifest?.branch || slug,
101
- updatedAt: state.updatedAt,
103
+ updatedAt: status?.updatedAt ?? state.updatedAt,
104
+ status: status?.status ?? null,
102
105
  summary: summarize(state),
103
106
  };
104
107
  });
@@ -114,6 +117,7 @@ function runDetail(dir: string, slug: string): unknown {
114
117
  return {
115
118
  slug,
116
119
  branch: state.branch || slug,
120
+ status: readRunStatus(dir),
117
121
  manifest: readRunJson(dir, "manifest.json"),
118
122
  summary: summarize(state),
119
123
  watchdogs: Object.keys(classification?.watchdogs ?? {}),
@@ -153,6 +157,7 @@ async function updateFinding(
153
157
  applyFindingUpdate(finding, body);
154
158
  reorder(state);
155
159
  store.write(state);
160
+ pingFindingsStatus(dir, state);
156
161
  return json({ finding });
157
162
  }
158
163
 
@@ -161,6 +166,7 @@ function syncRun(dir: string, slug: string): Response {
161
166
  const state = store.read() ?? buildForRun(dir, slug) ?? emptyState(slug);
162
167
  const result: SyncResult = syncState(state, fileReader(process.cwd()));
163
168
  store.write(state);
169
+ pingFindingsStatus(dir, state);
164
170
  return json({ result, summary: summarize(state) });
165
171
  }
166
172
 
@@ -301,6 +307,11 @@ code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospac
301
307
  .run.active { border-color:var(--accent); background:#22304d; }
302
308
  .run-branch { font-weight:600; font-size:13px; }
303
309
  .run-meta { color:var(--muted); font-size:11px; }
310
+ .run-status { font-size:10px; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); }
311
+ .status-reviewing, .status-fixing { color:#e3a008; }
312
+ .status-review_done { color:#4c8dff; }
313
+ .status-fix_done { color:#3fb950; }
314
+ .status-timeout { color:#e5484d; }
304
315
  .main { flex:1; padding:16px 20px; max-width:980px; }
305
316
  .topbar { display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; }
306
317
  .tabs { display:flex; gap:6px; flex-wrap:wrap; }
@@ -1,7 +1,7 @@
1
1
  # Protocolo de Auditoria dos Watchdogs — houndsman
2
2
 
3
- Referência do Modo B do skill `houndsman-update`. Objetivo: garantir que as regras dos
4
- watchdogs validam **apenas padrões que o projeto aplica hoje**. Regras "utópicas" (não
3
+ Referência do Modo B da capability `train` (skill `/houndsman`). Objetivo: garantir que as
4
+ regras dos watchdogs validam **apenas padrões que o projeto aplica hoje**. Regras "utópicas" (não
5
5
  aplicadas em nenhuma parte do código) devem ser **removidas**, não apenas rebaixadas.
6
6
 
7
7
  ---
@@ -2,6 +2,18 @@
2
2
 
3
3
  Revisão automatizada de Pull Requests — CLI independente + camada de configuração do projeto.
4
4
 
5
+ ## Capabilities
6
+
7
+ Um único skill (`/houndsman`), quatro capabilities (detalhadas em `hunt.md`, `train.md`,
8
+ `fix.md`, `verify.md`):
9
+
10
+ | Capability | O que faz |
11
+ |---|---|
12
+ | `hunt` | Revisão de PR (Passos 0–3; incremental quando possível). |
13
+ | `train` | Manutenção das regras dos watchdogs. |
14
+ | `fix` | Correção dos findings marcados como `execute`. |
15
+ | `verify` | Confere se as violações foram resolvidas, sem re-revisar a PR. |
16
+
5
17
  ## Terminologia
6
18
 
7
19
  - **houndsman** — o orquestrador/treinador (CLI + motor).
@@ -35,6 +47,8 @@ Revisão automatizada de Pull Requests — CLI independente + camada de configur
35
47
  | `houndsman` | Passo 1 — preparar (gera os briefs) |
36
48
  | `houndsman --finalize` | Passo 3 — gerar o relatório |
37
49
  | `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
50
+ | `houndsman findings <sub>` | Triagem/correção dos findings (`list`/`set`/`done`/`sync`/`batch`/`verify`/...) |
51
+ | `houndsman server` | UI local de triagem (Bun.serve + Preact) |
38
52
  | `houndsman setup` | Cria a configuração inicial do projeto |
39
53
  | `houndsman update` | Sincroniza os arquivos auto-gerados (`.houndsman/core`) |
40
54
  | `houndsman doctor` | Valida a configuração, o ambiente e a credencial Jev (anti-drift) |
@@ -43,7 +57,7 @@ Revisão automatizada de Pull Requests — CLI independente + camada de configur
43
57
  ### Flags
44
58
 
45
59
  `--config <path>` · `--base <branch>` (default `main`) · `--head <ref>` (default `HEAD`) ·
46
- `--branch <nome>` · `--dir <dir>` · `--clean` · `--no-jev` · `--fail-on-blocking` (no `--finalize`).
60
+ `--branch <nome>` · `--dir <dir>` · `--clean` · `--full` · `--no-jev` · `--fail-on-blocking` (no `--finalize`).
47
61
 
48
62
  ## Artefatos
49
63
 
@@ -60,6 +74,9 @@ Tudo em `.houndsman/.runs/<branch-slug>/` (default do `artifactDir`, `.houndsman
60
74
  | `findings/<watchdog>.json` | Saída dos sub-agentes (schema `OUTPUT-FORMAT.md`) |
61
75
  | `review.md` | Relatório final (achados agrupados por arquivo) |
62
76
  | `review.<watchdog>.md` | Relatório por domínio (só quando há achados) |
77
+ | `state.json` | Estado de triagem dos findings (decisão/execução + fingerprint + commit revisado) |
78
+ | `run.json` | Status do run (`reviewing`/`review_done`/`fixing`/`fix_done`) + timestamps |
79
+ | `verify.md` | Relatório do `findings verify` (resolvidos/persistem/incertos) |
63
80
 
64
81
  ## Estrutura
65
82
 
@@ -83,6 +100,12 @@ src/
83
100
  │ ├── diff-source.ts # diff único (patch + --numstat) p/ churn/orçamento
84
101
  │ ├── doc-discoverer.ts # descoberta de docs
85
102
  │ ├── report-builder.ts # dedupe/render do relatório
103
+ │ ├── finding-anchor.ts # âncora/fingerprint de conteúdo + reancoragem
104
+ │ ├── findings-state.ts # estado de triagem (state.json) + store atômico
105
+ │ ├── git-revision.ts # refs/ancestralidade + arquivo por commit + diff por intervalo
106
+ │ ├── verify.ts # verificação de findings (tier local + Jev)
107
+ │ ├── run-status.ts # run.json (reviewing/review_done/fixing/fix_done)
108
+ │ ├── fix-batch.ts # agrupamento/paginação do lote (findings batch)
86
109
  │ ├── registry-check.ts # validações anti-drift (config-driven)
87
110
  │ ├── commands/ # context · review · watchdog · setup · update · test
88
111
  │ └── jev/ # subsistema Jev (Passo 1.5)
@@ -105,8 +128,9 @@ houndsman.config.ts # HoundsmanConfig (dados; descoberto em runtime)
105
128
  └── doc-mappings.ts # USUÁRIO
106
129
  ```
107
130
 
108
- > Os `SKILL.md` em `.agents/skills/houndsman/` e `.claude/skills/houndsman/` são
109
- > ponteiros para `.houndsman/core/skill/houndsman.md`.
131
+ > O `SKILL.md` do skill (`.agents/skills/houndsman/SKILL.md` e
132
+ > `.claude/skills/houndsman/SKILL.md`) é gerado a partir de `src/skill/SKILL.md`
133
+ > pelo `houndsman setup`/`update` (com `{{projectName}}` resolvido).
110
134
 
111
135
  ## Manutenção
112
136
 
@@ -120,5 +144,5 @@ houndsman.config.ts # HoundsmanConfig (dados; descoberto em runtime)
120
144
  `.houndsman/watchdogs/<id>.ts` + entrada em `.houndsman/watchdogs/index.ts`.
121
145
  2. Rodar `bun run houndsman doctor` — valida a config (definições, classificação, specs Jev).
122
146
 
123
- > Para qualquer alteração de regra (pontual ou auditoria completa), use o skill
124
- > **`houndsman-update`**: `.houndsman/core/skill/houndsman-update.md`.
147
+ > Para qualquer alteração de regra (pontual ou auditoria completa), use a capability
148
+ > **`train`**: `/houndsman train` → `.houndsman/core/skill/train.md`.
@@ -39,7 +39,7 @@ A camada separa o que é **auto-gerado** do que é **do usuário**:
39
39
  | `.houndsman/core/types.ts` | **auto** | Snapshot dos tipos + helpers (tipagem sem install) |
40
40
  | `.houndsman/core/skill/*.md` | **auto** | Documentação do skill |
41
41
  | `.houndsman/.gitignore` | **auto** | Ignora `core/` e `.runs/` (gerados/temporários) |
42
- | `.agents/skills/houndsman/SKILL.md` etc. | **auto** | Ponteiros de skill dos harnesses |
42
+ | `.agents/skills/houndsman/SKILL.md` etc. | **auto** | `SKILL.md` do skill `/houndsman` (capabilities `hunt`/`train`/`fix`) por harness |
43
43
 
44
44
  Além disso, adiciona o script `"houndsman": "houndsman"` ao `package.json` — assim
45
45
  `bun run houndsman [...]` funciona na raiz do projeto. Os artefatos ficam em
@@ -64,6 +64,16 @@ bun run houndsman test # suíte da lib (project-agnóstica)
64
64
  bun run houndsman --base main # prepara briefs do diff atual
65
65
  ```
66
66
 
67
+ ## Capabilities do skill
68
+
69
+ Depois do setup, invoque o skill `/houndsman` no seu harness:
70
+
71
+ | Capability | Para quê |
72
+ |---|---|
73
+ | `/houndsman hunt` | Revisar a PR (default: `/houndsman`). |
74
+ | `/houndsman train` | Adicionar/ajustar/remover regras dos watchdogs. |
75
+ | `/houndsman fix` | Corrigir os findings marcados como `execute`. |
76
+
67
77
  ## Contrato do motor (`HoundsmanConfig`)
68
78
 
69
79
  Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.ts` (gerado):
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: houndsman
3
+ description: 'Revisa Pull Requests com watchdogs especializados por domínio de negócio e mantém essas regras alinhadas ao projeto. Use para revisar/code review de PR, atualizar as regras de revisão dos watchdogs e corrigir/verificar os findings da revisão. Capabilities: `hunt` (revisar a PR), `train` (atualizar regras), `fix` (corrigir achados), `verify` (violações resolvidas?).'
4
+ argument-hint: 'Capability: hunt | train | fix | verify (default: hunt)'
5
+ ---
6
+
7
+ # houndsman — {{projectName}}
8
+
9
+ O **houndsman** revisa Pull Requests com **watchdogs** — agentes especialistas por domínio de
10
+ negócio. Cada watchdog audita a parte do diff que é sua e grava **findings** (achados); o motor
11
+ consolida tudo num relatório. O motor é o CLI **`houndsman`**; as regras do projeto vivem em
12
+ `houndsman.config.ts` + `.houndsman/`.
13
+
14
+ **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
15
+ especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
16
+
17
+ ## Capabilities
18
+
19
+ | Capability | Objetivo | Documento |
20
+ |---|---|---|
21
+ | **`hunt`** | Revisar uma Pull Request e produzir o relatório de achados. | `.houndsman/core/skill/hunt.md` |
22
+ | **`train`** | Manter as regras dos watchdogs alinhadas ao que o projeto aplica. | `.houndsman/core/skill/train.md` |
23
+ | **`fix`** | Corrigir os achados de uma revisão já finalizada. | `.houndsman/core/skill/fix.md` |
24
+ | **`verify`** | Conferir se as violações foram resolvidas, sem re-revisar a PR. | `.houndsman/core/skill/verify.md` |
25
+
26
+ ## Invocação
27
+
28
+ ```
29
+ /houndsman → hunt (default)
30
+ /houndsman hunt → revisar a Pull Request
31
+ /houndsman train → atualizar as regras dos watchdogs
32
+ /houndsman fix → corrigir os findings
33
+ /houndsman verify → conferir se as violações foram resolvidas
34
+ ```
35
+
36
+ Um argumento extra é o alvo da capability (ex.: `/houndsman hunt feature/minha-branch`).
37
+ Escolha a capability pelo que o usuário quer, leia o documento correspondente em
38
+ `.houndsman/core/skill/<capability>.md` e siga-o.
39
+
40
+ > **Depois de revisar (`hunt`), valide na UI:** `bun run houndsman server --open` — revise os
41
+ > achados e marque os que devem ser executados (`execute`) antes de rodar `fix`.
42
+
43
+ ## Referências
44
+
45
+ - `.houndsman/core/skill/OUTPUT-FORMAT.md` — schema do JSON de saída dos watchdogs.
46
+ - `.houndsman/core/skill/AUDIT-PROTOCOL.md` — taxonomia da auditoria de regras (Modo B do `train`).
47
+ - `.houndsman/core/skill/SETUP.md` · `.houndsman/core/skill/README.md` — configuração e visão geral.
48
+ - `.houndsman/core/skill/example-review.md` — exemplo de relatório.
@@ -0,0 +1,206 @@
1
+ # houndsman — {{projectName}} · `fix` (correção dos findings)
2
+
3
+ > **Documento canônico da capability `fix`.** O entry point do skill é o `SKILL.md`
4
+ > (`.agents/skills/houndsman/SKILL.md` e `.claude/skills/houndsman/SKILL.md`).
5
+
6
+ Corrige os achados de uma revisão **já finalizada** (`hunt`): lê a triagem, aplica as
7
+ correções marcadas e mantém o estado de triagem em dia — **sem editar o `state.json` à mão**.
8
+
9
+ Invocação: `/houndsman fix`. Não revisa nem altera regras; consome o que o `hunt` produziu.
10
+
11
+ **Quando usar:**
12
+
13
+ - Depois de `/houndsman` (ou `houndsman --finalize`), para corrigir os achados.
14
+ - O usuário marcou achados como `execute` na UI (`bun run houndsman server --open`) ou via
15
+ `findings set <id> --decision execute`.
16
+ - "Corrija os findings", "aplica as correções", "resolve os bloqueantes".
17
+
18
+ > **Pré-requisito:** existe `.houndsman/.runs/<branch-slug>/state.json` da run atual
19
+ > (gerado no `--finalize`). Se não existir, a revisão não foi finalizada — rode o `hunt` antes.
20
+ > A triagem (`execute`) é feita na UI (`bun run houndsman server --open`) ou via `findings set`,
21
+ > e é o que alimenta a fila de correção.
22
+
23
+ ---
24
+
25
+ ## Modelo de triagem
26
+
27
+ Cada finding tem duas dimensões independentes (ver `findings-state.ts`):
28
+
29
+ - **decision:** `pending` · `execute` · `ignore` (+ `comment` opcional).
30
+ - **execState:** `pending` · `in_progress` · `done` · `stale`.
31
+
32
+ `fix` atua **somente** sobre `decision: execute`. Achados `pending` (ainda não triados) e
33
+ `ignore` (descartados) ficam intocados — não "conserte" o que o usuário não pediu.
34
+
35
+ > **A linha de um finding não é a identidade.** A identidade é o **fingerprint** de conteúdo
36
+ > (arquivo + regra + âncora). As correções deslocam linhas; o motor reancora pelo conteúdo.
37
+ > Ocorrências byte-idênticas (mesmo trecho E mesmo contexto) compartilham o id — tratadas
38
+ > como um grupo (`×N`); corrigir uma resolve o grupo.
39
+
40
+ ---
41
+
42
+ ## Procedimento (incremental — nunca de uma vez)
43
+
44
+ Em PRs grandes há muitos achados. **Nunca** carregue a fila inteira: o `batch` entrega um
45
+ **grupo coeso, já paginado**, e a fila avança sozinha conforme você conclui os itens.
46
+
47
+ ```
48
+ repita:
49
+ 1. findings summary --json # contagem barata da fila
50
+ 2. fila vazia? → fim
51
+ 3. findings batch --json # grupo atual + outros grupos (sem parâmetros)
52
+ 4. corrigir APENAS o grupo atual
53
+ 5. findings sync # reancora por conteúdo (uma vez)
54
+ 6. findings done <ids> | set --decision pending --comment <motivo>
55
+ até a fila esvaziar
56
+ ```
57
+
58
+ ### 1. Medir a fila
59
+
60
+ ```bash
61
+ bun run houndsman findings summary --json
62
+ ```
63
+
64
+ `byDecision.execute` (menos os `done`) é o tamanho da fila. Se for `0`, acabou.
65
+
66
+ ### 2. Pegar o lote (contexto para correção)
67
+
68
+ ```bash
69
+ bun run houndsman findings batch --json
70
+ ```
71
+
72
+ O `batch` decide sozinho o **melhor agrupamento** para a run atual (por arquivo, por regra ou
73
+ por watchdog) e devolve:
74
+
75
+ - o **grupo atual** (paginado) — a unidade de trabalho;
76
+ - a lista dos **outros grupos disponíveis**;
77
+ - os totais (`fila`, `retornados`, `grupos`).
78
+
79
+ Sem parâmetros, ele devolve **o primeiro grupo**. Como a fila exclui o que já está `done`,
80
+ cada chamada após progresso traz **o próximo grupo naturalmente** — não há contador para
81
+ gerenciar.
82
+
83
+ Flags (use só quando precisar — o mínimo de decisão):
84
+
85
+ | Flag | Quando usar |
86
+ |---|---|
87
+ | `--severity blocking` | Só os bloqueantes (ex.: "quero corrigir apenas os bloqueantes"). |
88
+ | `--group <key>` | Focar um grupo específico (a key aparece em "outros grupos"). |
89
+ | `--offset <n>` | Paginar dentro de um grupo grande. Raramente necessário. |
90
+ | `--include-done` | Auditar/rever itens já concluídos. |
91
+
92
+ ### 3. Corrigir apenas o grupo atual
93
+
94
+ Para cada finding do grupo: abra o arquivo, leia o trecho ancorado (`line` é cache; confirme
95
+ pelo conteúdo) e aplique a **correção mínima** que satisfaz a `rule`, seguindo a **`action`** e
96
+ a `evidence`. Respeite o padrão que o watchdog cobra — não introduza um novo anti-padrão para
97
+ "calar" o finding. Marque antes: `findings set <id> --exec in_progress`.
98
+
99
+ **Contexto grande? Use um subagente** (ver abaixo) para o grupo — um grupo por vez.
100
+
101
+ ### 4. Reancorar o estado
102
+
103
+ ```bash
104
+ bun run houndsman findings sync
105
+ ```
106
+
107
+ O `sync` reancora cada finding por **conteúdo** (trecho + contexto) e reporta `ok` / `moved` /
108
+ `stale`: âncora corrigida → vira `done` (quando a decisão era `execute`); âncora sumida de
109
+ outro modo → `stale` (revisar).
110
+
111
+ ### 5. Confirmar ou devolver
112
+
113
+ Antes de fechar, confirme com o `verify` (barato): ele diz o que **resolveu** (`resolved`), o que
114
+ **persiste** e o que ficou **incerto** — sem re-revisar a PR. Com `--apply`, os `resolved` viram
115
+ `done` automaticamente.
116
+
117
+ ```bash
118
+ bun run houndsman findings verify # relatório (não altera o estado)
119
+ bun run houndsman findings verify --apply # marca os resolvidos como done
120
+ bun run houndsman findings done <id...> # corrigidos (manual)
121
+ bun run houndsman findings set <id> --decision pending --comment "<motivo / falta>" # não corrigidos
122
+ ```
123
+
124
+ Não deixe achado `execute` no limbo. `--decision ignore` só quando o achado for aceito como
125
+ não-aplicável.
126
+
127
+ ### 6. Repetir
128
+
129
+ Volte ao passo 1. A fila encolhe a cada volta; o `batch` traz o próximo grupo sem `--offset`.
130
+
131
+ ---
132
+
133
+ ## Perguntas de decisão ao usuário
134
+
135
+ Pergunte (ferramenta de perguntas do harness) **antes** de corrigir quando o achado for:
136
+
137
+ - ambíguo ou com **múltiplas correções válidas**;
138
+ - uma mudança de **produto/arquitetura** (não é "só código");
139
+ - conflitante com outro achado/grupo.
140
+
141
+ Apresente o achado (`rule`, `message`, `action`, `evidence`) e as opções. Com a resposta,
142
+ registre-a: `findings set <id> --comment "<decisão>"`. Sem resposta, devolva à fila com
143
+ `--decision pending --comment "Aguardando decisão: …"` — **nunca "chute"**.
144
+
145
+ ---
146
+
147
+ ## Subagentes — contexto, não velocidade
148
+
149
+ Subagente serve para **isolar contexto**, não para paralelizar. Regras:
150
+
151
+ - **Um grupo por vez, em sequência.** Não dispare uma onda paralela: grupos podem editar o
152
+ mesmo arquivo, arquivos relacionados, imports ou código gerado — correções concorrentes
153
+ colidem.
154
+ - O subagente recebe **só** o grupo atual (findings + arquivo) e devolve um resumo compacto
155
+ (ids corrigidos / não corrigidos + motivo). Assim o agente principal não carrega o arquivo.
156
+ - A escrita do `state.json` fica **centralizada no agente principal**: o subagente apenas
157
+ lê/edita; `sync` / `done` / `set` são do orquestrador. Nada de `findings` dentro do subagente.
158
+ - Grupos pequenos (1–2 findings) o próprio agente corrige inline.
159
+
160
+ Prompt do subagente (modelo):
161
+
162
+ ```
163
+ Corrija APENAS os findings abaixo, sem tocar em mais nada. Aplique a correção mínima que
164
+ satisfaz cada `rule`, seguindo `action`/`evidence`. Não rode comandos `findings`.
165
+ Retorne: id → corrigido/não corrigido + 1 linha de motivo.
166
+
167
+ Arquivo: <file>
168
+ - <id> [<severity>] <rule> (linha <line>) — <message>
169
+ Ação: <action>
170
+ Evidência: `<evidence>`
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Verificação
176
+
177
+ - `bun run houndsman findings summary` → os corrigidos saíram de `execute`/`in_progress`.
178
+ - `bun run houndsman findings sync` → sem `stale` inesperado.
179
+ - `bun run houndsman findings verify` → o que **resolveu** / **persiste** / ficou **incerto**
180
+ (sem re-revisar). Use `--apply` para marcar os `resolved` como `done`.
181
+ - Rode o build/testes do **projeto consumidor** (não o houndsman) depois das correções.
182
+ - Se a mudança for grande, reexecute o `hunt` para uma segunda passada:
183
+
184
+ ```bash
185
+ bun run houndsman --base main
186
+ # ... subagentes ...
187
+ bun run houndsman --finalize
188
+ ```
189
+
190
+ > O `--finalize` preserva os ids/fingerprints entre execuções (reancoragem por conteúdo);
191
+ > use `--clean` só quando quiser descartar a triagem anterior.
192
+
193
+ ---
194
+
195
+ ## Anti-padrões
196
+
197
+ - ❌ Carregar a fila inteira de uma vez (`findings list` sem filtro) — use `findings batch`.
198
+ - ❌ Corrigir vários grupos em paralelo (subagentes simultâneos sobre arquivos que se relacionam).
199
+ - ❌ Editar `.houndsman/.runs/<slug>/state.json` à mão — use os comandos `findings`.
200
+ - ❌ Corrigir findings `pending` ou `ignore` sem o usuário marcar `execute`.
201
+ - ❌ Chavear por `(file, line)` — a confiança é o **fingerprint** de conteúdo.
202
+ - ❌ Correção cosmética para "sumir" com o finding sem atender a `rule`.
203
+ - ❌ Reescrever o arquivo inteiro — correção mínima e localizada.
204
+ - ❌ Inventar mudança de produto/arquitetura para fechar um achado ambíguo — pergunte.
205
+ - ❌ Marcar `done` sem ter aplicado a correção (o `sync` reancora; o achado volta).
206
+ - ❌ Reexecutar o `hunt` inteiro só para conferir o fix — use `findings verify`.