import type { SubmissionIssueCode } from "./submissionClassifier.js"; export declare const SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION: "submission-ledger-event/v1alpha1"; export declare const SUBMISSION_EVENT_KINDS: readonly ["expected", "accepted", "rejected", "recovered_by_hand", "accepted_via_recovery", "removed_by_operator"]; export type SubmissionEventKind = (typeof SUBMISSION_EVENT_KINDS)[number]; /** * One ledger event. Generic over the DRAW's issue-code vocabulary: the base * parameterization carries the shared submission codes, and a draw extending * the vocabulary on its own side (`RemediationIssueCode`, * `AuditIngestIssueCode`) parameterizes rather than widening the shared union * — the same direction {@link SubmissionIssue} takes. */ export interface SubmissionLedgerEvent { readonly contract_version: typeof SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION; readonly run_id: string; readonly submission_id: string; readonly lane: string; readonly kind: SubmissionEventKind; readonly issue_code?: TIssueCode; readonly message?: string; /** ISO-8601. A faithful event record is allowed to say when. */ readonly recorded_at: string; } /** `/submissions/submission-ledger.jsonl`. */ export declare function submissionLedgerPath(artifactsDir: string): string; /** * Append one event under the shared file lock, so concurrent appends cannot * interleave mid-line. The parent directory is created on demand (the lock * acquire creates its own parent; `appendNdjsonFile` creates the ledger's). */ export declare function appendSubmissionEvent(artifactsDir: string, event: SubmissionLedgerEvent): Promise; /** Why one ledger line did not become an event. */ export type SubmissionLedgerDropReason = /** The line is not JSON — a torn write, typically a crash mid-append. */ "unparsable" /** The line parsed but carries another release's contract version. */ | "schema_version_mismatch"; /** One line the reader skipped, with enough to find it in the file. */ export interface SubmissionLedgerDrop { /** 1-based physical line number in the ledger file. */ readonly line: number; readonly reason: SubmissionLedgerDropReason; } /** * What {@link readSubmissionLedger} returns: the events AND what it could not * read. * * SHAPE, and why it is this shape. The contract calls for a record carrying * both `events` and `dropped`. It is also still the events ARRAY, because the * consumers that adapt to the record — the audit bundle's `submission_ledger`, * promotion-time archiving, the remediate ingest's recovery-mark scan — adapt * in their OWN nodes, not this one, and a bare `{events, dropped}` would break * every one of them at once. So `events` and `dropped` are non-enumerable * properties on the array itself: `result.events` and `result.dropped` read as * the contract names them, while `for…of`, `.filter`, `.map` and a deep-equal * against a plain array keep working unchanged for a caller that has not been * updated yet. Non-enumerable specifically so `toEqual([])` still holds — a * drop signal must not change what an unrelated assertion sees. */ export type SubmissionLedgerRead = readonly SubmissionLedgerEvent[] & { readonly events: readonly SubmissionLedgerEvent[]; readonly dropped: readonly SubmissionLedgerDrop[]; }; /** * Read the ledger in arrival order. An absent ledger reads as empty — a run * that never drifted has nothing to say — and a partially-written tail is * skipped rather than thrown, because a bookkeeping record must never be able * to fail the call it is recording. * * An event stamped with another release's contract version is skipped EXACTLY * like a torn line, per event. The FILE stays a faithful historical record — * nothing is rewritten or dropped from disk — but this function is a REPORTING * surface, and its callers read `kind`, `issue_code` and `message` to decide * whether a lane is outstanding because it was refused, and to dedupe against * the last recorded event. Reinterpreting a foreign contract's event under * those field semantics is how a run gets MISreported; skipping it degrades to * the same shape as a ledger that had not recorded that event yet. The skip is * per line, so the current release's events on either side of it still load. * * EVERY SKIP IS REPORTED. Skipping used to be silent — no counter, no warning, * nothing in the return value — which made a `rejected` or `recovered_by_hand` * event that was dropped indistinguishable from one that was never recorded at * all, defeating the single thing the ledger exists to guarantee: that a * drifted-and-repaired run stays distinguishable after the fact. Each skipped * line now lands in `dropped` with its 1-based line number and a classified * reason, so no caller can be handed a ledger cleaner than the run actually * was. */ export declare function readSubmissionLedger(artifactsDir: string): Promise; //# sourceMappingURL=submissionLedger.d.ts.map