zelari-code 1.48.0 → 1.49.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/dist/cli/desktopConfig.js +51 -4
- package/dist/cli/desktopConfig.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +80 -0
- package/dist/cli/hooks/useChatTurn.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/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 +1369 -111
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/provider/openai-compatible.js +40 -6
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/provider/openai-compatible.timeout.test.js +72 -0
- package/dist/cli/provider/openai-compatible.timeout.test.js.map +1 -0
- package/dist/cli/providerConfig.js +46 -0
- package/dist/cli/providerConfig.js.map +1 -1
- package/dist/cli/runHeadless.js +85 -0
- package/dist/cli/runHeadless.js.map +1 -1
- 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/package.json +2 -2
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fase 8 (ADR-0020) — completion gate unit tests.
|
|
3
|
+
*
|
|
4
|
+
* classify: pure matching semantics (mirrors verifyReport).
|
|
5
|
+
* evaluate: registry-driven gating (build-only, selection-only).
|
|
6
|
+
* prompt: repair directive shape.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { buildKrakenRepairPrompt, classifyKrakenChecks, evaluateKrakenCompletionGate, } from './completionGate.js';
|
|
10
|
+
import { resetKrakenCandidates, setKrakenCheckResults, setKrakenSelection, } from './candidateRegistry.js';
|
|
11
|
+
const CHECKS = [
|
|
12
|
+
'session survives concurrent refresh',
|
|
13
|
+
'rotated cookie rejects the old token',
|
|
14
|
+
];
|
|
15
|
+
function result(check, status) {
|
|
16
|
+
return { check, status };
|
|
17
|
+
}
|
|
18
|
+
function selectWithChecks(checks) {
|
|
19
|
+
resetKrakenCandidates();
|
|
20
|
+
setKrakenSelection({
|
|
21
|
+
status: 'selected',
|
|
22
|
+
winnerIndex: 1,
|
|
23
|
+
rationale: 'stronger evidence',
|
|
24
|
+
requiredChecks: checks,
|
|
25
|
+
degraded: false,
|
|
26
|
+
verifier: null,
|
|
27
|
+
judgedBy: 'llm',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
describe('classifyKrakenChecks', () => {
|
|
31
|
+
it('null results → every check unknown (no report ≠ pass)', () => {
|
|
32
|
+
const out = classifyKrakenChecks(CHECKS, null);
|
|
33
|
+
expect(out.unknown).toEqual(CHECKS);
|
|
34
|
+
expect(out.passed).toEqual([]);
|
|
35
|
+
expect(out.failed).toEqual([]);
|
|
36
|
+
});
|
|
37
|
+
it('groups pass/fail/unknown by exact normalized match', () => {
|
|
38
|
+
const out = classifyKrakenChecks(CHECKS, [
|
|
39
|
+
result('Session survives concurrent refresh', 'pass'),
|
|
40
|
+
result('rotated cookie rejects the old token', 'fail'),
|
|
41
|
+
]);
|
|
42
|
+
expect(out.passed).toEqual([CHECKS[0]]);
|
|
43
|
+
expect(out.failed).toEqual([CHECKS[1]]);
|
|
44
|
+
expect(out.unknown).toEqual([]);
|
|
45
|
+
});
|
|
46
|
+
it('matches a lightly reworded criterion by containment', () => {
|
|
47
|
+
const out = classifyKrakenChecks(['race condition on concurrent session refresh'], [result('concurrent session refresh', 'pass')]);
|
|
48
|
+
expect(out.passed).toEqual(['race condition on concurrent session refresh']);
|
|
49
|
+
});
|
|
50
|
+
it('later duplicate results win (self-correction)', () => {
|
|
51
|
+
const out = classifyKrakenChecks(CHECKS, [
|
|
52
|
+
result(CHECKS[0], 'fail'),
|
|
53
|
+
result(CHECKS[0], 'pass'),
|
|
54
|
+
]);
|
|
55
|
+
expect(out.passed).toEqual([CHECKS[0]]);
|
|
56
|
+
expect(out.failed).toEqual([]);
|
|
57
|
+
});
|
|
58
|
+
it('a check with no matching block is unknown, never pass', () => {
|
|
59
|
+
const out = classifyKrakenChecks(CHECKS, [result('totally unrelated check', 'pass')]);
|
|
60
|
+
expect(out.unknown).toEqual(CHECKS);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('evaluateKrakenCompletionGate', () => {
|
|
64
|
+
it('open when no selection ran this turn', () => {
|
|
65
|
+
resetKrakenCandidates();
|
|
66
|
+
const gate = evaluateKrakenCompletionGate('build');
|
|
67
|
+
expect(gate.blocked).toBe(false);
|
|
68
|
+
expect(gate.selectionUsed).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it('open for needs_more_evidence — checks stay advisory', () => {
|
|
71
|
+
resetKrakenCandidates();
|
|
72
|
+
setKrakenSelection({
|
|
73
|
+
status: 'needs_more_evidence',
|
|
74
|
+
winnerIndex: null,
|
|
75
|
+
rationale: 'tie',
|
|
76
|
+
requiredChecks: ['advisory check'],
|
|
77
|
+
degraded: false,
|
|
78
|
+
verifier: null,
|
|
79
|
+
judgedBy: 'llm',
|
|
80
|
+
});
|
|
81
|
+
expect(evaluateKrakenCompletionGate('build').blocked).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
it('blocked when verification never ran (all unknown)', () => {
|
|
84
|
+
selectWithChecks(CHECKS);
|
|
85
|
+
const gate = evaluateKrakenCompletionGate('build');
|
|
86
|
+
expect(gate.blocked).toBe(true);
|
|
87
|
+
expect(gate.selectionUsed).toBe(true);
|
|
88
|
+
expect(gate.total).toBe(2);
|
|
89
|
+
expect(gate.passed).toBe(0);
|
|
90
|
+
expect(gate.unknownChecks).toEqual(CHECKS);
|
|
91
|
+
});
|
|
92
|
+
it('blocked while any check fails (pass does not offset fail)', () => {
|
|
93
|
+
selectWithChecks(CHECKS);
|
|
94
|
+
setKrakenCheckResults([
|
|
95
|
+
result(CHECKS[0], 'pass'),
|
|
96
|
+
result(CHECKS[1], 'fail'),
|
|
97
|
+
]);
|
|
98
|
+
const gate = evaluateKrakenCompletionGate('build');
|
|
99
|
+
expect(gate.blocked).toBe(true);
|
|
100
|
+
expect(gate.failedChecks).toEqual([CHECKS[1]]);
|
|
101
|
+
});
|
|
102
|
+
it('blocked while any check is unknown (unknown ≠ pass)', () => {
|
|
103
|
+
selectWithChecks(CHECKS);
|
|
104
|
+
setKrakenCheckResults([
|
|
105
|
+
result(CHECKS[0], 'pass'),
|
|
106
|
+
result(CHECKS[1], 'unknown'),
|
|
107
|
+
]);
|
|
108
|
+
expect(evaluateKrakenCompletionGate('build').blocked).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
it('open only when every check passes', () => {
|
|
111
|
+
selectWithChecks(CHECKS);
|
|
112
|
+
setKrakenCheckResults(CHECKS.map((c) => result(c, 'pass')));
|
|
113
|
+
const gate = evaluateKrakenCompletionGate('build');
|
|
114
|
+
expect(gate.blocked).toBe(false);
|
|
115
|
+
expect(gate.passed).toBe(2);
|
|
116
|
+
});
|
|
117
|
+
it('never blocks a PLAN turn even with unresolved checks', () => {
|
|
118
|
+
selectWithChecks(CHECKS);
|
|
119
|
+
// no results at all → would block in build
|
|
120
|
+
expect(evaluateKrakenCompletionGate('build').blocked).toBe(true);
|
|
121
|
+
expect(evaluateKrakenCompletionGate('plan').blocked).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
it('reset clears the gate state', () => {
|
|
124
|
+
selectWithChecks(CHECKS);
|
|
125
|
+
resetKrakenCandidates();
|
|
126
|
+
expect(evaluateKrakenCompletionGate('build').selectionUsed).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('buildKrakenRepairPrompt', () => {
|
|
130
|
+
it('lists failed and unknown checks with the pass counter', () => {
|
|
131
|
+
const prompt = buildKrakenRepairPrompt({
|
|
132
|
+
blocked: true,
|
|
133
|
+
selectionUsed: true,
|
|
134
|
+
total: 3,
|
|
135
|
+
passed: 1,
|
|
136
|
+
failedChecks: ['race on refresh'],
|
|
137
|
+
unknownChecks: ['cookie rotation'],
|
|
138
|
+
});
|
|
139
|
+
expect(prompt).toContain('passed 1/3');
|
|
140
|
+
expect(prompt).toContain('FAILED checks');
|
|
141
|
+
expect(prompt).toContain('- race on refresh');
|
|
142
|
+
expect(prompt).toContain('UNKNOWN checks');
|
|
143
|
+
expect(prompt).toContain('- cookie rotation');
|
|
144
|
+
});
|
|
145
|
+
it('forbids re-running kraken_select and demands a verify tentacle', () => {
|
|
146
|
+
const prompt = buildKrakenRepairPrompt({
|
|
147
|
+
blocked: true,
|
|
148
|
+
selectionUsed: true,
|
|
149
|
+
total: 1,
|
|
150
|
+
passed: 0,
|
|
151
|
+
failedChecks: ['x'],
|
|
152
|
+
unknownChecks: [],
|
|
153
|
+
});
|
|
154
|
+
expect(prompt).toContain('do NOT call kraken_select again');
|
|
155
|
+
expect(prompt).toContain('`task verify`');
|
|
156
|
+
expect(prompt).toContain('<verify-report>');
|
|
157
|
+
expect(prompt).toContain('status: pass');
|
|
158
|
+
});
|
|
159
|
+
it('omits empty sections', () => {
|
|
160
|
+
const prompt = buildKrakenRepairPrompt({
|
|
161
|
+
blocked: true,
|
|
162
|
+
selectionUsed: true,
|
|
163
|
+
total: 2,
|
|
164
|
+
passed: 0,
|
|
165
|
+
failedChecks: [],
|
|
166
|
+
unknownChecks: ['a', 'b'],
|
|
167
|
+
});
|
|
168
|
+
expect(prompt).not.toContain('FAILED checks');
|
|
169
|
+
expect(prompt).toContain('UNKNOWN checks');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
//# sourceMappingURL=completionGate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completionGate.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/completionGate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kraken Verified Selection — per-turn metrics (Fase 10, ADR-0020 §58).
|
|
3
|
+
*
|
|
4
|
+
* Captures the cost/effectiveness telemetry of a Kraken turn that used the
|
|
5
|
+
* selection flow, so alpha adoption can be measured against the key question:
|
|
6
|
+
* "do SIMPLE tasks pay a measurable price?" (They must not — with
|
|
7
|
+
* ZELARI_KRAKEN_SELECTION unset the registry stays empty, collect returns
|
|
8
|
+
* null and nothing is emitted.)
|
|
9
|
+
*
|
|
10
|
+
* Design mirrors candidateRegistry: in-memory, per-process, reset every
|
|
11
|
+
* parent turn. Transient counters (tokens, latency, repair flags) are
|
|
12
|
+
* recorded at call sites; everything derivable (selectionUsed,
|
|
13
|
+
* candidateCount, needsMoreEvidence, verification pass/fail/unknown) is
|
|
14
|
+
* derived at collect time from the candidate registry + completion gate —
|
|
15
|
+
* one source of truth, no double bookkeeping.
|
|
16
|
+
*
|
|
17
|
+
* Token numbers are REAL provider-reported usage (UsageBreakdown on
|
|
18
|
+
* message_end / usage deltas), never approximated. Absent usage stays
|
|
19
|
+
* undefined/0 — we do not fabricate data.
|
|
20
|
+
*/
|
|
21
|
+
import { getKrakenCheckResults, getKrakenSelection, krakenCandidates, krakenRequiredChecks, } from './candidateRegistry.js';
|
|
22
|
+
import { classifyKrakenChecks } from './completionGate.js';
|
|
23
|
+
function store() {
|
|
24
|
+
const g = globalThis;
|
|
25
|
+
g.__zelariKrakenTurnMetrics ??= {
|
|
26
|
+
candidateTokens: 0,
|
|
27
|
+
selectionRecorded: false,
|
|
28
|
+
selectionFallback: false,
|
|
29
|
+
repairTriggered: false,
|
|
30
|
+
repairSucceeded: false,
|
|
31
|
+
};
|
|
32
|
+
return g.__zelariKrakenTurnMetrics;
|
|
33
|
+
}
|
|
34
|
+
/** Reset per parent turn (call beside resetKrakenCandidates). */
|
|
35
|
+
export function resetKrakenTurnMetrics() {
|
|
36
|
+
const g = globalThis;
|
|
37
|
+
g.__zelariKrakenTurnMetrics = undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Record provider-reported tokens consumed by one candidate tentacle. */
|
|
40
|
+
export function recordCandidateTokens(totalTokens) {
|
|
41
|
+
if (!Number.isFinite(totalTokens) || totalTokens <= 0)
|
|
42
|
+
return;
|
|
43
|
+
store().candidateTokens += Math.round(totalTokens);
|
|
44
|
+
}
|
|
45
|
+
/** Record the judging-call outcome (called once per kraken_select). */
|
|
46
|
+
export function recordSelectionOutcome(outcome) {
|
|
47
|
+
const s = store();
|
|
48
|
+
s.selectionRecorded = true;
|
|
49
|
+
s.selectionLatencyMs = Math.max(0, Math.round(outcome.latencyMs));
|
|
50
|
+
if (typeof outcome.tokens === 'number' && Number.isFinite(outcome.tokens) && outcome.tokens > 0) {
|
|
51
|
+
s.selectionTokens = Math.round(outcome.tokens);
|
|
52
|
+
}
|
|
53
|
+
s.selectionFallback = outcome.degraded;
|
|
54
|
+
s.selectionFallbackReason = outcome.fallbackReason;
|
|
55
|
+
}
|
|
56
|
+
/** The completion gate forced a repair pass (budget = 1, Fase 8). */
|
|
57
|
+
export function markRepairTriggered() {
|
|
58
|
+
store().repairTriggered = true;
|
|
59
|
+
}
|
|
60
|
+
/** The repair pass ended with every blocking check resolved. */
|
|
61
|
+
export function markRepairSucceeded() {
|
|
62
|
+
if (store().repairTriggered)
|
|
63
|
+
store().repairSucceeded = true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Collect the turn snapshot. Returns null when the turn had NO selection
|
|
67
|
+
* activity (flag off, or a plain turn) — callers emit nothing, so simple
|
|
68
|
+
* tasks pay exactly zero telemetry overhead (§58).
|
|
69
|
+
*/
|
|
70
|
+
export function collectKrakenTurnMetrics() {
|
|
71
|
+
const s = store();
|
|
72
|
+
const verdict = getKrakenSelection();
|
|
73
|
+
const candidates = krakenCandidates();
|
|
74
|
+
if (!verdict && candidates.length === 0 && !s.selectionRecorded && !s.repairTriggered) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const classification = classifyKrakenChecks(krakenRequiredChecks(), getKrakenCheckResults());
|
|
78
|
+
return {
|
|
79
|
+
selectionUsed: verdict !== null,
|
|
80
|
+
candidateCount: candidates.length,
|
|
81
|
+
candidateTokens: s.candidateTokens,
|
|
82
|
+
...(s.selectionTokens !== undefined ? { selectionTokens: s.selectionTokens } : {}),
|
|
83
|
+
...(s.selectionLatencyMs !== undefined ? { selectionLatencyMs: s.selectionLatencyMs } : {}),
|
|
84
|
+
selectionFallback: s.selectionFallback,
|
|
85
|
+
...(s.selectionFallbackReason !== undefined
|
|
86
|
+
? { selectionFallbackReason: s.selectionFallbackReason }
|
|
87
|
+
: {}),
|
|
88
|
+
needsMoreEvidence: verdict?.status === 'needs_more_evidence',
|
|
89
|
+
verificationPass: classification.passed.length,
|
|
90
|
+
verificationFail: classification.failed.length,
|
|
91
|
+
verificationUnknown: classification.unknown.length,
|
|
92
|
+
repairTriggered: s.repairTriggered,
|
|
93
|
+
repairSucceeded: s.repairSucceeded,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/cli/kraken/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { collectKrakenTurnMetrics, markRepairSucceeded, markRepairTriggered, recordCandidateTokens, recordSelectionOutcome, resetKrakenTurnMetrics, } from './metrics.js';
|
|
3
|
+
import { registerCandidate, resetKrakenCandidates, setKrakenCheckResults, setKrakenSelection, } from './candidateRegistry.js';
|
|
4
|
+
function verdict(partial) {
|
|
5
|
+
return {
|
|
6
|
+
status: 'selected',
|
|
7
|
+
winnerIndex: 1,
|
|
8
|
+
rationale: 'test',
|
|
9
|
+
requiredChecks: [],
|
|
10
|
+
degraded: false,
|
|
11
|
+
verifier: null,
|
|
12
|
+
judgedBy: 'deterministic',
|
|
13
|
+
...partial,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function check(check, status) {
|
|
17
|
+
return { check, status };
|
|
18
|
+
}
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
resetKrakenCandidates();
|
|
21
|
+
resetKrakenTurnMetrics();
|
|
22
|
+
});
|
|
23
|
+
describe('collectKrakenTurnMetrics — null when no selection activity', () => {
|
|
24
|
+
it('returns null on a plain turn (flag off ⇒ zero telemetry)', () => {
|
|
25
|
+
resetKrakenCandidates();
|
|
26
|
+
resetKrakenTurnMetrics();
|
|
27
|
+
expect(collectKrakenTurnMetrics()).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
it('returns null when only unrelated counters were touched', () => {
|
|
30
|
+
recordCandidateTokens(0); // ignored by the guard
|
|
31
|
+
expect(collectKrakenTurnMetrics()).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('candidate counters', () => {
|
|
35
|
+
it('counts registered candidates (ok and malformed both cost)', () => {
|
|
36
|
+
registerCandidate({
|
|
37
|
+
status: 'ok',
|
|
38
|
+
description: 'h1',
|
|
39
|
+
report: {
|
|
40
|
+
hypothesis: 'h1',
|
|
41
|
+
evidence: [{ claim: 'observed', basis: 'src/x.ts:10', degraded: false }],
|
|
42
|
+
risks: [],
|
|
43
|
+
hasDegradedEvidence: false,
|
|
44
|
+
},
|
|
45
|
+
raw: '',
|
|
46
|
+
});
|
|
47
|
+
registerCandidate({ status: 'malformed', description: 'h2', error: 'bad', raw: '' });
|
|
48
|
+
const m = collectKrakenTurnMetrics();
|
|
49
|
+
expect(m?.candidateCount).toBe(2);
|
|
50
|
+
expect(m?.selectionUsed).toBe(false); // no kraken_select yet
|
|
51
|
+
});
|
|
52
|
+
it('sums provider-reported candidate tokens, ignoring junk', () => {
|
|
53
|
+
registerCandidate({
|
|
54
|
+
status: 'ok',
|
|
55
|
+
description: 'h1',
|
|
56
|
+
report: {
|
|
57
|
+
hypothesis: 'h1',
|
|
58
|
+
evidence: [],
|
|
59
|
+
risks: [],
|
|
60
|
+
hasDegradedEvidence: false,
|
|
61
|
+
},
|
|
62
|
+
raw: '',
|
|
63
|
+
});
|
|
64
|
+
recordCandidateTokens(1200);
|
|
65
|
+
recordCandidateTokens(800.4); // rounded
|
|
66
|
+
recordCandidateTokens(-5); // ignored
|
|
67
|
+
recordCandidateTokens(Number.NaN); // ignored
|
|
68
|
+
const m = collectKrakenTurnMetrics();
|
|
69
|
+
expect(m?.candidateTokens).toBe(2000);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('selection counters', () => {
|
|
73
|
+
it('records latency/tokens/fallback from the judging call', () => {
|
|
74
|
+
recordSelectionOutcome({ latencyMs: 1500, tokens: 900, degraded: false });
|
|
75
|
+
const m = collectKrakenTurnMetrics();
|
|
76
|
+
expect(m?.selectionLatencyMs).toBe(1500);
|
|
77
|
+
expect(m?.selectionTokens).toBe(900);
|
|
78
|
+
expect(m?.selectionFallback).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
it('keeps tokens undefined when the provider reports none', () => {
|
|
81
|
+
recordSelectionOutcome({ latencyMs: 200, degraded: true, fallbackReason: 'verifier call failed' });
|
|
82
|
+
const m = collectKrakenTurnMetrics();
|
|
83
|
+
expect(m?.selectionTokens).toBeUndefined();
|
|
84
|
+
expect(m?.selectionFallback).toBe(true);
|
|
85
|
+
expect(m?.selectionFallbackReason).toBe('verifier call failed');
|
|
86
|
+
});
|
|
87
|
+
it('flags needs_more_evidence from the persisted verdict', () => {
|
|
88
|
+
setKrakenSelection(verdict({ status: 'needs_more_evidence', winnerIndex: null }));
|
|
89
|
+
const m = collectKrakenTurnMetrics();
|
|
90
|
+
expect(m?.selectionUsed).toBe(true);
|
|
91
|
+
expect(m?.needsMoreEvidence).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('verification counters', () => {
|
|
95
|
+
it('classifies pass/fail/unknown from registry state', () => {
|
|
96
|
+
setKrakenSelection(verdict({ requiredChecks: ['tests pass', 'build clean', 'lint clean'] }));
|
|
97
|
+
setKrakenCheckResults([
|
|
98
|
+
check('tests pass', 'pass'),
|
|
99
|
+
check('build clean', 'fail'),
|
|
100
|
+
// 'lint clean' unreported ⇒ unknown
|
|
101
|
+
]);
|
|
102
|
+
const m = collectKrakenTurnMetrics();
|
|
103
|
+
expect(m?.verificationPass).toBe(1);
|
|
104
|
+
expect(m?.verificationFail).toBe(1);
|
|
105
|
+
expect(m?.verificationUnknown).toBe(1);
|
|
106
|
+
});
|
|
107
|
+
it('reports zero verification counters before any verify tentacle', () => {
|
|
108
|
+
setKrakenSelection(verdict({ requiredChecks: ['tests pass'] }));
|
|
109
|
+
const m = collectKrakenTurnMetrics();
|
|
110
|
+
expect(m?.verificationPass).toBe(0);
|
|
111
|
+
expect(m?.verificationUnknown).toBe(1);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('repair flags', () => {
|
|
115
|
+
it('tracks triggered and success independently', () => {
|
|
116
|
+
markRepairTriggered();
|
|
117
|
+
let m = collectKrakenTurnMetrics();
|
|
118
|
+
expect(m?.repairTriggered).toBe(true);
|
|
119
|
+
expect(m?.repairSucceeded).toBe(false);
|
|
120
|
+
markRepairSucceeded();
|
|
121
|
+
m = collectKrakenTurnMetrics();
|
|
122
|
+
expect(m?.repairSucceeded).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
it('success without trigger is ignored (defensive)', () => {
|
|
125
|
+
setKrakenSelection(verdict({})); // activity so the snapshot is non-null
|
|
126
|
+
markRepairSucceeded();
|
|
127
|
+
const m = collectKrakenTurnMetrics();
|
|
128
|
+
expect(m?.repairTriggered).toBe(false);
|
|
129
|
+
expect(m?.repairSucceeded).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('reset', () => {
|
|
133
|
+
it('clears transient counters but derives fresh from the registry', () => {
|
|
134
|
+
recordSelectionOutcome({ latencyMs: 100, tokens: 50, degraded: false });
|
|
135
|
+
markRepairTriggered();
|
|
136
|
+
resetKrakenTurnMetrics();
|
|
137
|
+
expect(collectKrakenTurnMetrics()).toBeNull(); // registry also empty here
|
|
138
|
+
setKrakenSelection(verdict({}));
|
|
139
|
+
const m = collectKrakenTurnMetrics();
|
|
140
|
+
expect(m?.repairTriggered).toBe(false);
|
|
141
|
+
expect(m?.candidateTokens).toBe(0);
|
|
142
|
+
expect(m?.selectionLatencyMs).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=metrics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/metrics.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { KRAKEN_SELECTION_PLAYBOOK_MODULE } from '@zelari/core/skills';
|
|
2
|
+
import { isKrakenSelectionEnabled } from './candidateRegistry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Adaptive Verified-Selection playbook (plan §53).
|
|
5
|
+
*
|
|
6
|
+
* Returns the selection playbook module for the Kraken parent prompt when
|
|
7
|
+
* BOTH the call site wants it (standard Kraken paths only — never Zelari
|
|
8
|
+
* mission slices) and the alpha feature flag `ZELARI_KRAKEN_SELECTION=1`
|
|
9
|
+
* is enabled. Flag off ⇒ the parent prompt stays byte-identical to
|
|
10
|
+
* today's (regression guard §65).
|
|
11
|
+
*
|
|
12
|
+
* The playbook teaches WHEN to explore candidates (simple → direct,
|
|
13
|
+
* ambiguous → 2, high uncertainty → 3) and the discipline around
|
|
14
|
+
* kraken_select; the candidate-side instructions (report format,
|
|
15
|
+
* diversity, integrity) live in the task tool's candidate
|
|
16
|
+
* systemPromptOverride (Fase 3).
|
|
17
|
+
*/
|
|
18
|
+
export function krakenSelectionPlaybook(include) {
|
|
19
|
+
if (!include || !isKrakenSelectionEnabled())
|
|
20
|
+
return [];
|
|
21
|
+
return [KRAKEN_SELECTION_PLAYBOOK_MODULE];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=selectionPlaybook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionPlaybook.js","sourceRoot":"","sources":["../../../src/cli/kraken/selectionPlaybook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,IAAI,CAAC,OAAO,IAAI,CAAC,wBAAwB,EAAE;QAAE,OAAO,EAAE,CAAC;IACvD,OAAO,CAAC,gCAAgC,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { krakenSelectionPlaybook } from './selectionPlaybook.js';
|
|
3
|
+
import { KRAKEN_LEAD_PLAYBOOK_MODULE } from '@zelari/core/skills';
|
|
4
|
+
const FLAG = 'ZELARI_KRAKEN_SELECTION';
|
|
5
|
+
describe('krakenSelectionPlaybook (Fase 5 — adaptive playbook)', () => {
|
|
6
|
+
const prev = process.env[FLAG];
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
if (prev === undefined)
|
|
9
|
+
delete process.env[FLAG];
|
|
10
|
+
else
|
|
11
|
+
process.env[FLAG] = prev;
|
|
12
|
+
});
|
|
13
|
+
it('flag off ⇒ no module (prompt byte-identical, regression guard)', () => {
|
|
14
|
+
delete process.env[FLAG];
|
|
15
|
+
expect(krakenSelectionPlaybook(true)).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
it('non-kraken call site ⇒ no module even with flag on', () => {
|
|
18
|
+
process.env[FLAG] = '1';
|
|
19
|
+
expect(krakenSelectionPlaybook(false)).toEqual([]);
|
|
20
|
+
});
|
|
21
|
+
it('flag on + kraken path ⇒ exactly one module', () => {
|
|
22
|
+
process.env[FLAG] = '1';
|
|
23
|
+
const mods = krakenSelectionPlaybook(true);
|
|
24
|
+
expect(mods).toHaveLength(1);
|
|
25
|
+
expect(mods[0].title).toMatch(/Verified Selection/i);
|
|
26
|
+
});
|
|
27
|
+
it('carries the adaptive thresholds (simple→direct, ambiguous→2, uncertainty→3)', () => {
|
|
28
|
+
process.env[FLAG] = '1';
|
|
29
|
+
const c = krakenSelectionPlaybook(true)[0].content;
|
|
30
|
+
expect(c).toMatch(/DIRECT/i);
|
|
31
|
+
expect(c).toMatch(/2 candidates/);
|
|
32
|
+
expect(c).toMatch(/up to 3 candidates/);
|
|
33
|
+
});
|
|
34
|
+
it('carries the orchestration contract (purpose=candidate, kraken_select, single path)', () => {
|
|
35
|
+
process.env[FLAG] = '1';
|
|
36
|
+
const c = krakenSelectionPlaybook(true)[0].content;
|
|
37
|
+
expect(c).toContain('purpose="candidate"');
|
|
38
|
+
expect(c).toContain('kraken_select');
|
|
39
|
+
expect(c).toContain('needs_more_evidence');
|
|
40
|
+
expect(c).toMatch(/Never blend/i);
|
|
41
|
+
});
|
|
42
|
+
it('carries check routing (PLAN → plan section, BUILD → verify Acceptance) + integrity', () => {
|
|
43
|
+
process.env[FLAG] = '1';
|
|
44
|
+
const c = krakenSelectionPlaybook(true)[0].content;
|
|
45
|
+
expect(c).toMatch(/verification section/i);
|
|
46
|
+
expect(c).toMatch(/Acceptance/i);
|
|
47
|
+
expect(c).toMatch(/proof of absence/i);
|
|
48
|
+
});
|
|
49
|
+
it('sorts after the lead playbook (priority ordering preserved)', () => {
|
|
50
|
+
process.env[FLAG] = '1';
|
|
51
|
+
const [m] = krakenSelectionPlaybook(true);
|
|
52
|
+
expect(m.priority).toBeGreaterThan(KRAKEN_LEAD_PLAYBOOK_MODULE.priority);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=selectionPlaybook.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionPlaybook.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/selectionPlaybook.test.ts"],"names":[],"mappings":"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"}
|