import { initDb } from '../shared/db.js'; import { type WorkItemSource, type WorkItemStatus } from './store.js'; export interface WorkflowTodoStatusEvent { id: string; workItemId: string; fromStatus: WorkItemStatus | null; toStatus: WorkItemStatus; /** Who performed the transition, read from the audit row's own `actor` * column rather than the provenance snapshot — so every event written * before the trigger filter existed replays with its actor intact. */ actor: string | null; /** The employee the status route stamped this move as armed on behalf of, or * null for every other event. It is written at the moment of the move, so a * later change to the delegate list never rewrites what already happened. */ armedAsDelegate: string | null; /** Whether the availability resume sweep wrote this move, having already * settled from the failure's own reset when the quota window reopens. Written * at the moment of the move, so nothing read later can claim a window nobody * waited out. */ quotaWindowDecided: boolean; /** A recovery sweep re-armed this Todo. Operator-filtered triggers accept it * the same way they accept an availability resume: this is resuming work the * operator already armed, not a new arming. */ armedAsRecovery?: boolean; /** `source`, `department`, and `assignee` are the provenance snapshot frozen * into the audit row when the Todo moved. `labels` and `live` are read at * replay time instead: labels, assignment, and parentage all change * independently of status, so a filter asking what the Todo *is* must read the * row rather than whatever it carried when it moved. `live` is null once the * row is gone, which is not the same as a Todo that is simply unassigned. Its * `status` is the Todo's status NOW, which is what says whether the Todo is * still sitting where this event put it. */ item: { source: WorkItemSource; department: string | null; assignee: string | null; labels: Array<{ id: string; name: string; }>; live: { assignee: string | null; parentId: string | null; status: WorkItemStatus; } | null; }; } export interface WorkflowTodoEventClaimOutcome { workflowId: string; outcome: 'started' | 'duplicate' | 'suppressed' | 'superseded' | 'deferred-then-superseded' | 'failed'; runId?: string; detail: string; } export type WorkflowTodoEventClaim = /** `deferred` marks an event an earlier pass put back rather than settled, so * the caller knows to re-check whatever it was waiting on before firing. */ { state: 'acquired'; definitionIds: string[]; deferred?: boolean; } | { state: 'busy'; } | { state: 'processed'; outcomes: WorkflowTodoEventClaimOutcome[]; }; export interface WorkflowTodoEventFeed { claimEvent(eventId: string, definitionIds: string[]): WorkflowTodoEventClaim; completeEvent(eventId: string, outcomes: WorkflowTodoEventClaimOutcome[]): void; /** Record what this pass decided WITHOUT sealing the event: a later drain has * to judge it again, against `definitionIds` as its candidates. */ deferEvent(eventId: string, definitionIds: string[], outcomes: WorkflowTodoEventClaimOutcome[]): void; releaseEvent(eventId: string): void; /** Unclaimed status events, oldest first, so a caller reading a backlog * sees the order the Todo actually moved in. */ listPendingEvents(limit?: number): WorkflowTodoStatusEvent[]; } export interface WorkflowTodoEventFeedOptions { ownerId?: string; now?: () => Date; leaseMs?: number; } export declare const CLAIMS_TABLE = "workflow_todo_event_claims"; export declare function ensureClaimsTable(): ReturnType; export declare function parseOutcomes(raw: string | null): WorkflowTodoEventClaimOutcome[]; export declare function createWorkflowTodoEventFeed(opts?: WorkflowTodoEventFeedOptions): WorkflowTodoEventFeed; //# sourceMappingURL=workflow-event-feed.d.ts.map