zelari-code 1.48.1 → 2.0.0-alpha.2
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/dist/cli/app.js +4 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/desktopConfig.js +51 -4
- package/dist/cli/desktopConfig.js.map +1 -1
- package/dist/cli/headless.js +65 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/headlessSpine.js +102 -0
- package/dist/cli/headlessSpine.js.map +1 -0
- package/dist/cli/headlessSpine.test.js +153 -0
- package/dist/cli/headlessSpine.test.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +85 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSession.js +16 -2
- package/dist/cli/hooks/useSession.js.map +1 -1
- package/dist/cli/kraken/candidateRegistry.js +195 -0
- package/dist/cli/kraken/candidateRegistry.js.map +1 -0
- package/dist/cli/kraken/candidateRegistry.test.js +211 -0
- package/dist/cli/kraken/candidateRegistry.test.js.map +1 -0
- package/dist/cli/kraken/completionGate.js +116 -0
- package/dist/cli/kraken/completionGate.js.map +1 -0
- package/dist/cli/kraken/completionGate.test.js +172 -0
- package/dist/cli/kraken/completionGate.test.js.map +1 -0
- package/dist/cli/kraken/metrics.js +96 -0
- package/dist/cli/kraken/metrics.js.map +1 -0
- package/dist/cli/kraken/metrics.test.js +145 -0
- package/dist/cli/kraken/metrics.test.js.map +1 -0
- package/dist/cli/kraken/selectionPlaybook.js +23 -0
- package/dist/cli/kraken/selectionPlaybook.js.map +1 -0
- package/dist/cli/kraken/selectionPlaybook.test.js +55 -0
- package/dist/cli/kraken/selectionPlaybook.test.js.map +1 -0
- package/dist/cli/kraken/turnRuntime.js +207 -0
- package/dist/cli/kraken/turnRuntime.js.map +1 -0
- package/dist/cli/kraken/turnRuntime.test.js +377 -0
- package/dist/cli/kraken/turnRuntime.test.js.map +1 -0
- package/dist/cli/kraken/verificationBridge.js +153 -0
- package/dist/cli/kraken/verificationBridge.js.map +1 -0
- package/dist/cli/kraken/verificationBridge.test.js +131 -0
- package/dist/cli/kraken/verificationBridge.test.js.map +1 -0
- package/dist/cli/kraken/verifier.js +233 -0
- package/dist/cli/kraken/verifier.js.map +1 -0
- package/dist/cli/kraken/verifier.test.js +232 -0
- package/dist/cli/kraken/verifier.test.js.map +1 -0
- package/dist/cli/kraken/verifierSettings.test.js +237 -0
- package/dist/cli/kraken/verifierSettings.test.js.map +1 -0
- package/dist/cli/kraken/verifyReport.js +115 -0
- package/dist/cli/kraken/verifyReport.js.map +1 -0
- package/dist/cli/kraken/verifyReport.test.js +111 -0
- package/dist/cli/kraken/verifyReport.test.js.map +1 -0
- package/dist/cli/main.bundled.js +4676 -943
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +29 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/providerConfig.js +46 -0
- package/dist/cli/providerConfig.js.map +1 -1
- package/dist/cli/runHeadless.js +198 -4
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/sessionSpine.js +272 -0
- package/dist/cli/sessionSpine.js.map +1 -0
- package/dist/cli/sessionSpine.test.js +171 -0
- package/dist/cli/sessionSpine.test.js.map +1 -0
- package/dist/cli/toolRegistry.js +50 -6
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/krakenSelectTool.js +165 -0
- package/dist/cli/tools/krakenSelectTool.js.map +1 -0
- package/dist/cli/tools/krakenSelectTool.test.js +246 -0
- package/dist/cli/tools/krakenSelectTool.test.js.map +1 -0
- package/dist/cli/tools/taskTool.dynamicChecks.test.js +156 -0
- package/dist/cli/tools/taskTool.dynamicChecks.test.js.map +1 -0
- package/dist/cli/tools/taskTool.js +174 -6
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/tools/taskTool.planSafety.test.js +280 -0
- package/dist/cli/tools/taskTool.planSafety.test.js.map +1 -0
- package/dist/cli/tools/taskTool.verifyReport.test.js +140 -0
- package/dist/cli/tools/taskTool.verifyReport.test.js.map +1 -0
- package/dist/cli/zelariMission.js +18 -8
- package/dist/cli/zelariMission.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifier.test — Fase 4 (ADR-0020) unit tests for the Kraken selection
|
|
3
|
+
* verifier: identity resolution (parent-exact default), judging prompt
|
|
4
|
+
* rules, lenient verdict parsing, and the never-throw fallback contract.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
import { buildSelectionPrompt, parseSelectionVerdict, resolveKrakenVerifier, runKrakenSelection, VERIFIER_SYSTEM_PROMPT, } from './verifier.js';
|
|
8
|
+
const PARENT = { provider: 'grok', model: 'grok-4-fast' };
|
|
9
|
+
function okCandidate(index, hypothesis, opts = {}) {
|
|
10
|
+
return {
|
|
11
|
+
status: 'ok',
|
|
12
|
+
index,
|
|
13
|
+
description: `candidate ${index}`,
|
|
14
|
+
report: {
|
|
15
|
+
hypothesis,
|
|
16
|
+
evidence: [
|
|
17
|
+
{ claim: `claim-${index}`, basis: `file:${index}`, degraded: opts.degraded === true },
|
|
18
|
+
],
|
|
19
|
+
risks: [],
|
|
20
|
+
hasDegradedEvidence: opts.degraded === true,
|
|
21
|
+
},
|
|
22
|
+
raw: '',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function malformedCandidate(index) {
|
|
26
|
+
return {
|
|
27
|
+
status: 'malformed',
|
|
28
|
+
index,
|
|
29
|
+
description: `candidate ${index}`,
|
|
30
|
+
error: 'missing report block',
|
|
31
|
+
raw: 'no block',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const verdictJson = (o) => `<selection-verdict>\n${JSON.stringify(o, null, 2)}\n</selection-verdict>`;
|
|
35
|
+
// ── resolveKrakenVerifier ──────────────────────────────────────────────────
|
|
36
|
+
describe('resolveKrakenVerifier', () => {
|
|
37
|
+
it('defaults to the EXACT parent identity (no cheap-model routing)', () => {
|
|
38
|
+
expect(resolveKrakenVerifier(PARENT, {})).toEqual(PARENT);
|
|
39
|
+
});
|
|
40
|
+
it('model-only env keeps parent provider, overrides model', () => {
|
|
41
|
+
expect(resolveKrakenVerifier(PARENT, { ZELARI_KRAKEN_SELECT_MODEL: 'glm-4.6' })).toEqual({
|
|
42
|
+
provider: 'grok',
|
|
43
|
+
model: 'glm-4.6',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('provider+model env fully overrides', () => {
|
|
47
|
+
expect(resolveKrakenVerifier(PARENT, {
|
|
48
|
+
ZELARI_KRAKEN_SELECT_PROVIDER: 'openai-compatible',
|
|
49
|
+
ZELARI_KRAKEN_SELECT_MODEL: 'gpt-5',
|
|
50
|
+
})).toEqual({ provider: 'openai-compatible', model: 'gpt-5' });
|
|
51
|
+
});
|
|
52
|
+
it('provider-only env is invalid → falls back to parent (§64)', () => {
|
|
53
|
+
expect(resolveKrakenVerifier(PARENT, { ZELARI_KRAKEN_SELECT_PROVIDER: 'glm' })).toEqual(PARENT);
|
|
54
|
+
});
|
|
55
|
+
it('explicit settings override (Fase 9) wins over env', () => {
|
|
56
|
+
expect(resolveKrakenVerifier(PARENT, { ZELARI_KRAKEN_SELECT_MODEL: 'env-model' }, { provider: 'anthropic', model: 'claude-x' })).toEqual({ provider: 'anthropic', model: 'claude-x' });
|
|
57
|
+
});
|
|
58
|
+
it('partial explicit override is ignored → env applies', () => {
|
|
59
|
+
expect(resolveKrakenVerifier(PARENT, { ZELARI_KRAKEN_SELECT_MODEL: 'env-model' }, { model: 'x' })).toEqual({ provider: 'grok', model: 'env-model' });
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
// ── Prompt ─────────────────────────────────────────────────────────────────
|
|
63
|
+
describe('buildSelectionPrompt / system rules', () => {
|
|
64
|
+
it('system prompt carries the evidence-integrity rules', () => {
|
|
65
|
+
expect(VERIFIER_SYSTEM_PROMPT).toContain('NOT proof of absence');
|
|
66
|
+
expect(VERIFIER_SYSTEM_PROMPT).toContain('Evidence decides');
|
|
67
|
+
expect(VERIFIER_SYSTEM_PROMPT).toContain('needs_more_evidence');
|
|
68
|
+
});
|
|
69
|
+
it('renders hypotheses, degraded tags and malformed candidates', () => {
|
|
70
|
+
const p = buildSelectionPrompt('fix session loss', [
|
|
71
|
+
okCandidate(1, 'token rotation race'),
|
|
72
|
+
okCandidate(2, 'cookie expiry bug', { degraded: true }),
|
|
73
|
+
malformedCandidate(3),
|
|
74
|
+
]);
|
|
75
|
+
expect(p).toContain('TASK');
|
|
76
|
+
expect(p).toContain('Candidate #1 — token rotation race');
|
|
77
|
+
expect(p).toContain('DEGRADED — inconclusive, NOT proof of absence');
|
|
78
|
+
expect(p).toContain('Candidate #3 — UNUSABLE');
|
|
79
|
+
expect(p).toContain('claim-1 (basis: file:1)');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ── parseSelectionVerdict ──────────────────────────────────────────────────
|
|
83
|
+
describe('parseSelectionVerdict', () => {
|
|
84
|
+
const two = [okCandidate(1, 'h1'), okCandidate(2, 'h2')];
|
|
85
|
+
it('accepts a valid selected verdict', () => {
|
|
86
|
+
const r = parseSelectionVerdict(verdictJson({ status: 'selected', winnerIndex: 2, rationale: 'grounded', requiredChecks: ['test:session'] }), two);
|
|
87
|
+
expect(r.ok).toBe(true);
|
|
88
|
+
if (r.ok) {
|
|
89
|
+
expect(r.verdict.status).toBe('selected');
|
|
90
|
+
expect(r.verdict.winnerIndex).toBe(2);
|
|
91
|
+
expect(r.verdict.requiredChecks).toEqual(['test:session']);
|
|
92
|
+
expect(r.verdict.degraded).toBe(false);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
it('accepts needs_more_evidence and ignores any winner', () => {
|
|
96
|
+
const r = parseSelectionVerdict(verdictJson({ status: 'needs_more_evidence', winnerIndex: 1, rationale: 'tie' }), two);
|
|
97
|
+
expect(r.ok).toBe(true);
|
|
98
|
+
if (r.ok)
|
|
99
|
+
expect(r.verdict.winnerIndex).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
it('rejects non-integer winnerIndex', () => {
|
|
102
|
+
expect(parseSelectionVerdict(verdictJson({ status: 'selected', winnerIndex: 1.5 }), two)).toMatchObject({ ok: false });
|
|
103
|
+
expect(parseSelectionVerdict(verdictJson({ status: 'selected', winnerIndex: '2' }), two)).toMatchObject({ ok: false });
|
|
104
|
+
});
|
|
105
|
+
it('rejects a winner pointing at a malformed candidate', () => {
|
|
106
|
+
const r = parseSelectionVerdict(verdictJson({ status: 'selected', winnerIndex: 3 }), [okCandidate(1, 'h1'), okCandidate(2, 'h2'), malformedCandidate(3)]);
|
|
107
|
+
expect(r).toMatchObject({ ok: false });
|
|
108
|
+
});
|
|
109
|
+
it('rejects missing block / invalid JSON / bad status', () => {
|
|
110
|
+
expect(parseSelectionVerdict('no block here', two)).toMatchObject({ ok: false });
|
|
111
|
+
expect(parseSelectionVerdict('<selection-verdict>{bad json}</selection-verdict>', two)).toMatchObject({ ok: false });
|
|
112
|
+
expect(parseSelectionVerdict(verdictJson({ status: 'maybe' }), two)).toMatchObject({ ok: false });
|
|
113
|
+
});
|
|
114
|
+
it('clamps requiredChecks to 5 and drops non-strings', () => {
|
|
115
|
+
const r = parseSelectionVerdict(verdictJson({
|
|
116
|
+
status: 'selected',
|
|
117
|
+
winnerIndex: 1,
|
|
118
|
+
requiredChecks: ['a', 'b', 'c', 'd', 'e', 'f', 42, null],
|
|
119
|
+
}), two);
|
|
120
|
+
expect(r.ok).toBe(true);
|
|
121
|
+
if (r.ok)
|
|
122
|
+
expect(r.verdict.requiredChecks).toEqual(['a', 'b', 'c', 'd', 'e']);
|
|
123
|
+
});
|
|
124
|
+
it('uses the LAST verdict block when the model rambles', () => {
|
|
125
|
+
const raw = `prose <selection-verdict>{"status":"needs_more_evidence"}</selection-verdict> more prose
|
|
126
|
+
<selection-verdict>{"status":"selected","winnerIndex":1}</selection-verdict>`;
|
|
127
|
+
const r = parseSelectionVerdict(raw, two);
|
|
128
|
+
expect(r.ok).toBe(true);
|
|
129
|
+
if (r.ok)
|
|
130
|
+
expect(r.verdict.status).toBe('selected');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
// ── runKrakenSelection ─────────────────────────────────────────────────────
|
|
134
|
+
describe('runKrakenSelection', () => {
|
|
135
|
+
it('zero usable candidates → deterministic needs_more_evidence, no LLM call', async () => {
|
|
136
|
+
let called = 0;
|
|
137
|
+
const v = await runKrakenSelection({
|
|
138
|
+
task: 't',
|
|
139
|
+
candidates: [malformedCandidate(1), malformedCandidate(2)],
|
|
140
|
+
identity: PARENT,
|
|
141
|
+
callModel: async () => {
|
|
142
|
+
called++;
|
|
143
|
+
return '';
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
expect(called).toBe(0);
|
|
147
|
+
expect(v.status).toBe('needs_more_evidence');
|
|
148
|
+
expect(v.degraded).toBe(true);
|
|
149
|
+
expect(v.fallbackReason).toBe('no usable candidates');
|
|
150
|
+
});
|
|
151
|
+
it('single usable candidate → deterministic selection, no LLM call', async () => {
|
|
152
|
+
let called = 0;
|
|
153
|
+
const v = await runKrakenSelection({
|
|
154
|
+
task: 't',
|
|
155
|
+
candidates: [okCandidate(1, 'only'), malformedCandidate(2)],
|
|
156
|
+
identity: PARENT,
|
|
157
|
+
callModel: async () => {
|
|
158
|
+
called++;
|
|
159
|
+
return '';
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
expect(called).toBe(0);
|
|
163
|
+
expect(v.status).toBe('selected');
|
|
164
|
+
expect(v.winnerIndex).toBe(1);
|
|
165
|
+
expect(v.judgedBy).toBe('deterministic');
|
|
166
|
+
});
|
|
167
|
+
it('two candidates → LLM judges with system+user and identity rides the verdict', async () => {
|
|
168
|
+
let seen = null;
|
|
169
|
+
const v = await runKrakenSelection({
|
|
170
|
+
task: 'fix intermittent session loss',
|
|
171
|
+
candidates: [okCandidate(1, 'race in refresh'), okCandidate(2, 'cookie expiry')],
|
|
172
|
+
identity: PARENT,
|
|
173
|
+
callModel: async ({ system, user }) => {
|
|
174
|
+
seen = { system, user };
|
|
175
|
+
return verdictJson({
|
|
176
|
+
status: 'selected',
|
|
177
|
+
winnerIndex: 1,
|
|
178
|
+
rationale: 'grounded in file evidence',
|
|
179
|
+
requiredChecks: ['regression test for concurrent refresh'],
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
expect(seen).not.toBeNull();
|
|
184
|
+
expect(seen.system).toContain('selection verifier');
|
|
185
|
+
expect(seen.user).toContain('fix intermittent session loss');
|
|
186
|
+
expect(v).toMatchObject({
|
|
187
|
+
status: 'selected',
|
|
188
|
+
winnerIndex: 1,
|
|
189
|
+
judgedBy: 'llm',
|
|
190
|
+
degraded: false,
|
|
191
|
+
verifier: PARENT,
|
|
192
|
+
});
|
|
193
|
+
expect(v.requiredChecks).toEqual(['regression test for concurrent refresh']);
|
|
194
|
+
});
|
|
195
|
+
it('model says tie → clean needs_more_evidence (not degraded)', async () => {
|
|
196
|
+
const v = await runKrakenSelection({
|
|
197
|
+
task: 't',
|
|
198
|
+
candidates: [okCandidate(1, 'a'), okCandidate(2, 'b')],
|
|
199
|
+
identity: PARENT,
|
|
200
|
+
callModel: async () => verdictJson({ status: 'needs_more_evidence', rationale: 'equally supported' }),
|
|
201
|
+
});
|
|
202
|
+
expect(v.status).toBe('needs_more_evidence');
|
|
203
|
+
expect(v.degraded).toBe(false);
|
|
204
|
+
expect(v.judgedBy).toBe('llm');
|
|
205
|
+
});
|
|
206
|
+
it('callModel throws (timeout/429/network) → degraded, run continues', async () => {
|
|
207
|
+
const v = await runKrakenSelection({
|
|
208
|
+
task: 't',
|
|
209
|
+
candidates: [okCandidate(1, 'a'), okCandidate(2, 'b')],
|
|
210
|
+
identity: PARENT,
|
|
211
|
+
callModel: async () => {
|
|
212
|
+
throw new Error('429 rate limited');
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
expect(v.status).toBe('needs_more_evidence');
|
|
216
|
+
expect(v.degraded).toBe(true);
|
|
217
|
+
expect(v.fallbackReason).toBe('verifier call failed');
|
|
218
|
+
expect(v.rationale).toContain('429');
|
|
219
|
+
});
|
|
220
|
+
it('malformed verifier response → degraded with reason', async () => {
|
|
221
|
+
const v = await runKrakenSelection({
|
|
222
|
+
task: 't',
|
|
223
|
+
candidates: [okCandidate(1, 'a'), okCandidate(2, 'b')],
|
|
224
|
+
identity: PARENT,
|
|
225
|
+
callModel: async () => 'I think candidate 1 is nicer',
|
|
226
|
+
});
|
|
227
|
+
expect(v.status).toBe('needs_more_evidence');
|
|
228
|
+
expect(v.degraded).toBe(true);
|
|
229
|
+
expect(v.fallbackReason).toContain('malformed verifier response');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
//# sourceMappingURL=verifier.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/verifier.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifierSettings — Fase 9 settings tests (ADR-0020 §57/§64).
|
|
3
|
+
*
|
|
4
|
+
* Coverage required by the plan:
|
|
5
|
+
* - old provider.json (no krakenVerifier field) → verifier inherit
|
|
6
|
+
* - inherit → follows the current run model (parent identity)
|
|
7
|
+
* - explicit custom verifier → fixed model (survives parent changes)
|
|
8
|
+
* - missing/invalid custom verifier → parent model fallback
|
|
9
|
+
* - save/reload round-trip persists the override
|
|
10
|
+
* - --set-config flag parsing (verifier-provider/model/clear)
|
|
11
|
+
* - applySetConfig + snapshot exposure (Desktop save/reload)
|
|
12
|
+
*
|
|
13
|
+
* All file I/O is redirected to a temp file via ANATHEMA_PROVIDER_CONFIG_FILE.
|
|
14
|
+
*/
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
16
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { tmpdir } from 'node:os';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { getProviderConfig, getKrakenVerifierOverride, setKrakenVerifier, clearKrakenVerifier, } from '../providerConfig.js';
|
|
20
|
+
import { parseSetConfigFlags, applySetConfig, buildDesktopConfigSnapshot, } from '../desktopConfig.js';
|
|
21
|
+
import { resolveKrakenVerifier } from './verifier.js';
|
|
22
|
+
let tmpDir = '';
|
|
23
|
+
let savedEnv;
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
tmpDir = mkdtempSync(path.join(tmpdir(), 'zelari-vf-'));
|
|
26
|
+
savedEnv = process.env.ANATHEMA_PROVIDER_CONFIG_FILE;
|
|
27
|
+
process.env.ANATHEMA_PROVIDER_CONFIG_FILE = path.join(tmpDir, 'provider.json');
|
|
28
|
+
delete process.env.ZELARI_KRAKEN_SELECT_PROVIDER;
|
|
29
|
+
delete process.env.ZELARI_KRAKEN_SELECT_MODEL;
|
|
30
|
+
});
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
if (savedEnv === undefined)
|
|
33
|
+
delete process.env.ANATHEMA_PROVIDER_CONFIG_FILE;
|
|
34
|
+
else
|
|
35
|
+
process.env.ANATHEMA_PROVIDER_CONFIG_FILE = savedEnv;
|
|
36
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
37
|
+
});
|
|
38
|
+
/** Write a provider.json blob (as an old or hand-edited file would look). */
|
|
39
|
+
function writeConfigFile(raw) {
|
|
40
|
+
writeFileSync(process.env.ANATHEMA_PROVIDER_CONFIG_FILE, JSON.stringify(raw, null, 2), 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
const OLD_FILE = {
|
|
43
|
+
activeProviderId: 'grok',
|
|
44
|
+
modelByProvider: { grok: 'grok-4.6' },
|
|
45
|
+
};
|
|
46
|
+
const PARENT = { provider: 'grok', model: 'grok-4.6' };
|
|
47
|
+
describe('providerConfig.krakenVerifier', () => {
|
|
48
|
+
it('old provider.json without the field → override undefined (inherit)', () => {
|
|
49
|
+
writeConfigFile(OLD_FILE);
|
|
50
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
51
|
+
// inherit resolution: exact parent model, no LLM-config surprise
|
|
52
|
+
expect(resolveKrakenVerifier(PARENT)).toEqual(PARENT);
|
|
53
|
+
});
|
|
54
|
+
it('inherit → follows the current run model', () => {
|
|
55
|
+
writeConfigFile(OLD_FILE);
|
|
56
|
+
const otherParent = { provider: 'glm', model: 'glm-4.6' };
|
|
57
|
+
// no override + no env → whatever model the run resolved wins
|
|
58
|
+
expect(resolveKrakenVerifier(otherParent)).toEqual(otherParent);
|
|
59
|
+
});
|
|
60
|
+
it('explicit custom verifier → fixed model, independent of parent', () => {
|
|
61
|
+
writeConfigFile(OLD_FILE);
|
|
62
|
+
setKrakenVerifier('anthropic', 'claude-sonnet-4-6');
|
|
63
|
+
const override = getKrakenVerifierOverride();
|
|
64
|
+
expect(override).toEqual({ provider: 'anthropic', model: 'claude-sonnet-4-6' });
|
|
65
|
+
// parent changed → verifier stays fixed (the tool passes the persisted
|
|
66
|
+
// override as `explicit` — see krakenSelectTool wiring)
|
|
67
|
+
expect(resolveKrakenVerifier({ provider: 'grok', model: 'grok-4.6' }, process.env, getKrakenVerifierOverride())).toEqual({
|
|
68
|
+
provider: 'anthropic',
|
|
69
|
+
model: 'claude-sonnet-4-6',
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
it('save/reload round-trip: persisted override survives a fresh read', () => {
|
|
73
|
+
writeConfigFile(OLD_FILE);
|
|
74
|
+
setKrakenVerifier('minimax', 'MiniMax-M2.5');
|
|
75
|
+
const reloaded = getProviderConfig();
|
|
76
|
+
expect(reloaded.krakenVerifier).toEqual({ provider: 'minimax', model: 'MiniMax-M2.5' });
|
|
77
|
+
});
|
|
78
|
+
it('invalid overrides on disk are dropped → parent fallback', () => {
|
|
79
|
+
// partial (provider only)
|
|
80
|
+
writeConfigFile({ ...OLD_FILE, krakenVerifier: { provider: 'grok' } });
|
|
81
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
82
|
+
// unknown provider
|
|
83
|
+
writeConfigFile({
|
|
84
|
+
...OLD_FILE,
|
|
85
|
+
krakenVerifier: { provider: 'nope', model: 'm' },
|
|
86
|
+
});
|
|
87
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
88
|
+
// empty model
|
|
89
|
+
writeConfigFile({
|
|
90
|
+
...OLD_FILE,
|
|
91
|
+
krakenVerifier: { provider: 'grok', model: ' ' },
|
|
92
|
+
});
|
|
93
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
94
|
+
// non-object garbage
|
|
95
|
+
writeConfigFile({ ...OLD_FILE, krakenVerifier: 'grok' });
|
|
96
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
97
|
+
// in every case resolution falls back to the exact parent model
|
|
98
|
+
expect(resolveKrakenVerifier(PARENT)).toEqual(PARENT);
|
|
99
|
+
});
|
|
100
|
+
it('clearKrakenVerifier → back to inherit (no-op when already inherit)', () => {
|
|
101
|
+
writeConfigFile(OLD_FILE);
|
|
102
|
+
setKrakenVerifier('grok', 'grok-4.6');
|
|
103
|
+
clearKrakenVerifier();
|
|
104
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
105
|
+
expect(() => clearKrakenVerifier()).not.toThrow();
|
|
106
|
+
});
|
|
107
|
+
it('setKrakenVerifier validates provider and model', () => {
|
|
108
|
+
writeConfigFile(OLD_FILE);
|
|
109
|
+
expect(() => setKrakenVerifier('nope', 'm')).toThrow(/Unknown provider id/);
|
|
110
|
+
expect(() => setKrakenVerifier('grok', ' ')).toThrow(/cannot be empty/);
|
|
111
|
+
});
|
|
112
|
+
it('env override still wins when no persisted config exists', () => {
|
|
113
|
+
writeConfigFile(OLD_FILE);
|
|
114
|
+
const resolved = resolveKrakenVerifier(PARENT, {
|
|
115
|
+
ZELARI_KRAKEN_SELECT_PROVIDER: 'deepseek',
|
|
116
|
+
ZELARI_KRAKEN_SELECT_MODEL: 'deepseek-v4-pro',
|
|
117
|
+
});
|
|
118
|
+
expect(resolved).toEqual({ provider: 'deepseek', model: 'deepseek-v4-pro' });
|
|
119
|
+
});
|
|
120
|
+
it('persisted override is passed as `explicit` → beats env', () => {
|
|
121
|
+
writeConfigFile(OLD_FILE);
|
|
122
|
+
setKrakenVerifier('glm', 'glm-4.6');
|
|
123
|
+
const resolved = resolveKrakenVerifier(PARENT, {
|
|
124
|
+
ZELARI_KRAKEN_SELECT_PROVIDER: 'deepseek',
|
|
125
|
+
ZELARI_KRAKEN_SELECT_MODEL: 'deepseek-v4-pro',
|
|
126
|
+
}, getKrakenVerifierOverride());
|
|
127
|
+
expect(resolved).toEqual({ provider: 'glm', model: 'glm-4.6' });
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe('parseSetConfigFlags — verifier flags', () => {
|
|
131
|
+
it('valid: --verifier-provider + --verifier-model together', () => {
|
|
132
|
+
const res = parseSetConfigFlags([
|
|
133
|
+
'--set-config',
|
|
134
|
+
'--verifier-provider',
|
|
135
|
+
'anthropic',
|
|
136
|
+
'--verifier-model',
|
|
137
|
+
'claude-sonnet-4-6',
|
|
138
|
+
]);
|
|
139
|
+
expect(res.error).toBeUndefined();
|
|
140
|
+
expect(res.request?.verifierProvider).toBe('anthropic');
|
|
141
|
+
expect(res.request?.verifierModel).toBe('claude-sonnet-4-6');
|
|
142
|
+
expect(res.request?.verifierClear).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
it('valid: --verifier-clear alone', () => {
|
|
145
|
+
const res = parseSetConfigFlags(['--set-config', '--verifier-clear']);
|
|
146
|
+
expect(res.error).toBeUndefined();
|
|
147
|
+
expect(res.request?.verifierClear).toBe(true);
|
|
148
|
+
expect(res.request?.verifierProvider).toBeUndefined();
|
|
149
|
+
});
|
|
150
|
+
it('provider without model → error', () => {
|
|
151
|
+
const res = parseSetConfigFlags(['--set-config', '--verifier-provider', 'grok']);
|
|
152
|
+
expect(res.request).toBeNull();
|
|
153
|
+
expect(res.error).toMatch(/must be used together/);
|
|
154
|
+
});
|
|
155
|
+
it('model without provider → error', () => {
|
|
156
|
+
const res = parseSetConfigFlags(['--set-config', '--verifier-model', 'm']);
|
|
157
|
+
expect(res.request).toBeNull();
|
|
158
|
+
expect(res.error).toMatch(/must be used together/);
|
|
159
|
+
});
|
|
160
|
+
it('clear + provider/model → conflict error', () => {
|
|
161
|
+
const res = parseSetConfigFlags([
|
|
162
|
+
'--set-config',
|
|
163
|
+
'--verifier-clear',
|
|
164
|
+
'--verifier-provider',
|
|
165
|
+
'grok',
|
|
166
|
+
'--verifier-model',
|
|
167
|
+
'm',
|
|
168
|
+
]);
|
|
169
|
+
expect(res.request).toBeNull();
|
|
170
|
+
expect(res.error).toMatch(/conflicts/);
|
|
171
|
+
});
|
|
172
|
+
it('empty values → error', () => {
|
|
173
|
+
const a = parseSetConfigFlags([
|
|
174
|
+
'--set-config',
|
|
175
|
+
'--verifier-provider',
|
|
176
|
+
' ',
|
|
177
|
+
'--verifier-model',
|
|
178
|
+
'm',
|
|
179
|
+
]);
|
|
180
|
+
expect(a.error).toMatch(/cannot be empty/);
|
|
181
|
+
const b = parseSetConfigFlags([
|
|
182
|
+
'--set-config',
|
|
183
|
+
'--verifier-provider',
|
|
184
|
+
'grok',
|
|
185
|
+
'--verifier-model',
|
|
186
|
+
'',
|
|
187
|
+
]);
|
|
188
|
+
expect(b.error).toMatch(/cannot be empty/);
|
|
189
|
+
});
|
|
190
|
+
it('no flags at all → still an error (same as before)', () => {
|
|
191
|
+
const res = parseSetConfigFlags(['--set-config']);
|
|
192
|
+
expect(res.request).toBeNull();
|
|
193
|
+
expect(res.error).toMatch(/--set-config requires/);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('applySetConfig + snapshot — verifier persistence', () => {
|
|
197
|
+
it('set via flags → persisted → snapshot exposes it', () => {
|
|
198
|
+
writeConfigFile(OLD_FILE);
|
|
199
|
+
const res = applySetConfig({
|
|
200
|
+
verifierProvider: 'anthropic',
|
|
201
|
+
verifierModel: 'claude-sonnet-4-6',
|
|
202
|
+
});
|
|
203
|
+
expect(res.ok).toBe(true);
|
|
204
|
+
if (res.ok)
|
|
205
|
+
expect(res.message).toContain('verifier=anthropic/claude-sonnet-4-6');
|
|
206
|
+
const snap = buildDesktopConfigSnapshot();
|
|
207
|
+
expect(snap.krakenVerifier).toEqual({
|
|
208
|
+
provider: 'anthropic',
|
|
209
|
+
model: 'claude-sonnet-4-6',
|
|
210
|
+
});
|
|
211
|
+
// save/reload equality (Desktop round-trip)
|
|
212
|
+
expect(getKrakenVerifierOverride()).toEqual(snap.krakenVerifier);
|
|
213
|
+
});
|
|
214
|
+
it('unknown verifier provider → explicit error, nothing persisted', () => {
|
|
215
|
+
writeConfigFile(OLD_FILE);
|
|
216
|
+
const res = applySetConfig({ verifierProvider: 'nope', verifierModel: 'm' });
|
|
217
|
+
expect(res.ok).toBe(false);
|
|
218
|
+
if (!res.ok)
|
|
219
|
+
expect(res.error).toMatch(/unknown verifier provider/);
|
|
220
|
+
expect(getKrakenVerifierOverride()).toBeUndefined();
|
|
221
|
+
});
|
|
222
|
+
it('clear via flags → snapshot back to null (inherit)', () => {
|
|
223
|
+
writeConfigFile(OLD_FILE);
|
|
224
|
+
setKrakenVerifier('grok', 'grok-4.6');
|
|
225
|
+
const res = applySetConfig({ verifierClear: true });
|
|
226
|
+
expect(res.ok).toBe(true);
|
|
227
|
+
if (res.ok)
|
|
228
|
+
expect(res.message).toContain('verifier=inherit');
|
|
229
|
+
expect(buildDesktopConfigSnapshot().krakenVerifier).toBeNull();
|
|
230
|
+
});
|
|
231
|
+
it('fresh install (no file) → snapshot krakenVerifier null, inherit default', () => {
|
|
232
|
+
// no config file written in this tmp dir
|
|
233
|
+
const snap = buildDesktopConfigSnapshot();
|
|
234
|
+
expect(snap.krakenVerifier).toBeNull();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=verifierSettings.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifierSettings.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/verifierSettings.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifyReport — structured per-check verification results (Fase 7, ADR-0020).
|
|
3
|
+
*
|
|
4
|
+
* A verify tentacle whose acceptance includes the turn's required checks
|
|
5
|
+
* (Fase 6 routing) ends its conclusion with ONE `<verify-report>` block per
|
|
6
|
+
* criterion:
|
|
7
|
+
*
|
|
8
|
+
* <verify-report>
|
|
9
|
+
* check: unit test for session refresh passes
|
|
10
|
+
* status: pass
|
|
11
|
+
* note: vitest 41/41
|
|
12
|
+
* </verify-report>
|
|
13
|
+
*
|
|
14
|
+
* Parsing is LENIENT and deterministic:
|
|
15
|
+
* - missing/invalid status word → `unknown`
|
|
16
|
+
* - criterion without a block → `unknown` (no report ≠ pass)
|
|
17
|
+
* - failed tentacle → all `unknown` (allUnknownCheckResults)
|
|
18
|
+
* - later duplicate blocks win (the tentacle may correct itself)
|
|
19
|
+
*
|
|
20
|
+
* Observation integrity (§23 of the plan): `unknown` is a first-class
|
|
21
|
+
* outcome. A degraded observation (timeout, broken tool) must never be
|
|
22
|
+
* recorded as `pass` — the completion gate (Fase 8) treats only `pass` as
|
|
23
|
+
* satisfied.
|
|
24
|
+
*/
|
|
25
|
+
const OPEN = '<verify-report>';
|
|
26
|
+
const CLOSE = '</verify-report>';
|
|
27
|
+
const VALID_STATUSES = new Set(['pass', 'fail', 'unknown']);
|
|
28
|
+
/** Lowercase + collapse whitespace (matching is wording-tolerant). */
|
|
29
|
+
function normalize(text) {
|
|
30
|
+
return text.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract raw `<verify-report>` blocks in order of appearance. Blocks
|
|
34
|
+
* without a `check:` line are skipped (nothing to match on); a missing or
|
|
35
|
+
* invalid `status:` is kept as '' and sanitized to `unknown` at match time.
|
|
36
|
+
*/
|
|
37
|
+
export function extractVerifyReportBlocks(raw) {
|
|
38
|
+
const blocks = [];
|
|
39
|
+
let cursor = 0;
|
|
40
|
+
for (;;) {
|
|
41
|
+
const open = raw.indexOf(OPEN, cursor);
|
|
42
|
+
if (open === -1)
|
|
43
|
+
break;
|
|
44
|
+
const close = raw.indexOf(CLOSE, open + OPEN.length);
|
|
45
|
+
if (close === -1)
|
|
46
|
+
break;
|
|
47
|
+
const block = { check: '', status: '' };
|
|
48
|
+
for (const line of raw.slice(open + OPEN.length, close).split(/\r?\n/)) {
|
|
49
|
+
const m = /^(check|status|note)\s*:\s*(.*)$/i.exec(line.trim());
|
|
50
|
+
if (!m)
|
|
51
|
+
continue;
|
|
52
|
+
const value = m[2].trim();
|
|
53
|
+
const key = m[1].toLowerCase();
|
|
54
|
+
if (key === 'check' && !block.check)
|
|
55
|
+
block.check = value;
|
|
56
|
+
else if (key === 'status' && !block.status)
|
|
57
|
+
block.status = value;
|
|
58
|
+
else if (key === 'note' && block.note === undefined)
|
|
59
|
+
block.note = value;
|
|
60
|
+
}
|
|
61
|
+
if (block.check)
|
|
62
|
+
blocks.push(block);
|
|
63
|
+
cursor = close + CLOSE.length;
|
|
64
|
+
}
|
|
65
|
+
return blocks;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Map the turn's required checks onto per-check results.
|
|
69
|
+
*
|
|
70
|
+
* Matching: normalized equality first, then containment (either direction)
|
|
71
|
+
* so a tentacle that lightly rewords a criterion still matches; later
|
|
72
|
+
* blocks for the same criterion override earlier ones.
|
|
73
|
+
*/
|
|
74
|
+
export function parseVerifyReport(raw, requiredChecks) {
|
|
75
|
+
const byCriterion = new Map();
|
|
76
|
+
for (const block of extractVerifyReportBlocks(raw)) {
|
|
77
|
+
byCriterion.set(normalize(block.check), block);
|
|
78
|
+
}
|
|
79
|
+
const keys = [...byCriterion.keys()];
|
|
80
|
+
return requiredChecks.map((check) => {
|
|
81
|
+
const norm = normalize(check);
|
|
82
|
+
let block = byCriterion.get(norm) ?? null;
|
|
83
|
+
if (!block) {
|
|
84
|
+
for (const key of keys) {
|
|
85
|
+
if (key.length >= 8 && (key.includes(norm) || norm.includes(key))) {
|
|
86
|
+
block = byCriterion.get(key) ?? null;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!block) {
|
|
92
|
+
return {
|
|
93
|
+
check,
|
|
94
|
+
status: 'unknown',
|
|
95
|
+
note: 'no verify-report block for this check',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const status = VALID_STATUSES.has(block.status)
|
|
99
|
+
? block.status
|
|
100
|
+
: 'unknown';
|
|
101
|
+
return { check, status, ...(block.note ? { note: block.note } : {}) };
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* All-unknown results for a verify tentacle that never produced a usable
|
|
106
|
+
* conclusion (failure, abort, empty output). Degraded ≠ proof of anything.
|
|
107
|
+
*/
|
|
108
|
+
export function allUnknownCheckResults(requiredChecks, reason) {
|
|
109
|
+
return requiredChecks.map((check) => ({
|
|
110
|
+
check,
|
|
111
|
+
status: 'unknown',
|
|
112
|
+
note: reason,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=verifyReport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyReport.js","sourceRoot":"","sources":["../../../src/cli/kraken/verifyReport.ts"],"names":[],"mappings":"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"}
|