dsh-doublecheck 0.9.7 → 0.9.9
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/CHANGELOG.md +33 -0
- package/README.es.md +7 -5
- package/README.hi.md +7 -5
- package/README.md +7 -5
- package/README.pt.md +7 -5
- package/README.zh.md +7 -5
- package/lib/domain/evidence.d.ts +36 -3
- package/lib/domain/evidence.js +38 -3
- package/lib/domain/gate.js +14 -10
- package/lib/domain/projection.js +17 -13
- package/lib/domain/report.js +18 -16
- package/lib/domain/stages.js +19 -17
- package/lib/guard/index.d.ts +8 -0
- package/lib/guard/index.js +39 -20
- package/package.json +24 -24
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to dsh-doublecheck are recorded here, newest first.
|
|
4
4
|
|
|
5
|
+
## [0.9.9] - 2026-09-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Register the gate settings namespace as **`doublecheck-gate`**. The previous `doublecheck.gate` name violated the host's `NAMESPACE_PATTERN` (`/^[a-z][a-z0-9-]*$/`), so `ctx.settings.register` threw a `TypeError` (the pattern has rejected dots since the settings seam landed), the guard swallowed it into a warn, and the namespace never reached `ctx.settings.describe()` — no settings surface could see or edit the checklist. The namespace is now typed against the host `SettingsProvider`, so a dotted name also fails at compile time.
|
|
10
|
+
- Wire the registered namespace into the runtime: `apply` now reads the resolved `SettingsScope` once at load, so the user section overrides the composition `gate.*` values for the `/gate` panel and the gate-red notice (`applies: restart`). Writes pass through `validate: validateGateConfig`, so a duplicate checklist id is refused at update time and the last good value stays in place.
|
|
11
|
+
- Remove the `expose: true` registration option: the host has no such option and silently ignored it.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Add `@deepseek-ai/dsh-settings` as a devDependency (type-only import) for the real settings contract in tests and the compile-time namespace guard; no runtime dependency change.
|
|
16
|
+
- Add `tests/settings.spec.ts`: the host rejects a dotted namespace with `/must match/`; `doublecheck-gate` is registered with `applies: 'restart'`, the composition base, and appears in `ctx.settings.describe()`; the row mounts without the "namespace skipped" warning; and a user section reaches the `/gate config` output. A pre-existing `doublecheck.gate` section (if any) was never read by any release and is now simply ignored.
|
|
17
|
+
|
|
18
|
+
### Docs
|
|
19
|
+
|
|
20
|
+
- Five-language READMEs and `AGENTS.md`: the `doublecheck-gate` namespace name, the `ctx.settings.describe()` visibility scope (the package ships no client card, so the shipped Web GUI plugin page does not list it), and the user-section-overrides-composition behavior.
|
|
21
|
+
|
|
22
|
+
## [0.9.8] - 2026-09-09
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Adapt the PTC sub-dispatch event vocabulary to the session-format V3 line: the host renamed the durable `tool/code-dispatch` event to `tool/ptc-dispatch` (payload unchanged), so on `0.1.5-alpha.1` the four evidence folds (discipline stage, test evidence, report facts, session projection) silently missed PTC test runs and dispatched `edit`/`write` calls. A shared `ptcSettle()` normalizer now folds the current label and matches the predecessor label structurally, so both the published `0.1.2-rc.1` line and the V3 line stay supported by the unchanged peer band.
|
|
27
|
+
- Point `scripts/scan-sessions.mjs` at the generation-suffixed log filename (`session.v3.jsonl.zstd`, highest `vN` per directory) instead of the hardcoded flat `session.jsonl.zstd`, and require the session project directory as an explicit argument so the tool can never default to the real `~/.dsh` store.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Add the `typecheck:ci` gate (`tsconfig.ci.json`, published-type resolution) and run it in `prepublishOnly`; no behavior change.
|
|
32
|
+
- Extend the CI/compat install probes to a `0.1.2-rc.1` + `0.1.5-alpha.1` matrix instead of replacing the old pin, so both release lines keep an install smoke.
|
|
33
|
+
|
|
34
|
+
### Docs
|
|
35
|
+
|
|
36
|
+
- Refresh the five-language README compatibility sections: harness baseline `dsh-v0.1.5-alpha.1`, the `tool/ptc-dispatch` event name, and the `Session.append` / settings-seam facts re-verified on `0.1.5-alpha.1`; no behavior change.
|
|
37
|
+
|
|
5
38
|
## [0.9.7] - 2026-09-07
|
|
6
39
|
|
|
7
40
|
### Fixed
|
package/README.es.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/topics/dsh-plugin)
|
|
12
|
+
[](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
|
|
12
13
|
[](#)
|
|
13
14
|
[](https://github.com/PerryLink/dsh-doublecheck/actions)
|
|
14
15
|
[](https://github.com/PerryLink/dsh-doublecheck/releases)
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
|
|
26
27
|
| Superficie | Estado |
|
|
27
28
|
|---|---|
|
|
28
|
-
| Harness | DeepSeek Harness `dsh-v0.1.
|
|
29
|
+
| Harness | DeepSeek Harness `dsh-v0.1.5-alpha.1`. Verificado el 2026-09-09 contra el checkout master `dsh-v0.1.5-alpha.1` (cadena completa de puertas + humo de instalación del perfil); la línea publicada `0.1.2-rc.1` sigue soportada. |
|
|
29
30
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
30
31
|
| Plataformas | Todas (host puro; sin código nativo, sin solicitudes de red directas propias) |
|
|
31
32
|
| Modelo | Cualquiera (el guard nunca llama a un modelo; las fases de crítico y revisor se ejecutan como subagentes del harness) |
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
`dsh-doublecheck` instala dos filas de plugin que leen y aplican desde el mismo registro de sesión durable:
|
|
36
37
|
|
|
37
38
|
1. **`doublecheck-grill`** — el horno de requisitos: la skill empaquetada `grill-requirements` más las herramientas orientadas al modelo `doublecheck_skills`, `doublecheck_spec` y `doublecheck_report`, y el flujo de verificación por dimensión.
|
|
38
|
-
2. **`doublecheck-guard`** — el guard de disciplina: la puerta grill, las puertas de evidencia rojo/verde, la revisión adversarial, los comandos `/doublecheck` y `/gate`, el espacio de ajustes `doublecheck
|
|
39
|
+
2. **`doublecheck-guard`** — el guard de disciplina: la puerta grill, las puertas de evidencia rojo/verde, la revisión adversarial, los comandos `/doublecheck` y `/gate`, el espacio de ajustes `doublecheck-gate` y la puerta de entrega de cuatro fases.
|
|
39
40
|
|
|
40
41
|
Juntos imponen el **bucle de disciplina** — *grill → design → red → green → review → verify*:
|
|
41
42
|
|
|
@@ -137,7 +138,7 @@ La mala configuración falla en voz alta al cargar: regex inválidas, listas de
|
|
|
137
138
|
| `/doublecheck status\|report\|on\|off` | comando | Interruptor, módulos, intensidad, hechos de etapa, informe plegado y la sobrescritura durable on/off. |
|
|
138
139
|
| `/gate status\|run\|config` | comando | Progreso de la lista en vivo, el informe entregable/rehacer asentado y la configuración efectiva. |
|
|
139
140
|
| `grill-requirements`, `red-green-tdd`, `delivery-review`, `delivery-proof` | skill | Skills de disciplina empaquetadas que cubren las seis etapas del bucle. |
|
|
140
|
-
| `doublecheck
|
|
141
|
+
| `doublecheck-gate` | espacio de ajustes | La lista enchufable: la sección del usuario sobrescribe los valores `gate.*` de la composición y se lee una vez al cargar (`applies: restart`), visible vía `ctx.settings.describe()`. |
|
|
141
142
|
| `strict.patch.yml` | capa superpuesta | Cada puerta activa con intensidad `block` más el requisito de cobertura, en una capa de parche. |
|
|
142
143
|
| `dsh-doublecheck/invariant` | fila acompañante | Informa contradicciones de ruta de escritura propias del paquete a través del registro `invariants` del host. |
|
|
143
144
|
|
|
@@ -208,7 +209,7 @@ El CLI solo serializa el `GateState` ya asentado — nunca vuelve a ejecutar la
|
|
|
208
209
|
|
|
209
210
|
## Permisos y datos
|
|
210
211
|
|
|
211
|
-
- **Lee**: el registro de sesión (`tool/call` / `tool/result` / `tool/
|
|
212
|
+
- **Lee**: el registro de sesión (`tool/call` / `tool/result` / `tool/ptc-dispatch`, fuentes `user/message` inyectadas y los registros de veredicto ajenos `autoReview/*`) solo en proceso; el estado opcional del servicio de modo plan. Antes del renombrado de V3 el host registra los subenvíos PTC con la etiqueta predecesora `tool/code-dispatch`; ambas etiquetas se pliegan de forma idéntica.
|
|
212
213
|
- **Escribe**: `doublecheck-spec.md`, `doublecheck-report.md` y `gate-report.md` en el workspace de sesión (rutas configurables) a través de la interfaz `ctx.fs`; los eventos de sesión durables `doublecheck/state` y `doublecheck/gate`.
|
|
213
214
|
- **Llamadas a modelo**: las fases de consistencia y revisión local de la puerta (un subagente cada una por `/gate run`), la revisión adversarial opcional y el flujo de verificación de `doublecheck_report` inician ejecuciones de subagente; nada más llama a un modelo o a la red.
|
|
214
215
|
- **Nunca toca**: credenciales, variables de entorno o cualquier archivo fuera del workspace de sesión. El manifiesto del workshop declara solo `filesystem:read` y `filesystem:write`. Los informes de la puerta llevan solo conteos, ids y veredictos; los secretos reconocidos en los textos del revisor se redactan antes de almacenarlos o mostrarlos.
|
|
@@ -225,7 +226,8 @@ El CLI solo serializa el `GateState` ya asentado — nunca vuelve a ejecutar la
|
|
|
225
226
|
|
|
226
227
|
- **Escrituras durables.** `/doublecheck on\|off` → `doublecheck/state` y `/gate run` → `doublecheck/gate` necesitan la superficie de append `ignorable` del host (post-rc.6 hasta `0.1.1-rc.2`). En hosts sin esa superficie (rc.6/rc.8 y `0.1.2-alpha.1`, que eliminó el sobre — `0.1.2-rc.1` restaura el campo solo para compatibilidad de lectura de logs almacenados y aún no puede estamparlo), las escrituras se omiten y el interruptor queda en proceso.
|
|
227
228
|
0.1.2-rc.1 (adaptado el 2026-09-02): el sobre de sesión conserva su campo ignorable solo para compatibilidad de lectura de logs almacenados - Session.append aún no puede estamparlo, por lo que el comportamiento de la puerta no cambia.
|
|
228
|
-
-
|
|
229
|
+
0.1.5-alpha.1 (adaptado el 2026-09-09): el formato de sesión V3 renombra el evento durable de subenvío `tool/code-dispatch` a `tool/ptc-dispatch` (carga útil sin cambios; ambas etiquetas se pliegan de forma idéntica). Session.append sigue sin canal `ignorable`, así que las escrituras durables se omiten y el interruptor permanece en proceso - comportamiento sin cambios. El espacio de ajustes `doublecheck-gate` es una interfaz débil, resuelta al cargar (véase Limitaciones conocidas).
|
|
230
|
+
- **Interfaces opcionales.** El espacio de ajustes `doublecheck-gate` se registra solo cuando el servicio de ajustes está montado; entonces aparece en `ctx.settings.describe()` y su sección del usuario sobrescribe los valores `gate.*` de la composición en la siguiente carga (el paquete no incluye tarjeta de cliente, así que la página de plugins de la Web GUI no lo lista); la línea de modo plan de `/gate status` lee el `ctx.planMode` opcional (muestra `unknown` sin él); la revisión adversarial necesita `ctx.subagents`; la verificación necesita `workflowEngine`.
|
|
229
231
|
- **Degradación local.** `gate.review.engine: auto` degrada al revisor local cuando dsh-auto-review está ausente o no tiene registros de veredicto en esta sesión — el informe nombra la razón en lugar de inventar un veredicto.
|
|
230
232
|
- **La evidencia dsh-eval se basa en archivos.** El motor de evaluación de dsh-auto-review (`dsh-eval`) escribe sus resultados de regresión de prompt / estrés / equidad en un archivo de informe del espacio de trabajo, no en el registro de sesión. `gate.tests.evalReports.enabled` pliega ese archivo (desactivado por defecto; salta cuando está ausente) y los recuentos pliegados viajan en el registro duradero `doublecheck/gate` para que una ejecución asentada siga siendo reproducible.
|
|
231
233
|
|
package/README.hi.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/topics/dsh-plugin)
|
|
12
|
+
[](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
|
|
12
13
|
[](#)
|
|
13
14
|
[](https://github.com/PerryLink/dsh-doublecheck/actions)
|
|
14
15
|
[](https://github.com/PerryLink/dsh-doublecheck/releases)
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
|
|
26
27
|
| सतह | स्थिति |
|
|
27
28
|
|---|---|
|
|
28
|
-
| Harness | DeepSeek Harness `dsh-v0.1.
|
|
29
|
+
| Harness | DeepSeek Harness `dsh-v0.1.5-alpha.1`। 2026-09-09 को `dsh-v0.1.5-alpha.1` master checkout के विरुद्ध सत्यापित (पूर्ण द्वार श्रृंखला + प्रोफ़ाइल इंस्टॉल स्मोक); प्रकाशित `0.1.2-rc.1` पिन लाइन अभी भी समर्थित है। |
|
|
29
30
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
30
31
|
| प्लेटफ़ॉर्म | सभी (शुद्ध host; कोई नेटिव कोड नहीं, स्वयं का कोई सीधा नेटवर्क अनुरोध नहीं) |
|
|
31
32
|
| मॉडल | कोई भी (guard स्वयं कभी मॉडल नहीं बुलाता; critic और reviewer चरण harness subagent के रूप में चलते हैं) |
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
`dsh-doublecheck` दो plugin पंक्तियाँ स्थापित करता है जो एक ही टिकाऊ सत्र लॉग से पढ़ती और लागू करती हैं:
|
|
36
37
|
|
|
37
38
|
1. **`doublecheck-grill`** — आवश्यकताओं की भट्टी: बंडल की गई `grill-requirements` skill, साथ ही मॉडल-मुखी `doublecheck_skills`, `doublecheck_spec` और `doublecheck_report` उपकरण, तथा प्रति-आयाम सत्यापन वर्कफ़्लो।
|
|
38
|
-
2. **`doublecheck-guard`** — अनुशासन guard: grill द्वार, लाल/हरा साक्ष्य द्वार, प्रतिकूल समीक्षा, `/doublecheck` और `/gate` कमांड, `doublecheck
|
|
39
|
+
2. **`doublecheck-guard`** — अनुशासन guard: grill द्वार, लाल/हरा साक्ष्य द्वार, प्रतिकूल समीक्षा, `/doublecheck` और `/gate` कमांड, `doublecheck-gate` सेटिंग्स नेमस्पेस, तथा चार-चरण डिलीवरी द्वार।
|
|
39
40
|
|
|
40
41
|
दोनों मिलकर **अनुशासन लूप** लागू करते हैं — *grill → design → red → green → review → verify*:
|
|
41
42
|
|
|
@@ -137,7 +138,7 @@ dsh --profile web --dump-config | grep -E -A3 'id: doublecheck-(grill|guard)'
|
|
|
137
138
|
| `/doublecheck status\|report\|on\|off` | कमांड | स्विच, मॉड्यूल, तीव्रता, चरण तथ्य, मुड़ी हुई रिपोर्ट, और टिकाऊ on/off ओवरराइड। |
|
|
138
139
|
| `/gate status\|run\|config` | कमांड | लाइव सूची प्रगति, तय deliverable/rework रिपोर्ट, और प्रभावी कॉन्फ़िग। |
|
|
139
140
|
| `grill-requirements`, `red-green-tdd`, `delivery-review`, `delivery-proof` | skill | सभी छह लूप चरणों को कवर करने वाली बंडल अनुशासन skills। |
|
|
140
|
-
| `doublecheck
|
|
141
|
+
| `doublecheck-gate` | सेटिंग्स नेमस्पेस | प्लग करने योग्य सूची: उपयोगकर्ता अनुभाग composition के `gate.*` मानों को ओवरराइड करता है और लोड पर एक बार पढ़ा जाता है (`applies: restart`), `ctx.settings.describe()` से दृश्य। |
|
|
141
142
|
| `strict.patch.yml` | ओवरले | `block` तीव्रता पर हर द्वार चालू और कवरेज आवश्यकता, एक पैच परत में। |
|
|
142
143
|
| `dsh-doublecheck/invariant` | सहयोगी पंक्ति | host `invariants` रजिस्ट्री के माध्यम से पैकेज-स्वामित्व वाले लेखन-पथ विरोधाभासों की रिपोर्ट करता है। |
|
|
143
144
|
|
|
@@ -208,7 +209,7 @@ CLI केवल पहले से स्थापित `GateState` को
|
|
|
208
209
|
|
|
209
210
|
## अनुमतियाँ और डेटा
|
|
210
211
|
|
|
211
|
-
- **पढ़ता है**: सत्र लॉग (`tool/call` / `tool/result` / `tool/
|
|
212
|
+
- **पढ़ता है**: सत्र लॉग (`tool/call` / `tool/result` / `tool/ptc-dispatch`, इंजेक्ट किए गए `user/message` स्रोत, और बाहरी `autoReview/*` निर्णय रिकॉर्ड) केवल प्रक्रिया के भीतर; वैकल्पिक प्लान-मोड सेवा स्थिति। V3 नाम-परिवर्तन से पहले का host PTC उप-प्रेषण पूर्ववर्ती लेबल `tool/code-dispatch` से दर्ज करता है; दोनों लेबल समान रूप से फ़ोल्ड होते हैं।
|
|
212
213
|
- **लिखता है**: सत्र कार्यक्षेत्र में `doublecheck-spec.md`, `doublecheck-report.md` और `gate-report.md` (पथ कॉन्फ़िगर करने योग्य) `ctx.fs` इंटरफ़ेस के माध्यम से; टिकाऊ `doublecheck/state` और `doublecheck/gate` सत्र इवेंट।
|
|
213
214
|
- **मॉडल कॉलें**: द्वार के संगति और स्थानीय-समीक्षा चरण (प्रत्येक `/gate run` पर एक-एक subagent), वैकल्पिक प्रतिकूल समीक्षा, और `doublecheck_report` सत्यापन वर्कफ़्लो subagent रन शुरू करते हैं; इसके अलावा कुछ भी मॉडल या नेटवर्क नहीं बुलाता।
|
|
214
215
|
- **कभी नहीं छूता**: क्रेडेंशियल, पर्यावरण चर, या सत्र कार्यक्षेत्र के बाहर कोई फ़ाइल। workshop मेनिफ़ेस्ट केवल `filesystem:read` और `filesystem:write` घोषित करता है। द्वार रिपोर्टें केवल गणना, id और निर्णय रखती हैं; समीक्षक पाठों में पहचाने गए रहस्य भंडारण या प्रदर्शन से पहले संपादित (redacted) कर दिए जाते हैं।
|
|
@@ -225,7 +226,8 @@ CLI केवल पहले से स्थापित `GateState` को
|
|
|
225
226
|
|
|
226
227
|
- **टिकाऊ लेखन।** `/doublecheck on\|off` → `doublecheck/state` और `/gate run` → `doublecheck/gate` को host की `ignorable` append सतह (rc.6 के बाद से `0.1.1-rc.2` तक) चाहिए। उस सतह के बिना hosts (rc.6/rc.8 और `0.1.2-alpha.1`, जिसने envelope हटा दिया — `0.1.2-rc.1` केवल संग्रहीत-लॉग पठन संगतता के लिए फ़ील्ड बहाल करता है और अभी भी स्टैम्प नहीं कर सकता) पर लेखन छोड़ दिया जाता है और स्विच प्रक्रिया-स्थानीय रहता है।
|
|
227
228
|
0.1.2-rc.1 (2026-09-02 को अनुकूलित): सत्र लिफ़ाफ़ा अपना ignorable फ़ील्ड केवल संग्रहीत-लॉग पठन संगतता के लिए रखता है - Session.append अभी भी इसे स्टैम्प नहीं कर सकता, इसलिए गेट व्यवहार अपरिवर्तित है।
|
|
228
|
-
-
|
|
229
|
+
0.1.5-alpha.1 (2026-09-09 को अनुकूलित): सत्र प्रारूप V3 टिकाऊ उप-प्रेषण इवेंट `tool/code-dispatch` का नाम `tool/ptc-dispatch` करता है (पेलोड अपरिवर्तित; दोनों लेबल समान रूप से फ़ोल्ड होते हैं)। Session.append में अभी भी `ignorable` चैनल नहीं है, इसलिए टिकाऊ लेखन छोड़े जाते हैं और स्विच प्रक्रिया-स्थानीय रहता है - व्यवहार अपरिवर्तित। `doublecheck-gate` सेटिंग्स नेमस्पेस एक कमज़ोर इंटरफ़ेस है, जो लोड पर हल होता है (ज्ञात सीमाएँ देखें)।
|
|
230
|
+
- **वैकल्पिक इंटरफ़ेस।** `doublecheck-gate` सेटिंग्स नेमस्पेस केवल तब पंजीकृत होता है जब सेटिंग्स सेवा माउंट हो; तब यह `ctx.settings.describe()` में दिखता है और इसका उपयोगकर्ता अनुभाग अगले लोड पर composition के `gate.*` मानों को ओवरराइड करता है (पैकेज में कोई client कार्ड नहीं है, इसलिए Web GUI का plugin पृष्ठ इसे सूचीबद्ध नहीं करता); `/gate status` की प्लान-मोड पंक्ति वैकल्पिक `ctx.planMode` पढ़ती है (इसके बिना `unknown` दिखाती है); प्रतिकूल समीक्षा को `ctx.subagents` चाहिए; सत्यापन को `workflowEngine` चाहिए।
|
|
229
231
|
- **स्थानीय अवनति।** जब dsh-auto-review अनुपस्थित हो या इस सत्र में उसके कोई निर्णय रिकॉर्ड न हों, तो `gate.review.engine: auto` स्थानीय समीक्षक पर घट जाता है — रिपोर्ट निर्णय गढ़ने के बजाय कारण बताती है।
|
|
230
232
|
- **dsh-eval साक्ष्य फ़ाइल-आधारित है।** dsh-auto-review का मूल्यांकन इंजन (`dsh-eval`) अपने prompt-regression / stress / fairness परिणाम कार्यक्षेत्र रिपोर्ट फ़ाइल में लिखता है, सत्र लॉग में नहीं। `gate.tests.evalReports.enabled` उस फ़ाइल को मोड़ता है (डिफ़ॉल्ट रूप से बंद; अनुपस्थित होने पर छोड़ देता है) और मोड़ी गई गणनाएँ टिकाऊ `doublecheck/gate` रिकॉर्ड पर चलती हैं, ताकि तयशुदा रन फिर भी रीप्ले हो सके।
|
|
231
233
|
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://github.com/topics/dsh-plugin)
|
|
13
|
+
[](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
|
|
13
14
|
[](#)
|
|
14
15
|
[](https://github.com/PerryLink/dsh-doublecheck/actions)
|
|
15
16
|
[](https://github.com/PerryLink/dsh-doublecheck/releases)
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
|
|
27
28
|
| Surface | Status |
|
|
28
29
|
|---|---|
|
|
29
|
-
| Harness | DeepSeek Harness `dsh-v0.1.
|
|
30
|
+
| Harness | DeepSeek Harness `dsh-v0.1.5-alpha.1`. Verified 2026-09-09 against the `dsh-v0.1.5-alpha.1` master checkout (full gate chain + profile install smoke); the published `0.1.2-rc.1` pin line stays supported. |
|
|
30
31
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
31
32
|
| Platforms | All (pure host; no native code, no direct network requests of its own) |
|
|
32
33
|
| Model | Any (the guard itself never calls a model; the critic and reviewer phases run as harness subagents) |
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
`dsh-doublecheck` installs two plugin rows that read and enforce from the same durable session log:
|
|
37
38
|
|
|
38
39
|
1. **`doublecheck-grill`** — the requirements furnace: the bundled `grill-requirements` skill plus the model-facing `doublecheck_skills`, `doublecheck_spec`, and `doublecheck_report` tools and the per-dimension verification workflow.
|
|
39
|
-
2. **`doublecheck-guard`** — the discipline guard: the grill gate, the red/green evidence gates, the adversary review, the `/doublecheck` and `/gate` commands, the `doublecheck
|
|
40
|
+
2. **`doublecheck-guard`** — the discipline guard: the grill gate, the red/green evidence gates, the adversary review, the `/doublecheck` and `/gate` commands, the `doublecheck-gate` settings namespace, and the four-phase delivery gate.
|
|
40
41
|
|
|
41
42
|
Together they enforce the **discipline loop** — *grill → design → red → green → review → verify*:
|
|
42
43
|
|
|
@@ -138,7 +139,7 @@ Misconfiguration fails loud at load: invalid regexes, empty or duplicated name l
|
|
|
138
139
|
| `/doublecheck status\|report\|on\|off` | command | Switch, modules, intensity, stage facts, folded report, and the durable on/off override. |
|
|
139
140
|
| `/gate status\|run\|config` | command | Live checklist progress, the settled deliverable/rework report, and the effective config. |
|
|
140
141
|
| `grill-requirements`, `red-green-tdd`, `delivery-review`, `delivery-proof` | skill | Bundled discipline skills covering all six loop stages. |
|
|
141
|
-
| `doublecheck
|
|
142
|
+
| `doublecheck-gate` | settings namespace | The pluggable checklist: the user section overrides the composition `gate.*` values and is read once at load (`applies: restart`), visible through `ctx.settings.describe()`. |
|
|
142
143
|
| `strict.patch.yml` | overlay | Every gate on at `block` intensity plus the coverage requirement, in one patch layer. |
|
|
143
144
|
| `dsh-doublecheck/invariant` | companion row | Reports package-owned write-path contradictions through the host `invariants` registry. |
|
|
144
145
|
|
|
@@ -209,7 +210,7 @@ The CLI only serializes the already-settled `GateState` — it never re-runs the
|
|
|
209
210
|
|
|
210
211
|
## Permissions & data
|
|
211
212
|
|
|
212
|
-
- **Reads**: the session log (`tool/call` / `tool/result` / `tool/
|
|
213
|
+
- **Reads**: the session log (`tool/call` / `tool/result` / `tool/ptc-dispatch`, injected `user/message` sources, and the foreign `autoReview/*` verdict records) in-process only; the optional plan-mode service state. PTC sub-dispatches carry the predecessor `tool/code-dispatch` label on hosts before the V3 rename; both labels fold identically.
|
|
213
214
|
- **Writes**: `doublecheck-spec.md`, `doublecheck-report.md`, `gate-report.md`, and `gate-report.json` in the session workspace (paths configurable) through the `ctx.fs` seam; the durable `doublecheck/state` and `doublecheck/gate` session events.
|
|
214
215
|
- **Model calls**: the gate's consistency and local-review phases (one subagent each per `/gate run`), the optional adversary review, and the `doublecheck_report` verification workflow start subagent runs; nothing else calls a model or the network.
|
|
215
216
|
- **Never touched**: credentials, environment variables, or any file outside the session workspace. The workshop manifest declares `filesystem:read` and `filesystem:write` only. Gate reports carry counts, ids, and verdicts only; recognized secrets in reviewer texts are redacted before storage or display.
|
|
@@ -226,7 +227,8 @@ The CLI only serializes the already-settled `GateState` — it never re-runs the
|
|
|
226
227
|
|
|
227
228
|
- **Durable writes.** `/doublecheck on\|off` → `doublecheck/state` and `/gate run` → `doublecheck/gate` ride the host's `ignorable` append surface (post-rc.6 through `0.1.1-rc.2`). On hosts without that surface (rc.6/rc.8, and `0.1.2-alpha.1`, which removed the envelope — `0.1.2-rc.1` restores the field for stored-log read compatibility only and still cannot stamp it), the writes are skipped and the switch stays process-local.
|
|
228
229
|
0.1.2-rc.1 (adapted 2026-09-02): the session envelope keeps its ignorable field for stored-log read compatibility only - Session.append still cannot stamp it, so audit-gate behavior is unchanged.
|
|
229
|
-
-
|
|
230
|
+
0.1.5-alpha.1 (adapted 2026-09-09): session format V3 renames the durable sub-dispatch event `tool/code-dispatch` to `tool/ptc-dispatch` (payload unchanged; both labels fold identically). Session.append still exposes no `ignorable` channel, so durable writes stay skipped and the switch stays process-local - behavior unchanged. The `doublecheck-gate` settings namespace is a weak seam resolved at load (see Known limitations).
|
|
231
|
+
- **Optional seams.** The `doublecheck-gate` settings namespace registers only when the settings service is mounted; it then appears in `ctx.settings.describe()`, and its user section overrides the composition `gate.*` values on the next load. The package ships no client card, so the shipped Web GUI plugin page does not list it. The `/gate status` plan-mode line reads the optional `ctx.planMode` (shows `unknown` without it); the adversary review needs `ctx.subagents`; verification needs `workflowEngine`.
|
|
230
232
|
- **Local degrade.** `gate.review.engine: auto` degrades to the local reviewer when dsh-auto-review is absent or has no verdict records this session — the report names the reason instead of inventing a verdict.
|
|
231
233
|
- **dsh-eval evidence is file-based.** The dsh-auto-review eval engine (`dsh-eval`) writes its prompt-regression / stress / fairness results to a workspace report file, not the session log. `gate.tests.evalReports.enabled` folds that file (off by default; skips when absent) and the folded counts ride the durable `doublecheck/gate` record so a settled run still replays.
|
|
232
234
|
|
package/README.pt.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/topics/dsh-plugin)
|
|
12
|
+
[](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
|
|
12
13
|
[](#)
|
|
13
14
|
[](https://github.com/PerryLink/dsh-doublecheck/actions)
|
|
14
15
|
[](https://github.com/PerryLink/dsh-doublecheck/releases)
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
|
|
26
27
|
| Superfície | Status |
|
|
27
28
|
|---|---|
|
|
28
|
-
| Harness | DeepSeek Harness `dsh-v0.1.
|
|
29
|
+
| Harness | DeepSeek Harness `dsh-v0.1.5-alpha.1`. Verificado em 2026-09-09 contra o checkout master `dsh-v0.1.5-alpha.1` (cadeia completa de portões + smoke de instalação do perfil); a linha publicada `0.1.2-rc.1` continua suportada. |
|
|
29
30
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
30
31
|
| Plataformas | Todas (host puro; sem código nativo, sem requisições de rede diretas próprias) |
|
|
31
32
|
| Modelo | Qualquer (o guard nunca chama um modelo; as fases de crítico e revisor rodam como subagentes do harness) |
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
`dsh-doublecheck` instala duas linhas de plugin que leem e aplicam a partir do mesmo registro de sessão durável:
|
|
36
37
|
|
|
37
38
|
1. **`doublecheck-grill`** — o forno de requisitos: a skill empacotada `grill-requirements` mais as ferramentas voltadas ao modelo `doublecheck_skills`, `doublecheck_spec` e `doublecheck_report`, e o fluxo de verificação por dimensão.
|
|
38
|
-
2. **`doublecheck-guard`** — o guard de disciplina: o portão grill, os portões de evidência vermelho/verde, a revisão adversarial, os comandos `/doublecheck` e `/gate`, o namespace de configurações `doublecheck
|
|
39
|
+
2. **`doublecheck-guard`** — o guard de disciplina: o portão grill, os portões de evidência vermelho/verde, a revisão adversarial, os comandos `/doublecheck` e `/gate`, o namespace de configurações `doublecheck-gate` e o portão de entrega de quatro fases.
|
|
39
40
|
|
|
40
41
|
Juntos impõem o **ciclo de disciplina** — *grill → design → red → green → review → verify*:
|
|
41
42
|
|
|
@@ -137,7 +138,7 @@ A má configuração falha em voz alta ao carregar: regex inválidas, listas de
|
|
|
137
138
|
| `/doublecheck status\|report\|on\|off` | comando | Interruptor, módulos, intensidade, fatos de etapa, relatório dobrado e a sobrescrita durável on/off. |
|
|
138
139
|
| `/gate status\|run\|config` | comando | Progresso da lista em tempo real, o relatório entregável/retrabalho assentado e a configuração efetiva. |
|
|
139
140
|
| `grill-requirements`, `red-green-tdd`, `delivery-review`, `delivery-proof` | skill | Skills de disciplina empacotadas que cobrem as seis etapas do ciclo. |
|
|
140
|
-
| `doublecheck
|
|
141
|
+
| `doublecheck-gate` | namespace de configurações | A lista plugável: a seção do usuário substitui os valores `gate.*` da composição e é lida uma vez ao carregar (`applies: restart`), visível via `ctx.settings.describe()`. |
|
|
141
142
|
| `strict.patch.yml` | camada de sobreposição | Cada portão ativo com intensidade `block` mais o requisito de cobertura, em uma camada de patch. |
|
|
142
143
|
| `dsh-doublecheck/invariant` | linha acompanhante | Reporta contradições de caminho de escrita próprias do pacote por meio do registro `invariants` do host. |
|
|
143
144
|
|
|
@@ -208,7 +209,7 @@ O CLI apenas serializa o `GateState` já assentado — nunca reexecuta a porta d
|
|
|
208
209
|
|
|
209
210
|
## Permissões e dados
|
|
210
211
|
|
|
211
|
-
- **Lê**: o registro de sessão (`tool/call` / `tool/result` / `tool/
|
|
212
|
+
- **Lê**: o registro de sessão (`tool/call` / `tool/result` / `tool/ptc-dispatch`, fontes `user/message` injetadas e os registros de veredicto alheios `autoReview/*`) somente em processo; o estado opcional do serviço de modo plano. Antes da renomeação da V3, o host registra os subenvios PTC com o rótulo predecessor `tool/code-dispatch`; os dois rótulos são dobrados de forma idêntica.
|
|
212
213
|
- **Escreve**: `doublecheck-spec.md`, `doublecheck-report.md` e `gate-report.md` no workspace da sessão (caminhos configuráveis) por meio da interface `ctx.fs`; os eventos de sessão duráveis `doublecheck/state` e `doublecheck/gate`.
|
|
213
214
|
- **Chamadas a modelo**: as fases de consistência e revisão local do portão (um subagente cada por `/gate run`), a revisão adversarial opcional e o fluxo de verificação de `doublecheck_report` iniciam execuções de subagente; nada mais chama um modelo ou a rede.
|
|
214
215
|
- **Nunca toca**: credenciais, variáveis de ambiente ou qualquer arquivo fora do workspace da sessão. O manifesto do workshop declara apenas `filesystem:read` e `filesystem:write`. Os relatórios do portão carregam apenas contagens, ids e veredictos; segredos reconhecidos nos textos do revisor são redigidos antes de armazenar ou exibir.
|
|
@@ -225,7 +226,8 @@ O CLI apenas serializa o `GateState` já assentado — nunca reexecuta a porta d
|
|
|
225
226
|
|
|
226
227
|
- **Escritas duráveis.** `/doublecheck on\|off` → `doublecheck/state` e `/gate run` → `doublecheck/gate` precisam da superfície de append `ignorable` do host (pós-rc.6 até `0.1.1-rc.2`). Em hosts sem essa superfície (rc.6/rc.8 e `0.1.2-alpha.1`, que removeu o envelope — `0.1.2-rc.1` restaura o campo apenas para compatibilidade de leitura de logs armazenados e ainda não consegue estampá-lo), as escritas são omitidas e o interruptor permanece em processo.
|
|
227
228
|
0.1.2-rc.1 (adaptado em 2026-09-02): o envelope de sessão mantém seu campo ignorable apenas para compatibilidade de leitura de logs armazenados - o Session.append ainda não consegue estampá-lo, então o comportamento da porta não muda.
|
|
228
|
-
-
|
|
229
|
+
0.1.5-alpha.1 (adaptado em 2026-09-09): o formato de sessão V3 renomeia o evento durável de subenvio `tool/code-dispatch` para `tool/ptc-dispatch` (carga útil inalterada; os dois rótulos são dobrados de forma idêntica). O Session.append continua sem canal `ignorable`, então as escritas duráveis são omitidas e o interruptor permanece em processo - comportamento inalterado. O namespace de configurações `doublecheck-gate` é uma interface fraca, resolvida ao carregar (ver Limitações conhecidas).
|
|
230
|
+
- **Interfaces opcionais.** O namespace de configurações `doublecheck-gate` é registrado apenas quando o serviço de configurações está montado; então aparece em `ctx.settings.describe()` e sua seção do usuário substitui os valores `gate.*` da composição no próximo carregamento (o pacote não inclui cartão de cliente, então a página de plugins da Web GUI não o lista); a linha de modo plano de `/gate status` lê o `ctx.planMode` opcional (mostra `unknown` sem ele); a revisão adversarial precisa de `ctx.subagents`; a verificação precisa de `workflowEngine`.
|
|
229
231
|
- **Degradação local.** `gate.review.engine: auto` degrada para o revisor local quando o dsh-auto-review está ausente ou não tem registros de veredicto nesta sessão — o relatório nomeia a razão em vez de inventar um veredicto.
|
|
230
232
|
- **A evidência dsh-eval é baseada em arquivos.** O motor de avaliação do dsh-auto-review (`dsh-eval`) grava seus resultados de regressão de prompt / estresse / equidade em um arquivo de relatório do espaço de trabalho, não no registro de sessão. `gate.tests.evalReports.enabled` dobra esse arquivo (desativado por padrão; pula quando ausente) e as contagens dobradas viajam no registro durável `doublecheck/gate` para que uma execução assentada ainda seja reproduzível.
|
|
231
233
|
|
package/README.zh.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/topics/dsh-plugin)
|
|
12
|
+
[](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
|
|
12
13
|
[](#)
|
|
13
14
|
[](https://github.com/PerryLink/dsh-doublecheck/actions)
|
|
14
15
|
[](https://github.com/PerryLink/dsh-doublecheck/releases)
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
|
|
26
27
|
| 方面 | 状态 |
|
|
27
28
|
|---|---|
|
|
28
|
-
| Harness | DeepSeek Harness `dsh-v0.1.
|
|
29
|
+
| Harness | DeepSeek Harness `dsh-v0.1.5-alpha.1`。已于 2026-09-09 对照 `dsh-v0.1.5-alpha.1` master checkout 核验(完整门禁链 + profile 安装冒烟);已发布的 `0.1.2-rc.1` 钉号线仍受支持。 |
|
|
29
30
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
30
31
|
| 平台 | 全部(纯宿主;无原生代码,自身无直接网络请求) |
|
|
31
32
|
| 模型 | 任意(守卫本身从不调用模型;评审与批评阶段作为宿主 subagent 运行) |
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
`dsh-doublecheck` 安装两个插件行,它们读取并执行同一份持久会话日志:
|
|
36
37
|
|
|
37
38
|
1. **`doublecheck-grill`** —— 需求熔炉:内置的 `grill-requirements` 技能,加上面向模型的 `doublecheck_skills`、`doublecheck_spec`、`doublecheck_report` 工具,以及按维度执行的验证工作流。
|
|
38
|
-
2. **`doublecheck-guard`** —— 纪律守卫:grill 门禁、红/绿证据门禁、对抗式评审、`/doublecheck` 与 `/gate` 命令、`doublecheck
|
|
39
|
+
2. **`doublecheck-guard`** —— 纪律守卫:grill 门禁、红/绿证据门禁、对抗式评审、`/doublecheck` 与 `/gate` 命令、`doublecheck-gate` 设置命名空间,以及四阶段交付门禁。
|
|
39
40
|
|
|
40
41
|
两者共同执行**纪律闭环** —— *grill → design → red → green → review → verify*:
|
|
41
42
|
|
|
@@ -137,7 +138,7 @@ dsh --profile web --dump-config | grep -E -A3 'id: doublecheck-(grill|guard)'
|
|
|
137
138
|
| `/doublecheck status\|report\|on\|off` | 命令 | 开关、模块、强度、阶段事实、折叠报告,以及持久的开/关覆盖。 |
|
|
138
139
|
| `/gate status\|run\|config` | 命令 | 实时清单进度、已确定的可交付/返工报告,以及生效配置。 |
|
|
139
140
|
| `grill-requirements`、`red-green-tdd`、`delivery-review`、`delivery-proof` | 技能 | 覆盖全部六个闭环阶段的内置纪律技能。 |
|
|
140
|
-
| `doublecheck
|
|
141
|
+
| `doublecheck-gate` | 设置命名空间 | 可插拔清单:用户段覆盖 composition 的 `gate.*` 值,在加载时读取一次(`applies: restart`),经 `ctx.settings.describe()` 可见。 |
|
|
141
142
|
| `strict.patch.yml` | 覆盖层 | 一个补丁层内以 `block` 强度开启每个门禁并启用覆盖率要求。 |
|
|
142
143
|
| `dsh-doublecheck/invariant` | 伴生行 | 通过宿主 `invariants` 注册表报告包自有写路径矛盾。 |
|
|
143
144
|
|
|
@@ -208,7 +209,7 @@ CLI 只序列化已定的 `GateState` —— 它从不重新运行四阶段门
|
|
|
208
209
|
|
|
209
210
|
## 权限与数据
|
|
210
211
|
|
|
211
|
-
- **读取**:仅进程内读取会话日志(`tool/call` / `tool/result` / `tool/
|
|
212
|
+
- **读取**:仅进程内读取会话日志(`tool/call` / `tool/result` / `tool/ptc-dispatch`、注入的 `user/message` 来源,以及外部的 `autoReview/*` 裁决记录);可选的计划模式服务状态。V3 改名前的宿主用旧标签 `tool/code-dispatch` 记录 PTC 子调用;两个标签折叠结果完全一致。
|
|
212
213
|
- **写入**:会话工作区中的 `doublecheck-spec.md`、`doublecheck-report.md` 和 `gate-report.md`(路径可配置),通过 `ctx.fs` 接口;持久的 `doublecheck/state` 和 `doublecheck/gate` 会话事件。
|
|
213
214
|
- **模型调用**:门禁的一致性阶段和本地评审阶段(每次 `/gate run` 各一个 subagent)、可选的对抗式评审,以及 `doublecheck_report` 验证工作流会启动 subagent 运行;除此之外不调用模型或网络。
|
|
214
215
|
- **绝不触碰**:凭据、环境变量,或会话工作区之外的任何文件。workshop 清单只声明 `filesystem:read` 和 `filesystem:write`。门禁报告只携带计数、id 和裁决;评审文本中被识别的机密在存储或显示之前会被脱敏。
|
|
@@ -225,7 +226,8 @@ CLI 只序列化已定的 `GateState` —— 它从不重新运行四阶段门
|
|
|
225
226
|
|
|
226
227
|
- **持久写入。** `/doublecheck on\|off` → `doublecheck/state` 与 `/gate run` → `doublecheck/gate` 需要宿主的 `ignorable` 追加接口(rc.6 之后至 `0.1.1-rc.2`)。在无此接口的宿主上(rc.6/rc.8,以及移除该信封的 `0.1.2-alpha.1`——`0.1.2-rc.1` 仅恢复存量日志读取兼容字段、仍无法盖章),写入被跳过、开关保持进程内状态。
|
|
227
228
|
0.1.2-rc.1(2026-09-02 已适配):会话信封保留 ignorable 字段但仅用于存量日志读取兼容——Session.append 仍无法盖章,门控行为不变。
|
|
228
|
-
-
|
|
229
|
+
0.1.5-alpha.1(2026-09-09 已适配):会话格式 V3 把持久子调用事件 `tool/code-dispatch` 改名为 `tool/ptc-dispatch`(载荷不变;两个标签折叠结果一致)。Session.append 仍无 `ignorable` 写入通道,写入继续跳过、开关保持进程内——行为不变。`doublecheck-gate` 设置命名空间是弱接口,在加载时解析(见「已知限制」)。
|
|
230
|
+
- **可选接口。** `doublecheck-gate` 设置命名空间仅在挂载设置服务时注册;注册后出现在 `ctx.settings.describe()` 中,其用户段在下次加载时覆盖 composition 的 `gate.*` 值;本包不带 client 卡片,故 Web GUI 插件页不会单列它。`/gate status` 的计划模式行读取可选的 `ctx.planMode`(没有则显示 `unknown`);对抗式评审需要 `ctx.subagents`;验证需要 `workflowEngine`。
|
|
229
231
|
- **本地降级。** 当 dsh-auto-review 缺失或本会话没有裁决记录时,`gate.review.engine: auto` 会降级到本地评审者——报告会写明原因,而不是捏造裁决。
|
|
230
232
|
- **dsh-eval 证据基于文件。** dsh-auto-review 评测引擎(`dsh-eval`)把其 prompt 回归 / 压测 / 公平性结果写入工作区报告文件,而非会话日志。`gate.tests.evalReports.enabled` 折叠该文件(默认关闭;缺失时跳过),折叠出的计数随持久 `doublecheck/gate` 记录保存,使已定的运行仍可重放。
|
|
231
233
|
|
package/lib/domain/evidence.d.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* Test-run evidence classification for the red/green gates.
|
|
3
3
|
*
|
|
4
4
|
* The durable session log is the only source of truth: a shell tool call
|
|
5
|
-
* (`bash` / `pwsh`, including
|
|
6
|
-
*
|
|
5
|
+
* (`bash` / `pwsh`, including PTC sub-dispatches) whose command matches the
|
|
6
|
+
* configured test patterns is a test run, and its rendered result text
|
|
7
7
|
* carries the exit facts (`[exit code: N]`, timeout, signal, sandbox-denial
|
|
8
8
|
* markers). A failing run is red evidence; a passing run is green evidence.
|
|
9
9
|
*
|
|
10
10
|
* @module dsh-doublecheck/domain/evidence
|
|
11
11
|
*/
|
|
12
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
12
13
|
/** Compiled red/green evidence detection knobs. */
|
|
13
14
|
export interface TestRunDetection {
|
|
14
15
|
/** Tool names that can execute shell commands. */
|
|
@@ -45,9 +46,41 @@ export interface DetectionConfig {
|
|
|
45
46
|
export declare function compileDetection(config: DetectionConfig): TestRunDetection;
|
|
46
47
|
/** The detection record with every list empty: test-run evidence is ignored. */
|
|
47
48
|
export declare function emptyDetection(): TestRunDetection;
|
|
49
|
+
/** The rendered result blocks of a settled sub-dispatch (structural: only the fields the evidence folds read). */
|
|
50
|
+
export type PtcContent = ReadonlyArray<{
|
|
51
|
+
type?: unknown;
|
|
52
|
+
text?: unknown;
|
|
53
|
+
content?: unknown;
|
|
54
|
+
}>;
|
|
55
|
+
/** One settled PTC sub-dispatch payload, whatever generation names the event. */
|
|
56
|
+
export interface PtcSettle {
|
|
57
|
+
/** The dispatched tool name (`bash` / `pwsh` / `edit` / `write` …). */
|
|
58
|
+
name: string;
|
|
59
|
+
/** The dispatch arguments: a normalized record on the current line, a JSON string on the predecessor. */
|
|
60
|
+
arguments: unknown;
|
|
61
|
+
/** Whether the sub-dispatch failed at the infrastructure level. */
|
|
62
|
+
isError: boolean;
|
|
63
|
+
/** The rendered model-facing result blocks. */
|
|
64
|
+
content: PtcContent;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalize one settled PTC sub-dispatch event, across the event-vocabulary
|
|
68
|
+
* rename at the session-format V2→V3 edge.
|
|
69
|
+
*
|
|
70
|
+
* The current line names the settled sub-dispatch `tool/ptc-dispatch` (the
|
|
71
|
+
* host's V2→V3 migration renames the predecessor `tool/code-dispatch`, keeping
|
|
72
|
+
* the payload values), so a stored V2 log arrives under the new label. A host
|
|
73
|
+
* on the older release line still emits the predecessor label, which is outside
|
|
74
|
+
* this line's `SessionEventMap`; it is matched structurally instead of as a
|
|
75
|
+
* switch case, so the fold never depends on which generation wrote the log.
|
|
76
|
+
*
|
|
77
|
+
* @param event - one committed session event.
|
|
78
|
+
* @returns the settled payload, or `undefined` when the event is not a settled sub-dispatch.
|
|
79
|
+
*/
|
|
80
|
+
export declare function ptcSettle(event: SessionEvent): PtcSettle | undefined;
|
|
48
81
|
/**
|
|
49
82
|
* Parse a raw tool-call `arguments` value (a JSON string from the model, or an
|
|
50
|
-
* already-normalized object from a
|
|
83
|
+
* already-normalized object from a PTC sub-dispatch) into a plain record.
|
|
51
84
|
* @param raw - the raw arguments value from the durable event.
|
|
52
85
|
* @returns the parsed record, or `undefined` when the string is not valid JSON.
|
|
53
86
|
*/
|
package/lib/domain/evidence.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Test-run evidence classification for the red/green gates.
|
|
3
3
|
*
|
|
4
4
|
* The durable session log is the only source of truth: a shell tool call
|
|
5
|
-
* (`bash` / `pwsh`, including
|
|
6
|
-
*
|
|
5
|
+
* (`bash` / `pwsh`, including PTC sub-dispatches) whose command matches the
|
|
6
|
+
* configured test patterns is a test run, and its rendered result text
|
|
7
7
|
* carries the exit facts (`[exit code: N]`, timeout, signal, sandbox-denial
|
|
8
8
|
* markers). A failing run is red evidence; a passing run is green evidence.
|
|
9
9
|
*
|
|
@@ -56,9 +56,44 @@ export function emptyDetection() {
|
|
|
56
56
|
testFilePatterns: [],
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Normalize one settled PTC sub-dispatch event, across the event-vocabulary
|
|
61
|
+
* rename at the session-format V2→V3 edge.
|
|
62
|
+
*
|
|
63
|
+
* The current line names the settled sub-dispatch `tool/ptc-dispatch` (the
|
|
64
|
+
* host's V2→V3 migration renames the predecessor `tool/code-dispatch`, keeping
|
|
65
|
+
* the payload values), so a stored V2 log arrives under the new label. A host
|
|
66
|
+
* on the older release line still emits the predecessor label, which is outside
|
|
67
|
+
* this line's `SessionEventMap`; it is matched structurally instead of as a
|
|
68
|
+
* switch case, so the fold never depends on which generation wrote the log.
|
|
69
|
+
*
|
|
70
|
+
* @param event - one committed session event.
|
|
71
|
+
* @returns the settled payload, or `undefined` when the event is not a settled sub-dispatch.
|
|
72
|
+
*/
|
|
73
|
+
export function ptcSettle(event) {
|
|
74
|
+
if (event.type === 'tool/ptc-dispatch') {
|
|
75
|
+
return {
|
|
76
|
+
name: event.data.name,
|
|
77
|
+
arguments: event.data.arguments,
|
|
78
|
+
isError: event.data.isError,
|
|
79
|
+
content: event.data.content,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (event.type !== 'tool/code-dispatch')
|
|
83
|
+
return undefined;
|
|
84
|
+
const legacy = event.data;
|
|
85
|
+
if (legacy === null || legacy === undefined || typeof legacy.name !== 'string')
|
|
86
|
+
return undefined;
|
|
87
|
+
return {
|
|
88
|
+
name: legacy.name,
|
|
89
|
+
arguments: legacy.arguments,
|
|
90
|
+
isError: legacy.isError === true,
|
|
91
|
+
content: Array.isArray(legacy.content) ? legacy.content : [],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
59
94
|
/**
|
|
60
95
|
* Parse a raw tool-call `arguments` value (a JSON string from the model, or an
|
|
61
|
-
* already-normalized object from a
|
|
96
|
+
* already-normalized object from a PTC sub-dispatch) into a plain record.
|
|
62
97
|
* @param raw - the raw arguments value from the durable event.
|
|
63
98
|
* @returns the parsed record, or `undefined` when the string is not valid JSON.
|
|
64
99
|
*/
|
package/lib/domain/gate.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*
|
|
26
26
|
* @module dsh-doublecheck/domain/gate
|
|
27
27
|
*/
|
|
28
|
-
import { isTestCommand, joinTextBlocks, parseRawArguments, shellCommand, testOutcome, } from "./evidence.js";
|
|
28
|
+
import { isTestCommand, joinTextBlocks, parseRawArguments, ptcSettle, shellCommand, testOutcome, } from "./evidence.js";
|
|
29
29
|
import { SPEC_TOOL_NAME } from "./stages.js";
|
|
30
30
|
import { SPEC_FIELD_NAMES } from "./vocabulary.js";
|
|
31
31
|
/** All gate phases in checklist order. */
|
|
@@ -110,6 +110,19 @@ export function foldTestEvidence(events, detection, coverageRegex) {
|
|
|
110
110
|
const evidence = { failed: 0, passed: 0, lastOutcome: 'none', failingAfterGreen: 0, coveragePct: null };
|
|
111
111
|
const pendingTests = new Map();
|
|
112
112
|
for (const event of events) {
|
|
113
|
+
// A settled PTC sub-dispatch is a test run exactly like a native shell
|
|
114
|
+
// call; the normalizer accepts both event generations, so the evidence
|
|
115
|
+
// does not depend on which one wrote the log.
|
|
116
|
+
const settle = ptcSettle(event);
|
|
117
|
+
if (settle !== undefined) {
|
|
118
|
+
const args = parseRawArguments(settle.arguments);
|
|
119
|
+
const command = shellCommand(settle.name, args, detection);
|
|
120
|
+
if (command !== undefined && isTestCommand(command, detection)) {
|
|
121
|
+
const text = joinTextBlocks(settle.content);
|
|
122
|
+
foldTestEvidenceOutcome(evidence, testOutcome(text, settle.isError), text, coverageRegex);
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
113
126
|
switch (event.type) {
|
|
114
127
|
case 'tool/call': {
|
|
115
128
|
const args = parseRawArguments(event.data.arguments);
|
|
@@ -127,15 +140,6 @@ export function foldTestEvidence(events, detection, coverageRegex) {
|
|
|
127
140
|
foldTestEvidenceOutcome(evidence, testOutcome(text, event.data.error !== undefined), text, coverageRegex);
|
|
128
141
|
break;
|
|
129
142
|
}
|
|
130
|
-
case 'tool/code-dispatch': {
|
|
131
|
-
const args = parseRawArguments(event.data.arguments);
|
|
132
|
-
const command = shellCommand(event.data.name, args, detection);
|
|
133
|
-
if (command !== undefined && isTestCommand(command, detection)) {
|
|
134
|
-
const text = joinTextBlocks(event.data.content);
|
|
135
|
-
foldTestEvidenceOutcome(evidence, testOutcome(text, event.data.isError), text, coverageRegex);
|
|
136
|
-
}
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
return evidence;
|
package/lib/domain/projection.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module dsh-doublecheck/domain/projection
|
|
12
12
|
*/
|
|
13
|
-
import { isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, shellCommand, testOutcome, } from "./evidence.js";
|
|
13
|
+
import { isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, ptcSettle, shellCommand, testOutcome, } from "./evidence.js";
|
|
14
14
|
import { SPEC_TOOL_NAME } from "./stages.js";
|
|
15
15
|
import { countRedChecks } from "./gate.js";
|
|
16
16
|
/** State for the empty log. */
|
|
@@ -38,6 +38,22 @@ export function emptyDoublecheckState() {
|
|
|
38
38
|
* discipline fact.
|
|
39
39
|
*/
|
|
40
40
|
export function applyDoublecheckEvent(state, event, detection) {
|
|
41
|
+
// A settled PTC sub-dispatch is a discipline fact exactly like a native
|
|
42
|
+
// call. The normalizer accepts both event generations, so the projection
|
|
43
|
+
// does not depend on which one wrote the log.
|
|
44
|
+
const settle = ptcSettle(event);
|
|
45
|
+
if (settle !== undefined) {
|
|
46
|
+
const args = parseRawArguments(settle.arguments);
|
|
47
|
+
const command = shellCommand(settle.name, args, detection);
|
|
48
|
+
if (command !== undefined && isTestCommand(command, detection)) {
|
|
49
|
+
const outcome = testOutcome(joinTextBlocks(settle.content), settle.isError);
|
|
50
|
+
if (outcome === 'fail')
|
|
51
|
+
return { ...state, color: 'red', stage: 'red' };
|
|
52
|
+
if (outcome === 'pass')
|
|
53
|
+
return { ...state, color: 'green', stage: 'green' };
|
|
54
|
+
}
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
41
57
|
switch (event.type) {
|
|
42
58
|
case 'tool/call': {
|
|
43
59
|
const args = parseRawArguments(event.data.arguments);
|
|
@@ -82,18 +98,6 @@ export function applyDoublecheckEvent(state, event, detection) {
|
|
|
82
98
|
}
|
|
83
99
|
return state;
|
|
84
100
|
}
|
|
85
|
-
case 'tool/code-dispatch': {
|
|
86
|
-
const args = parseRawArguments(event.data.arguments);
|
|
87
|
-
const command = shellCommand(event.data.name, args, detection);
|
|
88
|
-
if (command !== undefined && isTestCommand(command, detection)) {
|
|
89
|
-
const outcome = testOutcome(joinTextBlocks(event.data.content), event.data.isError);
|
|
90
|
-
if (outcome === 'fail')
|
|
91
|
-
return { ...state, color: 'red', stage: 'red' };
|
|
92
|
-
if (outcome === 'pass')
|
|
93
|
-
return { ...state, color: 'green', stage: 'green' };
|
|
94
|
-
}
|
|
95
|
-
return state;
|
|
96
|
-
}
|
|
97
101
|
case 'user/message': {
|
|
98
102
|
const source = event.data.source;
|
|
99
103
|
if (source.kind === 'doublecheck-review' && !state.reviewed) {
|
package/lib/domain/report.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module dsh-doublecheck/domain/report
|
|
13
13
|
*/
|
|
14
|
-
import { isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, shellCommand, testOutcome, } from "./evidence.js";
|
|
14
|
+
import { isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, ptcSettle, shellCommand, testOutcome, } from "./evidence.js";
|
|
15
15
|
import { SPEC_TOOL_NAME } from "./stages.js";
|
|
16
16
|
import { VERIFY_DIMENSIONS, } from "./vocabulary.js";
|
|
17
17
|
/** Maximum timeline rows rendered into the report document. */
|
|
@@ -32,6 +32,23 @@ export function foldReportFacts(events, detection) {
|
|
|
32
32
|
/** Spec calls awaiting a result: only a successful pair commits the spec. */
|
|
33
33
|
const pendingSpecs = new Map();
|
|
34
34
|
for (const event of events) {
|
|
35
|
+
// A settled PTC sub-dispatch runs through the same pre-execute policy
|
|
36
|
+
// gates, so a dispatched test run or edit is a real delivery fact and must
|
|
37
|
+
// count exactly like a native call. The normalizer accepts both event
|
|
38
|
+
// generations, so the fold does not depend on which one wrote the log.
|
|
39
|
+
const settle = ptcSettle(event);
|
|
40
|
+
if (settle !== undefined) {
|
|
41
|
+
const args = parseRawArguments(settle.arguments);
|
|
42
|
+
const command = shellCommand(settle.name, args, detection);
|
|
43
|
+
if (command !== undefined && isTestCommand(command, detection)) {
|
|
44
|
+
foldTestRun(facts, command, testOutcome(joinTextBlocks(settle.content), settle.isError));
|
|
45
|
+
}
|
|
46
|
+
const path = mutationTargetPath(settle.name, args, detection);
|
|
47
|
+
if (path !== undefined && !isTestFilePath(path, detection)) {
|
|
48
|
+
facts.edits += 1;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
35
52
|
switch (event.type) {
|
|
36
53
|
case 'tool/call': {
|
|
37
54
|
const args = parseRawArguments(event.data.arguments);
|
|
@@ -68,21 +85,6 @@ export function foldReportFacts(events, detection) {
|
|
|
68
85
|
foldTestRun(facts, command, testOutcome(joinTextBlocks(event.data.message.content), event.data.error !== undefined));
|
|
69
86
|
break;
|
|
70
87
|
}
|
|
71
|
-
case 'tool/code-dispatch': {
|
|
72
|
-
const args = parseRawArguments(event.data.arguments);
|
|
73
|
-
const command = shellCommand(event.data.name, args, detection);
|
|
74
|
-
if (command !== undefined && isTestCommand(command, detection)) {
|
|
75
|
-
foldTestRun(facts, command, testOutcome(joinTextBlocks(event.data.content), event.data.isError));
|
|
76
|
-
}
|
|
77
|
-
// Code Mode dispatches run through the same pre-execute policy gates,
|
|
78
|
-
// so a dispatched edit is a real implementation edit and must count
|
|
79
|
-
// toward the report exactly like a native call.
|
|
80
|
-
const path = mutationTargetPath(event.data.name, args, detection);
|
|
81
|
-
if (path !== undefined && !isTestFilePath(path, detection)) {
|
|
82
|
-
facts.edits += 1;
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
88
|
case 'user/message': {
|
|
87
89
|
const source = event.data.source;
|
|
88
90
|
if (source.kind !== 'doublecheck-review')
|
package/lib/domain/stages.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module dsh-doublecheck/domain/stages
|
|
16
16
|
*/
|
|
17
|
-
import { emptyDetection, isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, shellCommand, testOutcome, } from "./evidence.js";
|
|
17
|
+
import { emptyDetection, isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, ptcSettle, shellCommand, testOutcome, } from "./evidence.js";
|
|
18
18
|
/** All discipline stages in order. */
|
|
19
19
|
export const DISCIPLINE_STAGES = [
|
|
20
20
|
'grill', 'design', 'red', 'green', 'review', 'verify',
|
|
@@ -82,6 +82,24 @@ export function foldDisciplineRange(state, events, start, detection) {
|
|
|
82
82
|
const event = events[index];
|
|
83
83
|
if (event === undefined)
|
|
84
84
|
continue;
|
|
85
|
+
// A settled PTC sub-dispatch runs through the same pre-execute policy
|
|
86
|
+
// gates, so a dispatched test run or edit is a real discipline fact and
|
|
87
|
+
// must count exactly like a native call. The normalizer accepts both event
|
|
88
|
+
// generations, so the fold does not depend on which one wrote the log.
|
|
89
|
+
const settle = ptcSettle(event);
|
|
90
|
+
if (settle !== undefined) {
|
|
91
|
+
const args = parseRawArguments(settle.arguments);
|
|
92
|
+
const command = shellCommand(settle.name, args, detection);
|
|
93
|
+
if (command !== undefined && isTestCommand(command, detection)) {
|
|
94
|
+
foldTestOutcome(state, testOutcome(joinTextBlocks(settle.content), settle.isError));
|
|
95
|
+
}
|
|
96
|
+
const path = mutationTargetPath(settle.name, args, detection);
|
|
97
|
+
if (path !== undefined && !isTestFilePath(path, detection)) {
|
|
98
|
+
state.pendingGreen = true;
|
|
99
|
+
state.editCount += 1;
|
|
100
|
+
}
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
85
103
|
switch (event.type) {
|
|
86
104
|
case 'tool/call': {
|
|
87
105
|
const args = parseRawArguments(event.data.arguments);
|
|
@@ -118,22 +136,6 @@ export function foldDisciplineRange(state, events, start, detection) {
|
|
|
118
136
|
}
|
|
119
137
|
break;
|
|
120
138
|
}
|
|
121
|
-
case 'tool/code-dispatch': {
|
|
122
|
-
const args = parseRawArguments(event.data.arguments);
|
|
123
|
-
const command = shellCommand(event.data.name, args, detection);
|
|
124
|
-
if (command !== undefined && isTestCommand(command, detection)) {
|
|
125
|
-
foldTestOutcome(state, testOutcome(joinTextBlocks(event.data.content), event.data.isError));
|
|
126
|
-
}
|
|
127
|
-
// Code Mode dispatches run through the same pre-execute policy gates,
|
|
128
|
-
// so a dispatched edit is a real implementation edit and must count
|
|
129
|
-
// toward the green gate and the report exactly like a native call.
|
|
130
|
-
const path = mutationTargetPath(event.data.name, args, detection);
|
|
131
|
-
if (path !== undefined && !isTestFilePath(path, detection)) {
|
|
132
|
-
state.pendingGreen = true;
|
|
133
|
-
state.editCount += 1;
|
|
134
|
-
}
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
return state;
|
package/lib/guard/index.d.ts
CHANGED
|
@@ -36,6 +36,14 @@ import { type GateConfig } from './gate.js';
|
|
|
36
36
|
import { type GateVerdict } from '../domain/gate.js';
|
|
37
37
|
export declare const name = "doublecheck-guard";
|
|
38
38
|
export declare const inject: string[];
|
|
39
|
+
/**
|
|
40
|
+
* The gate's settings namespace. Hyphenated on purpose: the host's
|
|
41
|
+
* `NAMESPACE_PATTERN` (`/^[a-z][a-z0-9-]*$/`) rejects a dot with a
|
|
42
|
+
* `TypeError`, and a rejected registration never reaches
|
|
43
|
+
* `ctx.settings.describe()`, so no settings surface can see it. v0.9.8 and
|
|
44
|
+
* earlier registered `doublecheck.gate`, which never took effect anywhere.
|
|
45
|
+
*/
|
|
46
|
+
export declare const GATE_SETTINGS_NS = "doublecheck-gate";
|
|
39
47
|
/**
|
|
40
48
|
* Guard configuration. `intensity` is shared by all three gates; `modules`
|
|
41
49
|
* selects them. The `adversary` module (v0.3) dispatches a forked critic
|
package/lib/guard/index.js
CHANGED
|
@@ -42,6 +42,14 @@ import { installInvariant, PACKAGE_NAME } from "../invariant.js";
|
|
|
42
42
|
import { doublecheckHandler, hostStampsIgnorable } from "./command.js";
|
|
43
43
|
export const name = 'doublecheck-guard';
|
|
44
44
|
export const inject = ['commands'];
|
|
45
|
+
/**
|
|
46
|
+
* The gate's settings namespace. Hyphenated on purpose: the host's
|
|
47
|
+
* `NAMESPACE_PATTERN` (`/^[a-z][a-z0-9-]*$/`) rejects a dot with a
|
|
48
|
+
* `TypeError`, and a rejected registration never reaches
|
|
49
|
+
* `ctx.settings.describe()`, so no settings surface can see it. v0.9.8 and
|
|
50
|
+
* earlier registered `doublecheck.gate`, which never took effect anywhere.
|
|
51
|
+
*/
|
|
52
|
+
export const GATE_SETTINGS_NS = 'doublecheck-gate';
|
|
45
53
|
export const Config = z.object({
|
|
46
54
|
intensity: z.union(['remind', 'warn', 'block']).default('remind'),
|
|
47
55
|
modules: z.object({
|
|
@@ -73,6 +81,33 @@ export function apply(ctx, config) {
|
|
|
73
81
|
assertPositiveInteger('vagueTaskMaxChars', config.vagueTaskMaxChars);
|
|
74
82
|
assertGuardTools(config.guardTools);
|
|
75
83
|
validateGateConfig(config.gate);
|
|
84
|
+
// The effective gate config: the user's stored `doublecheck-gate` section
|
|
85
|
+
// overrides this row's composition entry, which overrides the Schema
|
|
86
|
+
// defaults (the settings service resolves exactly that order). The service
|
|
87
|
+
// is a weak seam — without it, or when the stored section is unusable, the
|
|
88
|
+
// composition entry stands and the reason is logged. `applies: 'restart'`
|
|
89
|
+
// is deliberate: `gate.enabled` decides whether the turn-stopping notice is
|
|
90
|
+
// installed at load, so a live swap could not honor it; the resolved value
|
|
91
|
+
// is therefore read once here and an edit takes effect on the next load.
|
|
92
|
+
const settings = ctx.get('settings');
|
|
93
|
+
let gateConfig = config.gate;
|
|
94
|
+
if (settings !== undefined) {
|
|
95
|
+
try {
|
|
96
|
+
const resolved = settings.register(GATE_SETTINGS_NS, GateConfigSchema, {
|
|
97
|
+
base: config.gate,
|
|
98
|
+
applies: 'restart',
|
|
99
|
+
validate: validateGateConfig,
|
|
100
|
+
}).get();
|
|
101
|
+
// The host validates the resolved section at registration, so this only
|
|
102
|
+
// fires on a host that ignores the `validate` option; degrade rather
|
|
103
|
+
// than fail the whole row over a settings typo.
|
|
104
|
+
validateGateConfig(resolved);
|
|
105
|
+
gateConfig = resolved;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
ctx.logger.warn(`dsh-doublecheck: gate settings namespace skipped, using the composition entry: ${String(error)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
76
111
|
if (config.modules.adversary) {
|
|
77
112
|
assertBoundedInteger('adversaryMaxFindings', config.adversaryMaxFindings, 20);
|
|
78
113
|
assertPositiveInteger('adversaryTimeoutMs', config.adversaryTimeoutMs);
|
|
@@ -262,35 +297,19 @@ export function apply(ctx, config) {
|
|
|
262
297
|
description: 'run the delivery quality gate and report the deliverable/rework decision',
|
|
263
298
|
input: { hint: 'status|run|config' },
|
|
264
299
|
handler: gateHandler({
|
|
265
|
-
config:
|
|
300
|
+
config: gateConfig,
|
|
266
301
|
detection,
|
|
267
302
|
prose,
|
|
268
|
-
runGate: (agent, signal) => runGate(ctx,
|
|
269
|
-
settleGate: (state, agent, signal) => settleGate(ctx,
|
|
303
|
+
runGate: (agent, signal) => runGate(ctx, gateConfig, detection, agent, signal, config.language),
|
|
304
|
+
settleGate: (state, agent, signal) => settleGate(ctx, gateConfig, state, agent, signal, hostStampsIgnorable()),
|
|
270
305
|
stampsIgnorable: hostStampsIgnorable,
|
|
271
306
|
planMode: ctx.get('planMode'),
|
|
272
307
|
}),
|
|
273
308
|
});
|
|
274
|
-
// The gate settings namespace: the pluggable checklist becomes editable
|
|
275
|
-
// through the harness settings surface when one is mounted (weak seam —
|
|
276
|
-
// a profile without the settings service simply has no settings page).
|
|
277
|
-
const settings = ctx.get('settings');
|
|
278
|
-
if (settings !== undefined) {
|
|
279
|
-
try {
|
|
280
|
-
settings.register('doublecheck.gate', GateConfigSchema, {
|
|
281
|
-
base: config.gate,
|
|
282
|
-
applies: 'restart',
|
|
283
|
-
expose: true,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
ctx.logger.warn(`dsh-doublecheck: gate settings namespace skipped: ${String(error)}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
309
|
// The gate-red turn notice: once per session, a settled rework verdict
|
|
291
310
|
// suggests re-opening the work in plan mode. Installed even when every
|
|
292
311
|
// discipline module is off — the gate panel is advisory, not a gate.
|
|
293
|
-
if (
|
|
312
|
+
if (gateConfig.enabled) {
|
|
294
313
|
ctx.on('agent/turn-stopping', async ({ agent }) => {
|
|
295
314
|
if (!doublecheckEnabled(agent.session))
|
|
296
315
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-doublecheck",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.9",
|
|
4
4
|
"description": "Delivery quality gate for DeepSeek Harness: grill the requirements, test the implementation, prove the delivery, and gate the handoff with a deliverable/rework decision.",
|
|
5
5
|
"packageManager": "pnpm@11.7.0",
|
|
6
6
|
"repository": {
|
|
@@ -56,8 +56,9 @@
|
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsc --noEmitOnError && node scripts/fix-dts.mjs",
|
|
58
58
|
"prepare": "tsc --noEmitOnError && node scripts/fix-dts.mjs",
|
|
59
|
-
"prepublishOnly": "tsc --noEmitOnError && node scripts/fix-dts.mjs && pnpm run test",
|
|
59
|
+
"prepublishOnly": "pnpm run typecheck:ci && tsc --noEmitOnError && node scripts/fix-dts.mjs && pnpm run test",
|
|
60
60
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
61
|
+
"typecheck:ci": "tsc -p tsconfig.ci.json --noEmit",
|
|
61
62
|
"lint": "eslint src tests",
|
|
62
63
|
"test": "vitest run",
|
|
63
64
|
"test:coverage": "vitest run --coverage",
|
|
@@ -110,9 +111,7 @@
|
|
|
110
111
|
"filesystem:write"
|
|
111
112
|
],
|
|
112
113
|
"compatibility": {
|
|
113
|
-
"dshVersions": [
|
|
114
|
-
"0.1.2-rc.1"
|
|
115
|
-
]
|
|
114
|
+
"dshVersions": ["0.1.2-rc.1","0.1.5-alpha.1"]
|
|
116
115
|
},
|
|
117
116
|
"capability": {
|
|
118
117
|
"id": "doublecheck",
|
|
@@ -129,14 +128,14 @@
|
|
|
129
128
|
},
|
|
130
129
|
"peerDependencies": {
|
|
131
130
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
132
|
-
"@deepseek-ai/dsh-agent": ">=0.1.2-rc.1 <0.2.0",
|
|
133
|
-
"@deepseek-ai/dsh-commands": ">=0.1.2-rc.1 <0.2.0",
|
|
134
|
-
"@deepseek-ai/dsh-invariants": ">=0.1.2-rc.1 <0.2.0",
|
|
135
|
-
"@deepseek-ai/dsh-llm": ">=0.1.2-rc.1 <0.2.0",
|
|
136
|
-
"@deepseek-ai/dsh-session": ">=0.1.2-rc.1 <0.2.0",
|
|
137
|
-
"@deepseek-ai/dsh-session-projection": ">=0.1.2-rc.1 <0.2.0",
|
|
138
|
-
"@deepseek-ai/dsh-skill": ">=0.1.2-rc.1 <0.2.0",
|
|
139
|
-
"@deepseek-ai/dsh-tools": ">=0.1.2-rc.1 <0.2.0",
|
|
131
|
+
"@deepseek-ai/dsh-agent": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
132
|
+
"@deepseek-ai/dsh-commands": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
133
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
134
|
+
"@deepseek-ai/dsh-llm": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
135
|
+
"@deepseek-ai/dsh-session": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
136
|
+
"@deepseek-ai/dsh-session-projection": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
137
|
+
"@deepseek-ai/dsh-skill": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
138
|
+
"@deepseek-ai/dsh-tools": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0",
|
|
140
139
|
"@deepseek-ai/schemastery": "^3.18.2"
|
|
141
140
|
},
|
|
142
141
|
"dependencies": {
|
|
@@ -146,17 +145,18 @@
|
|
|
146
145
|
"devDependencies": {
|
|
147
146
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
148
147
|
"@deepseek-ai/cordis-plugin-loader": "^1.0.3",
|
|
149
|
-
"@deepseek-ai/dsh-agent": "0.1.
|
|
150
|
-
"@deepseek-ai/dsh-commands": "0.1.
|
|
151
|
-
"@deepseek-ai/dsh-fs": "0.1.
|
|
152
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
153
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
154
|
-
"@deepseek-ai/dsh-session-projection": "0.1.
|
|
155
|
-
"@deepseek-ai/dsh-
|
|
156
|
-
"@deepseek-ai/dsh-
|
|
157
|
-
"@deepseek-ai/dsh-
|
|
158
|
-
"@deepseek-ai/dsh-
|
|
159
|
-
"@deepseek-ai/dsh-
|
|
148
|
+
"@deepseek-ai/dsh-agent": "0.1.5-alpha.1",
|
|
149
|
+
"@deepseek-ai/dsh-commands": "0.1.5-alpha.1",
|
|
150
|
+
"@deepseek-ai/dsh-fs": "0.1.5-alpha.1",
|
|
151
|
+
"@deepseek-ai/dsh-llm": "0.1.5-alpha.1",
|
|
152
|
+
"@deepseek-ai/dsh-session": "0.1.5-alpha.1",
|
|
153
|
+
"@deepseek-ai/dsh-session-projection": "0.1.5-alpha.1",
|
|
154
|
+
"@deepseek-ai/dsh-settings": "0.1.5-alpha.1",
|
|
155
|
+
"@deepseek-ai/dsh-skill": "0.1.5-alpha.1",
|
|
156
|
+
"@deepseek-ai/dsh-subagent": "0.1.5-alpha.1",
|
|
157
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.5-alpha.1",
|
|
158
|
+
"@deepseek-ai/dsh-tools": "0.1.5-alpha.1",
|
|
159
|
+
"@deepseek-ai/dsh-workflow": "0.1.5-alpha.1",
|
|
160
160
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
161
161
|
"@eslint/js": "^9.30.0",
|
|
162
162
|
"@types/node": "^22.15.0",
|