dsh-doublecheck 0.5.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 (45) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +201 -0
  3. package/README.es.md +252 -0
  4. package/README.hi.md +252 -0
  5. package/README.md +268 -0
  6. package/README.pt.md +252 -0
  7. package/README.zh.md +266 -0
  8. package/cordis.patch.yml +19 -0
  9. package/lib/domain/evidence.d.ts +100 -0
  10. package/lib/domain/evidence.js +180 -0
  11. package/lib/domain/projection.d.ts +60 -0
  12. package/lib/domain/projection.js +132 -0
  13. package/lib/domain/report.d.ts +93 -0
  14. package/lib/domain/report.js +266 -0
  15. package/lib/domain/stages.d.ts +98 -0
  16. package/lib/domain/stages.js +192 -0
  17. package/lib/domain/vagueness.d.ts +25 -0
  18. package/lib/domain/vagueness.js +56 -0
  19. package/lib/domain/vocabulary.d.ts +50 -0
  20. package/lib/domain/vocabulary.js +16 -0
  21. package/lib/events.d.ts +155 -0
  22. package/lib/events.js +15 -0
  23. package/lib/grill/index.d.ts +49 -0
  24. package/lib/grill/index.js +495 -0
  25. package/lib/grill/provider.d.ts +56 -0
  26. package/lib/grill/provider.js +189 -0
  27. package/lib/guard/command.d.ts +47 -0
  28. package/lib/guard/command.js +132 -0
  29. package/lib/guard/index.d.ts +111 -0
  30. package/lib/guard/index.js +516 -0
  31. package/lib/guard/prose.d.ts +34 -0
  32. package/lib/guard/prose.js +80 -0
  33. package/lib/guard/review.d.ts +67 -0
  34. package/lib/guard/review.js +184 -0
  35. package/lib/index.d.ts +17 -0
  36. package/lib/index.js +15 -0
  37. package/lib/invariant.d.ts +56 -0
  38. package/lib/invariant.js +112 -0
  39. package/lib/types.d.ts +39 -0
  40. package/lib/types.js +18 -0
  41. package/package.json +109 -0
  42. package/skills/delivery-proof/SKILL.md +52 -0
  43. package/skills/delivery-review/SKILL.md +49 -0
  44. package/skills/grill-requirements/SKILL.md +98 -0
  45. package/skills/red-green-tdd/SKILL.md +57 -0
