/** * Storage key builders for post-execution workflow lifecycle concerns: * deadlines and terminal timers, finalizer/teardown tracking, concurrency * limits, child-workflow bookkeeping, durable state/stream storage, and the * workflow visibility index. * * These are spread into `KEYS` in `interface.ts` rather than declared there, so * the lifecycle keyspace can carry its full rationale without pushing that * file's documented line ceiling. Callers still reach them through `KEYS`, * which keeps one import contract for storage keys. * * @module storage/workflow-lifecycle-keys */ /** * Deadline and terminal timer keys. * * Spread into `KEYS` after `SIGNAL_KEYS` and ahead of * `WORKFLOW_RECORD_KEYS_EXTENDED` to preserve the pre-split * `Object.keys(KEYS)` insertion order; not intended to be imported directly * by engine code. */ export declare const WORKFLOW_LIFECYCLE_KEYS_CORE: { readonly deadline: (deadline: number, workflowId: string) => string; readonly terminalCleanup: (fireAt: number, timerId: string) => string; /** * Durable timer that drives a workflow's finalizer after a `cancelled`/`timed-out` * terminal (issue #446 Phase 2). Sortable by `fireAt` and scanned by its own * source (`wf-teardown:`) so it dispatches as the `teardown` timer kind rather * than `terminal-cleanup`. Re-armed with exponential backoff on a failed finalizer * attempt; the scheduler deletes the fired entry after the drive returns without * throwing, so a backoff reschedule is a write of a new entry at the later `fireAt`. */ readonly teardownTimer: (fireAt: number, timerId: string) => string; readonly delayedStart: (startAt: number, workflowId: string) => string; readonly terminalWorkflowPrefix: () => string; readonly terminalWorkflow: (updatedAt: number, workflowId: string) => string; }; /** * Finalizer/teardown tracking, concurrency limits, child-workflow * bookkeeping, durable state/stream storage, and workflow visibility index * keys. * * Spread into `KEYS` after `MAILBOX_KEYS`, `OUTBOX_KEYS`, * `OWNERSHIP_CLAIM_KEYS`, and `WORKFLOW_CATALOG_KEYS` to preserve the * pre-split `Object.keys(KEYS)` insertion order; not intended to be imported * directly by engine code. */ export declare const WORKFLOW_LIFECYCLE_KEYS_EXTENDED: { readonly budget: (namespace: string, period: string, date: string) => string; readonly review: (workflowId: string, reviewId: string) => string; readonly workflowHeaders: (workflowId: string) => string; readonly childCancellationPrefix: (workflowId: string) => string; readonly childCancellation: (workflowId: string, childWorkflowId: string) => string; readonly childWorkflowByParentPrefix: (parentWorkflowId: string, parentWorkflowExecutionToken?: string) => string; readonly childWorkflowByParent: (parentWorkflowId: string, parentWorkflowExecutionToken: string | undefined, childWorkflowId: string) => string; readonly terminalCleanupNeeded: (workflowId: string) => string; readonly workflowConcurrency: (workflowType: string, partitionKey: string) => string; readonly workflowConcurrencyHolder: (workflowId: string) => string; /** * Presence-only marker written at start only when a run is launched with a * non-serialized `services` value (see `start-batch.ts`). It lets a * fresh-process recovery tell a run whose services were lost on crash apart * from one that never had any — the services value itself is never persisted, * so this bit is the only durable trace. Cleared on terminal cleanup. */ readonly workflowHasServices: (workflowId: string) => string; /** * Last-write-wins payload that `ctx.setFinalizerState(value)` records for a * workflow's definition-level `finalizer` activity (issue #446). Staged as a * pending atomic side-effect so it commits with the next checkpoint or the * terminal batch, and swept on terminal cleanup. * * **Current behavior (this release): recorded only.** Nothing reads this value * yet. **Planned behavior (future release):** the engine will pass the decoded * value as the finalizer's input when driving teardown after a * `cancelled`/`timed-out` terminal, where presence means "a resource was * recorded" and absence means the finalizer is skipped. */ readonly finalizerState: (workflowId: string) => string; /** * Durable execution-claim + attempt marker for a workflow that owes a finalizer * run after a `cancelled`/`timed-out` terminal (issue #446 Phase 2). Mirrors the * `wf-cleanup-needed:` lifecycle. The value is the encoded claim record * `{ status: 'owed' | 'running'; attempts: number; token: string; claimedAt?: number }`: * the engine fenced-CAS's `owed → running` (stamping `claimedAt`) before invoking the * finalizer, and settle-CAS's the exact `running` bytes it wrote when clearing or * rescheduling. Liveness is decided purely by TIME: a `running` claim is reclaimable * once `claimedAt` is older than the finalizer's per-attempt timeout plus a margin * (see `teardownStaleThresholdMs`), so crash recovery is an ordinary stale-claim retry * driven by the timer that survived the terminal batch — there is no in-memory liveness * set and no epoch in the record. The cost is that a finalizer running past the stale * threshold may be re-driven concurrently, which is why workflow finalizers must be * idempotent. Present while teardown is outstanding; deleted by the finalizer on * success or when it dead-letters, which is what unblocks purge. */ readonly teardownOwed: (workflowId: string) => string; /** Durable successful finalizer outcome, retained until workflow purge or retention. */ readonly teardownSucceeded: (workflowId: string) => string; /** * Durable audit record written when a workflow's finalizer permanently fails — the * retry horizon is reached, or the recorded resource state vanished so the finalizer * can never run (issue #446 Phase 2). Holds the `TeardownDeadLetterRecord` shape * `{ type, lastError, attempts, deadLetteredAt, workflowExecutionToken?, finalizerInput? }`. * **Excluded from the workflow purge delete-set** so it survives as the operator's * evidence of a leaked external resource and remains queryable through the durable * finalizer-status API after purge. */ readonly teardownDeadLetter: (workflowId: string) => string; /** * Prefix over every {@link teardownDeadLetter} record. Historically also the * `retainedRecoveryRecords` reference-count scan's own target, but that scan * now reads {@link teardownDeadLetterHistoryPrefix} instead (WFT-21, Codex * review round 3, P2) — see that key's own doc for why. */ readonly teardownDeadLetterPrefix: () => string; /** * Durable, PER-GENERATION sibling of {@link teardownDeadLetter} (WFT-21, * Codex review round 3, P2), written alongside it with the identical * {@link import('../core/engine/termination/finalizer-claim.ts').TeardownDeadLetterRecord} * value. `teardownDeadLetter` itself stays keyed by `workflowId` ALONE — * unchanged, so `getFinalizerStatus` keeps serving "the latest dead letter * for this workflow id" exactly as before — which means a workflow id * reused across generations (purge, or `onTerminalConflict: 'start-new'`) * has each LATER generation's dead letter silently overwrite an EARLIER * generation's at that single slot. This key adds `workflowExecutionToken` * as a second segment specifically so `retainedRecoveryRecords`' reference * counting — which must see every generation's leaked revision, not just * the most recent one — never loses an earlier generation's evidence to a * later generation reusing the same id. See * {@link import('../core/engine/retained-recovery-record-count.ts').countTeardownDeadLettersForRevision}, * which scans {@link teardownDeadLetterHistoryPrefix} rather than * `teardownDeadLetterPrefix`. A dead-lettering run with no * `workflowExecutionToken` (a legacy, pre-token run) uses a fixed sentinel * segment instead — see `deadLetterTeardown()`'s own doc for that bounded * edge case. Same purge-survival contract as `teardownDeadLetter`: never * in the purge delete-set. */ readonly teardownDeadLetterHistory: (workflowId: string, workflowExecutionToken: string) => string; /** * Prefix over every {@link teardownDeadLetterHistory} record, for the * bounded `retainedRecoveryRecords` reference-count scan (WFT-21, Codex * review round 3, P2). Mirrors {@link terminalWorkflowPrefix}'s existing * bare-prefix convention. */ readonly teardownDeadLetterHistoryPrefix: () => string; readonly offload: (workflowId: string, key: string) => string; readonly archive: (workflowId: string, key: string) => string; readonly stateExecution: (ownerWorkflowId: string, key: string) => string; readonly stateWorkflow: (workflowType: string, key: string) => string; readonly streamChunkPrefix: (workflowId: string, key: string) => string; readonly streamChunk: (workflowId: string, key: string, chunkIndex: number) => string; readonly streamTail: (workflowId: string, key: string) => string; readonly streamMetadata: (workflowId: string, key: string) => string; readonly budgetCharged: (operationId: string) => string; readonly toolEffect: (workflowId: string, agentId: string, semanticHash: string) => string; readonly workflowVisibilityStatus: (status: string, workflowId: string) => string; readonly workflowVisibilityType: (type: string, workflowId: string) => string; readonly workflowVisibilityCreated: (createdAt: number, workflowId: string) => string; readonly workflowVisibilityUpdated: (updatedAt: number, workflowId: string) => string; readonly workflowVisibilityDeadline: (deadline: number, workflowId: string) => string; readonly workflowVisibilityManifest: (workflowId: string) => string; readonly workflowVisibilityMetaVersion: () => string; readonly workflowVisibilityMetaBuiltAt: () => string; readonly workflowVisibilityMetaCursor: () => string; };