/** * Request completion — the single answer to "has this Request actually been * delivered?" * * Three writers used to decide it independently (the reconciler's * `reconcileRequestStatus`, the event-driven `cascadeRequestStatus`, and the * heartbeat's `closeStaleRequest`), and each had a variant of the same hole: * a Request counted as done as soon as its WorkItems were terminal and at * least one of them said `verified` — whatever that item was. * * Incident 2026-09-26, Request d86b5faf ("Demand test: one-click deploy a * ready-made AI team"): auto-decomposed into Plan → Execute → Review, all for * the orchestrator, plus a direct item for Ella. The orchestrator re-routed * the work to Ella as a NEW WorkItem (806dc528, which carried the request id * only in its title), completed Plan and Execute as "re-routed / no execution * needed", and cancelled Review and Ella's original item as duplicates. The * reconciler then saw `{verified:2, cancelled:2}` and closed the Request while * the only real work (806dc528) was still running. * * The rules here: * 1. Cancelled items never count as delivered work. * 2. A cancelled item that names its replacement (explicitly via * `metadata.supersededBy` / a `succeeded_by` disposition, or in its * cancel reason, e.g. "re-routed … as WI 806dc528") pulls that * replacement into the Request's set — its status now decides. * 3. Items that were split off the Request without the link (no * `requestId`, but the full request id in their title/brief — the shape * `delegate-task` produces when the orc pastes "[Request | …]") * belong to the Request too. * 4. Plan/Review bookkeeping from auto-decomposition is not a deliverable. * A Request whose only finished items are bookkeeping is not done. * * Pure functions only — callers pass in the pool snapshot. * * @module services/v3/request-completion */ import type { WorkItem } from '../../types/v2/work-item.types.js'; /** * Phases a planner can stamp on an auto-decomposed WorkItem * (`metadata.decompositionPhase`). `plan` and `review` are bookkeeping around * the work; `execute` is the work. */ export type DecompositionPhase = 'plan' | 'execute' | 'review'; /** Metadata key for {@link DecompositionPhase}. */ export declare const DECOMPOSITION_PHASE_METADATA_KEY = "decompositionPhase"; /** Metadata key a canceller sets to name the item(s) that replace this one. */ export declare const SUPERSEDED_BY_METADATA_KEY = "supersededBy"; /** * Whether a WorkItem is Plan/Review-style bookkeeping rather than a * deliverable. * * @param wi - WorkItem to classify * @returns True for SLA trackers and for auto-decomposed plan/review phases * * @example * ```typescript * isBookkeepingWorkItem({ ...wi, metadata: { decompositionPhase: 'plan' } }); // true * ``` */ export declare function isBookkeepingWorkItem(wi: Pick): boolean; /** * Whether a cancelled WorkItem was cancelled because its work moved to another * item (duplicate / superseded / re-routed). * * @param wi - WorkItem to test * @returns True only for `cancelled` items with an explicit successor or a * superseding cancel reason */ export declare function isSupersededCancellation(wi: Pick): boolean; /** * Finds the WorkItems that carry on the work of a cancelled item. * * @param wi - The cancelled WorkItem * @param allItems - Pool snapshot * @returns Successor WorkItems (never `wi` itself) */ export declare function findSuccessorWorkItems(wi: WorkItem, allItems: readonly WorkItem[]): WorkItem[]; /** * Collects every WorkItem whose status bears on a Request's completion: its * own items, unlinked items that name it, and — transitively — the * replacements of any superseded cancellations among them. * * @param requestId - Request id * @param allItems - Pool snapshot (all statuses) * @returns The Request's effective WorkItem set, own items first * * @example * ```typescript * const items = collectRequestWorkItems(request.id, await pool.getAllItems()); * ``` */ export declare function collectRequestWorkItems(requestId: string, allItems: readonly WorkItem[]): WorkItem[]; /** * Outcome of {@link evaluateRequestCompletion}. * * - `complete`: every live item is done/verified and at least one of them is * a real deliverable. * - `in_progress`: some live item is not finished yet. * - `bookkeeping_only`: every live item is finished, but none of them is a * deliverable — nothing was actually produced. * - `nothing_live`: every item was cancelled; nothing is left to deliver. */ export type RequestCompletionOutcome = 'complete' | 'in_progress' | 'bookkeeping_only' | 'nothing_live'; /** Result of {@link evaluateRequestCompletion}. */ export interface RequestCompletionEvaluation { outcome: RequestCompletionOutcome; /** Items that still count (not cancelled). */ liveItems: WorkItem[]; /** Live, finished, non-bookkeeping items. */ deliveredItems: WorkItem[]; /** One-line explanation for logs and correction reasons. */ reason: string; } /** * Decides whether a Request's work was actually delivered. * * @param items - The Request's effective WorkItems (see * {@link collectRequestWorkItems}) * @returns The outcome plus the items that justify it * * @example * ```typescript * const { outcome } = evaluateRequestCompletion(collectRequestWorkItems(id, all)); * if (outcome === 'complete') markDone(); * ``` */ export declare function evaluateRequestCompletion(items: readonly WorkItem[]): RequestCompletionEvaluation; //# sourceMappingURL=request-completion.d.ts.map