dsh-doublecheck 0.6.0 → 0.7.1
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 +22 -0
- package/README.es.md +199 -220
- package/README.hi.md +199 -228
- package/README.md +199 -225
- package/README.pt.md +199 -220
- package/README.zh.md +201 -225
- package/lib/domain/gate.d.ts +263 -0
- package/lib/domain/gate.js +658 -0
- package/lib/domain/projection.d.ts +8 -3
- package/lib/domain/projection.js +12 -0
- package/lib/domain/report.d.ts +2 -2
- package/lib/domain/stages.d.ts +1 -1
- package/lib/events.d.ts +46 -4
- package/lib/grill/index.d.ts +1 -1
- package/lib/guard/command.d.ts +2 -2
- package/lib/guard/command.js +3 -0
- package/lib/guard/gate.d.ts +170 -0
- package/lib/guard/gate.js +518 -0
- package/lib/guard/index.d.ts +15 -3
- package/lib/guard/index.js +81 -4
- package/lib/guard/prose.d.ts +17 -0
- package/lib/guard/prose.js +14 -0
- package/lib/guard/review.d.ts +2 -2
- package/lib/index.d.ts +10 -9
- package/lib/index.js +1 -0
- package/lib/invariant.d.ts +3 -1
- package/lib/invariant.js +15 -0
- package/lib/types.d.ts +8 -1
- package/lib/types.js +2 -0
- package/package.json +52 -6
- package/skills/delivery-proof/SKILL.md +12 -0
- package/strict.patch.yml +37 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The delivery gate domain: the configurable quality-gate checklist that
|
|
3
|
+
* turns one session's durable evidence into a deliverable/rework decision.
|
|
4
|
+
*
|
|
5
|
+
* Four phases compose the checklist:
|
|
6
|
+
*
|
|
7
|
+
* - **requirements** — a key-question checklist confirmed item by item
|
|
8
|
+
* against the committed spec (deterministic fold, no model calls).
|
|
9
|
+
* - **tests** — test evidence from the session log: the latest run color,
|
|
10
|
+
* failing runs after green, and (optionally) a coverage percentage parsed
|
|
11
|
+
* from the test output.
|
|
12
|
+
* - **consistency** — diff ↔ requirement mapping, audited by a local forked
|
|
13
|
+
* reviewer (orchestrated by the guard row; this module owns the result
|
|
14
|
+
* shape and the status fold).
|
|
15
|
+
* - **review** — the delivery conclusion: the dsh-auto-review engine's
|
|
16
|
+
* durable verdict records when they exist (`engine: auto`), degraded to
|
|
17
|
+
* the local reviewer when the engine is not installed or has not run.
|
|
18
|
+
*
|
|
19
|
+
* Everything here is pure: the durable session log in, structured gate facts
|
|
20
|
+
* out. Check summaries and suggestions are stable English audit ids (the
|
|
21
|
+
* workspace documents keep English headings by package policy); the guard
|
|
22
|
+
* row localizes the surrounding command chrome. Reports are audit-safe by
|
|
23
|
+
* construction — counts, ids, and verdicts only — and {@link redactSecrets}
|
|
24
|
+
* scrubs the model-produced finding texts before they are stored or shown.
|
|
25
|
+
*
|
|
26
|
+
* @module dsh-doublecheck/domain/gate
|
|
27
|
+
*/
|
|
28
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
29
|
+
import type { ObjectJsonSchema } from '@deepseek-ai/dsh-tools';
|
|
30
|
+
import { type TestRunDetection } from './evidence.js';
|
|
31
|
+
import { type GrilledSpec, type ReviewFinding } from './vocabulary.js';
|
|
32
|
+
/** The four gate phases, in checklist order. */
|
|
33
|
+
export type GatePhase = 'requirements' | 'tests' | 'consistency' | 'review';
|
|
34
|
+
/** All gate phases in checklist order. */
|
|
35
|
+
export declare const GATE_PHASES: readonly GatePhase[];
|
|
36
|
+
/** One checklist item's status. Worst-first: fail, warn, skip, pending, pass. */
|
|
37
|
+
export type GateCheckStatus = 'pass' | 'fail' | 'warn' | 'skip' | 'pending';
|
|
38
|
+
/** One settled checklist item. */
|
|
39
|
+
export interface GateCheck {
|
|
40
|
+
/** Stable id — schema-configurable and unique within the gate. */
|
|
41
|
+
id: string;
|
|
42
|
+
/** The phase this check belongs to. */
|
|
43
|
+
phase: GatePhase;
|
|
44
|
+
/** Short human-readable check name (stable English audit id). */
|
|
45
|
+
label: string;
|
|
46
|
+
status: GateCheckStatus;
|
|
47
|
+
/** One-line evidence summary: counts/verdicts only, no sensitive content. */
|
|
48
|
+
summary: string;
|
|
49
|
+
/** What to fix when the check failed (the rework suggestion). */
|
|
50
|
+
suggestion: string;
|
|
51
|
+
}
|
|
52
|
+
/** One phase's settled result. */
|
|
53
|
+
export interface GatePhaseResult {
|
|
54
|
+
phase: GatePhase;
|
|
55
|
+
/** Whether the phase is enabled in the configuration. */
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
/** The worst status of this phase's checks. */
|
|
58
|
+
status: GateCheckStatus;
|
|
59
|
+
checks: GateCheck[];
|
|
60
|
+
}
|
|
61
|
+
/** The gate's binary decision. */
|
|
62
|
+
export type GateVerdict = 'deliverable' | 'rework';
|
|
63
|
+
/** Which engine produced the review conclusion, or null when it did not run. */
|
|
64
|
+
export type GateReviewEngine = 'dsh-auto-review' | 'local' | null;
|
|
65
|
+
/** The complete settled gate state of one run. */
|
|
66
|
+
export interface GateState {
|
|
67
|
+
verdict: GateVerdict;
|
|
68
|
+
phases: Record<GatePhase, GatePhaseResult>;
|
|
69
|
+
/** The engine behind the review phase of this run. */
|
|
70
|
+
reviewEngine: GateReviewEngine;
|
|
71
|
+
/** ISO timestamp of the run. */
|
|
72
|
+
at: string;
|
|
73
|
+
}
|
|
74
|
+
/** One configurable key question of the requirements phase. */
|
|
75
|
+
export interface GateQuestion {
|
|
76
|
+
/** Stable id — unique within the checklist. */
|
|
77
|
+
id: string;
|
|
78
|
+
/** The key question the grill must answer. */
|
|
79
|
+
question: string;
|
|
80
|
+
/**
|
|
81
|
+
* The spec dimension whose committed text answers this question, or null
|
|
82
|
+
* for a free-form question with no automatic evidence binding (rendered
|
|
83
|
+
* as a warning: confirm manually).
|
|
84
|
+
*/
|
|
85
|
+
specDimension: (keyof GrilledSpec) | null;
|
|
86
|
+
/** A failed required question is a red light; an optional one is a warning. */
|
|
87
|
+
required: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** The default key-question checklist: one question per spec dimension. */
|
|
90
|
+
export declare const DEFAULT_GATE_QUESTIONS: readonly GateQuestion[];
|
|
91
|
+
/** Default regex parsing a coverage percentage from test output (one capture group, case-insensitive). */
|
|
92
|
+
export declare const DEFAULT_COVERAGE_PATTERN = "coverage[^\\d]{0,40}(\\d+(?:\\.\\d+)?)\\s*%";
|
|
93
|
+
/** The requirements-phase evidence folded from the log. */
|
|
94
|
+
export interface RequirementsEvidence {
|
|
95
|
+
/** The latest committed spec, or null before any exists. */
|
|
96
|
+
spec: GrilledSpec | null;
|
|
97
|
+
/** `ask_user_question`-style interrogation calls on record. */
|
|
98
|
+
interrogations: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Fold the requirements evidence: the latest committed spec (a successful
|
|
102
|
+
* `doublecheck_spec` pair, from the call's own arguments) and the count of
|
|
103
|
+
* interrogation tool calls on record.
|
|
104
|
+
* @param events - the session's append-only event log.
|
|
105
|
+
* @param interrogateTool - the tool name that counts as user interrogation.
|
|
106
|
+
* @returns the folded evidence.
|
|
107
|
+
*/
|
|
108
|
+
export declare function foldRequirementsEvidence(events: readonly SessionEvent[], interrogateTool: string): RequirementsEvidence;
|
|
109
|
+
/** The tests-phase evidence folded from the log. */
|
|
110
|
+
export interface TestEvidence {
|
|
111
|
+
/** Failing test runs on record. */
|
|
112
|
+
failed: number;
|
|
113
|
+
/** Passing test runs on record. */
|
|
114
|
+
passed: number;
|
|
115
|
+
/** The outcome of the latest settled test run. */
|
|
116
|
+
lastOutcome: 'pass' | 'fail' | 'none';
|
|
117
|
+
/** Failing runs after the latest passing run (the open red window). */
|
|
118
|
+
failingAfterGreen: number;
|
|
119
|
+
/** The best coverage percentage parsed from the test outputs, or null. */
|
|
120
|
+
coveragePct: number | null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Fold the test evidence: run counts, the latest outcome, the failing runs
|
|
124
|
+
* since the latest green, and the best parsed coverage percentage.
|
|
125
|
+
* @param events - the session's append-only event log.
|
|
126
|
+
* @param detection - the compiled test-run detection knobs.
|
|
127
|
+
* @param coverageRegex - regex with one capture group matching a percentage.
|
|
128
|
+
* @returns the folded evidence.
|
|
129
|
+
*/
|
|
130
|
+
export declare function foldTestEvidence(events: readonly SessionEvent[], detection: TestRunDetection, coverageRegex: RegExp): TestEvidence;
|
|
131
|
+
/** The requirements-phase tuning. */
|
|
132
|
+
export interface RequirementsGateConfig {
|
|
133
|
+
/** The configurable key-question checklist. */
|
|
134
|
+
checklist: readonly GateQuestion[];
|
|
135
|
+
/** Minimum required questions that must be confirmed for the phase to pass. */
|
|
136
|
+
minConfirmed: number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Evaluate the requirements phase: each key question is confirmed item by
|
|
140
|
+
* item against the committed spec. A failed required question is a red
|
|
141
|
+
* light; a failed optional question is a warning; a free-form question
|
|
142
|
+
* without a spec-dimension binding is a manual-confirm warning.
|
|
143
|
+
* @param evidence - the folded requirements evidence.
|
|
144
|
+
* @param config - the requirements-phase tuning.
|
|
145
|
+
* @returns the settled phase result.
|
|
146
|
+
*/
|
|
147
|
+
export declare function evaluateRequirements(evidence: RequirementsEvidence, config: RequirementsGateConfig): GatePhaseResult;
|
|
148
|
+
/** The tests-phase tuning. */
|
|
149
|
+
export interface TestsGateConfig {
|
|
150
|
+
/** Require a passing test run as the latest evidence. */
|
|
151
|
+
requirePassingRun: boolean;
|
|
152
|
+
/** Failing runs after the latest green allowed before the gate turns red. */
|
|
153
|
+
allowFailingRuns: number;
|
|
154
|
+
/** Require coverage evidence in the test output. */
|
|
155
|
+
requireCoverage: boolean;
|
|
156
|
+
/** Minimum coverage percentage when coverage is required. */
|
|
157
|
+
minCoveragePct: number;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Evaluate the tests phase: the latest run color, the open red window, and
|
|
161
|
+
* (optionally) the coverage percentage. Deterministic — no model calls.
|
|
162
|
+
* @param evidence - the folded test evidence.
|
|
163
|
+
* @param config - the tests-phase tuning.
|
|
164
|
+
* @returns the settled phase result.
|
|
165
|
+
*/
|
|
166
|
+
export declare function evaluateTests(evidence: TestEvidence, config: TestsGateConfig): GatePhaseResult;
|
|
167
|
+
/** The structured output the consistency and local review subagents must satisfy. */
|
|
168
|
+
export declare const GATE_FINDINGS_SCHEMA: ObjectJsonSchema;
|
|
169
|
+
/**
|
|
170
|
+
* Evaluate the consistency phase from the local reviewer's findings: blocker
|
|
171
|
+
* and major findings are red lights, minor/info findings are warnings, and
|
|
172
|
+
* an unavailable reviewer is an honest skip (never a red light — a broken
|
|
173
|
+
* critic is not evidence of a defect, and a skipped phase keeps the verdict
|
|
174
|
+
* honest instead of silent).
|
|
175
|
+
* @param findings - the structured findings, or null when the reviewer could not run.
|
|
176
|
+
* @param unavailableReason - why the reviewer could not run (for the skip notice).
|
|
177
|
+
* @returns the settled phase result.
|
|
178
|
+
*/
|
|
179
|
+
export declare function evaluateConsistency(findings: ReviewFinding[] | null, unavailableReason: string): GatePhaseResult;
|
|
180
|
+
/** The dsh-auto-review engine's durable evidence folded from the log. */
|
|
181
|
+
export interface EngineReviewEvidence {
|
|
182
|
+
engine: 'dsh-auto-review';
|
|
183
|
+
/** Calls the engine approved. */
|
|
184
|
+
approvals: number;
|
|
185
|
+
/** Calls the engine rejected. */
|
|
186
|
+
rejections: number;
|
|
187
|
+
/** The latest risk level on record, or null. */
|
|
188
|
+
latestRisk: string | null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Fold the dsh-auto-review engine's durable verdict records
|
|
192
|
+
* (`autoReview/verdict` / `autoReview/rejection`) from the session log. The
|
|
193
|
+
* engine row provides no service, so its verdict events ARE the weak
|
|
194
|
+
* dependency: records present means the engine is installed and has judged
|
|
195
|
+
* this session's calls; no records means it did not run, and the gate
|
|
196
|
+
* degrades to the local reviewer.
|
|
197
|
+
* @param events - the session's append-only event log.
|
|
198
|
+
* @returns the engine evidence, or null when the engine has no records here.
|
|
199
|
+
*/
|
|
200
|
+
export declare function foldAutoReviewEvidence(events: readonly SessionEvent[]): EngineReviewEvidence | null;
|
|
201
|
+
/**
|
|
202
|
+
* Evaluate the review conclusion phase. With `engine: auto`, the engine's
|
|
203
|
+
* durable verdict records are the evidence; when the engine has no records
|
|
204
|
+
* (not installed, or nothing triggered it this session), the phase degrades
|
|
205
|
+
* to the local reviewer's findings with a warn check naming the degrade
|
|
206
|
+
* reason. With `engine: local`, the local reviewer is always the evidence.
|
|
207
|
+
* A rejected engine call is a red light.
|
|
208
|
+
* @param engine - the engine evidence, or null.
|
|
209
|
+
* @param localFindings - the local reviewer's findings, or null when it could not run.
|
|
210
|
+
* @param localUnavailable - why the local reviewer could not run.
|
|
211
|
+
* @param engineConfigured - the configured engine preference.
|
|
212
|
+
* @param degradeNote - why the engine was not used (for the warn check).
|
|
213
|
+
* @returns the settled phase result and the engine that produced it.
|
|
214
|
+
*/
|
|
215
|
+
export declare function evaluateReview(engine: EngineReviewEvidence | null, localFindings: ReviewFinding[] | null, localUnavailable: string, engineConfigured: 'auto' | 'local', degradeNote?: string | null): {
|
|
216
|
+
result: GatePhaseResult;
|
|
217
|
+
engine: GateReviewEngine;
|
|
218
|
+
};
|
|
219
|
+
/** A disabled phase: present in the report as skipped, contributing nothing. */
|
|
220
|
+
export declare function skippedPhase(phase: GatePhase): GatePhaseResult;
|
|
221
|
+
/**
|
|
222
|
+
* Derive the gate's binary decision: any enabled phase with a failing check
|
|
223
|
+
* means rework. Warnings and skipped phases never flip the decision — a
|
|
224
|
+
* skipped review keeps the report honest ("not reviewed") without inventing
|
|
225
|
+
* a red light.
|
|
226
|
+
* @param phases - the settled phase results.
|
|
227
|
+
* @returns the gate verdict.
|
|
228
|
+
*/
|
|
229
|
+
export declare function deriveGateVerdict(phases: readonly GatePhaseResult[]): GateVerdict;
|
|
230
|
+
/**
|
|
231
|
+
* The count of red-light (failing) checks across the phases.
|
|
232
|
+
* @param phases - the settled phase results.
|
|
233
|
+
* @returns the red-item count.
|
|
234
|
+
*/
|
|
235
|
+
export declare function countRedChecks(phases: readonly GatePhaseResult[]): number;
|
|
236
|
+
/**
|
|
237
|
+
* Redact secrets from a model-produced text. The gate report is auditable
|
|
238
|
+
* by policy: counts, ids, and verdicts only. This scrubber catches the
|
|
239
|
+
* common credential shapes (cloud keys, GitHub tokens, OpenAI-style keys,
|
|
240
|
+
* Slack tokens, bearer tokens, private-key blocks, password assignments,
|
|
241
|
+
* and long hex/base64 runs) before a finding title or detail is stored or
|
|
242
|
+
* shown, so a reviewer quoting evidence cannot leak a credential.
|
|
243
|
+
* @param text - the text to scrub.
|
|
244
|
+
* @returns the text with recognized secrets replaced by `[redacted]`.
|
|
245
|
+
*/
|
|
246
|
+
export declare function redactSecrets(text: string): string;
|
|
247
|
+
/**
|
|
248
|
+
* Render the settled gate state as the model/human-facing markdown report —
|
|
249
|
+
* the `/gate run` output, ready to paste into a PR description.
|
|
250
|
+
* @param state - the settled gate state.
|
|
251
|
+
* @param planSuggestion - whether to append the plan-mode re-check suggestion.
|
|
252
|
+
* @returns the report document.
|
|
253
|
+
*/
|
|
254
|
+
export declare function renderGateReportMarkdown(state: GateState, planSuggestion: boolean): string;
|
|
255
|
+
/**
|
|
256
|
+
* Render one phase's checklist as markdown lines (shared by the full report
|
|
257
|
+
* and the `/gate status` panel).
|
|
258
|
+
* @param result - the phase result to render.
|
|
259
|
+
* @returns the markdown lines, without the trailing blank line.
|
|
260
|
+
*/
|
|
261
|
+
export declare function renderPhaseMarkdown(result: GatePhaseResult): string[];
|
|
262
|
+
/** Human-readable phase headings (stable English audit ids). */
|
|
263
|
+
export declare function phaseLabel(phase: GatePhase): string;
|