import type { LaneCoordinatorPort, SharedLaneReceiptPhase } from './lane-coordinator.js'; import { sharedLaneReceiptContentHash } from './lane-coordinator.js'; /** * Receipts are the shared queue's evidence of what ran under a ticket: who held * it, what request it was for, which provider job came of it, how it ended. The * coordinator has stored them since it shipped, and nothing in production ever * wrote one — only the manual `lane receipt` verb and a test script. * * Best-effort by contract: a receipt is evidence ABOUT a render, so failing to * write one must never fail, delay or alter the render. Every error is swallowed * and reported in the return value. The local queue has no receipts (one machine * needs no cross-machine evidence), so there it is a no-op. * * The id is `::`. Identical * facts are therefore the same receipt (a retried write, or the two status paths * reporting the same ending, dedupe), and DIFFERENT facts are a different receipt * rather than a rewrite: a ticket re-granted to a retry, or a re-poll that ends * differently, adds a line to the trail. The coordinator treats different content * under one id as tampering and raises an error incident, which an ordinary * render must never do. Payloads carry hashes, ids and counts — never a prompt, a * path, a token or an account name. */ export function recordLaneReceipt(input: { coordinator: Pick | null | undefined; lane: string; ticketId: string | null | undefined; phase: SharedLaneReceiptPhase; payload: Record; }): { written: boolean; reason?: string } { if (!input.coordinator?.recordReceipt) return { written: false, reason: 'local-queue-has-no-receipts' }; if (!input.ticketId) return { written: false, reason: 'no-ticket' }; try { const contentHash = sharedLaneReceiptContentHash(input.payload); input.coordinator.recordReceipt({ lane: input.lane, ticketId: input.ticketId, receiptId: `${input.ticketId}:${input.phase}:${contentHash.replace(/^sha256:/, '').slice(0, 12)}`, contentHash, phase: input.phase, payload: input.payload, }); return { written: true }; } catch (error) { return { written: false, reason: error instanceof Error ? error.message : String(error) }; } } /** * How a run ended, in ONE shape for every writer. `execute-status` reaches a * terminal job two ways (the report's own job, and a pending candidate's job), * and both can describe the same ticket: the same facts must serialise to the * same bytes so the second write dedupes. */ export function terminalReceiptPayload(input: { projectSlug: string; routeId: string | null | undefined; externalJobId: string | null | undefined; status: 'completed' | 'failed' | 'submit-failed'; }): Record { return { projectSlug: input.projectSlug, routeId: input.routeId ?? null, externalJobId: input.externalJobId ?? null, status: input.status }; }