@mmnto/totem 1.91.0 → 1.93.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/artifacts/verdict.d.ts +1088 -0
- package/dist/artifacts/verdict.d.ts.map +1 -0
- package/dist/artifacts/verdict.js +863 -0
- package/dist/artifacts/verdict.js.map +1 -0
- package/dist/artifacts/verdict.test.d.ts +25 -0
- package/dist/artifacts/verdict.test.d.ts.map +1 -0
- package/dist/artifacts/verdict.test.js +878 -0
- package/dist/artifacts/verdict.test.js.map +1 -0
- package/dist/config-schema.d.ts +155 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config-schema.js +22 -0
- package/dist/config-schema.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/sys/git.d.ts +21 -0
- package/dist/sys/git.d.ts.map +1 -1
- package/dist/sys/git.js +15 -3
- package/dist/sys/git.js.map +1 -1
- package/dist/sys/git.test.js +58 -1
- package/dist/sys/git.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1088 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verdict-artifact contract — the single convergence point both review lanes
|
|
3
|
+
* emit (mmnto-ai/totem#2106, Proposal 302 / 304 R2 local review runner).
|
|
4
|
+
*
|
|
5
|
+
* A verdict artifact is the immutable, content-addressed record of ONE review
|
|
6
|
+
* round over ONE masked diff: the fan of lanes that attempted it (each a
|
|
7
|
+
* terminal {@link RunArtifact} reference, one hop from provenance), the
|
|
8
|
+
* deterministic #2103 post-checks, the normalized findings, the optional #2104
|
|
9
|
+
* panel it assembled, and the derived round/lineage bookkeeping. Everything
|
|
10
|
+
* downstream (the CLI round loop, the pilot ledger's covariate PR-line, the
|
|
11
|
+
* Phase-2 disposition ledger) consumes this shape, so it stays minimal but
|
|
12
|
+
* versioned.
|
|
13
|
+
*
|
|
14
|
+
* ── LANE-BLINDNESS INVARIANT (Proposal 302, DELIBERATE EXCLUSION) ────────────
|
|
15
|
+
* There is NO warm/cold runner-lane discriminator field ANYWHERE in this schema
|
|
16
|
+
* — not at the top level, not on a lane. This exclusion is deliberate: a
|
|
17
|
+
* contract consumer reads the verdict and CANNOT discriminate WHICH runner lane
|
|
18
|
+
* (a warm resident agent vs a cold SDK invocation) produced it. The wording
|
|
19
|
+
* matters (strategy 1a): "consumers cannot discriminate lanes FROM the
|
|
20
|
+
* artifact", NOT "lane identity is unknowable" — `lanes[].runArtifactHash`
|
|
21
|
+
* reaches provenance one hop away and `resolvedBackend` is panel-DIVERSITY data,
|
|
22
|
+
* neither of which is a warm/cold runner discriminator. The absence is enforced
|
|
23
|
+
* by a structural test (snapshots the key set) IN ADDITION to this note.
|
|
24
|
+
*
|
|
25
|
+
* The KEY-set structural test is not enough on its own: a runner class could be
|
|
26
|
+
* smuggled through a laneId VALUE. So `laneId` is additionally constrained to a
|
|
27
|
+
* backend-derived vocabulary — `lane-<index>:<resolvedBackendOrConfiguredLane>`
|
|
28
|
+
* (see {@link LaneIdSchema}) — with a refinement rejecting warm/cold/headless/
|
|
29
|
+
* sdk-runner substrings (strategy-codex G1). Net invariant: a consumer can
|
|
30
|
+
* identify WHICH backend participated (diversity), NEVER whether the producer was
|
|
31
|
+
* warm / cold / headless.
|
|
32
|
+
*
|
|
33
|
+
* Schema-evolution policy mirrors {@link RunArtifactSchema} / the panel artifact
|
|
34
|
+
* (F1): the reader is version-tolerant WITHIN the major — `schemaVersion`
|
|
35
|
+
* validates as `1.x`, every post-1.0.0 field is additive-optional, and a MAJOR
|
|
36
|
+
* bump requires a migration entry in `loadVerdictArtifact` before the writer
|
|
37
|
+
* ships. Hard-reject only unknown majors. Zod is the persisted-JSON boundary
|
|
38
|
+
* (read back from disk), per the repo's Zod-at-boundaries-only rule.
|
|
39
|
+
*/
|
|
40
|
+
import { z } from 'zod';
|
|
41
|
+
import { type PersistedPostCheckFinding } from './panel.js';
|
|
42
|
+
/** The verdict schemaVersion WRITTEN by this code. Readers accept any 1.x (F1). */
|
|
43
|
+
export declare const VERDICT_ARTIFACT_SCHEMA_VERSION = "1.0.0";
|
|
44
|
+
/** The major this reader understands; other majors need a migration entry. */
|
|
45
|
+
export declare const VERDICT_ARTIFACT_KNOWN_MAJOR = 1;
|
|
46
|
+
/**
|
|
47
|
+
* The four `getDiffForReview` sources. Canonical order matches the design doc.
|
|
48
|
+
*/
|
|
49
|
+
export declare const VERDICT_DIFF_SOURCES: readonly ["explicit-range", "staged", "uncommitted", "branch-vs-base"];
|
|
50
|
+
export type VerdictDiffSource = (typeof VERDICT_DIFF_SOURCES)[number];
|
|
51
|
+
/**
|
|
52
|
+
* The reviewed diff's scope, DISCRIMINATED by `source`. `diffHash` is ALWAYS
|
|
53
|
+
* required (sha256 over the MASKED review-payload bytes the lanes actually
|
|
54
|
+
* reviewed — hash symmetry with the artifact chain, never binds secret-bearing
|
|
55
|
+
* bytes; agy fold 5). The git ref fields are required only where the source
|
|
56
|
+
* makes them meaningful:
|
|
57
|
+
* - `explicit-range` — `base` AND `head` (the two endpoints).
|
|
58
|
+
* - `branch-vs-base` — `base` only (head is the working ref, implicit).
|
|
59
|
+
* - `staged` / `uncommitted` — NO refs (the index / worktree has none).
|
|
60
|
+
*/
|
|
61
|
+
export declare const VerdictDiffScopeSchema: z.ZodDiscriminatedUnion<"source", [z.ZodObject<{
|
|
62
|
+
source: z.ZodLiteral<"explicit-range">;
|
|
63
|
+
diffHash: z.ZodString;
|
|
64
|
+
base: z.ZodString;
|
|
65
|
+
head: z.ZodString;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
source: "explicit-range";
|
|
68
|
+
diffHash: string;
|
|
69
|
+
base: string;
|
|
70
|
+
head: string;
|
|
71
|
+
}, {
|
|
72
|
+
source: "explicit-range";
|
|
73
|
+
diffHash: string;
|
|
74
|
+
base: string;
|
|
75
|
+
head: string;
|
|
76
|
+
}>, z.ZodObject<{
|
|
77
|
+
source: z.ZodLiteral<"branch-vs-base">;
|
|
78
|
+
diffHash: z.ZodString;
|
|
79
|
+
base: z.ZodString;
|
|
80
|
+
}, "strip", z.ZodTypeAny, {
|
|
81
|
+
source: "branch-vs-base";
|
|
82
|
+
diffHash: string;
|
|
83
|
+
base: string;
|
|
84
|
+
}, {
|
|
85
|
+
source: "branch-vs-base";
|
|
86
|
+
diffHash: string;
|
|
87
|
+
base: string;
|
|
88
|
+
}>, z.ZodObject<{
|
|
89
|
+
source: z.ZodLiteral<"staged">;
|
|
90
|
+
diffHash: z.ZodString;
|
|
91
|
+
}, "strip", z.ZodTypeAny, {
|
|
92
|
+
source: "staged";
|
|
93
|
+
diffHash: string;
|
|
94
|
+
}, {
|
|
95
|
+
source: "staged";
|
|
96
|
+
diffHash: string;
|
|
97
|
+
}>, z.ZodObject<{
|
|
98
|
+
source: z.ZodLiteral<"uncommitted">;
|
|
99
|
+
diffHash: z.ZodString;
|
|
100
|
+
}, "strip", z.ZodTypeAny, {
|
|
101
|
+
source: "uncommitted";
|
|
102
|
+
diffHash: string;
|
|
103
|
+
}, {
|
|
104
|
+
source: "uncommitted";
|
|
105
|
+
diffHash: string;
|
|
106
|
+
}>]>;
|
|
107
|
+
export type VerdictDiffScope = z.infer<typeof VerdictDiffScopeSchema>;
|
|
108
|
+
/**
|
|
109
|
+
* Typed terminal-failure reasons for a `failed` lane. A failed lane is never
|
|
110
|
+
* handed to `assemblePanelArtifact` and never stamps the cache. NOTE (Prop 302
|
|
111
|
+
* lane-blindness): these classify the FAILURE, never the runner lane — none of
|
|
112
|
+
* them names warm/cold.
|
|
113
|
+
*/
|
|
114
|
+
export declare const VERDICT_LANE_FAILURE_REASONS: readonly ["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error"];
|
|
115
|
+
export type VerdictLaneFailureReason = (typeof VERDICT_LANE_FAILURE_REASONS)[number];
|
|
116
|
+
/** A `completed` lane's own severity tally (from its extracted structured verdict). */
|
|
117
|
+
export declare const VerdictLaneSummarySchema: z.ZodObject<{
|
|
118
|
+
critical: z.ZodNumber;
|
|
119
|
+
warn: z.ZodNumber;
|
|
120
|
+
info: z.ZodNumber;
|
|
121
|
+
}, "strip", z.ZodTypeAny, {
|
|
122
|
+
warn: number;
|
|
123
|
+
info: number;
|
|
124
|
+
critical: number;
|
|
125
|
+
}, {
|
|
126
|
+
warn: number;
|
|
127
|
+
info: number;
|
|
128
|
+
critical: number;
|
|
129
|
+
}>;
|
|
130
|
+
export type VerdictLaneSummary = z.infer<typeof VerdictLaneSummarySchema>;
|
|
131
|
+
/**
|
|
132
|
+
* The EXACT laneId shape — `lane-<index>:<resolvedBackendOrConfiguredLane>`:
|
|
133
|
+
* - `lane-` literal prefix,
|
|
134
|
+
* - `<index>` — the lane's zero-based position in the fan (`\d+`),
|
|
135
|
+
* - `:` separator,
|
|
136
|
+
* - `<resolvedBackendOrConfiguredLane>` — the resolved backend (`provider:model`,
|
|
137
|
+
* which itself carries a colon) for a lane that reached a backend, or the
|
|
138
|
+
* CONFIGURED lane string for a lane that failed before one resolved. Non-empty,
|
|
139
|
+
* opaque backend/lane text (`.+` — newlines excluded).
|
|
140
|
+
*
|
|
141
|
+
* This is backend-DERIVED vocabulary: a consumer can read the id and identify
|
|
142
|
+
* WHICH backend participated (panel-diversity data), and NOTHING about whether the
|
|
143
|
+
* producer was warm / cold / headless.
|
|
144
|
+
*/
|
|
145
|
+
export declare const LANE_ID_SHAPE_RE: RegExp;
|
|
146
|
+
/**
|
|
147
|
+
* laneId: shape-validated here; the VALUE channel of lane-blindness (Prop 302
|
|
148
|
+
* G1) is closed STRUCTURALLY by the schema's superRefine — every lane's suffix
|
|
149
|
+
* must equal its binding field (`resolvedBackend` for completed/abstained,
|
|
150
|
+
* `configuredLane` for failed), so a laneId cannot carry free text at all and a
|
|
151
|
+
* runner class (`warm`/`cold`/`headless`) has no channel to ride. An earlier
|
|
152
|
+
* substring blacklist here was removed: with structural binding as the primary
|
|
153
|
+
* guard it added only false-positive risk against legitimate future model names
|
|
154
|
+
* (e.g. a model literally named `*-cold-*`; PR #2337 greptile P2).
|
|
155
|
+
*/
|
|
156
|
+
export declare const LaneIdSchema: z.ZodString;
|
|
157
|
+
/**
|
|
158
|
+
* One lane's terminal outcome, DISCRIMINATED by `status`. The union makes
|
|
159
|
+
* impossible records unrepresentable (codex fold 2): a `completed` lane STRUCTURALLY
|
|
160
|
+
* requires its `runArtifactHash` (a response-cache hit emits no run artifact and so
|
|
161
|
+
* can never be `completed`); a `failed` lane carries a typed reason and never a
|
|
162
|
+
* `runArtifactHash`. `resolvedBackend` records what actually ran (post quota
|
|
163
|
+
* fallback) and is panel-diversity data — NOT a runner discriminator.
|
|
164
|
+
*/
|
|
165
|
+
export declare const VerdictLaneSchema: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
|
|
166
|
+
status: z.ZodLiteral<"completed">;
|
|
167
|
+
laneId: z.ZodString;
|
|
168
|
+
resolvedBackend: z.ZodString;
|
|
169
|
+
runArtifactHash: z.ZodString;
|
|
170
|
+
verdictSummary: z.ZodObject<{
|
|
171
|
+
critical: z.ZodNumber;
|
|
172
|
+
warn: z.ZodNumber;
|
|
173
|
+
info: z.ZodNumber;
|
|
174
|
+
}, "strip", z.ZodTypeAny, {
|
|
175
|
+
warn: number;
|
|
176
|
+
info: number;
|
|
177
|
+
critical: number;
|
|
178
|
+
}, {
|
|
179
|
+
warn: number;
|
|
180
|
+
info: number;
|
|
181
|
+
critical: number;
|
|
182
|
+
}>;
|
|
183
|
+
}, "strip", z.ZodTypeAny, {
|
|
184
|
+
status: "completed";
|
|
185
|
+
laneId: string;
|
|
186
|
+
resolvedBackend: string;
|
|
187
|
+
runArtifactHash: string;
|
|
188
|
+
verdictSummary: {
|
|
189
|
+
warn: number;
|
|
190
|
+
info: number;
|
|
191
|
+
critical: number;
|
|
192
|
+
};
|
|
193
|
+
}, {
|
|
194
|
+
status: "completed";
|
|
195
|
+
laneId: string;
|
|
196
|
+
resolvedBackend: string;
|
|
197
|
+
runArtifactHash: string;
|
|
198
|
+
verdictSummary: {
|
|
199
|
+
warn: number;
|
|
200
|
+
info: number;
|
|
201
|
+
critical: number;
|
|
202
|
+
};
|
|
203
|
+
}>, z.ZodObject<{
|
|
204
|
+
status: z.ZodLiteral<"abstained">;
|
|
205
|
+
laneId: z.ZodString;
|
|
206
|
+
resolvedBackend: z.ZodString;
|
|
207
|
+
runArtifactHash: z.ZodString;
|
|
208
|
+
/** Why no usable structured verdict was extractable (invoke happened, output unparseable). */
|
|
209
|
+
reason: z.ZodString;
|
|
210
|
+
}, "strip", z.ZodTypeAny, {
|
|
211
|
+
status: "abstained";
|
|
212
|
+
reason: string;
|
|
213
|
+
laneId: string;
|
|
214
|
+
resolvedBackend: string;
|
|
215
|
+
runArtifactHash: string;
|
|
216
|
+
}, {
|
|
217
|
+
status: "abstained";
|
|
218
|
+
reason: string;
|
|
219
|
+
laneId: string;
|
|
220
|
+
resolvedBackend: string;
|
|
221
|
+
runArtifactHash: string;
|
|
222
|
+
}>, z.ZodObject<{
|
|
223
|
+
status: z.ZodLiteral<"failed">;
|
|
224
|
+
laneId: z.ZodString;
|
|
225
|
+
typedReason: z.ZodEnum<["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error"]>;
|
|
226
|
+
/**
|
|
227
|
+
* REQUIRED (rev-6 item 3): the configured `provider:model` string the lane was
|
|
228
|
+
* created from. A failed lane can have NO `resolvedBackend` (it failed before a
|
|
229
|
+
* backend resolved — e.g. `config-error` / `missing-artifact-emission`), so the
|
|
230
|
+
* laneId suffix has nothing to bind to unless the configured lane is persisted.
|
|
231
|
+
* The `superRefine` binds `laneId` suffix === `configuredLane` (closing the
|
|
232
|
+
* `lane-0:gemini:completely-invented` tautology): the suffix is no longer free —
|
|
233
|
+
* it must equal this declared field.
|
|
234
|
+
*/
|
|
235
|
+
configuredLane: z.ZodString;
|
|
236
|
+
/**
|
|
237
|
+
* OPTIONAL supplementary provenance: the backend that ACTUALLY ran before the
|
|
238
|
+
* lane failed (present only when a backend resolved — e.g. a quota fallback that
|
|
239
|
+
* then failed). NOT the id binding: after a quota fallback it can legitimately
|
|
240
|
+
* DIFFER from `configuredLane`, so the laneId suffix binds to `configuredLane`
|
|
241
|
+
* (stable at lane creation), never to this field.
|
|
242
|
+
*/
|
|
243
|
+
resolvedBackend: z.ZodOptional<z.ZodString>;
|
|
244
|
+
}, "strip", z.ZodTypeAny, {
|
|
245
|
+
status: "failed";
|
|
246
|
+
laneId: string;
|
|
247
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
248
|
+
configuredLane: string;
|
|
249
|
+
resolvedBackend?: string | undefined;
|
|
250
|
+
}, {
|
|
251
|
+
status: "failed";
|
|
252
|
+
laneId: string;
|
|
253
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
254
|
+
configuredLane: string;
|
|
255
|
+
resolvedBackend?: string | undefined;
|
|
256
|
+
}>]>;
|
|
257
|
+
export type VerdictLane = z.infer<typeof VerdictLaneSchema>;
|
|
258
|
+
/** Severity vocabulary — aligned VERBATIM with cli `ShieldFindingSeveritySchema` (defined here so core stays cli-independent). */
|
|
259
|
+
export declare const VerdictFindingSeveritySchema: z.ZodEnum<["CRITICAL", "WARN", "INFO"]>;
|
|
260
|
+
export type VerdictFindingSeverity = z.infer<typeof VerdictFindingSeveritySchema>;
|
|
261
|
+
/**
|
|
262
|
+
* A normalized finding from the shared review-output extractor. Field names
|
|
263
|
+
* align with cli `ShieldFinding` (`severity` / `confidence` / `message` /
|
|
264
|
+
* `file` / `line`); `confidence` is optional here because not every extracted
|
|
265
|
+
* lane output carries one, but when present it is a 0..1 probability (same
|
|
266
|
+
* bound as ShieldFinding). The diagnostic `message` is NEVER dropped or
|
|
267
|
+
* renamed.
|
|
268
|
+
*/
|
|
269
|
+
export declare const VerdictFindingSchema: z.ZodObject<{
|
|
270
|
+
severity: z.ZodEnum<["CRITICAL", "WARN", "INFO"]>;
|
|
271
|
+
confidence: z.ZodOptional<z.ZodNumber>;
|
|
272
|
+
file: z.ZodOptional<z.ZodString>;
|
|
273
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
274
|
+
message: z.ZodString;
|
|
275
|
+
}, "strip", z.ZodTypeAny, {
|
|
276
|
+
message: string;
|
|
277
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
278
|
+
confidence?: number | undefined;
|
|
279
|
+
file?: string | undefined;
|
|
280
|
+
line?: number | undefined;
|
|
281
|
+
}, {
|
|
282
|
+
message: string;
|
|
283
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
284
|
+
confidence?: number | undefined;
|
|
285
|
+
file?: string | undefined;
|
|
286
|
+
line?: number | undefined;
|
|
287
|
+
}>;
|
|
288
|
+
export type VerdictFinding = z.infer<typeof VerdictFindingSchema>;
|
|
289
|
+
/**
|
|
290
|
+
* Round bookkeeping (all DERIVED — see the CLI lifecycle). `lineageKey` is the
|
|
291
|
+
* composite hash over the RESOLVED scope selector (see {@link computeLineageKey}
|
|
292
|
+
* — worktree identity + branch + source + the meaningful range selectors), NOT
|
|
293
|
+
* the diff bytes, so legitimate fix rounds still chain; `priorVerdictHash` links
|
|
294
|
+
* the implicit prior round (latest verdict sharing the lineage key) or an
|
|
295
|
+
* explicit `--continues` override; absent at round 0.
|
|
296
|
+
*/
|
|
297
|
+
export declare const VerdictRoundSchema: z.ZodObject<{
|
|
298
|
+
index: z.ZodNumber;
|
|
299
|
+
priorVerdictHash: z.ZodOptional<z.ZodString>;
|
|
300
|
+
lineageKey: z.ZodString;
|
|
301
|
+
}, "strip", z.ZodTypeAny, {
|
|
302
|
+
index: number;
|
|
303
|
+
lineageKey: string;
|
|
304
|
+
priorVerdictHash?: string | undefined;
|
|
305
|
+
}, {
|
|
306
|
+
index: number;
|
|
307
|
+
lineageKey: string;
|
|
308
|
+
priorVerdictHash?: string | undefined;
|
|
309
|
+
}>;
|
|
310
|
+
export type VerdictRound = z.infer<typeof VerdictRoundSchema>;
|
|
311
|
+
/**
|
|
312
|
+
* The subset of a verdict the pure predicates read. The persisted boundary AND
|
|
313
|
+
* every CLI caller derive `settled` / cache-eligibility from THESE fields — the
|
|
314
|
+
* stored `settled` boolean is re-derived and checked at parse, never trusted
|
|
315
|
+
* (totem-codex finding 5). `findings` is the exemption-FILTERED union the CLI
|
|
316
|
+
* lands on the artifact; the R2 severity map is pinned `INFO = cosmetic`,
|
|
317
|
+
* `WARN | CRITICAL = actionable`.
|
|
318
|
+
*/
|
|
319
|
+
export interface VerdictPredicateInput {
|
|
320
|
+
lanes: readonly VerdictLane[];
|
|
321
|
+
findings: readonly VerdictFinding[];
|
|
322
|
+
postChecks: readonly PersistedPostCheckFinding[];
|
|
323
|
+
reviewedState: 'matched' | 'drifted';
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* `settled` — the current-round dryness predicate, PURE over artifact content (no
|
|
327
|
+
* cross-round input, no model output):
|
|
328
|
+
*
|
|
329
|
+
* settled = (every attempted lane completed)
|
|
330
|
+
* AND (zero actionable — WARN|CRITICAL — findings)
|
|
331
|
+
* AND (no decidable-tier post-check row with verdict 'fail')
|
|
332
|
+
* AND (reviewedState === 'matched')
|
|
333
|
+
*
|
|
334
|
+
* A failed/abstained lane ⇒ fan incomplete ⇒ never settled (a persistent CRITICAL
|
|
335
|
+
* can never settle by lane dropout — agy fold 1, satisfied structurally); drift ⇒
|
|
336
|
+
* the verdict is bound to the pre-fan diff and does NOT cover the current tree ⇒
|
|
337
|
+
* not settled (codex rev-2 fold 1). This export is the SINGLE SOURCE OF TRUTH: the
|
|
338
|
+
* CLI derives its loop-termination signal from it and {@link VerdictArtifactSchema}
|
|
339
|
+
* re-derives + checks the stored `settled` (finding 5) — a crafted lane output
|
|
340
|
+
* cannot flip it (pure function; the exemption filter is the only removal
|
|
341
|
+
* mechanism, upstream of this boundary).
|
|
342
|
+
*/
|
|
343
|
+
export declare function deriveSettled(v: VerdictPredicateInput): boolean;
|
|
344
|
+
/**
|
|
345
|
+
* Cache eligibility — the DISTINCT, weaker predicate (codex fold 4). Identical to
|
|
346
|
+
* {@link deriveSettled} except it tolerates WARNs (matching today's PASS
|
|
347
|
+
* semantics — the drip class the runner absorbs is WARN-shaped):
|
|
348
|
+
*
|
|
349
|
+
* cacheEligible = (every attempted lane completed)
|
|
350
|
+
* AND (zero CRITICAL findings)
|
|
351
|
+
* AND (no decidable-tier post-check row with verdict 'fail')
|
|
352
|
+
* AND (reviewedState === 'matched')
|
|
353
|
+
*
|
|
354
|
+
* A degraded fan (any failed/abstained lane) fails the first conjunct and is
|
|
355
|
+
* therefore never cache-eligible; drift blocks the stamp. `settled` (no WARNs) is
|
|
356
|
+
* deliberately STRICTER than cache-eligible (no CRITICALs).
|
|
357
|
+
*/
|
|
358
|
+
export declare function deriveCacheEligible(v: VerdictPredicateInput): boolean;
|
|
359
|
+
/**
|
|
360
|
+
* The verdict artifact. See the module docstring for the LANE-BLINDNESS
|
|
361
|
+
* invariant (Prop 302): NO warm/cold runner-lane discriminator field exists,
|
|
362
|
+
* deliberately.
|
|
363
|
+
*
|
|
364
|
+
* `superRefine` enforces the cross-field invariants that a hand-edited or
|
|
365
|
+
* builder-buggy record could otherwise violate silently — mirrored counts are
|
|
366
|
+
* NEVER accepted on trust (codex):
|
|
367
|
+
* - `attemptedLaneCount === lanes.length`; `completedLaneCount === #completed`.
|
|
368
|
+
* - lanes nonempty, laneIds unique (finding 9c).
|
|
369
|
+
* - panel ⟺ diversity AND panel ⟺ ≥2 completed lanes, BOTH directions
|
|
370
|
+
* (finding 9a): a panel is assembled from — and only from — ≥2 usable lanes,
|
|
371
|
+
* and always emits its diversity summary.
|
|
372
|
+
* - round-chain shape (finding 9b): `round.index === 0` ⟺ `priorVerdictHash`
|
|
373
|
+
* absent (round 0 starts a chain; round N>0 links its prior).
|
|
374
|
+
* - stored `settled === deriveSettled(value)` (finding 5): the persisted
|
|
375
|
+
* boundary re-derives the dryness predicate, never trusting a fabricated flag.
|
|
376
|
+
*/
|
|
377
|
+
export declare const VerdictArtifactSchema: z.ZodEffects<z.ZodObject<{
|
|
378
|
+
schemaVersion: z.ZodEffects<z.ZodString, string, string>;
|
|
379
|
+
/** The reviewed diff's scope + masked-payload hash (source-discriminated). */
|
|
380
|
+
diffScope: z.ZodDiscriminatedUnion<"source", [z.ZodObject<{
|
|
381
|
+
source: z.ZodLiteral<"explicit-range">;
|
|
382
|
+
diffHash: z.ZodString;
|
|
383
|
+
base: z.ZodString;
|
|
384
|
+
head: z.ZodString;
|
|
385
|
+
}, "strip", z.ZodTypeAny, {
|
|
386
|
+
source: "explicit-range";
|
|
387
|
+
diffHash: string;
|
|
388
|
+
base: string;
|
|
389
|
+
head: string;
|
|
390
|
+
}, {
|
|
391
|
+
source: "explicit-range";
|
|
392
|
+
diffHash: string;
|
|
393
|
+
base: string;
|
|
394
|
+
head: string;
|
|
395
|
+
}>, z.ZodObject<{
|
|
396
|
+
source: z.ZodLiteral<"branch-vs-base">;
|
|
397
|
+
diffHash: z.ZodString;
|
|
398
|
+
base: z.ZodString;
|
|
399
|
+
}, "strip", z.ZodTypeAny, {
|
|
400
|
+
source: "branch-vs-base";
|
|
401
|
+
diffHash: string;
|
|
402
|
+
base: string;
|
|
403
|
+
}, {
|
|
404
|
+
source: "branch-vs-base";
|
|
405
|
+
diffHash: string;
|
|
406
|
+
base: string;
|
|
407
|
+
}>, z.ZodObject<{
|
|
408
|
+
source: z.ZodLiteral<"staged">;
|
|
409
|
+
diffHash: z.ZodString;
|
|
410
|
+
}, "strip", z.ZodTypeAny, {
|
|
411
|
+
source: "staged";
|
|
412
|
+
diffHash: string;
|
|
413
|
+
}, {
|
|
414
|
+
source: "staged";
|
|
415
|
+
diffHash: string;
|
|
416
|
+
}>, z.ZodObject<{
|
|
417
|
+
source: z.ZodLiteral<"uncommitted">;
|
|
418
|
+
diffHash: z.ZodString;
|
|
419
|
+
}, "strip", z.ZodTypeAny, {
|
|
420
|
+
source: "uncommitted";
|
|
421
|
+
diffHash: string;
|
|
422
|
+
}, {
|
|
423
|
+
source: "uncommitted";
|
|
424
|
+
diffHash: string;
|
|
425
|
+
}>]>;
|
|
426
|
+
/** Every attempted lane's terminal outcome (status-discriminated union). */
|
|
427
|
+
lanes: z.ZodArray<z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
|
|
428
|
+
status: z.ZodLiteral<"completed">;
|
|
429
|
+
laneId: z.ZodString;
|
|
430
|
+
resolvedBackend: z.ZodString;
|
|
431
|
+
runArtifactHash: z.ZodString;
|
|
432
|
+
verdictSummary: z.ZodObject<{
|
|
433
|
+
critical: z.ZodNumber;
|
|
434
|
+
warn: z.ZodNumber;
|
|
435
|
+
info: z.ZodNumber;
|
|
436
|
+
}, "strip", z.ZodTypeAny, {
|
|
437
|
+
warn: number;
|
|
438
|
+
info: number;
|
|
439
|
+
critical: number;
|
|
440
|
+
}, {
|
|
441
|
+
warn: number;
|
|
442
|
+
info: number;
|
|
443
|
+
critical: number;
|
|
444
|
+
}>;
|
|
445
|
+
}, "strip", z.ZodTypeAny, {
|
|
446
|
+
status: "completed";
|
|
447
|
+
laneId: string;
|
|
448
|
+
resolvedBackend: string;
|
|
449
|
+
runArtifactHash: string;
|
|
450
|
+
verdictSummary: {
|
|
451
|
+
warn: number;
|
|
452
|
+
info: number;
|
|
453
|
+
critical: number;
|
|
454
|
+
};
|
|
455
|
+
}, {
|
|
456
|
+
status: "completed";
|
|
457
|
+
laneId: string;
|
|
458
|
+
resolvedBackend: string;
|
|
459
|
+
runArtifactHash: string;
|
|
460
|
+
verdictSummary: {
|
|
461
|
+
warn: number;
|
|
462
|
+
info: number;
|
|
463
|
+
critical: number;
|
|
464
|
+
};
|
|
465
|
+
}>, z.ZodObject<{
|
|
466
|
+
status: z.ZodLiteral<"abstained">;
|
|
467
|
+
laneId: z.ZodString;
|
|
468
|
+
resolvedBackend: z.ZodString;
|
|
469
|
+
runArtifactHash: z.ZodString;
|
|
470
|
+
/** Why no usable structured verdict was extractable (invoke happened, output unparseable). */
|
|
471
|
+
reason: z.ZodString;
|
|
472
|
+
}, "strip", z.ZodTypeAny, {
|
|
473
|
+
status: "abstained";
|
|
474
|
+
reason: string;
|
|
475
|
+
laneId: string;
|
|
476
|
+
resolvedBackend: string;
|
|
477
|
+
runArtifactHash: string;
|
|
478
|
+
}, {
|
|
479
|
+
status: "abstained";
|
|
480
|
+
reason: string;
|
|
481
|
+
laneId: string;
|
|
482
|
+
resolvedBackend: string;
|
|
483
|
+
runArtifactHash: string;
|
|
484
|
+
}>, z.ZodObject<{
|
|
485
|
+
status: z.ZodLiteral<"failed">;
|
|
486
|
+
laneId: z.ZodString;
|
|
487
|
+
typedReason: z.ZodEnum<["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error"]>;
|
|
488
|
+
/**
|
|
489
|
+
* REQUIRED (rev-6 item 3): the configured `provider:model` string the lane was
|
|
490
|
+
* created from. A failed lane can have NO `resolvedBackend` (it failed before a
|
|
491
|
+
* backend resolved — e.g. `config-error` / `missing-artifact-emission`), so the
|
|
492
|
+
* laneId suffix has nothing to bind to unless the configured lane is persisted.
|
|
493
|
+
* The `superRefine` binds `laneId` suffix === `configuredLane` (closing the
|
|
494
|
+
* `lane-0:gemini:completely-invented` tautology): the suffix is no longer free —
|
|
495
|
+
* it must equal this declared field.
|
|
496
|
+
*/
|
|
497
|
+
configuredLane: z.ZodString;
|
|
498
|
+
/**
|
|
499
|
+
* OPTIONAL supplementary provenance: the backend that ACTUALLY ran before the
|
|
500
|
+
* lane failed (present only when a backend resolved — e.g. a quota fallback that
|
|
501
|
+
* then failed). NOT the id binding: after a quota fallback it can legitimately
|
|
502
|
+
* DIFFER from `configuredLane`, so the laneId suffix binds to `configuredLane`
|
|
503
|
+
* (stable at lane creation), never to this field.
|
|
504
|
+
*/
|
|
505
|
+
resolvedBackend: z.ZodOptional<z.ZodString>;
|
|
506
|
+
}, "strip", z.ZodTypeAny, {
|
|
507
|
+
status: "failed";
|
|
508
|
+
laneId: string;
|
|
509
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
510
|
+
configuredLane: string;
|
|
511
|
+
resolvedBackend?: string | undefined;
|
|
512
|
+
}, {
|
|
513
|
+
status: "failed";
|
|
514
|
+
laneId: string;
|
|
515
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
516
|
+
configuredLane: string;
|
|
517
|
+
resolvedBackend?: string | undefined;
|
|
518
|
+
}>]>, "many">;
|
|
519
|
+
/** MUST equal `lanes.length` (validated below — never trusted). */
|
|
520
|
+
attemptedLaneCount: z.ZodNumber;
|
|
521
|
+
/** MUST equal the count of `completed` lanes (validated below — never trusted). */
|
|
522
|
+
completedLaneCount: z.ZodNumber;
|
|
523
|
+
/** Present IFF a #2104 panel was actually assembled (≥2 completed lanes; guarded below). */
|
|
524
|
+
panelArtifactHash: z.ZodOptional<z.ZodString>;
|
|
525
|
+
/** Deterministic #2103 post-checks — the persisted vocabulary VERBATIM (`ruleName`/`tier`/`verdict`/`message`). */
|
|
526
|
+
postChecks: z.ZodArray<z.ZodObject<{
|
|
527
|
+
ruleName: z.ZodString;
|
|
528
|
+
tier: z.ZodEnum<["decidable", "sensor"]>;
|
|
529
|
+
verdict: z.ZodEnum<["pass", "fail", "abstain"]>;
|
|
530
|
+
message: z.ZodString;
|
|
531
|
+
}, "strip", z.ZodTypeAny, {
|
|
532
|
+
message: string;
|
|
533
|
+
tier: "decidable" | "sensor";
|
|
534
|
+
ruleName: string;
|
|
535
|
+
verdict: "pass" | "fail" | "abstain";
|
|
536
|
+
}, {
|
|
537
|
+
message: string;
|
|
538
|
+
tier: "decidable" | "sensor";
|
|
539
|
+
ruleName: string;
|
|
540
|
+
verdict: "pass" | "fail" | "abstain";
|
|
541
|
+
}>, "many">;
|
|
542
|
+
/** Normalized findings from the shared extractor (exemption-filtered by the CLI before it lands here). */
|
|
543
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
544
|
+
severity: z.ZodEnum<["CRITICAL", "WARN", "INFO"]>;
|
|
545
|
+
confidence: z.ZodOptional<z.ZodNumber>;
|
|
546
|
+
file: z.ZodOptional<z.ZodString>;
|
|
547
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
548
|
+
message: z.ZodString;
|
|
549
|
+
}, "strip", z.ZodTypeAny, {
|
|
550
|
+
message: string;
|
|
551
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
552
|
+
confidence?: number | undefined;
|
|
553
|
+
file?: string | undefined;
|
|
554
|
+
line?: number | undefined;
|
|
555
|
+
}, {
|
|
556
|
+
message: string;
|
|
557
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
558
|
+
confidence?: number | undefined;
|
|
559
|
+
file?: string | undefined;
|
|
560
|
+
line?: number | undefined;
|
|
561
|
+
}>, "many">;
|
|
562
|
+
/** A SINGLE top-level panel-diversity summary (classifyDiversity output) — present only with a panel; NEVER mirrored per finding. */
|
|
563
|
+
diversity: z.ZodOptional<z.ZodObject<{
|
|
564
|
+
providers: z.ZodArray<z.ZodString, "many">;
|
|
565
|
+
distinctProviders: z.ZodNumber;
|
|
566
|
+
class: z.ZodEnum<["cross-vendor", "same-vendor-isolated"]>;
|
|
567
|
+
unrecognizedProviders: z.ZodArray<z.ZodString, "many">;
|
|
568
|
+
diversityConfidence: z.ZodEnum<["verified", "coarse"]>;
|
|
569
|
+
}, "strip", z.ZodTypeAny, {
|
|
570
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
571
|
+
providers: string[];
|
|
572
|
+
distinctProviders: number;
|
|
573
|
+
unrecognizedProviders: string[];
|
|
574
|
+
diversityConfidence: "verified" | "coarse";
|
|
575
|
+
}, {
|
|
576
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
577
|
+
providers: string[];
|
|
578
|
+
distinctProviders: number;
|
|
579
|
+
unrecognizedProviders: string[];
|
|
580
|
+
diversityConfidence: "verified" | "coarse";
|
|
581
|
+
}>>;
|
|
582
|
+
round: z.ZodObject<{
|
|
583
|
+
index: z.ZodNumber;
|
|
584
|
+
priorVerdictHash: z.ZodOptional<z.ZodString>;
|
|
585
|
+
lineageKey: z.ZodString;
|
|
586
|
+
}, "strip", z.ZodTypeAny, {
|
|
587
|
+
index: number;
|
|
588
|
+
lineageKey: string;
|
|
589
|
+
priorVerdictHash?: string | undefined;
|
|
590
|
+
}, {
|
|
591
|
+
index: number;
|
|
592
|
+
lineageKey: string;
|
|
593
|
+
priorVerdictHash?: string | undefined;
|
|
594
|
+
}>;
|
|
595
|
+
/**
|
|
596
|
+
* Post-fan tree compare against the PRE-fan content hash (codex rev-2 fold 1):
|
|
597
|
+
* `'matched'` when the tracked-source tree is byte-identical before and after
|
|
598
|
+
* the fan, `'drifted'` when it changed mid-fan. A DERIVED, non-sentinel field
|
|
599
|
+
* (the two hash domains stay separate — this records the OUTCOME of the compare,
|
|
600
|
+
* not the content hash itself). Drift forces `settled=false` and blocks the
|
|
601
|
+
* cache stamp: the verdict is bound to the pre-fan diff, so a dry fan over a
|
|
602
|
+
* mutated tree does NOT cover the current tree and must not settle the loop.
|
|
603
|
+
*/
|
|
604
|
+
reviewedState: z.ZodEnum<["matched", "drifted"]>;
|
|
605
|
+
/** Current-round dryness predicate (see the CLI lifecycle) — pure over artifact content. */
|
|
606
|
+
settled: z.ZodBoolean;
|
|
607
|
+
/**
|
|
608
|
+
* ISO-8601 emission time — a VALIDATED datetime (rev-5 item 8): a malformed
|
|
609
|
+
* `createdAt` is rejected at the persisted boundary rather than trusted.
|
|
610
|
+
* EXCLUDED from the content address (identical rounds dedup to one artifact
|
|
611
|
+
* regardless of when they ran) — observability only, and it is never a
|
|
612
|
+
* lineage tie-breaker (see {@link findLatestVerdictForLineage}). See
|
|
613
|
+
* {@link computeVerdictArtifactContentHash}.
|
|
614
|
+
*/
|
|
615
|
+
createdAt: z.ZodString;
|
|
616
|
+
}, "strip", z.ZodTypeAny, {
|
|
617
|
+
createdAt: string;
|
|
618
|
+
diffScope: {
|
|
619
|
+
source: "explicit-range";
|
|
620
|
+
diffHash: string;
|
|
621
|
+
base: string;
|
|
622
|
+
head: string;
|
|
623
|
+
} | {
|
|
624
|
+
source: "branch-vs-base";
|
|
625
|
+
diffHash: string;
|
|
626
|
+
base: string;
|
|
627
|
+
} | {
|
|
628
|
+
source: "staged";
|
|
629
|
+
diffHash: string;
|
|
630
|
+
} | {
|
|
631
|
+
source: "uncommitted";
|
|
632
|
+
diffHash: string;
|
|
633
|
+
};
|
|
634
|
+
schemaVersion: string;
|
|
635
|
+
lanes: ({
|
|
636
|
+
status: "completed";
|
|
637
|
+
laneId: string;
|
|
638
|
+
resolvedBackend: string;
|
|
639
|
+
runArtifactHash: string;
|
|
640
|
+
verdictSummary: {
|
|
641
|
+
warn: number;
|
|
642
|
+
info: number;
|
|
643
|
+
critical: number;
|
|
644
|
+
};
|
|
645
|
+
} | {
|
|
646
|
+
status: "abstained";
|
|
647
|
+
reason: string;
|
|
648
|
+
laneId: string;
|
|
649
|
+
resolvedBackend: string;
|
|
650
|
+
runArtifactHash: string;
|
|
651
|
+
} | {
|
|
652
|
+
status: "failed";
|
|
653
|
+
laneId: string;
|
|
654
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
655
|
+
configuredLane: string;
|
|
656
|
+
resolvedBackend?: string | undefined;
|
|
657
|
+
})[];
|
|
658
|
+
findings: {
|
|
659
|
+
message: string;
|
|
660
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
661
|
+
confidence?: number | undefined;
|
|
662
|
+
file?: string | undefined;
|
|
663
|
+
line?: number | undefined;
|
|
664
|
+
}[];
|
|
665
|
+
attemptedLaneCount: number;
|
|
666
|
+
completedLaneCount: number;
|
|
667
|
+
postChecks: {
|
|
668
|
+
message: string;
|
|
669
|
+
tier: "decidable" | "sensor";
|
|
670
|
+
ruleName: string;
|
|
671
|
+
verdict: "pass" | "fail" | "abstain";
|
|
672
|
+
}[];
|
|
673
|
+
round: {
|
|
674
|
+
index: number;
|
|
675
|
+
lineageKey: string;
|
|
676
|
+
priorVerdictHash?: string | undefined;
|
|
677
|
+
};
|
|
678
|
+
reviewedState: "matched" | "drifted";
|
|
679
|
+
settled: boolean;
|
|
680
|
+
diversity?: {
|
|
681
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
682
|
+
providers: string[];
|
|
683
|
+
distinctProviders: number;
|
|
684
|
+
unrecognizedProviders: string[];
|
|
685
|
+
diversityConfidence: "verified" | "coarse";
|
|
686
|
+
} | undefined;
|
|
687
|
+
panelArtifactHash?: string | undefined;
|
|
688
|
+
}, {
|
|
689
|
+
createdAt: string;
|
|
690
|
+
diffScope: {
|
|
691
|
+
source: "explicit-range";
|
|
692
|
+
diffHash: string;
|
|
693
|
+
base: string;
|
|
694
|
+
head: string;
|
|
695
|
+
} | {
|
|
696
|
+
source: "branch-vs-base";
|
|
697
|
+
diffHash: string;
|
|
698
|
+
base: string;
|
|
699
|
+
} | {
|
|
700
|
+
source: "staged";
|
|
701
|
+
diffHash: string;
|
|
702
|
+
} | {
|
|
703
|
+
source: "uncommitted";
|
|
704
|
+
diffHash: string;
|
|
705
|
+
};
|
|
706
|
+
schemaVersion: string;
|
|
707
|
+
lanes: ({
|
|
708
|
+
status: "completed";
|
|
709
|
+
laneId: string;
|
|
710
|
+
resolvedBackend: string;
|
|
711
|
+
runArtifactHash: string;
|
|
712
|
+
verdictSummary: {
|
|
713
|
+
warn: number;
|
|
714
|
+
info: number;
|
|
715
|
+
critical: number;
|
|
716
|
+
};
|
|
717
|
+
} | {
|
|
718
|
+
status: "abstained";
|
|
719
|
+
reason: string;
|
|
720
|
+
laneId: string;
|
|
721
|
+
resolvedBackend: string;
|
|
722
|
+
runArtifactHash: string;
|
|
723
|
+
} | {
|
|
724
|
+
status: "failed";
|
|
725
|
+
laneId: string;
|
|
726
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
727
|
+
configuredLane: string;
|
|
728
|
+
resolvedBackend?: string | undefined;
|
|
729
|
+
})[];
|
|
730
|
+
findings: {
|
|
731
|
+
message: string;
|
|
732
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
733
|
+
confidence?: number | undefined;
|
|
734
|
+
file?: string | undefined;
|
|
735
|
+
line?: number | undefined;
|
|
736
|
+
}[];
|
|
737
|
+
attemptedLaneCount: number;
|
|
738
|
+
completedLaneCount: number;
|
|
739
|
+
postChecks: {
|
|
740
|
+
message: string;
|
|
741
|
+
tier: "decidable" | "sensor";
|
|
742
|
+
ruleName: string;
|
|
743
|
+
verdict: "pass" | "fail" | "abstain";
|
|
744
|
+
}[];
|
|
745
|
+
round: {
|
|
746
|
+
index: number;
|
|
747
|
+
lineageKey: string;
|
|
748
|
+
priorVerdictHash?: string | undefined;
|
|
749
|
+
};
|
|
750
|
+
reviewedState: "matched" | "drifted";
|
|
751
|
+
settled: boolean;
|
|
752
|
+
diversity?: {
|
|
753
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
754
|
+
providers: string[];
|
|
755
|
+
distinctProviders: number;
|
|
756
|
+
unrecognizedProviders: string[];
|
|
757
|
+
diversityConfidence: "verified" | "coarse";
|
|
758
|
+
} | undefined;
|
|
759
|
+
panelArtifactHash?: string | undefined;
|
|
760
|
+
}>, {
|
|
761
|
+
createdAt: string;
|
|
762
|
+
diffScope: {
|
|
763
|
+
source: "explicit-range";
|
|
764
|
+
diffHash: string;
|
|
765
|
+
base: string;
|
|
766
|
+
head: string;
|
|
767
|
+
} | {
|
|
768
|
+
source: "branch-vs-base";
|
|
769
|
+
diffHash: string;
|
|
770
|
+
base: string;
|
|
771
|
+
} | {
|
|
772
|
+
source: "staged";
|
|
773
|
+
diffHash: string;
|
|
774
|
+
} | {
|
|
775
|
+
source: "uncommitted";
|
|
776
|
+
diffHash: string;
|
|
777
|
+
};
|
|
778
|
+
schemaVersion: string;
|
|
779
|
+
lanes: ({
|
|
780
|
+
status: "completed";
|
|
781
|
+
laneId: string;
|
|
782
|
+
resolvedBackend: string;
|
|
783
|
+
runArtifactHash: string;
|
|
784
|
+
verdictSummary: {
|
|
785
|
+
warn: number;
|
|
786
|
+
info: number;
|
|
787
|
+
critical: number;
|
|
788
|
+
};
|
|
789
|
+
} | {
|
|
790
|
+
status: "abstained";
|
|
791
|
+
reason: string;
|
|
792
|
+
laneId: string;
|
|
793
|
+
resolvedBackend: string;
|
|
794
|
+
runArtifactHash: string;
|
|
795
|
+
} | {
|
|
796
|
+
status: "failed";
|
|
797
|
+
laneId: string;
|
|
798
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
799
|
+
configuredLane: string;
|
|
800
|
+
resolvedBackend?: string | undefined;
|
|
801
|
+
})[];
|
|
802
|
+
findings: {
|
|
803
|
+
message: string;
|
|
804
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
805
|
+
confidence?: number | undefined;
|
|
806
|
+
file?: string | undefined;
|
|
807
|
+
line?: number | undefined;
|
|
808
|
+
}[];
|
|
809
|
+
attemptedLaneCount: number;
|
|
810
|
+
completedLaneCount: number;
|
|
811
|
+
postChecks: {
|
|
812
|
+
message: string;
|
|
813
|
+
tier: "decidable" | "sensor";
|
|
814
|
+
ruleName: string;
|
|
815
|
+
verdict: "pass" | "fail" | "abstain";
|
|
816
|
+
}[];
|
|
817
|
+
round: {
|
|
818
|
+
index: number;
|
|
819
|
+
lineageKey: string;
|
|
820
|
+
priorVerdictHash?: string | undefined;
|
|
821
|
+
};
|
|
822
|
+
reviewedState: "matched" | "drifted";
|
|
823
|
+
settled: boolean;
|
|
824
|
+
diversity?: {
|
|
825
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
826
|
+
providers: string[];
|
|
827
|
+
distinctProviders: number;
|
|
828
|
+
unrecognizedProviders: string[];
|
|
829
|
+
diversityConfidence: "verified" | "coarse";
|
|
830
|
+
} | undefined;
|
|
831
|
+
panelArtifactHash?: string | undefined;
|
|
832
|
+
}, {
|
|
833
|
+
createdAt: string;
|
|
834
|
+
diffScope: {
|
|
835
|
+
source: "explicit-range";
|
|
836
|
+
diffHash: string;
|
|
837
|
+
base: string;
|
|
838
|
+
head: string;
|
|
839
|
+
} | {
|
|
840
|
+
source: "branch-vs-base";
|
|
841
|
+
diffHash: string;
|
|
842
|
+
base: string;
|
|
843
|
+
} | {
|
|
844
|
+
source: "staged";
|
|
845
|
+
diffHash: string;
|
|
846
|
+
} | {
|
|
847
|
+
source: "uncommitted";
|
|
848
|
+
diffHash: string;
|
|
849
|
+
};
|
|
850
|
+
schemaVersion: string;
|
|
851
|
+
lanes: ({
|
|
852
|
+
status: "completed";
|
|
853
|
+
laneId: string;
|
|
854
|
+
resolvedBackend: string;
|
|
855
|
+
runArtifactHash: string;
|
|
856
|
+
verdictSummary: {
|
|
857
|
+
warn: number;
|
|
858
|
+
info: number;
|
|
859
|
+
critical: number;
|
|
860
|
+
};
|
|
861
|
+
} | {
|
|
862
|
+
status: "abstained";
|
|
863
|
+
reason: string;
|
|
864
|
+
laneId: string;
|
|
865
|
+
resolvedBackend: string;
|
|
866
|
+
runArtifactHash: string;
|
|
867
|
+
} | {
|
|
868
|
+
status: "failed";
|
|
869
|
+
laneId: string;
|
|
870
|
+
typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error";
|
|
871
|
+
configuredLane: string;
|
|
872
|
+
resolvedBackend?: string | undefined;
|
|
873
|
+
})[];
|
|
874
|
+
findings: {
|
|
875
|
+
message: string;
|
|
876
|
+
severity: "CRITICAL" | "WARN" | "INFO";
|
|
877
|
+
confidence?: number | undefined;
|
|
878
|
+
file?: string | undefined;
|
|
879
|
+
line?: number | undefined;
|
|
880
|
+
}[];
|
|
881
|
+
attemptedLaneCount: number;
|
|
882
|
+
completedLaneCount: number;
|
|
883
|
+
postChecks: {
|
|
884
|
+
message: string;
|
|
885
|
+
tier: "decidable" | "sensor";
|
|
886
|
+
ruleName: string;
|
|
887
|
+
verdict: "pass" | "fail" | "abstain";
|
|
888
|
+
}[];
|
|
889
|
+
round: {
|
|
890
|
+
index: number;
|
|
891
|
+
lineageKey: string;
|
|
892
|
+
priorVerdictHash?: string | undefined;
|
|
893
|
+
};
|
|
894
|
+
reviewedState: "matched" | "drifted";
|
|
895
|
+
settled: boolean;
|
|
896
|
+
diversity?: {
|
|
897
|
+
class: "cross-vendor" | "same-vendor-isolated";
|
|
898
|
+
providers: string[];
|
|
899
|
+
distinctProviders: number;
|
|
900
|
+
unrecognizedProviders: string[];
|
|
901
|
+
diversityConfidence: "verified" | "coarse";
|
|
902
|
+
} | undefined;
|
|
903
|
+
panelArtifactHash?: string | undefined;
|
|
904
|
+
}>;
|
|
905
|
+
export type VerdictArtifact = z.infer<typeof VerdictArtifactSchema>;
|
|
906
|
+
/**
|
|
907
|
+
* The round-chain lineage key is composite over the RESOLVED scope selector (agy
|
|
908
|
+
* fold 3; codex rev-2 fold 2) — NOT the source enum alone. The selector fields
|
|
909
|
+
* describe the *lineage*, never the changing diff bytes, so legitimate fix rounds
|
|
910
|
+
* still chain. Per-source contribution (the CLI resolver populates only the fields
|
|
911
|
+
* a source makes meaningful):
|
|
912
|
+
* - `repoIdentity` — the stable worktree identity (absolute resolved
|
|
913
|
+
* `git rev-parse --show-toplevel`), ALWAYS present.
|
|
914
|
+
* - `branch` — the current branch (or the `DETACHED:<sha>` marker), ALWAYS present.
|
|
915
|
+
* - `source` — the `getDiffForReview` source, ALWAYS present.
|
|
916
|
+
* - `explicit-range` — normalized `base` + `head` (the two endpoints).
|
|
917
|
+
* - `branch-vs-base` — resolved `base` + `mergeBase`.
|
|
918
|
+
* - `staged` / `uncommitted` — NO range fields (worktree identity + branch +
|
|
919
|
+
* source carry the lineage).
|
|
920
|
+
*/
|
|
921
|
+
/** Fields every lineage-key variant carries, regardless of source. */
|
|
922
|
+
interface LineageKeyCommon {
|
|
923
|
+
/** Stable worktree identity — the absolute resolved `git rev-parse --show-toplevel`. */
|
|
924
|
+
repoIdentity: string;
|
|
925
|
+
/** The current branch, or the `DETACHED:<sha>` marker. */
|
|
926
|
+
branch: string;
|
|
927
|
+
/**
|
|
928
|
+
* The raw CLI selector FORM (finding 10) — accepted on EVERY variant now so the
|
|
929
|
+
* key shape is stable before the CLI populates it. It distinguishes selectors
|
|
930
|
+
* that resolve to the same refs but describe different lineages, e.g. `--diff main`
|
|
931
|
+
* (working-tree mode) vs `main..HEAD` (range mode). Absent today (⇒ hashed as
|
|
932
|
+
* `null`); when the CLI agent supplies it (finding 10) the key already accounts
|
|
933
|
+
* for it — no further domain-tag bump needed.
|
|
934
|
+
*/
|
|
935
|
+
selectorForm?: string;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* `computeLineageKey` input, SOURCE-DISCRIMINATED (totem-codex finding 9d): each
|
|
939
|
+
* variant carries ONLY the range fields its source makes meaningful, so an
|
|
940
|
+
* impossible record (e.g. a `staged` scope with a `head` endpoint) is
|
|
941
|
+
* unrepresentable.
|
|
942
|
+
* - `explicit-range` — `base` + `head` (the two endpoints).
|
|
943
|
+
* - `branch-vs-base` — `base` (resolved base ref) + `mergeBase` (resolved sha).
|
|
944
|
+
* - `staged` / `uncommitted` — NO range fields; repoIdentity + branch + source
|
|
945
|
+
* (+ optional selectorForm) carry the lineage (the index/worktree has no endpoint).
|
|
946
|
+
*/
|
|
947
|
+
export type LineageKeyInput = (LineageKeyCommon & {
|
|
948
|
+
source: 'explicit-range';
|
|
949
|
+
base: string;
|
|
950
|
+
head: string;
|
|
951
|
+
}) | (LineageKeyCommon & {
|
|
952
|
+
source: 'branch-vs-base';
|
|
953
|
+
base: string;
|
|
954
|
+
mergeBase: string;
|
|
955
|
+
}) | (LineageKeyCommon & {
|
|
956
|
+
source: 'staged';
|
|
957
|
+
}) | (LineageKeyCommon & {
|
|
958
|
+
source: 'uncommitted';
|
|
959
|
+
});
|
|
960
|
+
/**
|
|
961
|
+
* The composite round-chain lineage key: a domain-tagged sha256 over the resolved
|
|
962
|
+
* scope selector (agy fold 3; codex rev-2 fold 2). Two branches sharing `base=main`
|
|
963
|
+
* can NEVER cross-link because `branch` participates, and two DIFFERENT explicit
|
|
964
|
+
* ranges on one branch + merge-base cannot cross-link because `base`/`head`
|
|
965
|
+
* participate.
|
|
966
|
+
*
|
|
967
|
+
* The domain tag is `verdict-lineage/3` — bumped from `/2` because the selector
|
|
968
|
+
* shape changed (source-discriminated input + `selectorForm`), so keys under the
|
|
969
|
+
* two tags are deliberately incompatible.
|
|
970
|
+
*
|
|
971
|
+
* Only the fields VALID for the discriminated `source` participate (the switch
|
|
972
|
+
* reads them per-variant), pinning the others to `null`. The selector is hashed as
|
|
973
|
+
* a canonicalized (recursively key-sorted) JSON object with the fixed domain tag,
|
|
974
|
+
* so there is NO delimiter-injection ambiguity — `branch='a', mergeBase='b|c'` and
|
|
975
|
+
* `branch='a|b', mergeBase='c'` serialize to distinct JSON and therefore distinct
|
|
976
|
+
* keys, which a naive `join('|')` would collide. A `null` hole (a source that omits
|
|
977
|
+
* a field) can never collide with an empty string a source supplies for it.
|
|
978
|
+
*/
|
|
979
|
+
export declare function computeLineageKey(input: LineageKeyInput): string;
|
|
980
|
+
/** Absolute verdicts directory for a given absolute totem dir. */
|
|
981
|
+
export declare function verdictsDir(totemDirAbs: string): string;
|
|
982
|
+
/**
|
|
983
|
+
* Content address of a verdict: deterministic hash over everything EXCEPT
|
|
984
|
+
* `createdAt` (observability, not identity). Identical rounds dedup to one
|
|
985
|
+
* artifact regardless of when they ran.
|
|
986
|
+
*/
|
|
987
|
+
export declare function computeVerdictArtifactContentHash(artifact: VerdictArtifact): string;
|
|
988
|
+
/**
|
|
989
|
+
* A loaded verdict paired with its VERIFIED content address (the filename stem = the
|
|
990
|
+
* raw-payload hash). The address SURVIVES the tolerant Zod parse (rev-6 item 1): a
|
|
991
|
+
* forward-minor artifact whose writer addressed a raw payload with an additive field
|
|
992
|
+
* THIS reader strips keeps its on-disk address here, so no downstream consumer
|
|
993
|
+
* (covariate line, lineage tie-break, round linkage) recomputes a DIVERGING identity
|
|
994
|
+
* over the normalized shape — the covariate line would otherwise advertise a hash with
|
|
995
|
+
* no file, and round linkage would point at a nonexistent prior. Every load/scan entry
|
|
996
|
+
* point returns this pair so the stored address is the single identity every consumer uses.
|
|
997
|
+
*/
|
|
998
|
+
export interface VerdictWithAddress {
|
|
999
|
+
artifact: VerdictArtifact;
|
|
1000
|
+
/** The verified content address = the filename stem (raw-payload hash, `createdAt` excluded). */
|
|
1001
|
+
contentHash: string;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Render the machine-readable covariate line — the CORE-OWNED signal every caller
|
|
1005
|
+
* (CLI print, headless, `/review-reply`) emits identically so the skill stays pure
|
|
1006
|
+
* transport (strategy-codex G4; resolves finding 14). Format, EXACTLY:
|
|
1007
|
+
*
|
|
1008
|
+
* `local-lane: <hash8> round=<n> settled=<true|false> lanes=<completed>/<attempted>`
|
|
1009
|
+
*
|
|
1010
|
+
* where `<hash8>` is the first 8 hex of the artifact's STORED content address. The
|
|
1011
|
+
* signature takes a {@link VerdictWithAddress} (rev-6 item 1) so the rendered `<hash8>`
|
|
1012
|
+
* is the VERIFIED on-disk address that survived the tolerant parse — NOT a recompute
|
|
1013
|
+
* over the Zod-stripped shape, which would diverge for a forward-minor artifact and
|
|
1014
|
+
* advertise a hash with no backing file. A caller with a freshly-assembled verdict
|
|
1015
|
+
* pairs it with the address `saveVerdictArtifact` returned.
|
|
1016
|
+
*
|
|
1017
|
+
* @remarks Covariate line format v1 — do NOT alter without a spec amendment (the
|
|
1018
|
+
* pilot ledger joins on this grep-able line; the format is contract, versioned with
|
|
1019
|
+
* the `review-loop` skill).
|
|
1020
|
+
*/
|
|
1021
|
+
export declare function renderCovariateLine(verdict: VerdictWithAddress): string;
|
|
1022
|
+
export interface SaveVerdictArtifactResult {
|
|
1023
|
+
/** The content address (= filename stem). */
|
|
1024
|
+
hash: string;
|
|
1025
|
+
/** Absolute path of the stored artifact. */
|
|
1026
|
+
path: string;
|
|
1027
|
+
/** True when an identical logical verdict was already recorded (no write happened). */
|
|
1028
|
+
existed: boolean;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Persist a verdict at its content address, write-if-absent (`wx` create-
|
|
1032
|
+
* exclusive). Validates on the way OUT so a writer bug never poisons the ledger
|
|
1033
|
+
* with a record the reader would reject.
|
|
1034
|
+
*
|
|
1035
|
+
* EEXIST is LOGICAL-IDENTITY DEDUP (`createdAt` excluded from the address; codex
|
|
1036
|
+
* fold 8 / agy fold 4): the existing record is loaded and its content hash
|
|
1037
|
+
* recomputed. If it matches this address (equal MODULO `createdAt`), the stored
|
|
1038
|
+
* record IS this save's outcome — first-write-wins, dedup return. If the record
|
|
1039
|
+
* at this address recomputes to a DIFFERENT hash, its bytes disagree with the
|
|
1040
|
+
* content address — a hard identity violation (a corrupted/tampered record or a
|
|
1041
|
+
* sha256 collision), never silently accepted.
|
|
1042
|
+
*/
|
|
1043
|
+
export declare function saveVerdictArtifact(totemDirAbs: string, artifact: VerdictArtifact): SaveVerdictArtifactResult;
|
|
1044
|
+
/**
|
|
1045
|
+
* Load + validate a verdict by content address, returning the artifact WITH its
|
|
1046
|
+
* verified content address (rev-6 item 1 — {@link VerdictWithAddress}). Throws
|
|
1047
|
+
* {@link TotemParseError} on a missing file, corrupt JSON, schema violation, or an
|
|
1048
|
+
* unknown major with no migration entry, and {@link TotemError} (`DATABASE_MISMATCH`)
|
|
1049
|
+
* when the stored bytes do not hash back to their filename address (finding 4) — loud,
|
|
1050
|
+
* never a silent partial (Tenet 4).
|
|
1051
|
+
*
|
|
1052
|
+
* Order (rev-6 item 5): the RAW stored address is verified FIRST — the content-address
|
|
1053
|
+
* guarantee is over the on-disk bytes (minus `createdAt`), MAJOR-agnostic and
|
|
1054
|
+
* migration-independent, so a mis-addressed / tampered file fails before it is
|
|
1055
|
+
* transformed. Only THEN is any migration applied and its output validated against the
|
|
1056
|
+
* current schema (a separate concern — migration correctness, not address integrity).
|
|
1057
|
+
* The returned `contentHash` is always this verified filename address.
|
|
1058
|
+
*/
|
|
1059
|
+
export declare function loadVerdictArtifact(totemDirAbs: string, hash: string): VerdictWithAddress;
|
|
1060
|
+
/**
|
|
1061
|
+
* Load every stored verdict under `artifacts/verdicts/`, verifying each through
|
|
1062
|
+
* the SAME content-address check as {@link loadVerdictArtifact}. A missing
|
|
1063
|
+
* directory yields `[]` (nothing written yet). Non-verdict file names are skipped
|
|
1064
|
+
* silently; a corrupt / mis-addressed verdict is skipped LOUDLY via `onWarn`.
|
|
1065
|
+
* `onWarn` is REQUIRED — core stays console-free (no presentation-layer default),
|
|
1066
|
+
* and the caller must decide where scan warnings land rather than inheriting a
|
|
1067
|
+
* silent noop (Tenet 4); see {@link loadVerifiedVerdictForScan}. (PR #2337 CR.)
|
|
1068
|
+
*/
|
|
1069
|
+
export declare function listVerdictArtifacts(totemDirAbs: string, onWarn: (message: string) => void): VerdictWithAddress[];
|
|
1070
|
+
/**
|
|
1071
|
+
* The latest verdict sharing `lineageKey` — highest `round.index`, ties broken by
|
|
1072
|
+
* the lexical STORED content address (rev-5 item 8 / rev-6 item 1), NOT `createdAt`.
|
|
1073
|
+
* Returns the winning {@link VerdictWithAddress} (artifact + verified address) or
|
|
1074
|
+
* `undefined` when no verdict carries the key. Used for implicit round linkage (the
|
|
1075
|
+
* next round's `priorVerdictHash` = the returned `contentHash`, so the link always
|
|
1076
|
+
* points at the on-disk file even for a forward-minor artifact). Goes through the same
|
|
1077
|
+
* verified scan load as {@link listVerdictArtifacts}: a corrupt / mis-addressed
|
|
1078
|
+
* artifact is warned + skipped (never silently winning or losing the lineage). `onWarn`
|
|
1079
|
+
* is REQUIRED — core is console-free and the caller owns where warnings land (Tenet 4).
|
|
1080
|
+
*
|
|
1081
|
+
* The tie-break is IDENTITY-BOUND and deterministic: two same-round verdicts break on
|
|
1082
|
+
* their STORED content address (the on-disk identity, `createdAt` excluded), so
|
|
1083
|
+
* selection never depends on wall-clock emission time (observability-only) — the same
|
|
1084
|
+
* corpus always resolves the same latest verdict regardless of when each round ran.
|
|
1085
|
+
*/
|
|
1086
|
+
export declare function findLatestVerdictForLineage(totemDirAbs: string, lineageKey: string, onWarn: (message: string) => void): VerdictWithAddress | undefined;
|
|
1087
|
+
export {};
|
|
1088
|
+
//# sourceMappingURL=verdict.d.ts.map
|