/** * Verdict-artifact contract — the single convergence point both review lanes * emit (mmnto-ai/totem#2106, Proposal 302 / 304 R2 local review runner). * * A verdict artifact is the immutable, content-addressed record of ONE review * round over ONE masked diff: the fan of lanes that attempted it (each a * terminal {@link RunArtifact} reference, one hop from provenance), the * deterministic #2103 post-checks, the normalized findings, the optional #2104 * panel it assembled, and the derived round/lineage bookkeeping. Everything * downstream (the CLI round loop, the pilot ledger's covariate PR-line, the * Phase-2 disposition ledger) consumes this shape, so it stays minimal but * versioned. * * ── LANE-BLINDNESS INVARIANT (Proposal 302, DELIBERATE EXCLUSION) ──────────── * There is NO warm/cold runner-lane discriminator field ANYWHERE in this schema * — not at the top level, not on a lane. This exclusion is deliberate: a * contract consumer reads the verdict and CANNOT discriminate WHICH runner lane * (a warm resident agent vs a cold SDK invocation) produced it. The wording * matters (strategy 1a): "consumers cannot discriminate lanes FROM the * artifact", NOT "lane identity is unknowable" — `lanes[].runArtifactHash` * reaches provenance one hop away and `resolvedBackend` is panel-DIVERSITY data, * neither of which is a warm/cold runner discriminator. The absence is enforced * by a structural test (snapshots the key set) IN ADDITION to this note. * * The KEY-set structural test is not enough on its own: a runner class could be * smuggled through a laneId VALUE. So `laneId` is additionally constrained to a * backend-derived vocabulary — `lane-:` * (see {@link LaneIdSchema}) — with a refinement rejecting warm/cold/headless/ * sdk-runner substrings (strategy-codex G1). Net invariant: a consumer can * identify WHICH backend participated (diversity), NEVER whether the producer was * warm / cold / headless. * * Schema-evolution policy mirrors {@link RunArtifactSchema} / the panel artifact * (F1): the reader is version-tolerant WITHIN the major — `schemaVersion` * validates as `1.x`, every post-1.0.0 field is additive-optional, and a MAJOR * bump requires a migration entry in `loadVerdictArtifact` before the writer * ships. Hard-reject only unknown majors. Zod is the persisted-JSON boundary * (read back from disk), per the repo's Zod-at-boundaries-only rule. */ import { z } from 'zod'; import { type PersistedPostCheckFinding } from './panel.js'; import type { GroundingBundle } from './schema.js'; /** * The verdict schemaVersion WRITTEN by this code. Readers accept any 1.x (F1). * 1.1.0 (mmnto-ai/totem#2363): additive-optional `lessonsConsulted` — the * round's lesson-recall record. * 1.2.0 (mmnto-ai/totem#2459): additive widening of {@link VERDICT_LANE_FAILURE_REASONS} * with slice-B invoke-failure kinds (auth/model/spawn/exit/timeout) + the * additive-optional failed-lane `failureArtifactHash`. Purely additive within the * major (new enum members + an optional field), so the minor is the observable * marker and the migration registry stays empty — the tolerant reader parses every * prior 1.x artifact unchanged (existing `typedReason` values and absent * `failureArtifactHash` remain valid). */ export declare const VERDICT_ARTIFACT_SCHEMA_VERSION = "1.2.0"; /** The major this reader understands; other majors need a migration entry. */ export declare const VERDICT_ARTIFACT_KNOWN_MAJOR = 1; /** * The four `getDiffForReview` sources. Canonical order matches the design doc. */ export declare const VERDICT_DIFF_SOURCES: readonly ["explicit-range", "staged", "uncommitted", "branch-vs-base"]; export type VerdictDiffSource = (typeof VERDICT_DIFF_SOURCES)[number]; /** * The reviewed diff's scope, DISCRIMINATED by `source`. `diffHash` is ALWAYS * required (sha256 over the MASKED review-payload bytes the lanes actually * reviewed — hash symmetry with the artifact chain, never binds secret-bearing * bytes; agy fold 5). The git ref fields are required only where the source * makes them meaningful: * - `explicit-range` — `base` AND `head` (the two endpoints). * - `branch-vs-base` — `base` only (head is the working ref, implicit). * - `staged` / `uncommitted` — NO refs (the index / worktree has none). */ export declare const VerdictDiffScopeSchema: z.ZodDiscriminatedUnion<"source", [z.ZodObject<{ source: z.ZodLiteral<"explicit-range">; diffHash: z.ZodString; base: z.ZodString; head: z.ZodString; }, "strip", z.ZodTypeAny, { source: "explicit-range"; head: string; diffHash: string; base: string; }, { source: "explicit-range"; head: string; diffHash: string; base: string; }>, z.ZodObject<{ source: z.ZodLiteral<"branch-vs-base">; diffHash: z.ZodString; base: z.ZodString; }, "strip", z.ZodTypeAny, { source: "branch-vs-base"; diffHash: string; base: string; }, { source: "branch-vs-base"; diffHash: string; base: string; }>, z.ZodObject<{ source: z.ZodLiteral<"staged">; diffHash: z.ZodString; }, "strip", z.ZodTypeAny, { source: "staged"; diffHash: string; }, { source: "staged"; diffHash: string; }>, z.ZodObject<{ source: z.ZodLiteral<"uncommitted">; diffHash: z.ZodString; }, "strip", z.ZodTypeAny, { source: "uncommitted"; diffHash: string; }, { source: "uncommitted"; diffHash: string; }>]>; export type VerdictDiffScope = z.infer; /** * Typed terminal-failure reasons for a `failed` lane. A failed lane is never * handed to `assemblePanelArtifact` and never stamps the cache. NOTE (Prop 302 * lane-blindness): these classify the FAILURE, never the runner lane — none of * them names warm/cold. * * ── EXECUTION-PHASE INVOKE KINDS (mmnto-ai/totem#2459, slice-B A-side follow-up) ── * The first block is the original coarse set. The `invoke-*` block widens it so an * EXECUTION-phase lane failure records the exact slice-B category (from * `OrchestratorInvokeError.kind`) instead of collapsing auth / model / spawn / exit / * timeout into the single `invoke-error`. The mapping is 1:1 with `InvokeFailureKind`: * `auth→invoke-auth`, `quota→quota-exhausted`, `model→invoke-model`, * `process-spawn→invoke-process-spawn`, `process-exit→invoke-process-exit`, * `timeout→invoke-timeout`, `unknown→invoke-error`. `quota-exhausted` and * `invoke-error` predate this widening and are reused, so the change is purely * additive (F1): every prior 1.x artifact's `typedReason` still validates. * * ADMISSION vs EXECUTION (the #2471 gate-semantics boundary): a pre-invoke ADMISSION * denial is NOT a lane invoke-failure — it never reached execution, so it maps to * `config-error`, never to one of these `invoke-*` kinds. Only execution-phase * failures (a thrown `OrchestratorInvokeError`) reach the widened kinds. */ export declare const VERDICT_LANE_FAILURE_REASONS: readonly ["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error", "invoke-auth", "invoke-model", "invoke-process-spawn", "invoke-process-exit", "invoke-timeout"]; export type VerdictLaneFailureReason = (typeof VERDICT_LANE_FAILURE_REASONS)[number]; /** A `completed` lane's own severity tally (from its extracted structured verdict). */ export declare const VerdictLaneSummarySchema: z.ZodObject<{ critical: z.ZodNumber; warn: z.ZodNumber; info: z.ZodNumber; }, "strip", z.ZodTypeAny, { critical: number; warn: number; info: number; }, { critical: number; warn: number; info: number; }>; export type VerdictLaneSummary = z.infer; /** * The EXACT laneId shape — `lane-:`: * - `lane-` literal prefix, * - `` — the lane's zero-based position in the fan (`\d+`), * - `:` separator, * - `` — the resolved backend (`provider:model`, * which itself carries a colon) for a lane that reached a backend, or the * CONFIGURED lane string for a lane that failed before one resolved. Non-empty, * opaque backend/lane text (`.+` — newlines excluded). * * This is backend-DERIVED vocabulary: a consumer can read the id and identify * WHICH backend participated (panel-diversity data), and NOTHING about whether the * producer was warm / cold / headless. */ export declare const LANE_ID_SHAPE_RE: RegExp; /** * laneId: shape-validated here; the VALUE channel of lane-blindness (Prop 302 * G1) is closed STRUCTURALLY by the schema's superRefine — every lane's suffix * must equal its binding field (`resolvedBackend` for completed/abstained, * `configuredLane` for failed), so a laneId cannot carry free text at all and a * runner class (`warm`/`cold`/`headless`) has no channel to ride. An earlier * substring blacklist here was removed: with structural binding as the primary * guard it added only false-positive risk against legitimate future model names * (e.g. a model literally named `*-cold-*`; PR #2337 greptile P2). */ export declare const LaneIdSchema: z.ZodString; /** * One lane's terminal outcome, DISCRIMINATED by `status`. The union makes * impossible records unrepresentable (codex fold 2): a `completed` lane STRUCTURALLY * requires its `runArtifactHash` (a response-cache hit emits no run artifact and so * can never be `completed`); a `failed` lane carries a typed reason and never a * `runArtifactHash`. `resolvedBackend` records what actually ran (post quota * fallback) and is panel-diversity data — NOT a runner discriminator. */ export declare const VerdictLaneSchema: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{ status: z.ZodLiteral<"completed">; laneId: z.ZodString; resolvedBackend: z.ZodString; runArtifactHash: z.ZodString; verdictSummary: z.ZodObject<{ critical: z.ZodNumber; warn: z.ZodNumber; info: z.ZodNumber; }, "strip", z.ZodTypeAny, { critical: number; warn: number; info: number; }, { critical: number; warn: number; info: number; }>; }, "strip", z.ZodTypeAny, { status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; }, { status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; }>, z.ZodObject<{ status: z.ZodLiteral<"abstained">; laneId: z.ZodString; resolvedBackend: z.ZodString; runArtifactHash: z.ZodString; /** Why no usable structured verdict was extractable (invoke happened, output unparseable). */ reason: z.ZodString; }, "strip", z.ZodTypeAny, { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; }, { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; }>, z.ZodObject<{ status: z.ZodLiteral<"failed">; laneId: z.ZodString; typedReason: z.ZodEnum<["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error", "invoke-auth", "invoke-model", "invoke-process-spawn", "invoke-process-exit", "invoke-timeout"]>; /** * REQUIRED (rev-6 item 3): the configured `provider:model` string the lane was * created from. A failed lane can have NO `resolvedBackend` (it failed before a * backend resolved — e.g. `config-error` / `missing-artifact-emission`), so the * laneId suffix has nothing to bind to unless the configured lane is persisted. * The `superRefine` binds `laneId` suffix === `configuredLane` (closing the * `lane-0:gemini:completely-invented` tautology): the suffix is no longer free — * it must equal this declared field. */ configuredLane: z.ZodString; /** * OPTIONAL supplementary provenance: the backend that ACTUALLY ran before the * lane failed (present only when a backend resolved — e.g. a quota fallback that * then failed). NOT the id binding: after a quota fallback it can legitimately * DIFFER from `configuredLane`, so the laneId suffix binds to `configuredLane` * (stable at lane creation), never to this field. */ resolvedBackend: z.ZodOptional; /** * OPTIONAL (mmnto-ai/totem#2459, additive 1.2.0): the content address of slice-B's * `InvocationFailureArtifact` for this lane's terminal EXECUTION-phase invoke * failure. It reaches B's bounded evidence — classified `kind`, bounded * stdout/stderr, exit code / signal, timeout state — ONE HOP away, mirroring how a * `completed` lane reaches its run artifact via `runArtifactHash`. Present only * when the orchestrator persisted the failure evidence (an `OrchestratorInvokeError` * carrying a `failureArtifactHash`); ABSENT for admission-phase / pre-invoke * failures that never produced one, and honest-absent on pre-1.2 artifacts. When * present it MUST resolve via `loadInvocationFailureArtifact` (the reference is a * real, loadable content address — never a dangling hash). */ failureArtifactHash: z.ZodOptional; }, "strip", z.ZodTypeAny, { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; }, { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; }>]>; export type VerdictLane = z.infer; /** Severity vocabulary — aligned VERBATIM with cli `ShieldFindingSeveritySchema` (defined here so core stays cli-independent). */ export declare const VerdictFindingSeveritySchema: z.ZodEnum<["CRITICAL", "WARN", "INFO"]>; export type VerdictFindingSeverity = z.infer; /** * A normalized finding from the shared review-output extractor. Field names * align with cli `ShieldFinding` (`severity` / `confidence` / `message` / * `file` / `line`); `confidence` is optional here because not every extracted * lane output carries one, but when present it is a 0..1 probability (same * bound as ShieldFinding). The diagnostic `message` is NEVER dropped or * renamed. */ export declare const VerdictFindingSchema: z.ZodObject<{ severity: z.ZodEnum<["CRITICAL", "WARN", "INFO"]>; confidence: z.ZodOptional; file: z.ZodOptional; line: z.ZodOptional; message: z.ZodString; }, "strip", z.ZodTypeAny, { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }, { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }>; export type VerdictFinding = z.infer; /** * One lesson delivered into the round's shared lane prompt — identity only * (`contentHash` over the delivered snippet + repo-relative `filePath`, * mirroring {@link GroundingItemSchema} identity semantics), never content * bytes. `sourceRepo` names a linked index for cross-repo hits; ABSENT = the * run's own repo. */ export declare const LessonConsultedItemSchema: z.ZodObject<{ contentHash: z.ZodString; filePath: z.ZodString; sourceRepo: z.ZodOptional; }, "strip", z.ZodTypeAny, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }>; export type LessonConsultedItem = z.infer; /** * The round's lesson-recall record (mmnto-ai/totem#2363, strategy#474 * grounding lever): which lessons the retrieval delivered into the shared * per-lane prompt, and whether recall hit at all. One field per VERDICT, not * per lane — identical-kit discipline means every lane received the same * retrieval, so a per-lane copy would be a mirrored count. * * Three observable states, honest-absent by construction: * - field ABSENT — the producer performed no lesson retrieval (pre-1.1 * artifacts, or a path without index retrieval); never fabricated. * - `status: 'empty'` — retrieval RAN and returned zero lessons: the * visibly-ungrounded state the strategy#474 abstain-on-empty rule needs * to be checkable. * - `status: 'hit'` — ≥1 lesson delivered; `items` carries identities. * * `status` ⟺ `items` consistency is enforced in the artifact `superRefine` * (never mirrored on trust). Per-lane delivery provenance stays one hop away * in each lane's run-artifact grounding bundle; this field is the round-level * contract line so recall can never silently drop out of the redesign. */ export declare const LessonsConsultedSchema: z.ZodObject<{ status: z.ZodEnum<["hit", "empty"]>; items: z.ZodArray; }, "strip", z.ZodTypeAny, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }>, "many">; }, "strip", z.ZodTypeAny, { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; }, { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; }>; export type LessonsConsulted = z.infer; /** * Derive the round-level recall record from the grounding bundle the runner * delivered to its lanes (single home for the mapping — every future runner * derives, never hand-builds). `lesson`-partition items only; identity fields * pass through verbatim. */ export declare function deriveLessonsConsulted(bundle: GroundingBundle): LessonsConsulted; /** * Round bookkeeping (all DERIVED — see the CLI lifecycle). `lineageKey` is the * composite hash over the RESOLVED scope selector (see {@link computeLineageKey} * — worktree identity + branch + source + the meaningful range selectors), NOT * the diff bytes, so legitimate fix rounds still chain; `priorVerdictHash` links * the implicit prior round (latest verdict sharing the lineage key) or an * explicit `--continues` override; absent at round 0. */ export declare const VerdictRoundSchema: z.ZodObject<{ index: z.ZodNumber; priorVerdictHash: z.ZodOptional; lineageKey: z.ZodString; }, "strip", z.ZodTypeAny, { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }, { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }>; export type VerdictRound = z.infer; /** * The subset of a verdict the pure predicates read. The persisted boundary AND * every CLI caller derive `settled` / cache-eligibility from THESE fields — the * stored `settled` boolean is re-derived and checked at parse, never trusted * (totem-codex finding 5). `findings` is the exemption-FILTERED union the CLI * lands on the artifact; the R2 severity map is pinned `INFO = cosmetic`, * `WARN | CRITICAL = actionable`. */ export interface VerdictPredicateInput { lanes: readonly VerdictLane[]; findings: readonly VerdictFinding[]; postChecks: readonly PersistedPostCheckFinding[]; reviewedState: 'matched' | 'drifted'; } /** * `settled` — the current-round dryness predicate, PURE over artifact content (no * cross-round input, no model output): * * settled = (every attempted lane completed) * AND (zero actionable — WARN|CRITICAL — findings) * AND (no decidable-tier post-check row with verdict 'fail') * AND (reviewedState === 'matched') * * A failed/abstained lane ⇒ fan incomplete ⇒ never settled (a persistent CRITICAL * can never settle by lane dropout — agy fold 1, satisfied structurally); drift ⇒ * the verdict is bound to the pre-fan diff and does NOT cover the current tree ⇒ * not settled (codex rev-2 fold 1). This export is the SINGLE SOURCE OF TRUTH: the * CLI derives its loop-termination signal from it and {@link VerdictArtifactSchema} * re-derives + checks the stored `settled` (finding 5) — a crafted lane output * cannot flip it (pure function; the exemption filter is the only removal * mechanism, upstream of this boundary). */ export declare function deriveSettled(v: VerdictPredicateInput): boolean; /** * Cache eligibility — the DISTINCT, weaker predicate (codex fold 4). Identical to * {@link deriveSettled} except it tolerates WARNs (matching today's PASS * semantics — the drip class the runner absorbs is WARN-shaped): * * cacheEligible = (every attempted lane completed) * AND (zero CRITICAL findings) * AND (no decidable-tier post-check row with verdict 'fail') * AND (reviewedState === 'matched') * * A degraded fan (any failed/abstained lane) fails the first conjunct and is * therefore never cache-eligible; drift blocks the stamp. `settled` (no WARNs) is * deliberately STRICTER than cache-eligible (no CRITICALs). */ export declare function deriveCacheEligible(v: VerdictPredicateInput): boolean; /** * The exit-contract's non-pass gate (mmnto-ai/totem#2452): a fan produced ZERO * `completed` verdict lanes. `completed` is the ONLY lane status that carries a * usable structured verdict — an `abstained` lane invoked but its output was not * extractable (sensor-down), and a `failed` lane never produced one — so neither * is a verdict. A zero-completed fan is therefore NEVER a review pass (Tenets * 12/13: a provider-unsettled round is honest-absent, never an external pass); * the CLI writes the honest verdict, then hard-errors on this predicate BEFORE * any cache stamp so `--override` can never mint a push authorization from it. * * Expressed over `lanes` as the SINGLE SOURCE OF TRUTH the artifact's * `completedLaneCount` is validated against (`VerdictArtifactSchema` superRefine * binds `completedLaneCount === #completed`), so `hasNoCompletedLane(v.lanes)` * and `v.completedLaneCount === 0` are equal by construction. An empty fan * (guarded upstream as a distinct pre-attempt error) trivially has none. */ export declare function hasNoCompletedLane(lanes: readonly VerdictLane[]): boolean; /** * The verdict artifact. See the module docstring for the LANE-BLINDNESS * invariant (Prop 302): NO warm/cold runner-lane discriminator field exists, * deliberately. * * `superRefine` enforces the cross-field invariants that a hand-edited or * builder-buggy record could otherwise violate silently — mirrored counts are * NEVER accepted on trust (codex): * - `attemptedLaneCount === lanes.length`; `completedLaneCount === #completed`. * - lanes nonempty, laneIds unique (finding 9c). * - panel ⟺ diversity AND panel ⟺ ≥2 completed lanes, BOTH directions * (finding 9a): a panel is assembled from — and only from — ≥2 usable lanes, * and always emits its diversity summary. * - round-chain shape (finding 9b): `round.index === 0` ⟺ `priorVerdictHash` * absent (round 0 starts a chain; round N>0 links its prior). * - stored `settled === deriveSettled(value)` (finding 5): the persisted * boundary re-derives the dryness predicate, never trusting a fabricated flag. */ export declare const VerdictArtifactSchema: z.ZodEffects; /** The reviewed diff's scope + masked-payload hash (source-discriminated). */ diffScope: z.ZodDiscriminatedUnion<"source", [z.ZodObject<{ source: z.ZodLiteral<"explicit-range">; diffHash: z.ZodString; base: z.ZodString; head: z.ZodString; }, "strip", z.ZodTypeAny, { source: "explicit-range"; head: string; diffHash: string; base: string; }, { source: "explicit-range"; head: string; diffHash: string; base: string; }>, z.ZodObject<{ source: z.ZodLiteral<"branch-vs-base">; diffHash: z.ZodString; base: z.ZodString; }, "strip", z.ZodTypeAny, { source: "branch-vs-base"; diffHash: string; base: string; }, { source: "branch-vs-base"; diffHash: string; base: string; }>, z.ZodObject<{ source: z.ZodLiteral<"staged">; diffHash: z.ZodString; }, "strip", z.ZodTypeAny, { source: "staged"; diffHash: string; }, { source: "staged"; diffHash: string; }>, z.ZodObject<{ source: z.ZodLiteral<"uncommitted">; diffHash: z.ZodString; }, "strip", z.ZodTypeAny, { source: "uncommitted"; diffHash: string; }, { source: "uncommitted"; diffHash: string; }>]>; /** Every attempted lane's terminal outcome (status-discriminated union). */ lanes: z.ZodArray; laneId: z.ZodString; resolvedBackend: z.ZodString; runArtifactHash: z.ZodString; verdictSummary: z.ZodObject<{ critical: z.ZodNumber; warn: z.ZodNumber; info: z.ZodNumber; }, "strip", z.ZodTypeAny, { critical: number; warn: number; info: number; }, { critical: number; warn: number; info: number; }>; }, "strip", z.ZodTypeAny, { status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; }, { status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; }>, z.ZodObject<{ status: z.ZodLiteral<"abstained">; laneId: z.ZodString; resolvedBackend: z.ZodString; runArtifactHash: z.ZodString; /** Why no usable structured verdict was extractable (invoke happened, output unparseable). */ reason: z.ZodString; }, "strip", z.ZodTypeAny, { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; }, { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; }>, z.ZodObject<{ status: z.ZodLiteral<"failed">; laneId: z.ZodString; typedReason: z.ZodEnum<["invoke-error", "quota-exhausted", "missing-artifact-emission", "config-error", "invoke-auth", "invoke-model", "invoke-process-spawn", "invoke-process-exit", "invoke-timeout"]>; /** * REQUIRED (rev-6 item 3): the configured `provider:model` string the lane was * created from. A failed lane can have NO `resolvedBackend` (it failed before a * backend resolved — e.g. `config-error` / `missing-artifact-emission`), so the * laneId suffix has nothing to bind to unless the configured lane is persisted. * The `superRefine` binds `laneId` suffix === `configuredLane` (closing the * `lane-0:gemini:completely-invented` tautology): the suffix is no longer free — * it must equal this declared field. */ configuredLane: z.ZodString; /** * OPTIONAL supplementary provenance: the backend that ACTUALLY ran before the * lane failed (present only when a backend resolved — e.g. a quota fallback that * then failed). NOT the id binding: after a quota fallback it can legitimately * DIFFER from `configuredLane`, so the laneId suffix binds to `configuredLane` * (stable at lane creation), never to this field. */ resolvedBackend: z.ZodOptional; /** * OPTIONAL (mmnto-ai/totem#2459, additive 1.2.0): the content address of slice-B's * `InvocationFailureArtifact` for this lane's terminal EXECUTION-phase invoke * failure. It reaches B's bounded evidence — classified `kind`, bounded * stdout/stderr, exit code / signal, timeout state — ONE HOP away, mirroring how a * `completed` lane reaches its run artifact via `runArtifactHash`. Present only * when the orchestrator persisted the failure evidence (an `OrchestratorInvokeError` * carrying a `failureArtifactHash`); ABSENT for admission-phase / pre-invoke * failures that never produced one, and honest-absent on pre-1.2 artifacts. When * present it MUST resolve via `loadInvocationFailureArtifact` (the reference is a * real, loadable content address — never a dangling hash). */ failureArtifactHash: z.ZodOptional; }, "strip", z.ZodTypeAny, { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; }, { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; }>]>, "many">; /** MUST equal `lanes.length` (validated below — never trusted). */ attemptedLaneCount: z.ZodNumber; /** MUST equal the count of `completed` lanes (validated below — never trusted). */ completedLaneCount: z.ZodNumber; /** Present IFF a #2104 panel was actually assembled (≥2 completed lanes; guarded below). */ panelArtifactHash: z.ZodOptional; /** Deterministic #2103 post-checks — the persisted vocabulary VERBATIM (`ruleName`/`tier`/`verdict`/`message`). */ postChecks: z.ZodArray; verdict: z.ZodEnum<["pass", "fail", "abstain"]>; message: z.ZodString; }, "strip", z.ZodTypeAny, { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }, { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }>, "many">; /** Normalized findings from the shared extractor (exemption-filtered by the CLI before it lands here). */ findings: z.ZodArray; confidence: z.ZodOptional; file: z.ZodOptional; line: z.ZodOptional; message: z.ZodString; }, "strip", z.ZodTypeAny, { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }, { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }>, "many">; /** A SINGLE top-level panel-diversity summary (classifyDiversity output) — present only with a panel; NEVER mirrored per finding. */ diversity: z.ZodOptional; distinctProviders: z.ZodNumber; class: z.ZodEnum<["cross-vendor", "same-vendor-isolated"]>; unrecognizedProviders: z.ZodArray; diversityConfidence: z.ZodEnum<["verified", "coarse"]>; }, "strip", z.ZodTypeAny, { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; }, { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; }>>; /** * The round's lesson-recall record (mmnto-ai/totem#2363) — see * {@link LessonsConsultedSchema}. Additive-optional 1.x (F1): pre-1.1 * artifacts predate it, and a producer that performed no retrieval omits * it (honest-absent) rather than fabricating an `empty`. */ lessonsConsulted: z.ZodOptional; items: z.ZodArray; }, "strip", z.ZodTypeAny, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }, { filePath: string; contentHash: string; sourceRepo?: string | undefined; }>, "many">; }, "strip", z.ZodTypeAny, { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; }, { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; }>>; round: z.ZodObject<{ index: z.ZodNumber; priorVerdictHash: z.ZodOptional; lineageKey: z.ZodString; }, "strip", z.ZodTypeAny, { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }, { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }>; /** * Post-fan tree compare against the PRE-fan content hash (codex rev-2 fold 1): * `'matched'` when the tracked-source tree is byte-identical before and after * the fan, `'drifted'` when it changed mid-fan. A DERIVED, non-sentinel field * (the two hash domains stay separate — this records the OUTCOME of the compare, * not the content hash itself). Drift forces `settled=false` and blocks the * cache stamp: the verdict is bound to the pre-fan diff, so a dry fan over a * mutated tree does NOT cover the current tree and must not settle the loop. */ reviewedState: z.ZodEnum<["matched", "drifted"]>; /** Current-round dryness predicate (see the CLI lifecycle) — pure over artifact content. */ settled: z.ZodBoolean; /** * ISO-8601 emission time — a VALIDATED datetime (rev-5 item 8): a malformed * `createdAt` is rejected at the persisted boundary rather than trusted. * EXCLUDED from the content address (identical rounds dedup to one artifact * regardless of when they ran) — observability only, and it is never a * lineage tie-breaker (see {@link findLatestVerdictForLineage}). See * {@link computeVerdictArtifactContentHash}. */ createdAt: z.ZodString; }, "strip", z.ZodTypeAny, { createdAt: string; diffScope: { source: "explicit-range"; head: string; diffHash: string; base: string; } | { source: "branch-vs-base"; diffHash: string; base: string; } | { source: "staged"; diffHash: string; } | { source: "uncommitted"; diffHash: string; }; schemaVersion: string; lanes: ({ status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; } | { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; } | { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; })[]; findings: { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }[]; attemptedLaneCount: number; completedLaneCount: number; postChecks: { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }[]; round: { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }; reviewedState: "matched" | "drifted"; settled: boolean; diversity?: { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; } | undefined; panelArtifactHash?: string | undefined; lessonsConsulted?: { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; } | undefined; }, { createdAt: string; diffScope: { source: "explicit-range"; head: string; diffHash: string; base: string; } | { source: "branch-vs-base"; diffHash: string; base: string; } | { source: "staged"; diffHash: string; } | { source: "uncommitted"; diffHash: string; }; schemaVersion: string; lanes: ({ status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; } | { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; } | { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; })[]; findings: { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }[]; attemptedLaneCount: number; completedLaneCount: number; postChecks: { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }[]; round: { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }; reviewedState: "matched" | "drifted"; settled: boolean; diversity?: { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; } | undefined; panelArtifactHash?: string | undefined; lessonsConsulted?: { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; } | undefined; }>, { createdAt: string; diffScope: { source: "explicit-range"; head: string; diffHash: string; base: string; } | { source: "branch-vs-base"; diffHash: string; base: string; } | { source: "staged"; diffHash: string; } | { source: "uncommitted"; diffHash: string; }; schemaVersion: string; lanes: ({ status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; } | { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; } | { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; })[]; findings: { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }[]; attemptedLaneCount: number; completedLaneCount: number; postChecks: { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }[]; round: { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }; reviewedState: "matched" | "drifted"; settled: boolean; diversity?: { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; } | undefined; panelArtifactHash?: string | undefined; lessonsConsulted?: { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; } | undefined; }, { createdAt: string; diffScope: { source: "explicit-range"; head: string; diffHash: string; base: string; } | { source: "branch-vs-base"; diffHash: string; base: string; } | { source: "staged"; diffHash: string; } | { source: "uncommitted"; diffHash: string; }; schemaVersion: string; lanes: ({ status: "completed"; laneId: string; resolvedBackend: string; runArtifactHash: string; verdictSummary: { critical: number; warn: number; info: number; }; } | { status: "abstained"; reason: string; laneId: string; resolvedBackend: string; runArtifactHash: string; } | { status: "failed"; laneId: string; typedReason: "invoke-error" | "quota-exhausted" | "missing-artifact-emission" | "config-error" | "invoke-auth" | "invoke-model" | "invoke-process-spawn" | "invoke-process-exit" | "invoke-timeout"; configuredLane: string; resolvedBackend?: string | undefined; failureArtifactHash?: string | undefined; })[]; findings: { message: string; severity: "CRITICAL" | "WARN" | "INFO"; confidence?: number | undefined; line?: number | undefined; file?: string | undefined; }[]; attemptedLaneCount: number; completedLaneCount: number; postChecks: { message: string; tier: "decidable" | "sensor"; ruleName: string; verdict: "pass" | "fail" | "abstain"; }[]; round: { index: number; lineageKey: string; priorVerdictHash?: string | undefined; }; reviewedState: "matched" | "drifted"; settled: boolean; diversity?: { class: "cross-vendor" | "same-vendor-isolated"; providers: string[]; distinctProviders: number; unrecognizedProviders: string[]; diversityConfidence: "verified" | "coarse"; } | undefined; panelArtifactHash?: string | undefined; lessonsConsulted?: { status: "empty" | "hit"; items: { filePath: string; contentHash: string; sourceRepo?: string | undefined; }[]; } | undefined; }>; export type VerdictArtifact = z.infer; /** * The round-chain lineage key is composite over the RESOLVED scope selector (agy * fold 3; codex rev-2 fold 2) — NOT the source enum alone. The selector fields * describe the *lineage*, never the changing diff bytes, so legitimate fix rounds * still chain. Per-source contribution (the CLI resolver populates only the fields * a source makes meaningful): * - `repoIdentity` — the stable worktree identity (absolute resolved * `git rev-parse --show-toplevel`), ALWAYS present. * - `branch` — the current branch (or the `DETACHED:` marker), ALWAYS present. * - `source` — the `getDiffForReview` source, ALWAYS present. * - `explicit-range` — normalized `base` + `head` (the two endpoints). * - `branch-vs-base` — resolved `base` + `mergeBase`. * - `staged` / `uncommitted` — NO range fields (worktree identity + branch + * source carry the lineage). */ /** Fields every lineage-key variant carries, regardless of source. */ interface LineageKeyCommon { /** Stable worktree identity — the absolute resolved `git rev-parse --show-toplevel`. */ repoIdentity: string; /** The current branch, or the `DETACHED:` marker. */ branch: string; /** * The raw CLI selector FORM (finding 10) — accepted on EVERY variant now so the * key shape is stable before the CLI populates it. It distinguishes selectors * that resolve to the same refs but describe different lineages, e.g. `--diff main` * (working-tree mode) vs `main..HEAD` (range mode). Absent today (⇒ hashed as * `null`); when the CLI agent supplies it (finding 10) the key already accounts * for it — no further domain-tag bump needed. */ selectorForm?: string; } /** * `computeLineageKey` input, SOURCE-DISCRIMINATED (totem-codex finding 9d): each * variant carries ONLY the range fields its source makes meaningful, so an * impossible record (e.g. a `staged` scope with a `head` endpoint) is * unrepresentable. * - `explicit-range` — `base` + `head` (the two endpoints). * - `branch-vs-base` — `base` (resolved base ref) + `mergeBase` (resolved sha). * - `staged` / `uncommitted` — NO range fields; repoIdentity + branch + source * (+ optional selectorForm) carry the lineage (the index/worktree has no endpoint). */ export type LineageKeyInput = (LineageKeyCommon & { source: 'explicit-range'; base: string; head: string; }) | (LineageKeyCommon & { source: 'branch-vs-base'; base: string; mergeBase: string; }) | (LineageKeyCommon & { source: 'staged'; }) | (LineageKeyCommon & { source: 'uncommitted'; }); /** * The composite round-chain lineage key: a domain-tagged sha256 over the resolved * scope selector (agy fold 3; codex rev-2 fold 2). Two branches sharing `base=main` * can NEVER cross-link because `branch` participates, and two DIFFERENT explicit * ranges on one branch + merge-base cannot cross-link because `base`/`head` * participate. * * The domain tag is `verdict-lineage/3` — bumped from `/2` because the selector * shape changed (source-discriminated input + `selectorForm`), so keys under the * two tags are deliberately incompatible. * * Only the fields VALID for the discriminated `source` participate (the switch * reads them per-variant), pinning the others to `null`. The selector is hashed as * a canonicalized (recursively key-sorted) JSON object with the fixed domain tag, * so there is NO delimiter-injection ambiguity — `branch='a', mergeBase='b|c'` and * `branch='a|b', mergeBase='c'` serialize to distinct JSON and therefore distinct * keys, which a naive `join('|')` would collide. A `null` hole (a source that omits * a field) can never collide with an empty string a source supplies for it. */ export declare function computeLineageKey(input: LineageKeyInput): string; /** Absolute verdicts directory for a given absolute totem dir. */ export declare function verdictsDir(totemDirAbs: string): string; /** * Content address of a verdict: deterministic hash over everything EXCEPT * `createdAt` (observability, not identity). Identical rounds dedup to one * artifact regardless of when they ran. */ export declare function computeVerdictArtifactContentHash(artifact: VerdictArtifact): string; /** * A loaded verdict paired with its VERIFIED content address (the filename stem = the * raw-payload hash). The address SURVIVES the tolerant Zod parse (rev-6 item 1): a * forward-minor artifact whose writer addressed a raw payload with an additive field * THIS reader strips keeps its on-disk address here, so no downstream consumer * (covariate line, lineage tie-break, round linkage) recomputes a DIVERGING identity * over the normalized shape — the covariate line would otherwise advertise a hash with * no file, and round linkage would point at a nonexistent prior. Every load/scan entry * point returns this pair so the stored address is the single identity every consumer uses. */ export interface VerdictWithAddress { artifact: VerdictArtifact; /** The verified content address = the filename stem (raw-payload hash, `createdAt` excluded). */ contentHash: string; } /** * Render the machine-readable covariate line — the CORE-OWNED signal every caller * (CLI print, headless, `/review-reply`) emits identically so the skill stays pure * transport (strategy-codex G4; resolves finding 14). Format, EXACTLY: * * `local-lane: round= settled= lanes=/` * * where `` is the first 8 hex of the artifact's STORED content address. The * signature takes a {@link VerdictWithAddress} (rev-6 item 1) so the rendered `` * is the VERIFIED on-disk address that survived the tolerant parse — NOT a recompute * over the Zod-stripped shape, which would diverge for a forward-minor artifact and * advertise a hash with no backing file. A caller with a freshly-assembled verdict * pairs it with the address `saveVerdictArtifact` returned. * * @remarks Covariate line format v1 — do NOT alter without a spec amendment (the * pilot ledger joins on this grep-able line; the format is contract, versioned with * the `review-loop` skill). */ export declare function renderCovariateLine(verdict: VerdictWithAddress): string; export interface SaveVerdictArtifactResult { /** The content address (= filename stem). */ hash: string; /** Absolute path of the stored artifact. */ path: string; /** True when an identical logical verdict was already recorded (no write happened). */ existed: boolean; } /** * Persist a verdict at its content address, write-if-absent (`wx` create- * exclusive). Validates on the way OUT so a writer bug never poisons the ledger * with a record the reader would reject. * * EEXIST is LOGICAL-IDENTITY DEDUP (`createdAt` excluded from the address; codex * fold 8 / agy fold 4): the existing record is loaded and its content hash * recomputed. If it matches this address (equal MODULO `createdAt`), the stored * record IS this save's outcome — first-write-wins, dedup return. If the record * at this address recomputes to a DIFFERENT hash, its bytes disagree with the * content address — a hard identity violation (a corrupted/tampered record or a * sha256 collision), never silently accepted. */ export declare function saveVerdictArtifact(totemDirAbs: string, artifact: VerdictArtifact): SaveVerdictArtifactResult; /** * Load + validate a verdict by content address, returning the artifact WITH its * verified content address (rev-6 item 1 — {@link VerdictWithAddress}). Throws * {@link TotemParseError} on a missing file, corrupt JSON, schema violation, or an * unknown major with no migration entry, and {@link TotemError} (`DATABASE_MISMATCH`) * when the stored bytes do not hash back to their filename address (finding 4) — loud, * never a silent partial (Tenet 4). * * Order (rev-6 item 5): the RAW stored address is verified FIRST — the content-address * guarantee is over the on-disk bytes (minus `createdAt`), MAJOR-agnostic and * migration-independent, so a mis-addressed / tampered file fails before it is * transformed. Only THEN is any migration applied and its output validated against the * current schema (a separate concern — migration correctness, not address integrity). * The returned `contentHash` is always this verified filename address. */ export declare function loadVerdictArtifact(totemDirAbs: string, hash: string): VerdictWithAddress; /** * Load every stored verdict under `artifacts/verdicts/`, verifying each through * the SAME content-address check as {@link loadVerdictArtifact}. A missing * directory yields `[]` (nothing written yet). Non-verdict file names are skipped * silently; a corrupt / mis-addressed verdict is skipped LOUDLY via `onWarn`. * `onWarn` is REQUIRED — core stays console-free (no presentation-layer default), * and the caller must decide where scan warnings land rather than inheriting a * silent noop (Tenet 4); see {@link loadVerifiedVerdictForScan}. (PR #2337 CR.) */ export declare function listVerdictArtifacts(totemDirAbs: string, onWarn: (message: string) => void): VerdictWithAddress[]; /** * The latest verdict sharing `lineageKey` — highest `round.index`, ties broken by * the lexical STORED content address (rev-5 item 8 / rev-6 item 1), NOT `createdAt`. * Returns the winning {@link VerdictWithAddress} (artifact + verified address) or * `undefined` when no verdict carries the key. Used for implicit round linkage (the * next round's `priorVerdictHash` = the returned `contentHash`, so the link always * points at the on-disk file even for a forward-minor artifact). Goes through the same * verified scan load as {@link listVerdictArtifacts}: a corrupt / mis-addressed * artifact is warned + skipped (never silently winning or losing the lineage). `onWarn` * is REQUIRED — core is console-free and the caller owns where warnings land (Tenet 4). * * The tie-break is IDENTITY-BOUND and deterministic: two same-round verdicts break on * their STORED content address (the on-disk identity, `createdAt` excluded), so * selection never depends on wall-clock emission time (observability-only) — the same * corpus always resolves the same latest verdict regardless of when each round ran. */ export declare function findLatestVerdictForLineage(totemDirAbs: string, lineageKey: string, onWarn: (message: string) => void): VerdictWithAddress | undefined; export {}; //# sourceMappingURL=verdict.d.ts.map