/** * Task rollup — canonical view of a task's execution + pipeline + children state. * * `computeTaskRollup` is the SINGLE source of truth consumed by Studio, the * SDK, and the CLI for answering "what is the state of this task?" Prior to * T943 each surface independently stitched together `tasks.status`, * `tasks.pipelineStage`, child counts, and gate results, producing divergent * views (e.g. `/tasks` vs `/tasks/pipeline` disagreeing about epic progress). * * Design contract: * - Pure read — no writes, no side effects. * - `pipelineStage` reads `tasks.pipelineStage` directly until T947 migrates * it to the derived lifecycle view. * - Archived children are EXCLUDED from both `childrenTotal` and * `childrenDone` so epic-progress bars reflect in-flight scope. * - `gatesVerified` is populated only when `lifecycle_gate_results` has at * least one `result='pass'` row linked to a stage owned by this task's * pipeline. Missing rows → empty array. * - `blockedBy` parses `tasks.blocked_by` robustly: JSON array, falling back * to comma-separated tokens, falling back to the raw string, and * collapsing to `[]` on empty/null. * - Batch API (`computeTaskRollups`) preserves input order and returns the * entries for missing task IDs as `null`-free by filtering them out. The * caller can re-align using the returned `id`s. * * @task T943 */ import type { DataAccessor } from '@cleocode/contracts'; /** * Canonical execution status exposed on a {@link TaskRollup}. * * Mirrors {@link TaskStatus} from contracts plus the forward-looking * `'proposed'` value that upcoming task-intake work (T947+) will emit before * a task is admitted to the active board. */ export type RollupExecStatus = 'pending' | 'active' | 'blocked' | 'done' | 'cancelled' | 'archived' | 'proposed'; /** * Canonical task rollup consumed by Studio, SDK and CLI surfaces. * * Every field is derived deterministically from the tasks table plus * `lifecycle_gate_results`. No persisted `_rollup` blob exists — the rollup * is recomputed on demand so it stays in sync with the underlying rows. */ export interface TaskRollup { /** Task identifier (e.g. `T123`). */ id: string; /** Canonical execution status. Mirrors `tasks.status`. */ execStatus: RollupExecStatus; /** * RCASD-IVTR+C pipeline stage this task is parked on. * * Reads `tasks.pipelineStage` verbatim. `null` when the task has never been * associated with a pipeline. A future wave (T947) will derive this value * from `lifecycle_stages` for epics that own a pipeline record. */ pipelineStage: string | null; /** * Names of gates that have at least one `pass` result against this task's * pipeline. Empty when no gate rows exist yet. */ gatesVerified: string[]; /** Count of non-archived direct children whose status is `done`. */ childrenDone: number; /** Count of non-archived direct children (any non-archived status). */ childrenTotal: number; /** Tokens parsed from `tasks.blocked_by`. Empty when the column is null/blank. */ blockedBy: string[]; /** * ISO timestamp of the most recent activity on the task — `max(updatedAt, * completedAt)`. `null` when neither is set. */ lastActivityAt: string | null; } /** * Compute the canonical {@link TaskRollup} for a single task. * * Performs three reads: * 1. `accessor.loadSingleTask` → the target row. * 2. One aggregated SQL query → direct-child counts. * 3. One aggregated SQL query → passed gate names (may be empty). * * Returns `null` when the task does not exist. The rollup of an archived task * is still returned — consumers filter on `execStatus` themselves. * * @param taskId - Identifier of the task to roll up (e.g. `T123`). * @param dataAccessor - Storage accessor used for the task lookup. * @returns The rollup or `null` when the task is missing. */ export declare function computeTaskRollup(taskId: string, dataAccessor: DataAccessor): Promise; /** * Compute rollups for many tasks in a single batch. * * Issues exactly one task load, one child-aggregate query, and one gate query * regardless of batch size. Results preserve the input order of `taskIds`. * Missing IDs are omitted from the return array — the caller can detect them * by comparing `taskIds.length` vs `result.length` or by mapping on `id`. * * @param taskIds - Ordered list of task identifiers to roll up. * @param dataAccessor - Storage accessor used for the batched task load. * @returns Rollups in the same order as `taskIds`, minus any missing ids. */ export declare function computeTaskRollups(taskIds: string[], dataAccessor: DataAccessor): Promise; //# sourceMappingURL=rollup.d.ts.map