@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.
- package/README.md +32 -14
- package/package.json +1 -1
- package/src/cli/index.ts +22 -11
- package/src/core/assets.ts +3 -0
- package/src/core/brief.ts +2 -3
- package/src/core/commands/findings.ts +232 -4
- package/src/core/commands/review.ts +2 -0
- package/src/core/commands/scaffold.ts +13 -44
- package/src/core/diff-source.ts +4 -4
- package/src/core/findings-state.ts +20 -2
- package/src/core/fix-batch.ts +236 -0
- package/src/core/git-revision.ts +105 -0
- package/src/core/jev/index.ts +1 -0
- package/src/core/jev/jev-detector.ts +2 -2
- package/src/core/jev/jev-verify.ts +178 -0
- package/src/core/orchestrator.ts +202 -15
- package/src/core/paths.ts +6 -0
- package/src/core/report-builder.ts +5 -0
- package/src/core/run-status.ts +123 -0
- package/src/core/verify.ts +175 -0
- package/src/core/watchdog-registry.ts +1 -2
- package/src/index.ts +1 -1
- package/src/server/artifacts.ts +1 -0
- package/src/server/client/RunList.tsx +22 -13
- package/src/server/client/constants.ts +32 -1
- package/src/server/client/types.ts +4 -0
- package/src/server/index.ts +12 -1
- package/src/skill/AUDIT-PROTOCOL.md +2 -2
- package/src/skill/README.md +29 -5
- package/src/skill/SETUP.md +11 -1
- package/src/skill/SKILL.md +48 -0
- package/src/skill/fix.md +206 -0
- package/src/skill/{houndsman.md → hunt.md} +41 -68
- package/src/skill/{houndsman-update.md → train.md} +11 -11
- package/src/skill/verify.md +70 -0
- package/src/tests/findings-commands.test.ts +252 -2
- package/src/tests/findings-state.test.ts +52 -1
- package/src/tests/fix-batch.test.ts +257 -0
- package/src/tests/run-status.test.ts +147 -0
- package/src/tests/scaffold.test.ts +59 -0
- package/src/tests/server.test.ts +30 -0
- 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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
package/src/server/index.ts
CHANGED
|
@@ -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
|
|
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
|
---
|
package/src/skill/README.md
CHANGED
|
@@ -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
|
-
>
|
|
109
|
-
>
|
|
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
|
|
124
|
-
> **`
|
|
147
|
+
> Para qualquer alteração de regra (pontual ou auditoria completa), use a capability
|
|
148
|
+
> **`train`**: `/houndsman train` → `.houndsman/core/skill/train.md`.
|
package/src/skill/SETUP.md
CHANGED
|
@@ -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** |
|
|
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.
|
package/src/skill/fix.md
ADDED
|
@@ -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`.
|