/** * Read-only view over a repo's QE evidence ledger (wicked-ledger). * * The ledger is the data contract between the QE pipeline (wicked-garden's qe * skills, formerly the retired wicked-testing package) and the acceptance gate * this daemon owns: a DomainStore rooted at `/.wicked-qe/` (legacy * `/.wicked-testing/` — see qeLedgerRoot) holding `runs` and * `verdicts`, plus the public evidence manifest at * `/evidence//manifest.json`. * * READ-ONLY means read-only (F-E2E-013). This module reads the ledger's * CANONICAL JSON files directly and never opens a `DomainStore`: opening one * is a write — `new DomainStore(root)` mkdirs the root, reaps `.tmp.*` files, * creates `wicked-qe.db` (+ WAL/SHM) inside the checkout, runs migrations and * a stale-run UPDATE sweep — and the index-healing `rebuildIndex()` this * module used to call on top of that bulk-inserted every canonical row into * the fresh index, which is where a legacy ledger's scenarios without * `format_version` failed ("SQLite write failed … NOT NULL constraint"). A * GET must leave the repository byte-identical. Canonical JSON is * authoritative by the ledger's own schema contract (the SQLite index is a * derived cache), so reading it directly loses nothing — and a record that * cannot be parsed is surfaced as a read failure (`error`), never skipped * into a cleaner answer. * * ATTRIBUTION (F-E2E-013): the gate answers about ONE crew run, so a verdict * is served only when it can be tied to that run — see {@link ReadSubject}. * "The newest PASS in the store" is not evidence about a run that recorded * none (the regression: an onboarding run that failed at plan time was shown a * two-month-old PASS from the repo's committed legacy ledger). Among the QE * runs that ARE this run's, deny-dominates holds ACROSS them: each QE run's * newest verdict is its current judgment, and one non-PASS among those denies * (review of #539, F2 — a later PASS on scenario Y must not mask a FAIL on * scenario X inside the same crew run). */ import type { EvidenceManifest, RunRecord, VerdictRecord } from 'wicked-ledger'; /** * The ledger root directory name under a repo root. * * Phase 6c (the wicked-testing retirement) renamed the wire contract to * `.wicked-qe`; `.wicked-testing` is the legacy dirname repos written by the * retired package (and pre-6c garden qe skills) still carry. Resolution is * dual-read and mirrors wicked-ledger's `resolveLedgerRoot`: the new name * wins, an existing legacy root is honored, fresh repos get the new name. */ export declare const DEFAULT_QE_LEDGER_DIRNAME = ".wicked-qe"; export declare const LEGACY_QE_LEDGER_DIRNAME = ".wicked-testing"; /** * The field a QE writer running INSIDE a governed run stamps on the ledger run * (and/or verdict) it records: the crew run id the engine hands every worker as * `WICKED_RUN_ID`. Canonical JSON preserves any field a writer supplies, so this * needs no ledger schema change; a record carrying it is attributed to that run * regardless of timing. (garden's QE runner does not stamp it yet — a wave-7 * follow-up; until then lifetime linkage below is the inferred fallback.) */ export declare const CREW_RUN_ID_FIELD = "crew_run_id"; /** The configured ledger dir name: `WICKED_QE_LEDGER_DIR` env override, else the default. */ export declare function qeLedgerDirName(): string; /** * Absolute ledger root for a repo (dual-read, Phase 6c). * * An explicit `WICKED_QE_LEDGER_DIR` pins the root exactly — the operator is * driving, no fallback probing. An absolute value IS the root; a relative * value is a dirname under `repoRoot`. Otherwise: `/.wicked-qe` when it * exists; else an existing legacy `/.wicked-testing` (that ledger keeps * its root — a store must never split across two dirs); else `.wicked-qe`. */ export declare function qeLedgerRoot(repoRoot: string): string; /** The variable garden's QE pipeline resolves wicked-ledger through first (`scripts/qe/lib/ledger-pkg.mjs`). */ export declare const LEDGER_PKG_ENV = "WICKED_LEDGER_PKG_DIR"; /** * (crew#951) Export crew's OWN wicked-ledger package dir as `WICKED_LEDGER_PKG_DIR` for every * worker the engine spawns (the daemon's env reaches them; `hardened()` strips only engine-internal * variables). A governed run's QE unit then records its verdict with the very package this daemon's * acceptance check reads it with — no `npm i` in the worktree, which a fenced seat is refused and * which would change the tree under review. Live on the rig the seat reached a PASS and wrote no * run/verdict rows because the package did not resolve. An operator's own value is kept. Returns * the dir in effect, or `null` when crew's own package cannot be located (nothing is set). */ export declare function exportLedgerPackageDir(env?: NodeJS.ProcessEnv): string | null; /** * The QE ledger ONE crew run's verdicts live in (crew#951) — the ONE rule every per-run read uses. * * A run with an EVIDENCE ROOT (every repo-bound launch mints one, `CoreAdapter.launchRun`, outside * every worktree and state home) keeps its QE ledger there: `/.wicked-qe`. The engine * hands that path to the run's QE unit as `WICKED_QE_LEDGER_DIR` and admits it in that unit's * read-only write boundary, so garden's `qe accept` records the verdict where this reads it — never * in the worktree, whose guard discarded the verdict (with its PASS) when it landed there. Exactly * that path: neither crew's own `WICKED_QE_LEDGER_DIR` nor the repo's ledger speaks for such a run. * A run without an evidence root (a caller-chosen id, an older addon) reads its repo's ledger * ({@link qeLedgerRoot}); no repo and no evidence root ⇒ no ledger (`null`). */ export declare function runQeLedgerRoot(session: { evidence_root?: unknown; }, repoRoot: string | null): string | null; /** * The crew run a ledger read is FOR — what a verdict has to be tied to before * it is served as that run's acceptance evidence. */ export interface RunLinkage { /** The crew run id (what a QE writer inside the run sees as `WICKED_RUN_ID`). */ runId: string; /** * Epoch millis the crew run started — its `sessionStarted` capture time from * the durable event log. `null` when the log records no start (an unknown * window links nothing: evidence that cannot be placed inside the run is not * the run's evidence). */ startedAt: number | null; /** * Epoch millis the run reached a terminal state — the FIRST terminal frame in * its log (`sessionCompleted` / `sessionFailed` / `runCancelled`); `null` * while it is live (window open). */ finishedAt: number | null; /** * Set when the run's event log could not be read at all (the read binding * threw) — a different fact from "the log records no start", with a * different remedy, so the denial names it (review of #539, F5). */ logUnreadable?: string; /** * (crew#971) The run's QE attempts, from its event log: each dispatch of the QE unit (the ord * `qeAcceptanceDecided` names) to that attempt's `gateEvaluated`, with the tree the gate judged * (`assurance.tree`). A verdict recorded inside an attempt's window judged that attempt's tree. * Absent when the log names no QE unit (an older engine) — no tree scoping then. */ qeAttempts?: QeAttemptWindow[]; /** * (crew#971) The run's CURRENT deliverable tree (`session.verified_tree`; null ⇒ no scoping). With {@link qeAttempts}, only verdicts recorded in an attempt that judged THIS tree are * the run's evidence: a FAIL on a tree a send-back superseded no longer blocks the delivery. */ currentTree?: string | null; } /** One dispatch of the run's QE unit: when it ran and which tree its gate judged. */ export interface QeAttemptWindow { start: number; /** The attempt's `gateEvaluated` time; `null` while it is still running. */ end: number | null; /** The tree the attempt's gate judged; `null` when the gate records none (or has not run yet). */ tree: string | null; } /** * What a read is scoped to: an explicit QE run (`?qeRun=` — the caller * asserts the linkage), or the crew run whose evidence is wanted. */ export type ReadSubject = { qeRunId: string; } | { run: RunLinkage; }; /** * How the served verdict was tied to the crew run — or why none was. Always * populated on a found ledger; the route serves it so the answer explains itself. */ export type QeAttribution = /** The caller pinned the QE run (`?qeRun=`); its newest verdict is served. */ { kind: 'pinned'; qeRunId: string; } /** The ledger run (or one of its verdicts) carries `crew_run_id` naming this crew run. */ | { kind: 'stamped'; qeRunId: string; } /** INFERRED: the QE run started inside this crew run's recorded lifetime (not stamped by the writer). */ | { kind: 'run-window'; qeRunId: string; qeRunStartedAt: string; } /** Nothing in the ledger is this run's evidence; `reason` says what the ledger does hold. */ | { kind: 'none'; reason: string; }; /** * One line a human can read on `gate.reason`: HOW the served verdict was tied to * the run, with the inferred kind labelled as such — an operator must be able to * tell "the writer said so" from "it happened while the run was live". */ export declare function describeAttribution(a: QeAttribution): string; /** * The acceptance-relevant slice of a repo's ledger, scoped to one subject. * * `found: false` means the repo has no ledger at all (the dir is absent) — * a distinct fact from "a ledger with no verdicts", and the gate treats both * as a deny with different reasons. `error` carries a read-layer failure * (unreadable dir, a record that is not valid JSON); it is never set on an * ordinary empty ledger. */ export interface QeAcceptanceState { /** Absolute ledger root that was read (or probed). */ root: string; /** Whether the ledger root exists on disk. */ found: boolean; /** The QE run the served verdict belongs to, when resolvable. */ run: RunRecord | null; /** * The governing verdict for the subject: among the attributed QE runs' newest * verdicts, the newest non-PASS if there is one (deny-dominates), else the * newest PASS. */ verdict: VerdictRecord | null; /** The public evidence manifest for that run, when present and parseable. */ manifest: EvidenceManifest | null; /** Absolute path the manifest was read from (null when absent). */ manifestPath: string | null; /** How `verdict` was tied to the subject, or why nothing was. */ attribution: QeAttribution; /** How many live verdicts the ledger holds in total — the repo-level picture the scoped read was carved from. */ ledgerVerdicts: number; /** * How many QE runs are attributed to the subject (each contributes its newest * verdict to the deny-dominates set `verdict` was resolved over). 1 for a pin. */ attributedVerdicts: number; /** * (j4-gates) How many verdicts on the run's current tree were recorded before the latest QE * attempt that judged it, and no longer count (absent when none). */ supersededByLatest?: number; /** Read-layer failure detail (a record could not be read or parsed). */ error?: string; } /** * Read the ledger's acceptance state for a repo, scoped to `subject`. * * The verdicts TABLE is the system of record — the manifest is the public * artifact built from it at run finalization, returned here as display * evidence, never as a gate input: a run can legitimately be re-reviewed * after its manifest was built, and the newer verdict row wins. * * Reads canonical JSON only (see the module header): nothing under the ledger * root is created, modified or removed by this call. */ export declare function readAcceptanceState(repoRoot: string, subject: ReadSubject): Promise; /** * {@link readAcceptanceState} over an already-resolved LEDGER ROOT — what a per-run read passes * ({@link runQeLedgerRoot}). Read-only, canonical JSON only. */ export declare function readLedgerAcceptanceState(root: string, subject: ReadSubject): Promise; /** The summary of a manifest the acceptance route serves (never the full artifact list). */ export interface QeManifestSummary { manifestVersion: string; runId: string; scenarioName: string | null; status: string; artifactCount: number; verdict: { value: string; reviewer: string; recordedAt: string | null; }; } /** Reduce a manifest to the route's summary shape. */ export declare function summarizeManifest(manifest: EvidenceManifest): QeManifestSummary; /** One ledger verdict a walkthrough recorder stamped (WT-W2), with the stamps read off the verdict or its run. */ export interface StampedLedgerVerdict { verdict: VerdictRecord; /** The chapter key the row is about (`chapter`, else the run's `scenario_id`); `null` when neither names one. */ chapter: string | null; tree: string | null; take: number | null; } /** * The verdicts of a PROOF ROOT's own ledger (`/.wicked-qe/`) stamped with `crew_run_id` = * `runId` and `step_id` = `stepId` (on the verdict or on its run), newest first — the rows a * walkthrough's recorder writes, one run and one verdict per chapter per take (DES-walkthrough-proof * §4.4 step 6). Read-only, canonical JSON only, like {@link readAcceptanceState}. A ledger that does * not exist reads `found: false`; one that cannot be parsed reads `error`. */ export declare function readStampedVerdicts(proofRoot: string, runId: string, stepId: string): { found: boolean; rows: StampedLedgerVerdict[]; error?: string; }; /** One review verdict of a document, as the interactive-review seam recorded it (EP-C2). */ export interface DocReviewLedgerRow { /** The ledger verdict row's id. */ id: string; /** The crew run that reviewed (`crew_run_id`). */ runId: string; doc: string; version: number; /** The reviewer's schema id (`match` | `a11y` | `copy` | `qe`). */ reviewer: string; /** `pass` | `changes` | `error` (`review_verdict`; the ledger's own `verdict` is PASS | FAIL | INCONCLUSIVE). */ reviewVerdict: string; findings: unknown[]; /** The seat that ran the review, when the run named one. */ seat: string | null; /** The seats the launch excluded (the document's authors). */ excludedSeats: string[]; /** Whether the document's authoring runs were found (an empty exclusion with `false` = author unknown). */ authorKnown: boolean; skill: string | null; reason: string | null; createdAt: string; } /** * The review verdicts in a document's REVIEW ROOT ledger (`/.wicked-qe/`), newest first — * the rows the interactive-review seam writes, one per reviewer per review run, each stamped with * `crew_run_id` (DES-artifact-editor-plugins §7.6). Read-only, canonical JSON only, like * {@link readStampedVerdicts}; `runId` narrows to one review run. A ledger that does not exist reads * `found: false`; one that cannot be parsed reads `error` — never a cleaner answer. */ export declare function readDocReviewVerdicts(reviewRoot: string, runId?: string): { found: boolean; rows: DocReviewLedgerRow[]; error?: string; }; /** One verdict of a crew run, as the default evals read it (DES-DEFAULT-EVALS-001 S3). */ export interface RunVerdictRow { id: string; verdict: string; reason: string; /** The tree the writer stamped, when it stamped one. */ tree: string | null; createdAt: string; } /** * Every live verdict in a QE ledger root stamped with `crew_run_id` = `runId` (on the verdict or on its run), * newest first. Read-only, canonical JSON only, like {@link readAcceptanceState}. A root that does not exist reads * as no verdicts; one that cannot be parsed throws, for the caller to surface. */ export declare function readRunVerdicts(root: string, runId: string): RunVerdictRow[]; //# sourceMappingURL=ledger.d.ts.map