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.
Files changed (59) hide show
  1. package/dist/cli/desktopConfig.js +51 -4
  2. package/dist/cli/desktopConfig.js.map +1 -1
  3. package/dist/cli/hooks/useChatTurn.js +80 -0
  4. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  5. package/dist/cli/kraken/candidateRegistry.js +195 -0
  6. package/dist/cli/kraken/candidateRegistry.js.map +1 -0
  7. package/dist/cli/kraken/candidateRegistry.test.js +211 -0
  8. package/dist/cli/kraken/candidateRegistry.test.js.map +1 -0
  9. package/dist/cli/kraken/completionGate.js +116 -0
  10. package/dist/cli/kraken/completionGate.js.map +1 -0
  11. package/dist/cli/kraken/completionGate.test.js +172 -0
  12. package/dist/cli/kraken/completionGate.test.js.map +1 -0
  13. package/dist/cli/kraken/metrics.js +96 -0
  14. package/dist/cli/kraken/metrics.js.map +1 -0
  15. package/dist/cli/kraken/metrics.test.js +145 -0
  16. package/dist/cli/kraken/metrics.test.js.map +1 -0
  17. package/dist/cli/kraken/selectionPlaybook.js +23 -0
  18. package/dist/cli/kraken/selectionPlaybook.js.map +1 -0
  19. package/dist/cli/kraken/selectionPlaybook.test.js +55 -0
  20. package/dist/cli/kraken/selectionPlaybook.test.js.map +1 -0
  21. package/dist/cli/kraken/turnRuntime.js +207 -0
  22. package/dist/cli/kraken/turnRuntime.js.map +1 -0
  23. package/dist/cli/kraken/turnRuntime.test.js +377 -0
  24. package/dist/cli/kraken/turnRuntime.test.js.map +1 -0
  25. package/dist/cli/kraken/verifier.js +233 -0
  26. package/dist/cli/kraken/verifier.js.map +1 -0
  27. package/dist/cli/kraken/verifier.test.js +232 -0
  28. package/dist/cli/kraken/verifier.test.js.map +1 -0
  29. package/dist/cli/kraken/verifierSettings.test.js +237 -0
  30. package/dist/cli/kraken/verifierSettings.test.js.map +1 -0
  31. package/dist/cli/kraken/verifyReport.js +115 -0
  32. package/dist/cli/kraken/verifyReport.js.map +1 -0
  33. package/dist/cli/kraken/verifyReport.test.js +111 -0
  34. package/dist/cli/kraken/verifyReport.test.js.map +1 -0
  35. package/dist/cli/main.bundled.js +1369 -111
  36. package/dist/cli/main.bundled.js.map +4 -4
  37. package/dist/cli/provider/openai-compatible.js +40 -6
  38. package/dist/cli/provider/openai-compatible.js.map +1 -1
  39. package/dist/cli/provider/openai-compatible.timeout.test.js +72 -0
  40. package/dist/cli/provider/openai-compatible.timeout.test.js.map +1 -0
  41. package/dist/cli/providerConfig.js +46 -0
  42. package/dist/cli/providerConfig.js.map +1 -1
  43. package/dist/cli/runHeadless.js +85 -0
  44. package/dist/cli/runHeadless.js.map +1 -1
  45. package/dist/cli/toolRegistry.js +50 -6
  46. package/dist/cli/toolRegistry.js.map +1 -1
  47. package/dist/cli/tools/krakenSelectTool.js +165 -0
  48. package/dist/cli/tools/krakenSelectTool.js.map +1 -0
  49. package/dist/cli/tools/krakenSelectTool.test.js +246 -0
  50. package/dist/cli/tools/krakenSelectTool.test.js.map +1 -0
  51. package/dist/cli/tools/taskTool.dynamicChecks.test.js +156 -0
  52. package/dist/cli/tools/taskTool.dynamicChecks.test.js.map +1 -0
  53. package/dist/cli/tools/taskTool.js +174 -6
  54. package/dist/cli/tools/taskTool.js.map +1 -1
  55. package/dist/cli/tools/taskTool.planSafety.test.js +280 -0
  56. package/dist/cli/tools/taskTool.planSafety.test.js.map +1 -0
  57. package/dist/cli/tools/taskTool.verifyReport.test.js +140 -0
  58. package/dist/cli/tools/taskTool.verifyReport.test.js.map +1 -0
  59. 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":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAIhC,SAAS,OAAO,CAAC,OAAwC;IACvD,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,MAAM;QACjB,cAAc,EAAE,EAAE;QAClB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,eAAe;QACzB,GAAG,OAAO;KACX,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,MAAmC;IAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,CAAC,GAAG,EAAE;IACb,qBAAqB,EAAE,CAAC;IACxB,sBAAsB,EAAE,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,4DAA4D,EAAE,GAAG,EAAE;IAC1E,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,qBAAqB,EAAE,CAAC;QACxB,sBAAsB,EAAE,CAAC;QACzB,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB;QACjD,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,iBAAiB,CAAC;YAChB,MAAM,EAAE,IAAI;YACZ,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;gBACxE,KAAK,EAAE,EAAE;gBACT,mBAAmB,EAAE,KAAK;aAC3B;YACD,GAAG,EAAE,EAAE;SACR,CAAC,CAAC;QACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,uBAAuB;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,iBAAiB,CAAC;YAChB,MAAM,EAAE,IAAI;YACZ,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,EAAE;gBACT,mBAAmB,EAAE,KAAK;aAC3B;YACD,GAAG,EAAE,EAAE;SACR,CAAC,CAAC;QACH,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC5B,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU;QACxC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU;QACrC,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU;QAC7C,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,sBAAsB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,sBAAsB,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,sBAAsB,EAAE,CAAC,CAAC;QACnG,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,aAAa,EAAE,CAAC;QAC3C,MAAM,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,qBAAqB,CAAC;YACpB,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC;YAC3B,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC;YAC5B,oCAAoC;SACrC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,mBAAmB,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACnC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEvC,mBAAmB,EAAE,CAAC;QACtB,CAAC,GAAG,wBAAwB,EAAE,CAAC;QAC/B,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,uCAAuC;QACxE,mBAAmB,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,sBAAsB,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACxE,mBAAmB,EAAE,CAAC;QACtB,sBAAsB,EAAE,CAAC;QACzB,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,2BAA2B;QAE1E,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,aAAa,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -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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"}