export type WorkReceiptStateStatus = | 'queued' | 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; export type WorkReceiptStateInput = { status: WorkReceiptStateStatus; runId?: string | null; error?: string | null; failureKind?: 'terminal' | 'repairable' | null; leaseId?: string | null; leaseOwnerRunId?: string | null; leaseOwnerAttempt?: number | null; leaseExpiresAt?: string | null; }; export type WorkReceiptLeaseState = | { kind: 'none' } | { kind: 'active'; leaseId: string; ownerRunId: string; ownerAttempt: number; expiresAt: string; expiresAtMs: number; } | { kind: 'expired'; leaseId: string | null; ownerRunId: string; ownerAttempt: number; expiresAt: string; expiresAtMs: number; } | { kind: 'invalid'; reason: | 'missing_owner' | 'missing_expiry' | 'missing_lease_id' | 'invalid_expiry'; leaseId: string | null; ownerRunId: string | null; expiresAt: string | null; }; export type WorkReceiptInvalidLeaseReason = Extract< WorkReceiptLeaseState, { kind: 'invalid' } >['reason']; export type WorkReceiptState = | { kind: 'queued'; terminal: false; reusable: false; lease: WorkReceiptLeaseState; } | { kind: 'pending'; terminal: false; reusable: false; lease: WorkReceiptLeaseState; } | { kind: 'running'; terminal: false; reusable: false; lease: WorkReceiptLeaseState; } | { kind: 'completed'; terminal: true; reusable: true; lease: WorkReceiptLeaseState; } | { kind: 'skipped'; terminal: true; reusable: true; lease: WorkReceiptLeaseState; } | { kind: 'failed'; terminal: true; reusable: false; lease: WorkReceiptLeaseState; }; export type WorkReceiptClaimDecision = | { kind: 'claim' } | { kind: 'reuse_terminal' } | { kind: 'blocked_active_lease'; status: WorkReceiptStateStatus; ownerRunId: string | null; leaseId: string | null; } | { kind: 'blocked_running'; ownerRunId: string | null; leaseId: string | null; } | { kind: 'blocked_invalid_lease'; reason: WorkReceiptInvalidLeaseReason; status: WorkReceiptStateStatus; } | { kind: 'blocked_failed' }; export type WorkReceiptOwnerOperationDecision = | { kind: 'allow' } | { kind: 'reject'; reason: | 'missing_receipt' | 'not_running' | 'owner_mismatch' | 'attempt_mismatch' | 'lease_mismatch' | 'missing_request_lease'; }; export type WorkReceiptOwnerOperationInput = { receipt: WorkReceiptStateInput | null; ownerRunId?: string | null; ownerRunAttempt?: number | null; leaseId?: string | null; }; function normalize(value: string | null | undefined): string | null { const trimmed = value?.trim(); return trimmed ? trimmed : null; } function normalizeAttempt(value: number | null | undefined): number { return typeof value === 'number' && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0; } export function classifyWorkReceiptLeaseState( receipt: WorkReceiptStateInput, nowMs: number, ): WorkReceiptLeaseState { const ownerRunId = normalize(receipt.leaseOwnerRunId) ?? normalize(receipt.runId); const leaseId = normalize(receipt.leaseId); const expiresAt = normalize(receipt.leaseExpiresAt); if (!leaseId && !expiresAt) { return { kind: 'none' }; } if (!ownerRunId) { return { kind: 'invalid', reason: 'missing_owner', leaseId, ownerRunId, expiresAt, }; } if (!expiresAt) { return { kind: 'invalid', reason: 'missing_expiry', leaseId, ownerRunId, expiresAt, }; } const expiresAtMs = Date.parse(expiresAt); if (!Number.isFinite(expiresAtMs)) { return { kind: 'invalid', reason: 'invalid_expiry', leaseId, ownerRunId, expiresAt, }; } if (expiresAtMs <= nowMs) { return { kind: 'expired', leaseId, ownerRunId, ownerAttempt: normalizeAttempt(receipt.leaseOwnerAttempt), expiresAt, expiresAtMs, }; } if (!leaseId) { return { kind: 'invalid', reason: 'missing_lease_id', leaseId, ownerRunId, expiresAt, }; } return { kind: 'active', leaseId, ownerRunId, ownerAttempt: normalizeAttempt(receipt.leaseOwnerAttempt), expiresAt, expiresAtMs, }; } export function classifyWorkReceiptState( receipt: WorkReceiptStateInput, nowMs: number, ): WorkReceiptState { const lease = classifyWorkReceiptLeaseState(receipt, nowMs); switch (receipt.status) { case 'pending': case 'queued': return { kind: 'queued', terminal: false, reusable: false, lease }; case 'running': return { kind: 'running', terminal: false, reusable: false, lease }; case 'completed': return { kind: 'completed', terminal: true, reusable: true, lease }; case 'skipped': return { kind: 'skipped', terminal: true, reusable: true, lease }; case 'failed': return { kind: 'failed', terminal: true, reusable: false, lease }; default: return assertNever(receipt.status); } } export function decideWorkReceiptClaim(input: { receipt: WorkReceiptStateInput | null; claimantRunId?: string | null; claimantRunAttempt?: number | null; reclaimRunning?: boolean; forceRefresh?: boolean; forceFailedRefresh?: boolean; nowMs: number; }): WorkReceiptClaimDecision { if (!input.receipt) return { kind: 'claim' }; const state = classifyWorkReceiptState(input.receipt, input.nowMs); const sameLogicalRun = normalize(input.claimantRunId) !== null && normalize(input.claimantRunId) === normalize(input.receipt.runId); const sameRunNewerLeaseAttempt = state.reusable && state.lease.kind === 'active' && state.lease.ownerRunId === normalize(input.claimantRunId) && state.lease.ownerAttempt < normalizeAttempt(input.claimantRunAttempt); // Force refresh means new intent across runs. Within one run it is a replay, // so reuse terminal output instead of creating a second terminal payload // under the run's existing Runtime Sheet write version. A newer lease // generation is the exception: it is a new attempt and retains the existing // stale-owner fence semantics. if (state.reusable && sameLogicalRun && !sameRunNewerLeaseAttempt) { return { kind: 'reuse_terminal' }; } if (state.reusable && input.forceRefresh !== true) { return { kind: 'reuse_terminal' }; } if (state.kind === 'failed' && input.forceRefresh !== true) { if (input.forceFailedRefresh === true) { return { kind: 'claim' }; } const claimantRunId = normalize(input.claimantRunId); const ownerRunId = normalize(input.receipt.runId); if (claimantRunId !== null && claimantRunId !== ownerRunId) { return { kind: 'claim' }; } return { kind: 'blocked_failed' }; } if ( state.kind === 'pending' || state.kind === 'queued' || state.kind === 'running' ) { if (state.lease.kind === 'active') { if ( (state.kind !== 'running' || input.reclaimRunning === true || input.forceRefresh === true) && state.lease.ownerRunId !== null && state.lease.ownerRunId === normalize(input.claimantRunId) && state.lease.ownerAttempt < normalizeAttempt(input.claimantRunAttempt) ) { return { kind: 'claim' }; } return { kind: 'blocked_active_lease', status: state.kind, ownerRunId: state.lease.ownerRunId, leaseId: state.lease.leaseId, }; } if (state.lease.kind === 'invalid') { return { kind: 'blocked_invalid_lease', reason: state.lease.reason, status: state.kind, }; } if (input.forceRefresh === true && input.reclaimRunning === true) { return { kind: 'claim' }; } if (state.kind === 'pending' || state.kind === 'queued') { return { kind: 'claim' }; } if ( input.reclaimRunning === true && (state.lease.kind === 'expired' || state.lease.kind === 'none') ) { return { kind: 'claim' }; } return { kind: 'blocked_running', ownerRunId: state.lease.kind === 'expired' ? state.lease.ownerRunId : normalize(input.receipt.runId), leaseId: state.lease.kind === 'expired' ? state.lease.leaseId : normalize(input.receipt.leaseId), }; } if ( input.forceRefresh === true && (state.kind === 'completed' || state.kind === 'skipped') ) { if (state.lease.kind === 'active') { if ( state.lease.ownerRunId !== null && state.lease.ownerRunId === normalize(input.claimantRunId) && state.lease.ownerAttempt < normalizeAttempt(input.claimantRunAttempt) ) { return { kind: 'claim' }; } return { kind: 'blocked_active_lease', status: state.kind, ownerRunId: state.lease.ownerRunId, leaseId: state.lease.leaseId, }; } if (state.lease.kind === 'invalid') { return { kind: 'blocked_invalid_lease', reason: state.lease.reason, status: state.kind, }; } } if (input.forceRefresh === true) { return { kind: 'claim' }; } return { kind: 'claim' }; } function ownerRunIdForReceipt(receipt: WorkReceiptStateInput): string | null { return normalize(receipt.leaseOwnerRunId) ?? normalize(receipt.runId); } function baseRunningOwnerDecision( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { if (!input.receipt) { return { kind: 'reject', reason: 'missing_receipt' }; } if (input.receipt.status !== 'running') { return { kind: 'reject', reason: 'not_running' }; } const ownerRunId = normalize(input.ownerRunId); if (!ownerRunId || ownerRunIdForReceipt(input.receipt) !== ownerRunId) { return { kind: 'reject', reason: 'owner_mismatch' }; } if ( normalizeAttempt(input.receipt.leaseOwnerAttempt) !== normalizeAttempt(input.ownerRunAttempt) ) { return { kind: 'reject', reason: 'attempt_mismatch' }; } return { kind: 'allow' }; } function baseActiveOwnerDecision( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { if (!input.receipt) { return { kind: 'reject', reason: 'missing_receipt' }; } if ( input.receipt.status !== 'queued' && input.receipt.status !== 'pending' && input.receipt.status !== 'running' ) { return { kind: 'reject', reason: 'not_running' }; } const ownerRunId = normalize(input.ownerRunId); if (!ownerRunId || ownerRunIdForReceipt(input.receipt) !== ownerRunId) { return { kind: 'reject', reason: 'owner_mismatch' }; } if ( normalizeAttempt(input.receipt.leaseOwnerAttempt) !== normalizeAttempt(input.ownerRunAttempt) ) { return { kind: 'reject', reason: 'attempt_mismatch' }; } return { kind: 'allow' }; } /** * Law for complete/fail/skip. A terminal write may only be made by the * running receipt owner for the same attempt. When the receipt has a lease id, * the writer must also present that exact lease id; legacy unleased running * receipts remain writable by their run+attempt owner during the migration. */ export function decideWorkReceiptTerminalWrite( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { const ownerDecision = baseRunningOwnerDecision(input); if (ownerDecision.kind === 'reject') return ownerDecision; const receiptLeaseId = normalize(input.receipt?.leaseId); if (!receiptLeaseId) return { kind: 'allow' }; if (receiptLeaseId !== normalize(input.leaseId)) { return { kind: 'reject', reason: 'lease_mismatch' }; } return { kind: 'allow' }; } /** * Law for a single suspended receipt release. The owner may release queued or * running work, and a leased receipt requires the exact lease id. */ export function decideWorkReceiptExactRelease( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { const ownerDecision = baseActiveOwnerDecision(input); if (ownerDecision.kind === 'reject') return ownerDecision; const receiptLeaseId = normalize(input.receipt?.leaseId); if (!receiptLeaseId) return { kind: 'allow' }; if (receiptLeaseId !== normalize(input.leaseId)) { return { kind: 'reject', reason: 'lease_mismatch' }; } return { kind: 'allow' }; } /** * Law for run-fatal teardown. The owner may release all of its still-running * receipts for the same attempt without threading every per-receipt lease id. * It must never match another run or another attempt. */ export function decideWorkReceiptOwnerRelease( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { return baseActiveOwnerDecision(input); } /** * Law for heartbeat. Heartbeats are stricter than terminal writes: they renew a * specific live lease, so both receipt and request must carry the same lease id. */ export function decideWorkReceiptHeartbeat( input: WorkReceiptOwnerOperationInput, ): WorkReceiptOwnerOperationDecision { const ownerDecision = baseActiveOwnerDecision(input); if (ownerDecision.kind === 'reject') return ownerDecision; const requestLeaseId = normalize(input.leaseId); if (!requestLeaseId) { return { kind: 'reject', reason: 'missing_request_lease' }; } if (normalize(input.receipt?.leaseId) !== requestLeaseId) { return { kind: 'reject', reason: 'lease_mismatch' }; } return { kind: 'allow' }; } export function isReusableWorkReceiptState( receipt: WorkReceiptStateInput, ): boolean { return receipt.status === 'completed' || receipt.status === 'skipped'; } function assertNever(value: never): never { throw new Error(`Unhandled work receipt state: ${String(value)}`); }