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,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verificationBridge — adapts the 1.x Kraken check registry onto the 2.0
|
|
3
|
+
* deterministic evidence contract (ADR-0023), and enforces ZELARI_STRICT_DONE.
|
|
4
|
+
*
|
|
5
|
+
* The legacy completion gate (completionGate.ts) already implements
|
|
6
|
+
* `unknown ≠ pass` over verify-report blocks. This bridge additionally maps
|
|
7
|
+
* those results onto Criterion/VerificationResult and runs the strict
|
|
8
|
+
* CompletionPolicy, where "pass without evidence" is ALSO blockable — the
|
|
9
|
+
* false-done guarantee the 2.0 contract adds on top.
|
|
10
|
+
*
|
|
11
|
+
* Composition rule: the strict verdict can only ADD blockers, never remove
|
|
12
|
+
* them. A legacy-blocked turn stays blocked; a legacy-open turn can become
|
|
13
|
+
* blocked only when strict evaluation is enabled AND the evidence contract
|
|
14
|
+
* is not satisfied.
|
|
15
|
+
*/
|
|
16
|
+
import { getKrakenCheckResults, krakenRequiredChecks } from './candidateRegistry.js';
|
|
17
|
+
import { evaluateKrakenCompletionGate } from './completionGate.js';
|
|
18
|
+
import { evaluateCompletion, STRICT_ALL_POLICY, } from '@zelari/core/verification';
|
|
19
|
+
/** Strict done gate — opt-in during the alpha (default off for compat). */
|
|
20
|
+
export function strictDoneEnabled() {
|
|
21
|
+
const v = process.env.ZELARI_STRICT_DONE;
|
|
22
|
+
return v === '1' || v === 'true';
|
|
23
|
+
}
|
|
24
|
+
/** Stable criterion id for a required-check text (deterministic per turn). */
|
|
25
|
+
function criterionId(check, index) {
|
|
26
|
+
const slug = check
|
|
27
|
+
.toLowerCase()
|
|
28
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
29
|
+
.replace(/^-+|-+$/g, '')
|
|
30
|
+
.slice(0, 48);
|
|
31
|
+
return `check-${index + 1}-${slug || 'criterion'}`;
|
|
32
|
+
}
|
|
33
|
+
/** Lowercase + collapse whitespace (mirrors completionGate matching). */
|
|
34
|
+
function normalize(text) {
|
|
35
|
+
return text.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find the reported result for a required check using the same tolerant
|
|
39
|
+
* matching as the legacy gate (normalized equality, then containment either
|
|
40
|
+
* direction at minimum length 8) so the two gates never disagree on mapping.
|
|
41
|
+
*/
|
|
42
|
+
function matchResult(check, byNormalized) {
|
|
43
|
+
const norm = normalize(check);
|
|
44
|
+
const direct = byNormalized.get(norm);
|
|
45
|
+
if (direct)
|
|
46
|
+
return direct;
|
|
47
|
+
for (const key of byNormalized.keys()) {
|
|
48
|
+
if (key.length >= 8 && (key.includes(norm) || norm.includes(key))) {
|
|
49
|
+
return byNormalized.get(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Map registry check results onto the evidence contract.
|
|
56
|
+
*
|
|
57
|
+
* Evidence discipline (ADR-0023): a `pass` counts only when the verify
|
|
58
|
+
* tentacle left an evidence note pointing back at real tool output. A pass
|
|
59
|
+
* without a note produces an empty evidence array — the CompletionPolicy
|
|
60
|
+
* then treats it as `unknown` (pass without evidence ≠ done).
|
|
61
|
+
*/
|
|
62
|
+
export function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
|
|
63
|
+
const byNormalized = new Map();
|
|
64
|
+
for (const r of results ?? [])
|
|
65
|
+
byNormalized.set(normalize(r.check), r); // later duplicates win
|
|
66
|
+
const criteria = [];
|
|
67
|
+
const verifications = [];
|
|
68
|
+
requiredChecks.forEach((check, i) => {
|
|
69
|
+
const id = criterionId(check, i);
|
|
70
|
+
criteria.push({
|
|
71
|
+
id,
|
|
72
|
+
text: check,
|
|
73
|
+
source: 'kraken-selection',
|
|
74
|
+
required: true,
|
|
75
|
+
check: { kind: 'none', reason: 'verified by verify tentacle report' },
|
|
76
|
+
});
|
|
77
|
+
const reported = matchResult(check, byNormalized);
|
|
78
|
+
const evidence = reported?.note && reported.note.trim().length > 0
|
|
79
|
+
? [
|
|
80
|
+
{
|
|
81
|
+
tier: 'tool-output',
|
|
82
|
+
ref: reported.note.trim().slice(0, 500),
|
|
83
|
+
capturedAt: now,
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
: [];
|
|
87
|
+
verifications.push({
|
|
88
|
+
criterionId: id,
|
|
89
|
+
status: reported?.status ?? 'unknown',
|
|
90
|
+
source: 'verify-agent',
|
|
91
|
+
evidence,
|
|
92
|
+
evaluatedAt: now,
|
|
93
|
+
durationMs: 0,
|
|
94
|
+
...(reported?.note ? { detail: `verify-report note: ${reported.note.slice(0, 200)}` } : {}),
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return { criteria, results: verifications };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Evaluate the BUILD completion gate. When `ZELARI_STRICT_DONE` is enabled
|
|
101
|
+
* and the turn registered required checks, the evidence contract is evaluated
|
|
102
|
+
* as well and the verdicts merged (blockers add up).
|
|
103
|
+
*/
|
|
104
|
+
export function evaluateStrictBuildGate(mode) {
|
|
105
|
+
const gate = evaluateKrakenCompletionGate(mode);
|
|
106
|
+
if (!gate.selectionUsed || gate.total === 0 || !strictDoneEnabled()) {
|
|
107
|
+
return {
|
|
108
|
+
gate,
|
|
109
|
+
strict: false,
|
|
110
|
+
evaluation: null,
|
|
111
|
+
blocked: gate.blocked,
|
|
112
|
+
summary: gate.blocked
|
|
113
|
+
? `blocked: ${gate.failedChecks.length} failed, ${gate.unknownChecks.length} unknown`
|
|
114
|
+
: 'open',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const checks = krakenRequiredChecks();
|
|
118
|
+
const contract = krakenResultsToContract(checks, getKrakenCheckResults());
|
|
119
|
+
const evaluation = evaluateCompletion(contract.criteria, contract.results, STRICT_ALL_POLICY);
|
|
120
|
+
const blocked = gate.blocked || evaluation.verdict !== 'PASS';
|
|
121
|
+
return {
|
|
122
|
+
gate,
|
|
123
|
+
strict: true,
|
|
124
|
+
evaluation,
|
|
125
|
+
blocked,
|
|
126
|
+
summary: blocked
|
|
127
|
+
? `blocked (strict ${evaluation?.verdict ?? 'n/a'}): ${gate.passed}/${gate.total} legacy-pass, evidence ${evaluation?.evidenceComplete ? 'complete' : 'incomplete'}`
|
|
128
|
+
: `open (strict PASS): ${evaluation?.satisfied.length ?? 0}/${gate.total} criteria pass with evidence`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** Machine-readable record for the session spine `verification.run` event. */
|
|
132
|
+
export function strictGateEventPayload(evaluation) {
|
|
133
|
+
return {
|
|
134
|
+
engine: 'kraken-legacy+completion-policy',
|
|
135
|
+
strict: evaluation.strict,
|
|
136
|
+
verdict: evaluation.evaluation?.verdict ?? (evaluation.blocked ? 'BLOCKED' : 'PASS'),
|
|
137
|
+
legacy: {
|
|
138
|
+
total: evaluation.gate.total,
|
|
139
|
+
passed: evaluation.gate.passed,
|
|
140
|
+
failed: evaluation.gate.failedChecks,
|
|
141
|
+
unknown: evaluation.gate.unknownChecks,
|
|
142
|
+
},
|
|
143
|
+
evidence: evaluation.evaluation
|
|
144
|
+
? {
|
|
145
|
+
satisfied: evaluation.evaluation.satisfied,
|
|
146
|
+
unsatisfied: evaluation.evaluation.unsatisfied,
|
|
147
|
+
complete: evaluation.evaluation.evidenceComplete,
|
|
148
|
+
}
|
|
149
|
+
: null,
|
|
150
|
+
summary: evaluation.summary,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=verificationBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verificationBridge.js","sourceRoot":"","sources":["../../../src/cli/kraken/verificationBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,4BAA4B,EAA6B,MAAM,qBAAqB,CAAC;AAE9F,OAAO,EACL,kBAAkB,EAClB,iBAAiB,GAKlB,MAAM,2BAA2B,CAAC;AAEnC,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB;IAC/B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACzC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC;AACnC,CAAC;AAOD,8EAA8E;AAC9E,SAAS,WAAW,CAAC,KAAa,EAAE,KAAa;IAC/C,MAAM,IAAI,GAAG,KAAK;SACf,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,SAAS,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,WAAW,EAAE,CAAC;AACrD,CAAC;AAED,yEAAyE;AACzE,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAClB,KAAa,EACb,YAA4C;IAE5C,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;QACtC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAClE,OAAO,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,cAAiC,EACjC,OAA4C,EAC5C,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,YAAY,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC1D,KAAK,MAAM,CAAC,IAAI,OAAO,IAAI,EAAE;QAAE,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,uBAAuB;IAC/F,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,MAAM,aAAa,GAAyB,EAAE,CAAC;IAC/C,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjC,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE;YACF,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oCAAoC,EAAE;SACtE,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAClD,MAAM,QAAQ,GACZ,QAAQ,EAAE,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC/C,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,aAAa;oBACnB,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;oBACvC,UAAU,EAAE,GAAG;iBAChB;aACF;YACH,CAAC,CAAC,EAAE,CAAC;QACT,aAAa,CAAC,IAAI,CAAC;YACjB,WAAW,EAAE,EAAE;YACf,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,SAAS;YACrC,MAAM,EAAE,cAAc;YACtB,QAAQ;YACR,WAAW,EAAE,GAAG;YAChB,UAAU,EAAE,CAAC;YACb,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,uBAAuB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5F,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AAC9C,CAAC;AAaD;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAsB;IAC5D,MAAM,IAAI,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACpE,OAAO;YACL,IAAI;YACJ,MAAM,EAAE,KAAK;YACb,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACnB,CAAC,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,UAAU;gBACrF,CAAC,CAAC,MAAM;SACX,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,KAAK,MAAM,CAAC;IAC9D,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,IAAI;QACZ,UAAU;QACV,OAAO;QACP,OAAO,EAAE,OAAO;YACd,CAAC,CAAC,mBAAmB,UAAU,EAAE,OAAO,IAAI,KAAK,MAAM,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,0BAC5E,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAC9C,EAAE;YACJ,CAAC,CAAC,uBAAuB,UAAU,EAAE,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,8BAA8B;KACzG,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,sBAAsB,CAAC,UAAqC;IAC1E,OAAO;QACL,MAAM,EAAE,iCAAiC;QACzC,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,OAAO,EAAE,UAAU,CAAC,UAAU,EAAE,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QACpF,MAAM,EAAE;YACN,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK;YAC5B,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM;YAC9B,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY;YACpC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,aAAa;SACvC;QACD,QAAQ,EAAE,UAAU,CAAC,UAAU;YAC7B,CAAC,CAAC;gBACE,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,SAAS;gBAC1C,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC,WAAW;gBAC9C,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,gBAAgB;aACjD;YACH,CAAC,CAAC,IAAI;QACR,OAAO,EAAE,UAAU,CAAC,OAAO;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verificationBridge tests (ADR-0023 host integration).
|
|
3
|
+
*
|
|
4
|
+
* Covers: check→contract mapping with tolerant matching, the pass-without-
|
|
5
|
+
* evidence rule, ZELARI_STRICT_DONE composition (blockers add, never
|
|
6
|
+
* subtract), and the machine-readable payload shape.
|
|
7
|
+
*/
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
9
|
+
import { evaluateStrictBuildGate, krakenResultsToContract, strictDoneEnabled, strictGateEventPayload, } from './verificationBridge.js';
|
|
10
|
+
import { resetKrakenCandidates, setKrakenCheckResults, setKrakenSelection, } from './candidateRegistry.js';
|
|
11
|
+
const CHECKS = ['session survives concurrent refresh', 'rotated cookie rejects the old token'];
|
|
12
|
+
function selectWithChecks(checks) {
|
|
13
|
+
resetKrakenCandidates();
|
|
14
|
+
setKrakenSelection({
|
|
15
|
+
status: 'selected',
|
|
16
|
+
winnerIndex: 1,
|
|
17
|
+
rationale: 'stronger evidence',
|
|
18
|
+
requiredChecks: checks,
|
|
19
|
+
degraded: false,
|
|
20
|
+
verifier: null,
|
|
21
|
+
judgedBy: 'llm',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
let envPrev;
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
envPrev = process.env.ZELARI_STRICT_DONE;
|
|
27
|
+
resetKrakenCandidates();
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
if (envPrev === undefined)
|
|
31
|
+
delete process.env.ZELARI_STRICT_DONE;
|
|
32
|
+
else
|
|
33
|
+
process.env.ZELARI_STRICT_DONE = envPrev;
|
|
34
|
+
resetKrakenCandidates();
|
|
35
|
+
});
|
|
36
|
+
describe('krakenResultsToContract', () => {
|
|
37
|
+
it('maps every required check to a required criterion with a stable id', () => {
|
|
38
|
+
const contract = krakenResultsToContract(CHECKS, [], 1000);
|
|
39
|
+
expect(contract.criteria).toHaveLength(2);
|
|
40
|
+
expect(contract.criteria.every((c) => c.required && c.source === 'kraken-selection')).toBe(true);
|
|
41
|
+
expect(contract.results.every((r) => r.status === 'unknown' && r.source === 'verify-agent')).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
it('a pass WITH a note carries evidence; a pass WITHOUT a note does not', () => {
|
|
44
|
+
const results = [
|
|
45
|
+
{ check: CHECKS[0], status: 'pass', note: 'vitest 41/41' },
|
|
46
|
+
{ check: CHECKS[1], status: 'pass' },
|
|
47
|
+
];
|
|
48
|
+
const contract = krakenResultsToContract(CHECKS, results, 2000);
|
|
49
|
+
expect(contract.results[0].evidence).toHaveLength(1);
|
|
50
|
+
expect(contract.results[0].evidence[0].tier).toBe('tool-output');
|
|
51
|
+
expect(contract.results[1].evidence).toHaveLength(0);
|
|
52
|
+
});
|
|
53
|
+
it('tolerates lightly reworded check text (containment matching)', () => {
|
|
54
|
+
const results = [
|
|
55
|
+
{ check: 'Session survives concurrent REFRESH (reworded)', status: 'pass', note: 'x' },
|
|
56
|
+
];
|
|
57
|
+
const contract = krakenResultsToContract([CHECKS[0]], results);
|
|
58
|
+
expect(contract.results[0].status).toBe('pass');
|
|
59
|
+
expect(contract.results[0].evidence).toHaveLength(1);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('evaluateStrictBuildGate', () => {
|
|
63
|
+
it('strict off (default): mirrors the legacy gate exactly', () => {
|
|
64
|
+
delete process.env.ZELARI_STRICT_DONE;
|
|
65
|
+
expect(strictDoneEnabled()).toBe(false);
|
|
66
|
+
selectWithChecks(CHECKS);
|
|
67
|
+
setKrakenCheckResults([
|
|
68
|
+
{ check: CHECKS[0], status: 'pass', note: 'ok' },
|
|
69
|
+
{ check: CHECKS[1], status: 'fail', note: 'assert' },
|
|
70
|
+
]);
|
|
71
|
+
const evaluation = evaluateStrictBuildGate('build');
|
|
72
|
+
expect(evaluation.strict).toBe(false);
|
|
73
|
+
expect(evaluation.evaluation).toBeNull();
|
|
74
|
+
expect(evaluation.blocked).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
it('strict on + all pass with notes → PASS', () => {
|
|
77
|
+
process.env.ZELARI_STRICT_DONE = '1';
|
|
78
|
+
selectWithChecks(CHECKS);
|
|
79
|
+
setKrakenCheckResults([
|
|
80
|
+
{ check: CHECKS[0], status: 'pass', note: 'vitest 41/41' },
|
|
81
|
+
{ check: CHECKS[1], status: 'pass', note: 'curl 401' },
|
|
82
|
+
]);
|
|
83
|
+
const evaluation = evaluateStrictBuildGate('build');
|
|
84
|
+
expect(evaluation.strict).toBe(true);
|
|
85
|
+
expect(evaluation.evaluation.verdict).toBe('PASS');
|
|
86
|
+
expect(evaluation.blocked).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
it('strict on + pass WITHOUT evidence → BLOCKED (false-done guard)', () => {
|
|
89
|
+
process.env.ZELARI_STRICT_DONE = '1';
|
|
90
|
+
selectWithChecks(CHECKS);
|
|
91
|
+
setKrakenCheckResults([
|
|
92
|
+
{ check: CHECKS[0], status: 'pass', note: 'vitest 41/41' },
|
|
93
|
+
{ check: CHECKS[1], status: 'pass' }, // no note → no evidence
|
|
94
|
+
]);
|
|
95
|
+
const evaluation = evaluateStrictBuildGate('build');
|
|
96
|
+
expect(evaluation.evaluation.verdict).toBe('BLOCKED');
|
|
97
|
+
expect(evaluation.blocked).toBe(true);
|
|
98
|
+
expect(evaluation.evaluation.unsatisfied[0].status).toBe('unknown');
|
|
99
|
+
expect(evaluation.evaluation.unsatisfied[0].reason).toContain('without evidence');
|
|
100
|
+
});
|
|
101
|
+
it('strict on + legacy fail → REPAIR_REQUIRED (fail wins over unknown)', () => {
|
|
102
|
+
process.env.ZELARI_STRICT_DONE = '1';
|
|
103
|
+
selectWithChecks(CHECKS);
|
|
104
|
+
setKrakenCheckResults([
|
|
105
|
+
{ check: CHECKS[0], status: 'fail', note: 'assert false' },
|
|
106
|
+
{ check: CHECKS[1], status: 'unknown' },
|
|
107
|
+
]);
|
|
108
|
+
const evaluation = evaluateStrictBuildGate('build');
|
|
109
|
+
expect(evaluation.evaluation.verdict).toBe('REPAIR_REQUIRED');
|
|
110
|
+
expect(evaluation.blocked).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
it('PLAN turns and turns without selection stay open', () => {
|
|
113
|
+
process.env.ZELARI_STRICT_DONE = '1';
|
|
114
|
+
expect(evaluateStrictBuildGate('plan').blocked).toBe(false);
|
|
115
|
+
resetKrakenCandidates();
|
|
116
|
+
expect(evaluateStrictBuildGate('build').blocked).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('strictGateEventPayload', () => {
|
|
120
|
+
it('is JSON-serializable and carries both gate layers', () => {
|
|
121
|
+
process.env.ZELARI_STRICT_DONE = '1';
|
|
122
|
+
selectWithChecks(CHECKS);
|
|
123
|
+
setKrakenCheckResults([{ check: CHECKS[0], status: 'pass', note: 'n' }]);
|
|
124
|
+
const payload = strictGateEventPayload(evaluateStrictBuildGate('build'));
|
|
125
|
+
expect(() => JSON.stringify(payload)).not.toThrow();
|
|
126
|
+
expect(payload).toMatchObject({ strict: true, engine: 'kraken-legacy+completion-policy' });
|
|
127
|
+
expect(payload.legacy).toMatchObject({ total: 2 });
|
|
128
|
+
expect(payload.evidence).not.toBeNull();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=verificationBridge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verificationBridge.test.js","sourceRoot":"","sources":["../../../src/cli/kraken/verificationBridge.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifier — Kraken selection verifier (Fase 4, ADR-0020).
|
|
3
|
+
*
|
|
4
|
+
* Compares the candidate reports registered this turn (Fase 3) and produces
|
|
5
|
+
* ONE structured {@link KrakenSelectionVerdict}. Design rules:
|
|
6
|
+
*
|
|
7
|
+
* - Verifier identity DEFAULTS to the exact PARENT model (no cheap-model
|
|
8
|
+
* auto-pick — judging quality is the point). Overrides: explicit param
|
|
9
|
+
* (Fase 9 settings) > ZELARI_KRAKEN_SELECT_PROVIDER/MODEL env > parent.
|
|
10
|
+
* - Structured judging: the model must answer with a
|
|
11
|
+
* `<selection-verdict>` JSON block, parsed LENIENTLY.
|
|
12
|
+
* - `needs_more_evidence` is a first-class outcome (ties, weak evidence).
|
|
13
|
+
* - Fallback NEVER fails the parent turn: a malformed/failed verifier
|
|
14
|
+
* response degrades to `needs_more_evidence` with `degraded: true` and
|
|
15
|
+
* the parent proceeds with its own judgment.
|
|
16
|
+
* - Deterministic short-circuits (no LLM call): zero usable candidates,
|
|
17
|
+
* single usable candidate.
|
|
18
|
+
*
|
|
19
|
+
* Pure module: the LLM call is injected (`callModel`), so tests never hit
|
|
20
|
+
* the network.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the verifier identity.
|
|
24
|
+
*
|
|
25
|
+
* 1. explicit override (both provider+model required — partial overrides
|
|
26
|
+
* are treated as invalid and fall through)
|
|
27
|
+
* 2. env: ZELARI_KRAKEN_SELECT_PROVIDER + ZELARI_KRAKEN_SELECT_MODEL
|
|
28
|
+
* (model-only keeps the parent provider; provider-only is invalid)
|
|
29
|
+
* 3. parent identity — the DEFAULT (ADR-0020: verifier = parent model)
|
|
30
|
+
*/
|
|
31
|
+
export function resolveKrakenVerifier(parent, env = process.env, explicit) {
|
|
32
|
+
if (explicit?.provider?.trim() && explicit?.model?.trim()) {
|
|
33
|
+
return { provider: explicit.provider.trim(), model: explicit.model.trim() };
|
|
34
|
+
}
|
|
35
|
+
const envProvider = env.ZELARI_KRAKEN_SELECT_PROVIDER?.trim();
|
|
36
|
+
const envModel = env.ZELARI_KRAKEN_SELECT_MODEL?.trim();
|
|
37
|
+
if (envProvider && envModel)
|
|
38
|
+
return { provider: envProvider, model: envModel };
|
|
39
|
+
if (envModel)
|
|
40
|
+
return { provider: parent.provider, model: envModel };
|
|
41
|
+
// Provider-only (env or explicit) is not actionable without a model →
|
|
42
|
+
// documented fallback: inherit the parent exactly.
|
|
43
|
+
return { provider: parent.provider, model: parent.model };
|
|
44
|
+
}
|
|
45
|
+
// ── Prompt ─────────────────────────────────────────────────────────────────
|
|
46
|
+
export const VERIFIER_SYSTEM_PROMPT = [
|
|
47
|
+
'You are the Kraken selection verifier. You compare independent research',
|
|
48
|
+
'reports (candidates) about ONE task and decide which hypothesis is best',
|
|
49
|
+
'supported by OBSERVED EVIDENCE. You do not explore anything yourself —',
|
|
50
|
+
'you judge what the candidates actually observed.',
|
|
51
|
+
'',
|
|
52
|
+
'RULES:',
|
|
53
|
+
'- Evidence decides. A specific observation (file:line, command output,',
|
|
54
|
+
' test result) outweighs any amount of confident wording.',
|
|
55
|
+
'- An eloquent candidate with no observations must NOT beat a plainly',
|
|
56
|
+
' worded candidate whose claims are grounded in evidence.',
|
|
57
|
+
'- Degraded observations (timeouts, empty searches, unavailable backends)',
|
|
58
|
+
' are NOT proof of absence — never treat them as confirmation that',
|
|
59
|
+
' something does not exist or cannot happen.',
|
|
60
|
+
'- A candidate CONTRADICTED by a concrete observation loses to one',
|
|
61
|
+
' consistent with it. Weigh listed risks.',
|
|
62
|
+
'- If the leading candidates are equally (un)supported, answer',
|
|
63
|
+
' needs_more_evidence — do not guess.',
|
|
64
|
+
'- requiredChecks: 0-5 concrete, runnable checks the implementation must',
|
|
65
|
+
' pass to prove the winning hypothesis (test names, commands, behaviors).',
|
|
66
|
+
'',
|
|
67
|
+
'Answer with EXACTLY this block (valid JSON, no prose before/after):',
|
|
68
|
+
'<selection-verdict>',
|
|
69
|
+
'{',
|
|
70
|
+
' "status": "selected" | "needs_more_evidence",',
|
|
71
|
+
' "winnerIndex": <1-based index of the winning candidate, or null>,',
|
|
72
|
+
' "rationale": "2-4 sentences grounded in the evidence",',
|
|
73
|
+
' "requiredChecks": ["concrete check", "..."]',
|
|
74
|
+
'}',
|
|
75
|
+
'</selection-verdict>',
|
|
76
|
+
].join('\n');
|
|
77
|
+
function renderCandidate(entry) {
|
|
78
|
+
if (entry.status === 'malformed') {
|
|
79
|
+
return [
|
|
80
|
+
`## Candidate #${entry.index} — UNUSABLE (malformed report: ${entry.error})`,
|
|
81
|
+
'This candidate cannot win; it is listed for completeness.',
|
|
82
|
+
].join('\n');
|
|
83
|
+
}
|
|
84
|
+
const lines = [`## Candidate #${entry.index} — ${entry.report.hypothesis || '(no hypothesis stated)'}`];
|
|
85
|
+
if (entry.report.evidence.length === 0) {
|
|
86
|
+
lines.push('Evidence: NONE (unsupported hypothesis)');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
lines.push('Evidence:');
|
|
90
|
+
for (const e of entry.report.evidence) {
|
|
91
|
+
const tag = e.degraded ? 'DEGRADED — inconclusive, NOT proof of absence' : 'OK';
|
|
92
|
+
lines.push(`- [${tag}] ${e.claim}${e.basis ? ` (basis: ${e.basis})` : ''}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (entry.report.risks.length > 0) {
|
|
96
|
+
lines.push('Risks:');
|
|
97
|
+
for (const r of entry.report.risks)
|
|
98
|
+
lines.push(`- ${r}`);
|
|
99
|
+
}
|
|
100
|
+
return lines.join('\n');
|
|
101
|
+
}
|
|
102
|
+
/** Build the user prompt for the judging call. */
|
|
103
|
+
export function buildSelectionPrompt(task, candidates) {
|
|
104
|
+
return [
|
|
105
|
+
'TASK',
|
|
106
|
+
task || '(the current user task — judge against the candidates below)',
|
|
107
|
+
'',
|
|
108
|
+
'CANDIDATES (read-only explorer reports):',
|
|
109
|
+
...candidates.map(renderCandidate),
|
|
110
|
+
'',
|
|
111
|
+
'Decide which candidate is best supported by the evidence above.',
|
|
112
|
+
].join('\n');
|
|
113
|
+
}
|
|
114
|
+
// ── Verdict parsing ────────────────────────────────────────────────────────
|
|
115
|
+
const VERDICT_OPEN = '<selection-verdict>';
|
|
116
|
+
const VERDICT_CLOSE = '</selection-verdict>';
|
|
117
|
+
function needsMoreEvidence(rationale, fallbackReason) {
|
|
118
|
+
return {
|
|
119
|
+
status: 'needs_more_evidence',
|
|
120
|
+
winnerIndex: null,
|
|
121
|
+
rationale,
|
|
122
|
+
requiredChecks: [],
|
|
123
|
+
degraded: true,
|
|
124
|
+
...(fallbackReason ? { fallbackReason } : {}),
|
|
125
|
+
verifier: null,
|
|
126
|
+
judgedBy: 'deterministic',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parse + validate the verifier response against the candidate set.
|
|
131
|
+
* Lenient on shapes, STRICT on semantics: `selected` requires a valid
|
|
132
|
+
* winnerIndex pointing at an OK candidate.
|
|
133
|
+
*/
|
|
134
|
+
export function parseSelectionVerdict(raw, candidates) {
|
|
135
|
+
const open = raw.lastIndexOf(VERDICT_OPEN);
|
|
136
|
+
const close = raw.lastIndexOf(VERDICT_CLOSE);
|
|
137
|
+
if (open === -1 || close === -1 || close < open) {
|
|
138
|
+
return { ok: false, error: 'missing verdict block' };
|
|
139
|
+
}
|
|
140
|
+
const body = raw.slice(open + VERDICT_OPEN.length, close).trim();
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(body);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
return { ok: false, error: `invalid JSON (${err instanceof Error ? err.message : String(err)})` };
|
|
147
|
+
}
|
|
148
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
149
|
+
return { ok: false, error: 'verdict is not a JSON object' };
|
|
150
|
+
}
|
|
151
|
+
const obj = parsed;
|
|
152
|
+
const status = obj.status;
|
|
153
|
+
if (status !== 'selected' && status !== 'needs_more_evidence') {
|
|
154
|
+
return { ok: false, error: `invalid status (${String(status)})` };
|
|
155
|
+
}
|
|
156
|
+
const rationale = typeof obj.rationale === 'string' ? obj.rationale.trim() : '';
|
|
157
|
+
const requiredChecks = (Array.isArray(obj.requiredChecks) ? obj.requiredChecks : [])
|
|
158
|
+
.filter((c) => typeof c === 'string' && c.trim().length > 0)
|
|
159
|
+
.map((c) => c.trim())
|
|
160
|
+
.slice(0, 5);
|
|
161
|
+
if (status === 'needs_more_evidence') {
|
|
162
|
+
return {
|
|
163
|
+
ok: true,
|
|
164
|
+
verdict: {
|
|
165
|
+
status,
|
|
166
|
+
winnerIndex: null,
|
|
167
|
+
rationale: rationale || 'Candidates are not sufficiently differentiated by evidence.',
|
|
168
|
+
requiredChecks,
|
|
169
|
+
degraded: false,
|
|
170
|
+
verifier: null,
|
|
171
|
+
judgedBy: 'llm',
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const winner = obj.winnerIndex;
|
|
176
|
+
if (typeof winner !== 'number' || !Number.isInteger(winner)) {
|
|
177
|
+
return { ok: false, error: `selected without integer winnerIndex (${String(winner)})` };
|
|
178
|
+
}
|
|
179
|
+
const entry = candidates.find((c) => c.index === winner);
|
|
180
|
+
if (!entry || entry.status !== 'ok') {
|
|
181
|
+
return { ok: false, error: `winnerIndex ${winner} does not point at a usable candidate` };
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
ok: true,
|
|
185
|
+
verdict: {
|
|
186
|
+
status: 'selected',
|
|
187
|
+
winnerIndex: winner,
|
|
188
|
+
rationale: rationale || 'Selected by evidence comparison.',
|
|
189
|
+
requiredChecks,
|
|
190
|
+
degraded: false,
|
|
191
|
+
verifier: null,
|
|
192
|
+
judgedBy: 'llm',
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Run one selection. NEVER throws: every failure path degrades to a
|
|
198
|
+
* `needs_more_evidence` verdict so the parent turn always continues.
|
|
199
|
+
*/
|
|
200
|
+
export async function runKrakenSelection(opts) {
|
|
201
|
+
const okEntries = opts.candidates.filter((c) => c.status === 'ok');
|
|
202
|
+
// Deterministic short-circuit: nothing usable to compare.
|
|
203
|
+
if (okEntries.length === 0) {
|
|
204
|
+
return needsMoreEvidence('No usable candidate reports this turn (all malformed). Proceed with your own judgment.', 'no usable candidates');
|
|
205
|
+
}
|
|
206
|
+
// Deterministic short-circuit: single candidate — nothing to compare.
|
|
207
|
+
if (okEntries.length === 1) {
|
|
208
|
+
return {
|
|
209
|
+
status: 'selected',
|
|
210
|
+
winnerIndex: okEntries[0].index,
|
|
211
|
+
rationale: 'Single usable candidate this turn — selected without a comparison call.',
|
|
212
|
+
requiredChecks: [],
|
|
213
|
+
degraded: false,
|
|
214
|
+
verifier: null,
|
|
215
|
+
judgedBy: 'deterministic',
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const system = VERIFIER_SYSTEM_PROMPT;
|
|
219
|
+
const user = buildSelectionPrompt(opts.task, opts.candidates);
|
|
220
|
+
let raw;
|
|
221
|
+
try {
|
|
222
|
+
raw = await opts.callModel({ system, user, identity: opts.identity });
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
return needsMoreEvidence(`Verifier call failed (${err instanceof Error ? err.message : String(err)}). Proceed with your own judgment.`, 'verifier call failed');
|
|
226
|
+
}
|
|
227
|
+
const parsed = parseSelectionVerdict(raw, opts.candidates);
|
|
228
|
+
if (!parsed.ok) {
|
|
229
|
+
return needsMoreEvidence(`Verifier response unusable (${parsed.error}). Proceed with your own judgment.`, `malformed verifier response: ${parsed.error}`);
|
|
230
|
+
}
|
|
231
|
+
return { ...parsed.verdict, verifier: opts.identity };
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../src/cli/kraken/verifier.ts"],"names":[],"mappings":"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"}
|