// Types for hosted-completion-contract.js — see build-job-contract.d.ts's header for why these are // hand-written rather than `@ts-expect-error`'d. import type { BuildJobOutcome } from "../runner/worker/build-job-contract.d.mts"; export { assertCredentialFree } from "../runner/worker/build-job-contract.d.mts"; export type StepClass = "required" | "best-effort" | "read-only"; export interface StepSpec { step: string; class: StepClass; surfacedAs?: string | null; } export const COMPLETION_STEPS: Readonly>; export type CompletionCaller = keyof typeof COMPLETION_STEPS; export function operationKey(siteKey: string, operationId: string): string; export function latestKey(siteKey: string, target: string): string; export function activeOperationKey(): string; export function latestActorKey(siteKey: string, target: string, accountId: string): string; export function retentionItemKey(siteKey: string, operationId: string): string; export function retentionHeadKey(): string; export function retentionTailKey(): string; export function indexBackfillKey(): string; export interface CompletionStepOutcome { ok: boolean; reason?: string; error?: string; [k: string]: unknown; } export interface CompletionRecord { caller: CompletionCaller; operationKey: string; runner: BuildJobOutcome | null; outcomes: Record; gaps: Array<{ step: string; reason: string }>; enrichmentUnavailable: Array<{ step: string; reason: string }>; phase: "pending" | "complete" | "failed"; tombstone?: true; detailExpired?: true; fingerprint?: string | null; operationId?: string; siteKey?: string; target?: "preview" | "production"; accountId?: string; deploymentBuildId?: string; startedAt?: string | null; finishedAt?: string | null; /** Bounded unknown-readback counter (S2b, hosted/src/site-operations.ts's own * UNKNOWN_READBACK_DELAYS_MS) — additive: existing callers that never set it are unaffected. */ readbackAttempts?: number; } export interface CompletionTombstone { readonly tombstone: true; readonly detailExpired: true; readonly operationId: string; readonly operationKey: string; readonly caller: CompletionCaller; readonly siteKey: string; readonly target: "preview" | "production"; readonly accountId: string; readonly fingerprint: string | null; readonly phase: "complete" | "failed"; readonly runner: { phase?: string; reason?: string; unresolved?: true } | null; readonly deploymentBuildId?: string; readonly startedAt: string | null; readonly finishedAt: string | null; } export function retentionDecision( record: Pick & { tombstone?: true }, now: number, policy?: { compactAfterMs?: number }, ): "keep" | "compact"; export function tombstoneFor(record: CompletionRecord & { operationId: string; siteKey: string; target: "preview" | "production"; accountId: string; startedAt: string; finishedAt: string; }): CompletionTombstone; export function completionRecord(caller: CompletionCaller, operationKeyValue: string): CompletionRecord; export function attachRunnerOutcome(record: CompletionRecord, runnerOutcome: BuildJobOutcome): CompletionRecord; export function applyStepOutcome(record: CompletionRecord, step: string, outcome: CompletionStepOutcome): CompletionRecord; export function unresolved(record: CompletionRecord): string[]; export function finalize(record: CompletionRecord): CompletionRecord; export interface ResultProjection { operationId: string; phase: CompletionRecord["phase"]; gaps?: string[]; enrichmentUnavailable?: string[]; unresolved?: string[]; previewUrl?: string; shareLink?: string; detailExpired?: true; reason?: string; } export function resultProjection( record: CompletionRecord, viewer: { grants: (capability: string) => boolean }, ): ResultProjection;