package/README.pt.md ADDED
@@ -0,0 +1,252 @@
1
+ # dsh-doublecheck
2
+
3
+ > **Verifique duas vezes antes de publicar: interrogue os requisitos, teste a implementação, comprove a entrega.**
4
+
5
+ [![version](https://img.shields.io/badge/version-0.5.0-blue)](https://github.com/PerryLink/dsh-doublecheck/releases)
6
+ [![license](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
7
+ [![topics](https://img.shields.io/badge/topics-dsh%20%7C%20dsh--plugin-22c55e)](https://github.com/topics/dsh-plugin)
8
+
9
+ Um **bundle de disciplina de engenharia** para o [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness). Agentes adoram começar a codar; requisitos odeiam ser presumidos. O `dsh-doublecheck` instala um ciclo de disciplina que faz o agente **interrogar os requisitos antes da primeira edição e comprovar a entrega em vez de afirmá-la** — reimplementado de forma nativa nos pontos de extensão do próprio DSH (registro de skills, pipeline de políticas de ferramentas, seam de aprovação, seams de subagente e workflow, log de sessão), sem arquivos de prompt emprestados. Testado contra DSH `0.1.0-rc.6`.
10
+
11
+ A metodologia é inspirada em [obra/superpowers](https://github.com/obra/superpowers) e [TimothyVang/Grill-me](https://github.com/TimothyVang/Grill-me). Todos os prompts, termos, exemplos e arquivos deste pacote foram escritos do zero — nada é copiado de nenhum dos dois projetos.
12
+
13
+ ## Por quê
14
+
15
+ - Tarefas vagas produzem software errado. Um pedido curto («faz uma função pra mim») esconde seis decisões em aberto; hoje o agente chuta todas elas e você paga pelo chute.
16
+ - Times disciplinados fazem isso com humanos: revisão de requisitos → teste que falha → teste que passa → autorrevisão → comprovação de entrega. Agentes merecem o mesmo ciclo, imposto pelo harness, não pela boa vontade.
17
+
18
+ ## O ciclo de disciplina
19
+
20
+ ```
21
+ grill ──▶ design ──▶ red ──▶ green ──▶ review ──▶ verify
22
+ │ │
23
+ │ (v0.1) (v0.2+) (v0.3) (v0.4)
24
+ │
25
+ └─ fornalha de requisitos: seis dimensões, portão de consenso,
26
+ spec estruturado gravado na sessão e no workspace
27
+ ```
28
+
29
+ | Etapa | Significado | Status |
30
+ |---|---|---|
31
+ | **grill** | Interrogar as seis dimensões de requisitos; recusar implementar até o consenso. | ✅ v0.1 |
32
+ | **design** | Spec registrado via `doublecheck_spec`. | ✅ v0.1 |
33
+ | **red** | Um teste que falha comprova a lacuna; edições de implementação precisam dele no registro. | ✅ v0.2 |
34
+ | **green** | Um teste que passa após as edições fecha o ciclo. | ✅ v0.2 |
35
+ | **review** | Um crítico adversário bifurcado audita a entrega contra o spec. | ✅ v0.3 |
36
+ | **verify** | `doublecheck_report` + um workflow de verificação por dimensão comprovam a entrega. | ✅ v0.4 |
37
+
38
+ ## Recursos (v0.5)
39
+
40
+ - 🔥 **Skill `grill-requirements`** — um skill empacotado no formato Agent Skills que interroga a tarefa em seis dimensões (**objetivo, escopo, critérios de aceite, modos de falha, prioridades, não-objetivos**) usando a UI nativa `ask_user_question` do DSH, recusa escrever código até o consenso e registra o contrato.
41
+ - 🧰 **Skills de etapa para o ciclo inteiro** — `red-green-tdd` (escreva o teste que falha, rode red, implemente, rode green), `delivery-review` (autorrevisão adversária contra o spec uma vez em green) e `delivery-proof` (consolide a evidência no relatório de entrega antes de declarar concluído) juntam-se ao `grill-requirements`: as seis etapas têm orientação de modelo, não só a primeira.
42
+ - 📜 **Ferramenta `doublecheck_spec`** — grava o spec acordado no log da sessão e escreve uma cópia em markdown no workspace, para o contrato sobreviver à conversa.
43
+ - 🔄 **Re-grill na mudança de tarefa** — um spec registrado cobre a própria tarefa: um novo pedido direto do usuário após o último spec reabre o portão grill para esse follow-up, em vez de herdar o contrato anterior em silêncio.
44
+ - 🛡️ **Guard de disciplina** — um portão suave no pipeline de políticas de ferramentas. Tarefa vaga + sem spec + rumo a `edit`/`write` → **lembrar**, **pedir aprovação humana** ou **bloquear**, conforme `intensity`.
45
+ - 🟥🟩 **Portões de evidência red/green** (`modules.tdd`) — verificações duras sobre o log da sessão: uma edição de implementação exige um **teste que falha registrado** desde o último teste que passa (escrever arquivos de teste é sempre permitido — é assim que o passo red acontece), e um turno que termina com edições mas sem nenhum teste que passa recebe um lembrete green injetado.
46
+ - 👁️ **Revisão adversária** (`modules.adversary`) — assim que a entrega chega ao green, um subagente crítico bifurcado (seam nativo de subagentes do DSH, provider `fork` por padrão) audita a sessão contra o spec registrado com postura adversária e devolve achados estruturados. `remind` injeta a crítica; `warn`/`block` ainda direcionam uma rodada para o modelo responder aos achados. `adversaryModel` roteia o crítico para um modelo separado; a allowlist de ferramentas do crítico é somente leitura por padrão. Os achados trafegam pela fonte de mensagens durável `doublecheck-review`. A revisão se rearma quando o crítico termina: edições de implementação após o último registro de revisão disparam outra rodada, e cancelar o turno aborta o crítico em voo.
47
+ - 📊 **Relatório doublecheck + workflow de verificação** (`doublecheck_report`, v0.4) — consolida a evidência de disciplina da sessão (spec, cronologia red/green, achados da revisão, edições) em um relatório de entrega com um veredito derivado (`grill → draft → red → green → objections/verified → proven/challenged/unverified`), gravado no workspace. Com `verify`, os verificadores por dimensão rodam pelo seam de workflow do DSH (`verifyMode: all` lança um verificador paralelo por dimensão; `single` executa um combinado) e os vereditos se dobram no relatório — `proven` exige um veredito para cada dimensão.
48
+ - 🚦 **Portão de entrega** — no limite do turno, uma entrega que chegou ao green sem `doublecheck_report` registrado recebe um lembrete de relatório esperado antes de declarar concluído; um relatório bem-sucedido avança a etapa para `verify`.
49
+ - 🔁 **Estado durável** — todo artefato visível ao modelo (spec, lembretes, feedback de negação, achados da revisão, o interruptor `/doublecheck on|off`) fica no log da sessão; as decisões dos portões derivam só do log (`tool/call` + `tool/result`, incluindo os sub-despachos do Code Mode), então sessões retomadas ou bifurcadas se comportam igual. `remindOnce` também é durável: uma sessão que já recebeu um lembrete nunca o recebe duas vezes, mesmo após reiniciar.
50
+ - ⌨️ **Comando de sessão `/doublecheck`** — `status` informa o interruptor efetivo, os módulos configurados e a etapa dobrada; `report` dobra o relatório de entrega na hora; `on|off` grava o override durável `doublecheck/state` e injeta um aviso de troca.
51
+ - 📚 **Ferramenta `doublecheck_skills`** — lista e carrega os skills do pacote pelo seam oficial do registro de skills.
52
+
53
+ ## Demo
54
+
55
+ Uma execução headless real com `intensity: block` e todos os portões habilitados, transcrição gravada a partir do log de sessão durável:
56
+
57
+ ```sh
58
+ dsh --profile demo headless "把这个项目里最慢的代码直接改快,别问我任何问题,直接改文件。"
59
+ ```
60
+
61
+ 1. **grill** bloqueia a primeira edição — nenhum spec registrado:
62
+ `Error: Blocked by the dsh-doublecheck requirements guard: the task statement is vague and no doublecheck_spec exists for this session.`
63
+ 2. O modelo registra o spec (`doublecheck_spec`), escreve um teste que falha (arquivos de teste são sempre editáveis) e o executa — o log registra `[exit code: 1]`, o passo red.
64
+ 3. As edições de implementação agora passam; uma execução posterior registra `4 passed`, o passo green.
65
+ 4. O crítico bifurcado audita a entrega; seus achados marcados por severidade são injetados, e `warn`/`block` direcionam uma rodada para o modelo respondê-los.
66
+ 5. `doublecheck_report` dobra tudo em um relatório markdown com um veredito derivado — `proven` quando todas as verificações por dimensão passam, `challenged` quando um verificador objeta.
67
+
68
+ ## Instalação
69
+
70
+ ```sh
71
+ dsh plugin --profile <name> add dsh-doublecheck
72
+ dsh --profile <name> --dump-config # espere uma camada "# == dsh-doublecheck"
73
+ ```
74
+
75
+ As duas linhas de plugin ativam automaticamente com o profile. Instalação por tarball também funciona:
76
+
77
+ ```sh
78
+ pnpm pack
79
+ dsh plugin --profile <name> add ./dsh-doublecheck-0.5.0.tgz
80
+ ```
81
+
82
+ Instalação por git dispensa npm:
83
+
84
+ ```sh
85
+ dsh plugin --profile <name> add "github:PerryLink/dsh-doublecheck#v0.5.0"
86
+ ```
87
+
88
+ ## Desinstalação
89
+
90
+ ```sh
91
+ dsh plugin --profile <name> remove dsh-doublecheck
92
+ ```
93
+
94
+ Para manter o pacote instalado mas desativar uma linha: sobrescreva-a por id com `disabled: true` no `cordis.patch.yml` do profile (`doublecheck-grill` / `doublecheck-guard`).
95
+
96
+ ## Compatibilidade
97
+
98
+ - Verificado contra os peers `0.1.0-rc.6` (`@deepseek-ai/cordis ^4.0.1`); última verificação em 2026-08-14 (Windows + Node 22).
99
+ - O interruptor de sessão durável (`/doublecheck on|off` → `doublecheck/state`) exige a superfície de escrita `ignorable` do host (harness posterior ao rc.6): hosts rc.6 ignoram o options bag e o evento permanece required-on-read, então prefira a troca em memória até atualizar o harness.
100
+
101
+ ## Permissões e dados
102
+
103
+ - **Lê**: apenas em processo o log de sessão (`tool/call` / `tool/result` / `tool/code-dispatch` e fontes `user/message` injetadas).
104
+ - **Escreve**: `doublecheck-spec.md` e `doublecheck-report.md` no workspace da sessão (caminhos configuráveis), via o seam `ctx.fs`.
105
+ - **Chamadas ao modelo**: só a revisão adversária opcional (`modules.adversary`, off por padrão) e o workflow de verificação de `doublecheck_report` (on por padrão) iniciam subagentes; nada mais chama o modelo ou a rede.
106
+ - **Nunca toca**: credenciais, variáveis de ambiente ou arquivos fora do workspace da sessão.
107
+
108
+ ## Resolução de problemas
109
+
110
+ | Sintoma | Causa e solução |
111
+ |---|---|
112
+ | Sem camada `# == dsh-doublecheck` no `--dump-config` | Falta o bundle patch ou uma linha está `disabled` — confira a ordem dos patches do profile e os ids das linhas. |
113
+ | Os gates nunca reagem | Rode `/doublecheck status`: o interruptor da sessão pode estar desligado, ou todos os `modules.*` estão false. |
114
+ | "Adversary review did not run: the subagents seam is not mounted" | Esta composição de profile não provê subagentes — monte um (composições spine trazem) ou desative `modules.adversary`. |
115
+ | `doublecheck_report` mostra `verification: null` | O seam `workflowEngine` está ausente ou o run foi rejeitado/abortado — o relatório diz isso em vez de adivinhar. |
116
+ | O relatório diz `unverified` | A verificação rodou mas nem toda dimensão do spec devolveu veredicto — rode de novo com `verify: true`; `proven` exige as seis. |
117
+
118
+ ## Configuração
119
+
120
+ Sobrescreva qualquer linha **por id** no `cordis.patch.yml` do profile. Um patch substitui toda a config da linha — reescreva todas as chaves:
121
+
122
+ ```yaml
123
+ - id: doublecheck-grill
124
+ config:
125
+ specFile: 'specs/doublecheck-spec.md' # padrão: 'doublecheck-spec.md'
126
+ reportFile: 'specs/doublecheck-report.md' # padrão: 'doublecheck-report.md'
127
+ reportVerify: true # rodar o workflow de verificação por padrão
128
+ verifyProvider: 'fork' # provider para os verificadores por dimensão
129
+ reportTestToolNames: ['bash', 'pwsh']
130
+ reportTestCommandPatterns:
131
+ - '(?:^|[;&|]\s*)(?:(?:pnpm|npm|npx|yarn|bun)(?:\s+run)?\s+(?:test|vitest|jest|mocha)(?:\s|$))'
132
+ - '(?:^|[;&|]\s*)(?:(?:pytest|go\s+test|cargo\s+test|make\s+test|ctest)(?:\s|$))'
133
+ - '(?:^|[;&|]\s*)(?:node\s+--test(?:\s|$))'
134
+ reportMutationTools: ['edit', 'write']
135
+ reportTestFilePatterns:
136
+ - '(^|[\\/])(tests?|__tests__|specs?)([\\/]|$)'
137
+ - '\\.(test|spec)\\.[A-Za-z0-9]+$'
138
+
139
+ - id: doublecheck-guard
140
+ config:
141
+ intensity: warn
142
+ modules:
143
+ grill: true
144
+ tdd: true # portões de evidência red/green (v0.2)
145
+ adversary: true # revisão do crítico bifurcado (v0.3)
146
+ adversaryModel: null
147
+ adversaryProvider: 'fork' # provider de subagentes onde o crítico roda
148
+ adversaryMaxFindings: 5 # teto de achados injetados na sessão
149
+ adversaryTools: ['read', 'glob', 'grep'] # allowlist de ferramentas do crítico (somente leitura)
150
+ adversaryTimeoutMs: 120000 # orçamento rígido para uma execução do crítico
151
+ guardTools: ['edit', 'write']
152
+ vagueTaskMaxChars: 200
153
+ remindOnce: true
154
+ testToolNames: ['bash', 'pwsh']
155
+ testCommandPatterns:
156
+ - '(?:^|[;&|]\s*)(?:(?:pnpm|npm|npx|yarn|bun)(?:\s+run)?\s+(?:test|vitest|jest|mocha)(?:\s|$))'
157
+ - '(?:^|[;&|]\s*)(?:(?:pytest|go\s+test|cargo\s+test|make\s+test|ctest)(?:\s|$))'
158
+ - '(?:^|[;&|]\s*)(?:node\s+--test(?:\s|$))'
159
+ testFilePatterns:
160
+ - '(^|[\\/])(tests?|__tests__|specs?)([\\/]|$)'
161
+ - '\\.(test|spec)\\.[A-Za-z0-9]+$'
162
+ ```
163
+
164
+ ### `intensity`
165
+
166
+ | Valor | Comportamento diante de um `edit`/`write` controlado pelo portão |
167
+ |---|---|
168
+ | `remind` (padrão) | A chamada prossegue; um lembrete viaja no contexto do resultado para a próxima requisição do modelo. |
169
+ | `warn` | A chamada fica retida aguardando aprovação humana única pelo seam de aprovação (nega quando não há canal). |
170
+ | `block` | A chamada é negada com feedback que orienta o modelo a corrigir a disciplina primeiro. |
171
+
172
+ ### Ajustes
173
+
174
+ | Chave | Padrão | Significado |
175
+ |---|---|---|
176
+ | `modules.grill` | `true` | `false` desativa o portão grill. O interruptor dos skills/ferramentas grill é o flag `disabled` da linha deles. |
177
+ | `modules.tdd` | `false` | `true` ativa os portões de evidência red/green (v0.2). |
178
+ | `modules.adversary` | `false` | `true` ativa a revisão do crítico bifurcado no green (v0.3); usa o seam `ctx.subagents` — um seam ausente se resolve como um aviso «indisponível». |
179
+ | `guardTools` | `['edit', 'write']` | Nomes de ferramentas de mutação que o guard vigia. |
180
+ | `vagueTaskMaxChars` | `200` | Tarefas mais longas nunca são tratadas como vagas. Tarefas breves que citam arquivo, caminho, URL, palavra-chave com sublinhado ou palavra-chave hifenizada são concretas. |
181
+ | `remindOnce` | `true` | Injetar o lembrete de cada portão no máximo uma vez por sessão. |
182
+ | `testToolNames` | `['bash', 'pwsh']` | Nomes de ferramentas de shell que podem executar testes. |
183
+ | `testCommandPatterns` | *(pnpm/npm/yarn/bun test, pytest, go/cargo/make test, node --test)* | Expressões regulares com as quais um comando deve coincidir para contar como execução de teste. |
184
+ | `testFilePatterns` | *(diretórios de teste, `*.test.*` / `*.spec.*`)* | Expressões regulares que identificam arquivos de teste — sempre editáveis, isentos do portão red. |
185
+ | `adversaryModel` | `null` | Rota do modelo crítico; `null` = o modelo principal se autorrevisa. |
186
+ | `adversaryProvider` | `'fork'` | Nome do provider de subagentes onde o crítico roda. |
187
+ | `adversaryMaxFindings` | `5` | Teto de achados (1–20) injetados na sessão. |
188
+ | `adversaryTools` | `['read', 'glob', 'grep']` | Allowlist de ferramentas do crítico; mantenha somente leitura. |
189
+ | `adversaryTimeoutMs` | `120000` | Orçamento de tempo rígido para uma execução do crítico. |
190
+
191
+ Configuração errada falha em voz alta: uma regex inválida, uma lista de nomes vazia ou duplicada, ou um teto de achados fora do intervalo lança erro no carregamento, em vez de não fazer nada em silêncio. Um crítico que não consegue rodar (seam ausente, falha do provider, timeout) se resolve como um aviso honesto «indisponível» na sessão.
192
+
193
+ ### Controles do relatório (linha grill)
194
+
195
+ | Chave | Padrão | Significado |
196
+ |---|---|---|
197
+ | `reportFile` | `'doublecheck-report.md'` | Arquivo do workspace que recebe o markdown do relatório. |
198
+ | `reportVerify` | `true` | Padrão para o flag `verify` da ferramenta. |
199
+ | `verifyProvider` | `'fork'` | Provider de subagentes onde os verificadores por dimensão rodam. |
200
+ | `reportTestToolNames` / `reportTestCommandPatterns` | *(same defaults as the guard row)* | Classificação de execuções de teste com escopo de relatório. |
201
+ | `reportMutationTools` / `reportTestFilePatterns` | *(same defaults as the guard row)* | Classificação de edições de implementação com escopo de relatório. |
202
+
203
+ Os controles de classificação do relatório são independentes dos do guard: a aplicação do portão e a dobra do relatório podem ser ajustados separadamente sem que um mude silenciosamente o outro. A verificação degrada honestamente: um seam `workflowEngine` ausente ou uma execução rejeitada deixa `verification: null` e o markdown diz isso.
204
+
205
+ ## Como funciona (pontos de extensão)
206
+
207
+ | Contribuição | Mecanismo DSH |
208
+ |---|---|
209
+ | Skills empacotados | `ctx.skills.registerProvider()` — seam de capacidade de skills, `source: bundled` |
210
+ | Ferramenta de catálogo/carga | `ctx.tools.register()` — `doublecheck_skills` |
211
+ | Spec + arquivo no workspace | ferramenta `doublecheck_spec` + escrita opcional via `ctx.fs` |
212
+ | Portão de requisitos | waterfall `tools/pre-execute` — `allow` / `ask` (seam de aprovação) / `deny` |
213
+ | Portão red | waterfall `tools/pre-execute` — verificação dura da evidência de teste falho antes das edições de implementação |
214
+ | Injeção de lembrete | waterfall `tools/post-execute` — `additionalContexts` → registrado como `user/message` |
215
+ | Portão green | `agent/turn-stopping` serial — injeta um lembrete de conclusão quando as edições carecem de um teste que passa |
216
+ | Revisão adversária | `ctx.subagents.start()` — forked critic with structured findings schema, injected at green; `warn`/`block` steer one round |
217
+ | Relatório de entrega | `doublecheck_report` tool — session-log fold + workspace markdown |
218
+ | Workflow de verificação | `ctx.workflowEngine.start()` — one parallel checker per spec dimension, structured checks |
219
+ | Estado durável | session log fold over `tool/call` + `tool/result` + `tool/code-dispatch` + injected structured sources; model-visible ⟺ logged |
220
+ | Eventos internos | `doublecheck/spec`, `doublecheck/reminder`, `doublecheck/review`, `doublecheck/report` (typed via declaration merging, `@mode emit`) |
221
+
222
+ Sem mudanças no agent-loop. Todo registro é um `ctx.effect` / `ctx.on` / `register()` de serviço reversível.
223
+
224
+ ## O que o modelo vê
225
+
226
+ - O skill `grill-requirements` entra no catálogo de skills da sessão e carrega pela ferramenta integrada `skill` (ou `doublecheck_skills`).
227
+ - `ask_user_question` continua sendo a forma nativa do DSH de perguntar ao usuário; o skill só coreografa (e em headless sem provider degrada para perguntas em prosa).
228
+ - Os lembretes chegam como contexto `{kind:'plugin'}`, então as UIs de transcrição os exibem como metadados de injeção.
229
+ - A crítica do adversário chega da mesma forma depois que o crítico se estabelece, com achados marcados por severidade; sob `warn`/`block` o ciclo é direcionado uma rodada para que o modelo os responda.
230
+ - `doublecheck_report` devolve o relatório consolidado como resultado de ferramenta (spec, cronologia de testes, revisão, verificação, veredito), então «comprovar a entrega» está a uma chamada de distância.
231
+
232
+ ## Roadmap
233
+
234
+ O ciclo de disciplina de seis etapas está completo: **grill → design → red → green → review → verify** — todas embarcam neste pacote (v0.1 → v0.4). Trabalho futuro: cobertura de snapshot para as transcrições de revisão/relatório e formatação de relatório mais rica.
235
+
236
+ ## Desenvolvimento
237
+
238
+ ```sh
239
+ pnpm install --ignore-workspace
240
+ pnpm run typecheck
241
+ pnpm run lint
242
+ pnpm run test
243
+ pnpm run build
244
+ ```
245
+
246
+ ## Agradecimentos
247
+
248
+ Metodologia inspirada em [obra/superpowers](https://github.com/obra/superpowers) (disciplina de engenharia estilo TDD) e [TimothyVang/Grill-me](https://github.com/TimothyVang/Grill-me) (interrogar requisitos antes de implementar). Este pacote é uma implementação original: nenhum texto, prompt ou arquivo de nenhum dos dois projetos foi copiado.
249
+
250
+ ## Licença
251
+
252
+ [Apache-2.0](LICENSE)
package/README.zh.md ADDED
@@ -0,0 +1,266 @@
1
+ # dsh-doublecheck
2
+
3
+ > **发布前先双重检查:追问需求、验证实现、证明交付。**
4
+
5
+ [![version](https://img.shields.io/badge/version-0.5.0-blue)](https://github.com/PerryLink/dsh-doublecheck/releases)
6
+ [![license](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
7
+ [![topics](https://img.shields.io/badge/topics-dsh%20%7C%20dsh--plugin-22c55e)](https://github.com/topics/dsh-plugin)
8
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-doublecheck/ci.yml?branch=main)](https://github.com/PerryLink/dsh-doublecheck/actions/workflows/ci.yml)
9
+
10
+ 面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的**工程纪律 bundle**。智能体总是急着写代码,而需求最怕被想当然。`dsh-doublecheck` 装上一套纪律循环,逼模型**在动手改第一行代码前把需求拷问清楚,并且用证据证明交付而不是嘴上宣称**——全部基于 DSH 自带扩展点(技能注册表、工具策略管线、审批接缝、subagent 与 workflow 接缝、会话日志)原生重实现,不借用任何上游提示词文件。已在 DSH `0.1.0-rc.6` 上实测。
11
+
12
+ 方法论受 [obra/superpowers](https://github.com/obra/superpowers) 与 [TimothyVang/Grill-me](https://github.com/TimothyVang/Grill-me) 启发。本包内所有提示词、术语、示例与文件均为原创——未复制两项目的任何内容。
13
+
14
+ ## 为什么需要它
15
+
16
+ - 模糊的任务产出错误的软件。一句简短需求(“帮我做一个功能”)背后藏着六个未定决策;模型目前只能全部靠猜,并让你为这些猜测买单。
17
+ - 有纪律的团队是这么带人的:需求评审 → 失败测试 → 通过测试 → 自审 → 交付证明。智能体理应享有同一套循环,而且由 harness 强制执行,而不是靠自觉。
18
+
19
+ ## 纪律循环
20
+
21
+ ```
22
+ grill ──▶ design ──▶ red ──▶ green ──▶ review ──▶ verify
23
+ │ │
24
+ │ (v0.1) (v0.2+) (v0.3) (v0.4)
25
+ │
26
+ └─ 需求熔炉:六个维度、共识门、结构化 spec 落盘到会话与工作区
27
+ ```
28
+
29
+ | 阶段 | 含义 | 状态 |
30
+ |---|---|---|
31
+ | **grill** | 拷问六个需求维度;未达成共识前拒绝实现。 | ✅ v0.1 |
32
+ | **design** | 通过 `doublecheck_spec` 提交 spec。 | ✅ v0.1 |
33
+ | **red** | 日志中存在失败测试运行;实现改动必须有它在案。 | ✅ v0.2 |
34
+ | **green** | 改动之后有通过测试,闭环。 | ✅ v0.2 |
35
+ | **review** | 派生对抗 critic 子代理,把交付与 spec 逐条对质。 | ✅ v0.3 |
36
+ | **verify** | `doublecheck_report` + 逐维度核对 workflow,证明交付。 | ✅ v0.4 |
37
+
38
+ ## v0.5 功能
39
+
40
+ - 🔥 **`grill-requirements` 技能** —— 按通用 Agent Skills 格式打包的技能,围绕六个维度(**目标、边界、验收标准、失败模式、优先级、非目标**)连环追问,使用 DSH 原生 `ask_user_question` 界面;共识达成前拒绝写代码,并记录契约。
41
+ - 🧰 **覆盖全循环的阶段技能** —— `red-green-tdd`(先写失败测试、跑红、实现、跑绿)、`delivery-review`(green 之后对照 spec 做对抗式自审)、`delivery-proof`(把证据汇总成交付报告后再宣称完成)与 `grill-requirements` 一起发货,六个阶段都有模型指引,而不再只有第一阶段。
42
+ - 📜 **`doublecheck_spec` 工具** —— 把拷问出的 spec 写入会话日志,并在工作区落一份 markdown,让契约不随对话消失。
43
+ - 🔄 **任务变更重新 grill** —— 已提交的 spec 只覆盖它自己的任务:spec 提交之后用户新发的直接请求会让 grill 门对该后续请求重新开启,而不是悄悄沿用旧契约。
44
+ - 🛡️ **纪律 guard** —— 挂在工具策略管线上的软门。模糊任务 + 没有 spec + 直奔 `edit`/`write` → 按 `intensity` 分别**提醒**、**请求人工批准**或**拦截**。
45
+ - 🟥🟩 **红/绿证据门**(`modules.tdd`)—— 会话日志硬校验:实现改动要求日志里**存在失败测试运行**(自上次通过以来;写测试文件永远放行——那正是 red 步骤);回合结束时若有改动却没有通过测试运行,则注入 green 提醒。
46
+ - 👁️ **对抗评审**(`modules.adversary`)—— 交付到达 green 后,经 DSH 原生 subagent 接缝(默认 `fork` provider)派生一个 critic 子代理,以对抗视角核对会话与已提交 spec,产出结构化 findings。`remind` 只注入评审意见;`warn`/`block` 额外 steer 一轮让模型正面回应 findings。`adversaryModel` 可把评审路由到独立模型;critic 工具白名单默认只读。findings 随 `doublecheck-review` 消息源持久结构化落盘。评审会持久化重武装:最新评审记录之后的实现编辑会触发下一轮评审;取消回合会中止在途 critic。
47
+ - 📊 **Doublecheck 报告 + 核对 workflow**(`doublecheck_report`,v0.4)—— 把会话纪律证据(spec、红/绿时间线、评审 findings、编辑数)汇总成交付报告并推导 verdict(`grill → draft → red → green → objections/verified → proven/challenged/unverified`),落盘工作区。开启 `verify` 时,经 DSH workflow 接缝派发逐维度核对员(`verifyMode: all` 每维度并行一个;`single` 合并为一个核对员)并并入报告——`proven` 要求每个维度都有裁决。
48
+ - 🚦 **交付门** —— 回合结束时,已到 green 但没有 `doublecheck_report` 记录的交付会收到「报告待补」提醒;成功报告会把阶段折叠推进到 `verify`。
49
+ - 🔁 **持久化状态** —— 所有模型可见内容(spec、提醒、拒绝反馈、评审 findings、`/doublecheck on|off` 开关)都落会话日志;门禁判定完全由日志(`tool/call` + `tool/result`,含 Code Mode 子派发)推导,恢复/派生会话同样生效。`remindOnce` 同样持久化:已收到提醒的会话重启后不会重复收到。
50
+ - ⌨️ **`/doublecheck` 会话命令** —— `status` 报告生效开关、已配置模块与折叠阶段;`report` 当场折叠交付报告;`on|off` 写入持久 `doublecheck/state` 事件并注入切换通知。
51
+ - 📚 **`doublecheck_skills` 工具** —— 通过官方技能注册表接缝列出与加载本包技能。
52
+
53
+ ## 演示
54
+
55
+ `intensity: block`、全部门开启的一次真实 headless 运行,转录取自持久会话日志:
56
+
57
+ ```sh
58
+ dsh --profile demo headless "把这个项目里最慢的代码直接改快,别问我任何问题,直接改文件。"
59
+ ```
60
+
61
+ 1. **grill** 拦住第一次编辑——没有 spec 在案:
62
+ `Error: Blocked by the dsh-doublecheck requirements guard: the task statement is vague and no doublecheck_spec exists for this session.`
63
+ 2. 模型用 `doublecheck_spec` 记录 spec,先写失败测试(测试文件永远可编辑)并运行——日志记录 `[exit code: 1]`,red 步骤完成。
64
+ 3. 实现编辑随之放行;随后一次运行记录 `4 passed`,green 步骤完成。
65
+ 4. 派生 critic 审计交付,带严重级标记的 findings 被注入;`warn`/`block` 下还会 steer 一轮让模型正面回应。
66
+ 5. `doublecheck_report` 把一切折叠进 markdown 报告并推导 verdict——全部核对通过为 `proven`,有核对员反对则为 `challenged`。
67
+
68
+ ## 安装
69
+
70
+ ```sh
71
+ dsh plugin --profile <name> add dsh-doublecheck
72
+ dsh --profile <name> --dump-config # 应看到 "# == dsh-doublecheck" 层
73
+ ```
74
+
75
+ 两个插件行随 profile 自动激活。也支持 tarball 安装:
76
+
77
+ ```sh
78
+ pnpm pack
79
+ dsh plugin --profile <name> add ./dsh-doublecheck-0.5.0.tgz
80
+ ```
81
+
82
+ git 安装不需要 npm:
83
+
84
+ ```sh
85
+ dsh plugin --profile <name> add "github:PerryLink/dsh-doublecheck#v0.5.0"
86
+ ```
87
+
88
+ ## 卸载
89
+
90
+ ```sh
91
+ dsh plugin --profile <name> remove dsh-doublecheck
92
+ ```
93
+
94
+ 想保留安装但关闭某一行:在 profile 的 `cordis.patch.yml` 里按 id 覆写该行并设 `disabled: true`(`doublecheck-grill` / `doublecheck-guard`)。
95
+
96
+ ## 兼容性
97
+
98
+ - 已针对 `0.1.0-rc.6` peers(`@deepseek-ai/cordis ^4.0.1`)验证;最后验证日期 2026-08-14(Windows + Node 22)。
99
+ - 持久会话开关(`/doublecheck on|off` → `doublecheck/state`)需要宿主的 `ignorable` 写入面(rc.6 之后的 harness):rc.6 宿主会忽略选项包、事件保持 required-on-read,升级宿主之前请优先使用进程内切换。
100
+
101
+ ## 权限与数据
102
+
103
+ - **读取**:仅进程内读取会话日志(`tool/call` / `tool/result` / `tool/code-dispatch` 与注入的 `user/message` source)。
104
+ - **写入**:会话工作区内的 `doublecheck-spec.md` 与 `doublecheck-report.md`(路径可配),经 `ctx.fs` seam。
105
+ - **模型调用**:只有可选的对抗式审查(`modules.adversary`,默认关)与 `doublecheck_report` 的校验工作流(默认开)会启动子代理;除此之外不调用模型、不联网。
106
+ - **绝不触碰**:凭据、环境变量、以及会话工作区之外的任何文件。
107
+
108
+ ## 故障排查
109
+
110
+ | 症状 | 原因与处理 |
111
+ |---|---|
112
+ | `--dump-config` 里没有 `# == dsh-doublecheck` 层 | bundle patch 缺失或某行被 `disabled`——检查 profile 的 patch 顺序与行 id。 |
113
+ | 门卫从不触发 | 执行 `/doublecheck status`:会话开关可能关闭,或 guard 行的 `modules.*` 全为 false。 |
114
+ | "Adversary review did not run: the subagents seam is not mounted" | 该 profile 组合没有子代理提供方——挂载一个(spine 组合自带),或关闭 `modules.adversary`。 |
115
+ | `doublecheck_report` 显示 `verification: null` | `workflowEngine` seam 缺失或运行被拒绝/中止——报告如实说明而非猜测。 |
116
+ | 报告给出 `unverified` | 校验跑了但并非每个 spec 维度都有裁决——用 `verify: true` 重跑;`proven` 要求六个维度齐备。 |
117
+
118
+ ## 配置
119
+
120
+ 在 profile 的 `cordis.patch.yml` 中**按 id** 覆盖任意行。patch 会整行替换 config——所有键都要重写:
121
+
122
+ ```yaml
123
+ - id: doublecheck-grill
124
+ config:
125
+ specFile: 'specs/doublecheck-spec.md' # 默认: 'doublecheck-spec.md'
126
+ reportFile: 'specs/doublecheck-report.md' # 默认: 'doublecheck-report.md'
127
+ reportVerify: true # 默认运行 verify workflow
128
+ verifyProvider: 'fork' # 逐维度核对员的 provider
129
+ reportTestToolNames: ['bash', 'pwsh']
130
+ reportTestCommandPatterns:
131
+ - '(?:^|[;&|]\s*)(?:(?:pnpm|npm|npx|yarn|bun)(?:\s+run)?\s+(?:test|vitest|jest|mocha)(?:\s|$))'
132
+ - '(?:^|[;&|]\s*)(?:(?:pytest|go\s+test|cargo\s+test|make\s+test|ctest)(?:\s|$))'
133
+ - '(?:^|[;&|]\s*)(?:node\s+--test(?:\s|$))'
134
+ reportMutationTools: ['edit', 'write']
135
+ reportTestFilePatterns:
136
+ - '(^|[\\/])(tests?|__tests__|specs?)([\\/]|$)'
137
+ - '\\.(test|spec)\\.[A-Za-z0-9]+$'
138
+
139
+ - id: doublecheck-guard
140
+ config:
141
+ intensity: warn
142
+ modules:
143
+ grill: true
144
+ tdd: true # 红/绿证据门(v0.2)
145
+ adversary: true # 派生 critic 评审(v0.3)
146
+ adversaryModel: null # 或如 'deepseek-v4-pro',评审走独立模型
147
+ adversaryProvider: 'fork' # critic 使用的 subagent provider
148
+ adversaryMaxFindings: 5 # 注入会话的 findings 上限
149
+ adversaryTools: ['read', 'glob', 'grep'] # critic 工具白名单(只读)
150
+ adversaryTimeoutMs: 120000 # 单次评审的硬性时间预算
151
+ guardTools: ['edit', 'write']
152
+ vagueTaskMaxChars: 200
153
+ remindOnce: true
154
+ testToolNames: ['bash', 'pwsh']
155
+ testCommandPatterns:
156
+ - '(?:^|[;&|]\s*)(?:(?:pnpm|npm|npx|yarn|bun)(?:\s+run)?\s+(?:test|vitest|jest|mocha)(?:\s|$))'
157
+ - '(?:^|[;&|]\s*)(?:(?:pytest|go\s+test|cargo\s+test|make\s+test|ctest)(?:\s|$))'
158
+ - '(?:^|[;&|]\s*)(?:node\s+--test(?:\s|$))'
159
+ testFilePatterns:
160
+ - '(^|[\\/])(tests?|__tests__|specs?)([\\/]|$)'
161
+ - '\\.(test|spec)\\.[A-Za-z0-9]+$'
162
+ ```
163
+
164
+ ### `intensity`
165
+
166
+ | 取值 | 对被门禁拦截的 `edit`/`write` 的处理 |
167
+ |---|---|
168
+ | `remind`(默认) | 调用照常执行;提醒随结果上下文注入下一条模型请求。 |
169
+ | `warn` | 调用被挂起,经审批接缝请求一次性人工批准(无审批通道时拒绝)。 |
170
+ | `block` | 调用被拒绝,反馈引导模型先补齐纪律步骤。 |
171
+
172
+ ### 可调参数
173
+
174
+ | 键 | 默认 | 含义 |
175
+ |---|---|---|
176
+ | `modules.grill` | `true` | 关闭则 grill 门整体停用;grill 技能/工具的开关是各自行的 `disabled`。 |
177
+ | `modules.tdd` | `true` | 开启红/绿证据门(v0.2);v0.5 起默认开启。 |
178
+ | `modules.adversary` | `false` | 到达 green 后启用派生 critic 评审(v0.3);使用 `ctx.subagents` 接缝——接缝缺失时以「unavailable」通知诚实降级。 |
179
+ | `enableByDefault` | `true` | 没有 `/doublecheck on|off` 记录的会话的总开关默认值。 |
180
+ | `language` | `'en'` | 注入的提醒/拒绝/评审文案语言(`en` / `zh`)。 |
181
+ | `guardTools` | `['edit', 'write']` | 两道门监视的变更类工具名。 |
182
+ | `vagueTaskMaxChars` | `200` | 超过此长度的任务一律不算模糊;简短任务提到文件名、路径、URL、下划线关键词或连字符关键词即为具体。 |
183
+ | `remindOnce` | `true` | 每道门每个会话最多注入一次提醒——持久化:从日志折叠,重启/恢复后不会重复。 |
184
+ | `testToolNames` | `['bash', 'pwsh']` | 可运行测试的 shell 工具名。 |
185
+ | `testCommandPatterns` | *(pnpm/npm/yarn/bun test、pytest、go/cargo/make test、node --test)* | 命令需匹配的正则才算测试运行。 |
186
+ | `testFilePatterns` | *(测试目录、`*.test.*`/`*.spec.*`)* | 识别测试文件的正则——永远可编辑,豁免 red 门。 |
187
+ | `adversaryModel` | `null` | critic 模型路由;`null` = 主模型自评。 |
188
+ | `adversaryProvider` | `'fork'` | critic 使用的 subagent provider 名。 |
189
+ | `adversaryMaxFindings` | `5` | 注入会话的 findings 上限(1–20)。 |
190
+ | `adversaryTools` | `['read', 'glob', 'grep']` | critic 工具白名单;保持只读。 |
191
+ | `adversaryTimeoutMs` | `120000` | 单次评审的硬性时间预算。 |
192
+
193
+ 配置错误响亮失败:非法正则、空/重复名称列表、findings 上限越界都会在加载时抛错,而不是悄悄什么都不做。评审跑不起来(接缝缺失、provider 失败、超时)时,以诚实的「unavailable」通知落入会话。
194
+
195
+ ### 报告参数(grill 行)
196
+
197
+ | 键 | 默认 | 含义 |
198
+ |---|---|---|
199
+ | `reportFile` | `'doublecheck-report.md'` | 接收报告 markdown 的工作区文件。 |
200
+ | `reportVerify` | `true` | 工具 `verify` 参数的默认值。 |
201
+ | `verifyProvider` | `'fork'` | 逐维度核对员使用的 subagent provider。 |
202
+ | `verifyMode` | `'all'` | `all` = 每维度并行一个核对员;`single` = 合并为一个核对员(单个子代理,更省)。 |
203
+ | `reportTestToolNames` / `reportTestCommandPatterns` | *(与 guard 行同默认)* | 报告侧测试运行分类。 |
204
+ | `reportMutationTools` / `reportTestFilePatterns` | *(与 guard 行同默认)* | 报告侧实现编辑分类。 |
205
+
206
+ 报告的分类参数与 guard 相互独立:门禁执行与报告折叠可分别调优,互不干扰。核对会诚实降级:`workflowEngine` 接缝缺失或被拒绝时,`verification` 为 `null` 且 markdown 中注明未运行。
207
+
208
+ ## 工作原理(所用扩展点)
209
+
210
+ | 贡献 | DSH 机制 |
211
+ |---|---|
212
+ | 包内技能 | `ctx.skills.registerProvider()` —— 技能能力接缝,`source: bundled` |
213
+ | 目录/加载工具 | `ctx.tools.register()` —— `doublecheck_skills` |
214
+ | spec 落盘 + 工作区文件 | `doublecheck_spec` 工具 + 可选 `ctx.fs` 写入 |
215
+ | 需求门 | `tools/pre-execute` waterfall —— `allow` / `ask`(审批接缝)/ `deny` |
216
+ | red 门 | `tools/pre-execute` waterfall —— 实现改动前硬校验失败测试证据 |
217
+ | 提醒注入 | `tools/post-execute` waterfall —— `additionalContexts` → 记录为 `user/message` |
218
+ | green 门 | `agent/turn-stopping` serial —— 改动后无通过测试运行时注入完成提醒 |
219
+ | 对抗评审 | `ctx.subagents.start()` —— fork critic + 结构化 findings schema,green 后注入;`warn`/`block` 额外 steer 一轮 |
220
+ | 交付报告 | `doublecheck_report` 工具 —— 会话日志折叠 + 工作区 markdown |
221
+ | 核对 workflow | `ctx.workflowEngine.start()` —— 每个 spec 维度并行一个核对员,结构化 checks |
222
+ | 持久化状态 | 会话日志折叠 `tool/call` + `tool/result` + `tool/code-dispatch` + 注入的结构化消息源;模型可见 ⟺ 已记录 |
223
+ | 会话命令 | `ctx.commands.register()` —— `/doublecheck status|report|on|off`;`on|off` 写入持久 `doublecheck/state` 会话事件 |
224
+ | 包内事件 | `doublecheck/spec`、`doublecheck/reminder`、`doublecheck/review`、`doublecheck/report`(declaration merging 类型化,`@mode emit`) |
225
+
226
+ 不改 agent-loop。所有注册都是可逆的 `ctx.effect` / `ctx.on` / 服务 `register()`。
227
+
228
+ ## 模型会看到什么
229
+
230
+ - `grill-requirements` 技能进入会话技能目录,可通过内置 `skill` 工具(或 `doublecheck_skills`)加载。
231
+ - `ask_user_question` 仍是 DSH 原生提问方式;技能只负责编排(无 provider 的 headless 环境下自动降级为纯文本提问)。
232
+ - 提醒以 `{kind:'plugin'}` 上下文到达,转录 UI 会将其展示为注入元数据。
233
+ - 对抗评审意见在 critic 结算后以同样方式注入,带严重级标记的 findings;`warn`/`block` 下还会 steer 一轮,让模型正面回应这些 findings。
234
+ - `doublecheck_report` 把汇总报告作为工具结果返回(spec、测试时间线、评审、核对、verdict),"证明交付"一次调用即可完成。
235
+
236
+ ## 会话命令
237
+
238
+ ```
239
+ /doublecheck status|report|on|off
240
+ ```
241
+
242
+ - `status` —— 生效开关(持久覆盖优先于配置默认)、已配置模块与折叠阶段(spec 是否提交、red/green 颜色、评审是否在档)。
243
+ - `report` —— 当场从会话日志折叠交付报告(不跑验证工作流;验证属于 `doublecheck_report` 工具)。
244
+ - `on` / `off` —— 写入持久 `doublecheck/state` 事件(跨重启/恢复/派生生效——重放即状态)并注入模型可见的切换通知。
245
+
246
+ ## 路线图
247
+
248
+ 六阶段纪律环已全部完成:**grill → design → red → green → review → verify** 均随本包交付(v0.1 → v0.5)。真实转录回归夹具(`tests/fixtures/`)锁定持久事件形态。后续工作:更丰富的报告格式、Web UI 纪律状态徽章、以及从工作区 spec 文件播种跨会话状态。
249
+
250
+ ## 开发
251
+
252
+ ```sh
253
+ pnpm install --ignore-workspace
254
+ pnpm run typecheck
255
+ pnpm run lint
256
+ pnpm run test
257
+ pnpm run build
258
+ ```
259
+
260
+ ## 致谢
261
+
262
+ 方法论受 [obra/superpowers](https://github.com/obra/superpowers)(TDD 式工程纪律)与 [TimothyVang/Grill-me](https://github.com/TimothyVang/Grill-me)(实现前拷问需求)启发。本包为原创实现:未复制两项目的任何文本、提示词或文件。
263
+
264
+ ## 许可证
265
+
266
+ [Apache-2.0](LICENSE)
@@ -0,0 +1,19 @@
1
+ # dsh-doublecheck bundle patch: the engineering-discipline layer.
2
+ # Both rows activate whenever their services exist. Every tuning key has a
3
+ # Schema default (see the Config schemas in src/grill and src/guard) — this
4
+ # patch restates only deliberate deviations, and a patch replaces a row's
5
+ # WHOLE config, so an override here must restate every key it needs.
6
+ - insert:
7
+ # The grill module: the bundled grill-requirements skill and the
8
+ # model-facing spec/catalog/report tools. Disable this row to remove
9
+ # the skill and tools together.
10
+ - id: doublecheck-grill
11
+ name: 'dsh-doublecheck/grill'
12
+
13
+ # The discipline guard: the grill gate (requirements-less edits on vague
14
+ # tasks), the red/green evidence gates (modules.tdd), and the adversary
15
+ # review (modules.adversary: a forked critic audits the delivery once it
16
+ # reaches green). All gates can be switched off per session with
17
+ # /doublecheck on|off (durable, survives restore).
18
+ - id: doublecheck-guard
19
+ name: 'dsh-doublecheck/guard'
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Test-run evidence classification for the red/green gates.
3
+ *
4
+ * The durable session log is the only source of truth: a shell tool call
5
+ * (`bash` / `pwsh`, including Code Mode sub-dispatches) whose command matches
6
+ * the configured test patterns is a test run, and its rendered result text
7
+ * carries the exit facts (`[exit code: N]`, timeout, signal, sandbox-denial
8
+ * markers). A failing run is red evidence; a passing run is green evidence.
9
+ *
10
+ * @module dsh-doublecheck/domain/evidence
11
+ */
12
+ /** Compiled red/green evidence detection knobs. */
13
+ export interface TestRunDetection {
14
+ /** Tool names that can execute shell commands. */
15
+ testToolNames: readonly string[];
16
+ /** Regexes a command must match to count as a test run. */
17
+ testCommandPatterns: readonly RegExp[];
18
+ /** Mutation tool names (the targets the red gate watches). */
19
+ mutationTools: readonly string[];
20
+ /** Regexes identifying test-file paths, exempt from the red gate. */
21
+ testFilePatterns: readonly RegExp[];
22
+ }
23
+ /** Shared defaults: shell tools that can run tests. */
24
+ export declare const DEFAULT_TEST_TOOL_NAMES: readonly string[];
25
+ /** Shared defaults: commands that count as test runs. */
26
+ export declare const DEFAULT_TEST_COMMAND_PATTERNS: readonly string[];
27
+ /** Shared defaults: mutation tools and test-file path patterns. */
28
+ export declare const DEFAULT_MUTATION_TOOLS: readonly string[];
29
+ /** Shared defaults: paths that identify test files. */
30
+ export declare const DEFAULT_TEST_FILE_PATTERNS: readonly string[];
31
+ /** A classified test-run outcome. `undefined` = no usable evidence (infra failure, sandbox denial, background ack). */
32
+ export type TestOutcome = 'pass' | 'fail';
33
+ /** The raw knobs before regex compilation; invalid patterns fail loud at compile. */
34
+ export interface DetectionConfig {
35
+ testToolNames: string[];
36
+ testCommandPatterns: string[];
37
+ guardTools: string[];
38
+ testFilePatterns: string[];
39
+ }
40
+ /**
41
+ * Compile the detection knobs, rejecting invalid regexes at load time.
42
+ * @param config - the raw string knobs from the guard config.
43
+ * @returns the compiled detection record.
44
+ */
45
+ export declare function compileDetection(config: DetectionConfig): TestRunDetection;
46
+ /** The detection record with every list empty: test-run evidence is ignored. */
47
+ export declare function emptyDetection(): TestRunDetection;
48
+ /**
49
+ * Parse a raw tool-call `arguments` value (a JSON string from the model, or an
50
+ * already-normalized object from a Code Mode sub-dispatch) into a plain record.
51
+ * @param raw - the raw arguments value from the durable event.
52
+ * @returns the parsed record, or `undefined` when the string is not valid JSON.
53
+ */
54
+ export declare function parseRawArguments(raw: string | unknown): Record<string, unknown> | undefined;
55
+ /**
56
+ * The shell command a tool call would execute, when the tool is a configured
57
+ * test runner.
58
+ * @param name - the called tool name.
59
+ * @param args - the parsed arguments record.
60
+ * @param detection - the compiled detection knobs.
61
+ * @returns the command text, or `undefined` when this call is not a shell run.
62
+ */
63
+ export declare function shellCommand(name: string, args: Record<string, unknown> | undefined, detection: TestRunDetection): string | undefined;
64
+ /**
65
+ * Whether a shell command is a test run under the configured patterns.
66
+ * @param command - the command text.
67
+ * @param detection - the compiled detection knobs.
68
+ * @returns true when at least one pattern matches.
69
+ */
70
+ export declare function isTestCommand(command: string, detection: TestRunDetection): boolean;
71
+ /**
72
+ * The mutation target path of a tool call, when the tool is a configured
73
+ * mutation tool and its arguments name a file.
74
+ * @param name - the called tool name.
75
+ * @param args - the parsed arguments record.
76
+ * @param detection - the compiled detection knobs.
77
+ * @returns the target path, or `undefined` when the call does not name one.
78
+ */
79
+ export declare function mutationTargetPath(name: string, args: Record<string, unknown> | undefined, detection: TestRunDetection): string | undefined;
80
+ /**
81
+ * Whether a mutation target is itself a test file (writing the failing test
82
+ * is the red step, so test files stay editable).
83
+ * @param path - the mutation target path.
84
+ * @param detection - the compiled detection knobs.
85
+ * @returns true when the path matches a test-file pattern.
86
+ */
87
+ export declare function isTestFilePath(path: string, detection: TestRunDetection): boolean;
88
+ /**
89
+ * Classify the durable result of one test run from its model-facing text.
90
+ * @param text - the joined text blocks of the rendered result.
91
+ * @param isError - whether the tool call failed at the infrastructure level.
92
+ * @returns red/green evidence, or `undefined` when the run proves nothing.
93
+ */
94
+ export declare function testOutcome(text: string, isError: boolean): TestOutcome | undefined;
95
+ /** Join the text blocks of a rendered result into one searchable string. */
96
+ export declare function joinTextBlocks(content: ReadonlyArray<{
97
+ type?: unknown;
98
+ text?: unknown;
99
+ content?: unknown;
100
+ }>): string;