dsh-doublecheck 0.5.0 → 0.7.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.
- package/CHANGELOG.md +36 -0
- package/README.es.md +259 -34
- package/README.hi.md +265 -40
- package/README.md +236 -27
- package/README.pt.md +259 -34
- package/README.zh.md +326 -115
- package/lib/domain/evidence.d.ts +4 -1
- package/lib/domain/evidence.js +7 -2
- package/lib/domain/gate.d.ts +263 -0
- package/lib/domain/gate.js +658 -0
- package/lib/domain/projection.d.ts +5 -0
- package/lib/domain/projection.js +12 -0
- package/lib/domain/vocabulary.d.ts +2 -0
- package/lib/domain/vocabulary.js +4 -0
- package/lib/events.d.ts +44 -2
- package/lib/grill/index.js +8 -1
- package/lib/guard/command.d.ts +7 -0
- package/lib/guard/command.js +28 -21
- package/lib/guard/gate.d.ts +170 -0
- package/lib/guard/gate.js +518 -0
- package/lib/guard/index.d.ts +14 -0
- package/lib/guard/index.js +93 -7
- package/lib/guard/prose.d.ts +64 -0
- package/lib/guard/prose.js +79 -0
- package/lib/guard/review.d.ts +8 -0
- package/lib/guard/review.js +20 -20
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/invariant.d.ts +2 -0
- package/lib/invariant.js +17 -3
- package/lib/types.d.ts +7 -0
- package/lib/types.js +2 -0
- package/package.json +56 -6
- package/skills/delivery-proof/SKILL.md +12 -0
- package/strict.patch.yml +70 -0
package/lib/domain/projection.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { isTestCommand, isTestFilePath, joinTextBlocks, mutationTargetPath, parseRawArguments, shellCommand, testOutcome, } from "./evidence.js";
|
|
14
14
|
import { SPEC_TOOL_NAME } from "./stages.js";
|
|
15
|
+
import { countRedChecks } from "./gate.js";
|
|
15
16
|
/** State for the empty log. */
|
|
16
17
|
export function emptyDoublecheckState() {
|
|
17
18
|
return {
|
|
@@ -21,6 +22,8 @@ export function emptyDoublecheckState() {
|
|
|
21
22
|
specGoal: '',
|
|
22
23
|
reviewed: false,
|
|
23
24
|
editCount: 0,
|
|
25
|
+
gateVerdict: 'none',
|
|
26
|
+
gateRedCount: 0,
|
|
24
27
|
pendingSpecCalls: {},
|
|
25
28
|
pendingTestCalls: {},
|
|
26
29
|
};
|
|
@@ -98,6 +101,13 @@ export function applyDoublecheckEvent(state, event, detection) {
|
|
|
98
101
|
}
|
|
99
102
|
return state;
|
|
100
103
|
}
|
|
104
|
+
case 'doublecheck/gate': {
|
|
105
|
+
const gate = event.data;
|
|
106
|
+
const redCount = countRedChecks(Object.values(gate.phases));
|
|
107
|
+
if (state.gateVerdict === gate.verdict && state.gateRedCount === redCount)
|
|
108
|
+
return state;
|
|
109
|
+
return { ...state, gateVerdict: gate.verdict, gateRedCount: redCount };
|
|
110
|
+
}
|
|
101
111
|
default:
|
|
102
112
|
return state;
|
|
103
113
|
}
|
|
@@ -128,5 +138,7 @@ export function viewDoublecheck(state) {
|
|
|
128
138
|
specGoal: state.specGoal,
|
|
129
139
|
reviewed: state.reviewed,
|
|
130
140
|
editCount: state.editCount,
|
|
141
|
+
gateVerdict: state.gateVerdict,
|
|
142
|
+
gateRedCount: state.gateRedCount,
|
|
131
143
|
};
|
|
132
144
|
}
|
|
@@ -20,6 +20,8 @@ export interface GrilledSpec {
|
|
|
20
20
|
/** What the user explicitly does not want. */
|
|
21
21
|
nonGoals: string;
|
|
22
22
|
}
|
|
23
|
+
/** All six spec fields, in declaration order. */
|
|
24
|
+
export declare const SPEC_FIELD_NAMES: readonly (keyof GrilledSpec)[];
|
|
23
25
|
/** One structured objection from the adversary review. */
|
|
24
26
|
export interface ReviewFinding {
|
|
25
27
|
/** How much the finding threatens the delivery claim. */
|
package/lib/domain/vocabulary.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module dsh-doublecheck/domain/vocabulary
|
|
7
7
|
*/
|
|
8
|
+
/** All six spec fields, in declaration order. */
|
|
9
|
+
export const SPEC_FIELD_NAMES = [
|
|
10
|
+
'goal', 'scope', 'acceptanceCriteria', 'failureModes', 'priorities', 'nonGoals',
|
|
11
|
+
];
|
|
8
12
|
/** All verify dimensions, in spec order. */
|
|
9
13
|
export const VERIFY_DIMENSIONS = [
|
|
10
14
|
'goal',
|
package/lib/events.d.ts
CHANGED
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
16
16
|
import type { Session, SessionEventMap } from '@deepseek-ai/dsh-session';
|
|
17
17
|
import type { GrilledSpec, ReviewFinding, ReviewVerdict, ReportVerdict, VerifyCheck } from './domain/vocabulary.ts';
|
|
18
|
+
import type { GateState, GateVerdict } from './domain/gate.ts';
|
|
18
19
|
export type { GrilledSpec, ReviewFinding, ReviewVerdict, ReportVerdict, VerifyCheck } from './domain/vocabulary.ts';
|
|
20
|
+
export type { GateState } from './domain/gate.ts';
|
|
19
21
|
/** Guard enforcement strength. */
|
|
20
22
|
export type GuardIntensity = 'remind' | 'warn' | 'block';
|
|
21
23
|
/** Which discipline gate produced a guard reaction. */
|
|
22
|
-
export type GuardGate = 'grill' | 'tdd' | 'delivery';
|
|
24
|
+
export type GuardGate = 'grill' | 'tdd' | 'delivery' | 'gate';
|
|
23
25
|
/** Policy outcome of one guard reaction. */
|
|
24
|
-
export type GuardVerdict = 'reminded' | 'held' | 'denied' | 'green-pending' | 'report-expected';
|
|
26
|
+
export type GuardVerdict = 'reminded' | 'held' | 'denied' | 'green-pending' | 'report-expected' | 'gate-red';
|
|
25
27
|
declare module '@deepseek-ai/dsh-session' {
|
|
26
28
|
interface SessionEventMap {
|
|
27
29
|
/**
|
|
@@ -34,6 +36,14 @@ declare module '@deepseek-ai/dsh-session' {
|
|
|
34
36
|
'doublecheck/state': {
|
|
35
37
|
enabled: boolean;
|
|
36
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* One settled delivery-gate run written by `/gate run`: the full gate
|
|
41
|
+
* state (checklist statuses, red items, verdict, engine, timestamp).
|
|
42
|
+
* Audit-safe by construction — counts, ids, and verdicts only — and the
|
|
43
|
+
* replayable source the `/gate status` panel and the turn-boundary red
|
|
44
|
+
* notice re-derive from. Rides `ignorable: true` like the state switch.
|
|
45
|
+
*/
|
|
46
|
+
'doublecheck/gate': GateState;
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
/**
|
|
@@ -46,6 +56,15 @@ export interface StateAppend {
|
|
|
46
56
|
ignorable: true;
|
|
47
57
|
}): void;
|
|
48
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* `Session.append` narrowed to the `doublecheck/gate` event, with the same
|
|
61
|
+
* `ignorable: true` envelope marker as the state switch.
|
|
62
|
+
*/
|
|
63
|
+
export interface GateAppend {
|
|
64
|
+
(type: 'doublecheck/gate', data: SessionEventMap['doublecheck/gate'], options: {
|
|
65
|
+
ignorable: true;
|
|
66
|
+
}): void;
|
|
67
|
+
}
|
|
49
68
|
declare module '@deepseek-ai/dsh-llm' {
|
|
50
69
|
interface MessageSourceMap {
|
|
51
70
|
/**
|
|
@@ -59,6 +78,17 @@ declare module '@deepseek-ai/dsh-llm' {
|
|
|
59
78
|
verdict: ReviewVerdict;
|
|
60
79
|
findings: ReviewFinding[];
|
|
61
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* The delivery-gate red notice injected at the turn boundary: the
|
|
83
|
+
* model-facing text is the short gate notice (role statement first), and
|
|
84
|
+
* the structured verdict + red count ride this source so the durable
|
|
85
|
+
* once-semantics and the report folds read them without re-parsing prose.
|
|
86
|
+
*/
|
|
87
|
+
'doublecheck-gate': {
|
|
88
|
+
kind: 'doublecheck-gate';
|
|
89
|
+
verdict: GateVerdict;
|
|
90
|
+
redCount: number;
|
|
91
|
+
};
|
|
62
92
|
}
|
|
63
93
|
}
|
|
64
94
|
declare module '@deepseek-ai/cordis' {
|
|
@@ -151,5 +181,17 @@ declare module '@deepseek-ai/cordis' {
|
|
|
151
181
|
path: string | null;
|
|
152
182
|
written: boolean;
|
|
153
183
|
}): void;
|
|
184
|
+
/**
|
|
185
|
+
* One delivery-gate run settled: the full gate state the `/gate run`
|
|
186
|
+
* command derived, after the durable `doublecheck/gate` session event was
|
|
187
|
+
* appended. Observability only — listeners must not veto or reroute.
|
|
188
|
+
* @param payload.session - the gated session.
|
|
189
|
+
* @param payload.state - the settled gate state (redacted by construction).
|
|
190
|
+
* @mode emit
|
|
191
|
+
*/
|
|
192
|
+
'doublecheck/gate'(payload: {
|
|
193
|
+
session: Session;
|
|
194
|
+
state: GateState;
|
|
195
|
+
}): void;
|
|
154
196
|
}
|
|
155
197
|
}
|
package/lib/grill/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import z from '@deepseek-ai/schemastery';
|
|
|
18
18
|
import { DEFAULT_MUTATION_TOOLS, DEFAULT_TEST_COMMAND_PATTERNS, DEFAULT_TEST_FILE_PATTERNS, DEFAULT_TEST_TOOL_NAMES, compileDetection, } from "../domain/evidence.js";
|
|
19
19
|
import { SPEC_TOOL_NAME } from "../domain/stages.js";
|
|
20
20
|
import { buildVerifyScript, deriveReportVerdict, foldReportFacts, renderReportMarkdown, VERIFY_META, } from "../domain/report.js";
|
|
21
|
-
import { VERIFY_DIMENSIONS } from "../domain/vocabulary.js";
|
|
21
|
+
import { SPEC_FIELD_NAMES, VERIFY_DIMENSIONS } from "../domain/vocabulary.js";
|
|
22
22
|
import { BundledSkillProvider, PROVIDER_NAME } from "./provider.js";
|
|
23
23
|
export const name = 'doublecheck-grill';
|
|
24
24
|
export const inject = ['skills', 'tools'];
|
|
@@ -215,6 +215,13 @@ export function apply(ctx, config) {
|
|
|
215
215
|
priorities: args.priorities,
|
|
216
216
|
nonGoals: args.nonGoals,
|
|
217
217
|
};
|
|
218
|
+
// Fail fast at the commit: an empty dimension would satisfy the gate
|
|
219
|
+
// shape while recording an uncheckable contract. The grill must settle
|
|
220
|
+
// every dimension before the spec counts.
|
|
221
|
+
const empty = SPEC_FIELD_NAMES.filter(field => spec[field].trim() === '');
|
|
222
|
+
if (empty.length > 0) {
|
|
223
|
+
throw new Error(`doublecheck_spec: the spec dimension(s) ${empty.join(', ')} must not be empty; finish the requirements grill before committing the spec`);
|
|
224
|
+
}
|
|
218
225
|
const outcome = await writeSpecFile(ctx, spec, args.filePath ?? config.specFile, exec);
|
|
219
226
|
if (exec.agent !== undefined) {
|
|
220
227
|
ctx.emit('doublecheck/spec', { session: exec.agent.session, spec, ...outcome });
|
package/lib/guard/command.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export interface CommandDeps {
|
|
|
34
34
|
snapshotOf: (session: Session) => Snapshot;
|
|
35
35
|
/** The compiled test-run detection shared with the tdd/adversary gates. */
|
|
36
36
|
detection: TestRunDetection;
|
|
37
|
+
/**
|
|
38
|
+
* The effective session switch — the exact reader the gates use (local
|
|
39
|
+
* override → durable `doublecheck/state` → configured default), so the
|
|
40
|
+
* command answers consistently with what the gates enforce, including on
|
|
41
|
+
* rc.6 hosts where the override is process-local.
|
|
42
|
+
*/
|
|
43
|
+
effectiveEnabled: (session: Session) => boolean;
|
|
37
44
|
/** Whether the host append surface stamps `ignorable` (see {@link hostStampsIgnorable}). */
|
|
38
45
|
stampsIgnorable: () => boolean;
|
|
39
46
|
/** Record a process-local switch override when the durable write is unavailable. */
|
package/lib/guard/command.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
17
17
|
import { Session, SessionId } from '@deepseek-ai/dsh-session';
|
|
18
18
|
import { deriveReportVerdict, foldReportFacts, renderReportMarkdown } from "../domain/report.js";
|
|
19
|
+
import { PROSE } from "./prose.js";
|
|
19
20
|
/**
|
|
20
21
|
* Whether this host's `Session.append` stamps the `ignorable` envelope marker.
|
|
21
22
|
* Detected once per process on a detached probe session: hosts without the
|
|
@@ -54,14 +55,11 @@ export function effectiveDoublecheckEnabled(events, fallback) {
|
|
|
54
55
|
return fallback;
|
|
55
56
|
}
|
|
56
57
|
/** The switch notice injected after `/doublecheck on|off`. */
|
|
57
|
-
function switchNotice(enabled, durable) {
|
|
58
|
+
function switchNotice(enabled, durable, prose) {
|
|
58
59
|
const source = { kind: 'plugin', plugin: 'dsh-doublecheck', form: 'notice', summary: 'doublecheck state' };
|
|
59
|
-
const scope = durable
|
|
60
|
-
? 'for this session'
|
|
61
|
-
: 'for this process only (this harness build predates the ignorable append surface, so the switch is not durable)';
|
|
62
60
|
const text = enabled
|
|
63
|
-
?
|
|
64
|
-
:
|
|
61
|
+
? durable ? prose.switchOnDurable : prose.switchOnLocal
|
|
62
|
+
: durable ? prose.switchOffDurable : prose.switchOffLocal;
|
|
65
63
|
return createUserMessage({ content: [{ type: 'text', text }], source });
|
|
66
64
|
}
|
|
67
65
|
/**
|
|
@@ -70,26 +68,35 @@ function switchNotice(enabled, durable) {
|
|
|
70
68
|
* @returns the command handler for `ctx.commands.register`.
|
|
71
69
|
*/
|
|
72
70
|
export function doublecheckHandler(deps) {
|
|
73
|
-
const { config, snapshotOf, detection, stampsIgnorable, setLocalOverride } = deps;
|
|
71
|
+
const { config, snapshotOf, detection, stampsIgnorable, setLocalOverride, effectiveEnabled } = deps;
|
|
72
|
+
const prose = PROSE[config.language];
|
|
74
73
|
return (invocation) => {
|
|
75
74
|
const agent = invocation.agent;
|
|
76
75
|
if (agent === undefined) {
|
|
77
|
-
return { kind: 'error', text:
|
|
76
|
+
return { kind: 'error', text: prose.commandNoAgent };
|
|
78
77
|
}
|
|
79
78
|
const session = agent.session;
|
|
80
79
|
const input = invocation.rawInput.trim().toLowerCase();
|
|
81
|
-
const enabled =
|
|
80
|
+
const enabled = effectiveEnabled(session);
|
|
82
81
|
if (input === 'status' || input === '') {
|
|
83
82
|
const snapshot = snapshotOf(session);
|
|
84
83
|
const discipline = snapshot.discipline;
|
|
85
84
|
return {
|
|
86
85
|
kind: 'success',
|
|
87
|
-
text:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
text: prose.commandStatus({
|
|
87
|
+
enabled,
|
|
88
|
+
defaultEnabled: config.enableByDefault,
|
|
89
|
+
modules: config.modules,
|
|
90
|
+
intensity: config.intensity,
|
|
91
|
+
remindOnce: config.remindOnce,
|
|
92
|
+
hasSpec: discipline.hasSpec,
|
|
93
|
+
color: discipline.color,
|
|
94
|
+
reviewed: snapshot.lastReviewSeq >= 0,
|
|
95
|
+
editCount: discipline.editCount,
|
|
96
|
+
gate: snapshot.lastGate === null
|
|
97
|
+
? null
|
|
98
|
+
: { verdict: snapshot.lastGate.verdict, redCount: snapshot.lastGate.redCount },
|
|
99
|
+
}),
|
|
93
100
|
};
|
|
94
101
|
}
|
|
95
102
|
if (input === 'report') {
|
|
@@ -104,11 +111,11 @@ export function doublecheckHandler(deps) {
|
|
|
104
111
|
return { kind: 'success', text: renderReportMarkdown(report) };
|
|
105
112
|
}
|
|
106
113
|
if (input !== 'on' && input !== 'off') {
|
|
107
|
-
return { kind: 'error', text:
|
|
114
|
+
return { kind: 'error', text: prose.commandUnknown(invocation.rawInput.trim()) };
|
|
108
115
|
}
|
|
109
116
|
const target = input === 'on';
|
|
110
117
|
if (enabled === target) {
|
|
111
|
-
return { kind: 'success', text:
|
|
118
|
+
return { kind: 'success', text: target ? prose.commandAlreadyOn : prose.commandAlreadyOff };
|
|
112
119
|
}
|
|
113
120
|
// Adaptive durable write: only hosts that stamp `ignorable` may write the
|
|
114
121
|
// state event; on rc.6 the options bag is ignored and an unmarked foreign
|
|
@@ -121,12 +128,12 @@ export function doublecheckHandler(deps) {
|
|
|
121
128
|
else {
|
|
122
129
|
setLocalOverride(session, target);
|
|
123
130
|
}
|
|
124
|
-
agent.inject(switchNotice(target, durable));
|
|
131
|
+
agent.inject(switchNotice(target, durable, prose));
|
|
125
132
|
return {
|
|
126
133
|
kind: 'success',
|
|
127
|
-
text:
|
|
128
|
-
?
|
|
129
|
-
:
|
|
134
|
+
text: target
|
|
135
|
+
? durable ? prose.commandOnDurable : prose.commandOnLocal
|
|
136
|
+
: durable ? prose.commandOffDurable : prose.commandOffLocal,
|
|
130
137
|
};
|
|
131
138
|
};
|
|
132
139
|
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The delivery gate runner: orchestrates the four-phase quality checklist
|
|
3
|
+
* over one session's durable evidence and settles the deliverable/rework
|
|
4
|
+
* decision.
|
|
5
|
+
*
|
|
6
|
+
* - **requirements** + **tests** — deterministic folds of the session log
|
|
7
|
+
* (no model calls): the key-question checklist against the committed
|
|
8
|
+
* spec, and the test-run/coverage evidence.
|
|
9
|
+
* - **consistency** — a local forked reviewer audits the diff ↔ requirement
|
|
10
|
+
* mapping (every edit must serve a spec dimension).
|
|
11
|
+
* - **review** — the delivery conclusion. With `engine: auto`, the
|
|
12
|
+
* dsh-auto-review engine's durable verdict records (`autoReview/verdict` /
|
|
13
|
+
* `autoReview/rejection`) are the evidence; when the engine is not
|
|
14
|
+
* installed or has no records this session, the phase degrades to the
|
|
15
|
+
* local forked reviewer and says so. `engine: local` always uses the
|
|
16
|
+
* local reviewer. The gate never synthesizes approval requests: that
|
|
17
|
+
* chain may reach a human.
|
|
18
|
+
*
|
|
19
|
+
* Everything a run settles is audit-safe: counts, ids, verdicts, and
|
|
20
|
+
* redacted findings only. The settled state rides the durable
|
|
21
|
+
* `doublecheck/gate` session event (replay IS the state), the workspace
|
|
22
|
+
* `gate-report.md`, and the `/gate run` command result.
|
|
23
|
+
*
|
|
24
|
+
* @module dsh-doublecheck/guard/gate
|
|
25
|
+
*/
|
|
26
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
27
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
28
|
+
import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands';
|
|
29
|
+
import type { UserMessage } from '@deepseek-ai/dsh-llm';
|
|
30
|
+
import type Schema from '@deepseek-ai/schemastery';
|
|
31
|
+
import type { TestRunDetection } from '../domain/evidence.ts';
|
|
32
|
+
import { type GateQuestion, type GateState, type GateVerdict } from '../domain/gate.ts';
|
|
33
|
+
import type { GuardProse, ProseLanguage } from './prose.ts';
|
|
34
|
+
/** The reviewer knobs shared by the consistency and review phases. */
|
|
35
|
+
export interface GateReviewerConfig {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
/** Subagent provider name the local reviewer runs on (default `fork`). */
|
|
38
|
+
provider: string;
|
|
39
|
+
/** Model route for the local reviewer; null means the main model reviews. */
|
|
40
|
+
model: string | null;
|
|
41
|
+
/** Tools the local reviewer may call (read-only by default). */
|
|
42
|
+
tools: string[];
|
|
43
|
+
/** Hard time budget for one local reviewer run. */
|
|
44
|
+
timeoutMs: number;
|
|
45
|
+
/** Maximum structured findings per phase. */
|
|
46
|
+
maxFindings: number;
|
|
47
|
+
}
|
|
48
|
+
/** The delivery-gate configuration block of the guard row. */
|
|
49
|
+
export interface GateConfig {
|
|
50
|
+
/** Master switch for the gate panel and the turn-boundary red notice. */
|
|
51
|
+
enabled: boolean;
|
|
52
|
+
/** Suggest re-opening in plan mode when the verdict is rework. */
|
|
53
|
+
planSuggestion: boolean;
|
|
54
|
+
/** Workspace file (relative to the session cwd) receiving the gate report. */
|
|
55
|
+
reportFile: string;
|
|
56
|
+
/** The requirements-interrogation phase. */
|
|
57
|
+
requirements: {
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** The configurable key-question checklist. */
|
|
60
|
+
checklist: GateQuestion[];
|
|
61
|
+
/** Minimum required questions that must be confirmed for the phase to pass. */
|
|
62
|
+
minConfirmed: number;
|
|
63
|
+
/** Tool name whose calls count as user interrogation evidence. */
|
|
64
|
+
interrogateTool: string;
|
|
65
|
+
};
|
|
66
|
+
/** The test-evidence phase. */
|
|
67
|
+
tests: {
|
|
68
|
+
enabled: boolean;
|
|
69
|
+
/** Require a passing test run as the latest evidence. */
|
|
70
|
+
requirePassingRun: boolean;
|
|
71
|
+
/** Failing runs after the latest green allowed before the gate turns red. */
|
|
72
|
+
allowFailingRuns: number;
|
|
73
|
+
/** Require coverage evidence in the test output. */
|
|
74
|
+
requireCoverage: boolean;
|
|
75
|
+
/** Minimum coverage percentage when coverage is required. */
|
|
76
|
+
minCoveragePct: number;
|
|
77
|
+
/** Regex (one capture group) parsing a coverage percentage from test output. */
|
|
78
|
+
coveragePattern: string;
|
|
79
|
+
};
|
|
80
|
+
/** The implementation-consistency phase (local forked reviewer). */
|
|
81
|
+
consistency: GateReviewerConfig;
|
|
82
|
+
/** The review-conclusion phase (engine verdict records + local degrade). */
|
|
83
|
+
review: GateReviewerConfig & {
|
|
84
|
+
/** `auto` = dsh-auto-review verdict records when present, else local. */
|
|
85
|
+
engine: 'auto' | 'local';
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** The default gate configuration: every phase on, the six key questions required. */
|
|
89
|
+
export declare const DEFAULT_GATE_CONFIG: GateConfig;
|
|
90
|
+
/** The delivery-gate configuration schema (the pluggable checklist + knobs). */
|
|
91
|
+
export declare const GateConfigSchema: Schema<GateConfig>;
|
|
92
|
+
/**
|
|
93
|
+
* Validate the gate configuration fail-loud: checklist ids unique and
|
|
94
|
+
* non-empty, valid spec-dimension bindings, bounded thresholds, compilable
|
|
95
|
+
* coverage regex, and sound reviewer knobs. A bad gate config must not
|
|
96
|
+
* silently produce an uncheckable checklist.
|
|
97
|
+
* @param gate - the gate config block.
|
|
98
|
+
*/
|
|
99
|
+
export declare function validateGateConfig(gate: GateConfig): void;
|
|
100
|
+
/**
|
|
101
|
+
* Run the full delivery gate over the agent's session and settle the state.
|
|
102
|
+
* The deterministic phases fold first; the two reviewer phases run in
|
|
103
|
+
* parallel. Failures degrade to honest skip notices, never to throws.
|
|
104
|
+
* @param ctx - plugin context (subagents, commands, fs seams).
|
|
105
|
+
* @param config - the gate configuration.
|
|
106
|
+
* @param detection - the compiled test-run detection knobs.
|
|
107
|
+
* @param agent - the gated agent.
|
|
108
|
+
* @param signal - the caller's cancellation signal.
|
|
109
|
+
* @param language - prose language for the reviewer tasks.
|
|
110
|
+
* @returns the settled gate state.
|
|
111
|
+
*/
|
|
112
|
+
export declare function runGate(ctx: Context, config: GateConfig, detection: TestRunDetection, agent: Agent, signal: AbortSignal, language: ProseLanguage): Promise<GateState>;
|
|
113
|
+
/**
|
|
114
|
+
* Settle one gate run's side effects: the durable `doublecheck/gate` session
|
|
115
|
+
* event (when the host stamps `ignorable`), the observability announcement,
|
|
116
|
+
* and the workspace `gate-report.md` copy. Failures of the file write never
|
|
117
|
+
* fail the run — the command result and the durable event remain.
|
|
118
|
+
* @param ctx - plugin context.
|
|
119
|
+
* @param config - the gate configuration.
|
|
120
|
+
* @param state - the settled gate state.
|
|
121
|
+
* @param agent - the gated agent.
|
|
122
|
+
* @param signal - the caller's cancellation signal.
|
|
123
|
+
* @param stampsIgnorable - whether the host stamps the `ignorable` marker.
|
|
124
|
+
*/
|
|
125
|
+
export declare function settleGate(ctx: Context, config: GateConfig, state: GateState, agent: Agent, signal: AbortSignal, stampsIgnorable: boolean): Promise<void>;
|
|
126
|
+
/** The closures the `/gate` command reads; all live inside the guard's `apply` scope. */
|
|
127
|
+
export interface GateCommandDeps {
|
|
128
|
+
config: GateConfig;
|
|
129
|
+
detection: TestRunDetection;
|
|
130
|
+
prose: GuardProse;
|
|
131
|
+
/** Runs the full gate and returns the settled state. */
|
|
132
|
+
runGate: (agent: Agent, signal: AbortSignal) => Promise<GateState>;
|
|
133
|
+
/** Settles the durable append, the announcement, and the workspace file. */
|
|
134
|
+
settleGate: (state: GateState, agent: Agent, signal: AbortSignal) => Promise<void>;
|
|
135
|
+
/** Whether the host stamps the `ignorable` marker (the durable write gate). */
|
|
136
|
+
stampsIgnorable: () => boolean;
|
|
137
|
+
/** The optional plan-mode service (weak seam: `ctx.get('planMode')`). */
|
|
138
|
+
planMode?: {
|
|
139
|
+
get(agent: Agent): {
|
|
140
|
+
active?: boolean;
|
|
141
|
+
} | undefined;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The `/gate` command handler: `status` renders the live checklist progress
|
|
146
|
+
* plus the latest settled run; `run` settles the full gate and returns the
|
|
147
|
+
* PR-ready markdown report; `config` renders the effective checklist.
|
|
148
|
+
* @param deps - the guard closures the handler reads.
|
|
149
|
+
* @returns the command handler for `ctx.commands.register`.
|
|
150
|
+
*/
|
|
151
|
+
export declare function gateHandler(deps: GateCommandDeps): (invocation: CommandInvocation) => CommandResult | Promise<CommandResult>;
|
|
152
|
+
/**
|
|
153
|
+
* The injected gate-red notice message: short model-facing prose (role
|
|
154
|
+
* statement first) with the structured verdict and red count riding the
|
|
155
|
+
* durable `doublecheck-gate` message source, so the durable once-semantics
|
|
156
|
+
* and the report folds read the record without re-parsing the prose.
|
|
157
|
+
* @param verdict - the settled verdict.
|
|
158
|
+
* @param redCount - the red-item count.
|
|
159
|
+
* @param text - the model-facing notice text.
|
|
160
|
+
* @returns the injection-ready user message.
|
|
161
|
+
*/
|
|
162
|
+
export declare function gateInjection(verdict: GateVerdict, redCount: number, text: string): UserMessage;
|
|
163
|
+
/**
|
|
164
|
+
* Render the effective gate configuration as markdown — the `/gate config`
|
|
165
|
+
* output: the pluggable checklist, the thresholds, and the reviewer knobs.
|
|
166
|
+
* Configuration contains no secrets by construction; nothing is redacted.
|
|
167
|
+
* @param config - the gate configuration.
|
|
168
|
+
* @returns the configuration document.
|
|
169
|
+
*/
|
|
170
|
+
export declare function renderGateConfigMarkdown(config: GateConfig): string;
|