/** * Wave computation and dependency graph operations. * @task T4784 */ import type { ScoreTaskContext, Task, TaskPriority, TaskRef } from '@cleocode/contracts'; import type { DataAccessor } from '../store/data-accessor.js'; /** Basic execution wave: task IDs grouped by dependency depth. */ export interface Wave { /** 1-based wave number. */ waveNumber: number; /** Task IDs belonging to this wave. */ tasks: string[]; /** Computed lifecycle status of this wave. */ status: 'pending' | 'in_progress' | 'completed'; } /** * Enriched task reference within a wave. * * Carries all fields needed by the wave renderer so callers do not need a * secondary lookup. `blockedBy` lists dependencies that do not satisfy spawn readiness; * `ready` is `true` when the task is immediately actionable. */ export interface EnrichedWaveTask extends TaskRef { /** Task priority level. */ priority: TaskPriority; /** * All declared dependency IDs for this task. * * Empty array when the task has no dependencies. */ depends: string[]; /** * Dependency IDs that are currently blocking this task from spawning. * * Only `'done'` and `'archived'` satisfy dependencies; missing records block. */ blockedBy: string[]; /** * Whether this task is immediately actionable. * * `true` when `blockedBy` is empty AND `status` is `'pending'` or `'active'`. */ ready: boolean; } /** * Enriched execution wave carrying per-task metadata for rendering. * * Tasks within the wave are in THE comparator's order (D11161, T12692): * priority band, attested severity, bounded tiebreak, createdAt, id. */ export interface EnrichedWave { /** 1-based wave number. */ waveNumber: number; /** Enriched tasks for this wave, in comparator order. */ tasks: EnrichedWaveTask[]; /** * Plain task ID list — convenience alias for `tasks.map(t => t.id)`. * * Orchestrators and scripts that only need the IDs (e.g. to spawn agents or * log wave membership) can read this field directly without mapping over * the enriched task objects. Always populated when `tasks` is non-empty. */ taskIds: string[]; /** Computed lifecycle status of this wave. */ status: 'pending' | 'in_progress' | 'completed'; /** * ISO timestamp of the latest `completedAt` among wave tasks. * * Present only when `status === 'completed'` and at least one task carries a * `completedAt` value. */ completedAt?: string; } /** * Whether a task has finished: done, cancelled or archived. * * @param status - Task status. * @returns True for a terminal status. * @task T12682 */ export declare function isTerminalWaveStatus(status: string): boolean; /** * Compute execution waves: each task's wave is its STRUCTURAL DEPTH in the * dependency graph (T12682, T12683 — owner option A). * * @remarks * `wave(t) = 1 + max(wave(d))` over every dependency `d` the lookup knows, * whatever `d`'s status and whichever epic holds it; 1 when there is none. * A wave number therefore never changes when work completes, a finished task * is archived, a dependency is re-parented to another epic, or an external * dependency finishes — only an edit to the dependency edges themselves can * move a task. Numbers can skip (a task whose external prerequisite sits at * depth 3 is in wave 4 even if waves 2–3 hold nothing of this epic); the * listing shows the waves that hold tasks, each under its own number. * * - A finished wave (every task done, cancelled or archived) is `completed`; * a partly finished one, or one with an active task, is `in_progress`. * - A dependency the lookup does not know contributes nothing to depth; * readiness still reports it as a blocker. * - Tasks on a dependency cycle have no depth; they share a final wave after * the deepest one. * - Readiness (`ready`, `blockedBy`) is per task, not per wave: an earlier * wave is ordering, not completion. * * @param tasks - Selected tasks to partition into dependency waves. * @param dependencyLookup - Dependency population: the selection plus every * task reachable through `depends` (see {@link planEpicWaves}). * @returns Waves ordered by number, finished ones included as `completed`. * * @example * ```ts * const waves = computeWaves(tasks, projectTaskMap); * ``` */ export declare function computeWaves(tasks: Task[], dependencyLookup?: ReadonlyMap): Wave[]; /** * The planned waves of an epic, numbered exactly as `cleo orchestrate waves` * prints them (from 1). The one plan every wave consumer reads — the waves * listing, `orchestrate roll-up --wave`, and the wave topic a spawned worker * publishes on — so a wave number means the same wave everywhere (T12682). * * Members of each wave are in THE comparator's order (D11161, T12692); the * wave numbers are structural depth and never depend on the ranking. * * @param epicId - Epic whose direct children are planned. * @param accessor - Task accessor. * @param parentIds - Containment parents to select; defaults to the epic. * @param ranking - Shared ranking context; when absent, the project-wide one * `cleo next` and `orchestrate waves` use is loaded once (`loadRankingContext`), * so every wave surface orders members identically (T12692). Pass it in when * planning several waves or epics in one call. * @param cwd - Project root, for the ranking context's focus phase (T12501). * @returns The selected children, the dependency lookup and the waves. * @task T12682 * @task T12692 */ export declare function planEpicWaves(epicId: string, accessor: DataAccessor, parentIds?: readonly string[], ranking?: ScoreTaskContext, cwd?: string): Promise<{ children: Task[]; taskMap: Map; waves: Wave[]; }>; /** * Get enriched wave data for an epic or a selected set of saga members. * * @remarks * Resolves the selected parents' direct children, computes one topological plan, enriches * each wave's task list with dependency metadata, keeps each wave's members in * the comparator order of {@link planEpicWaves} (D11161, T12692), and attaches * a `completedAt` timestamp to completed waves. * * @param epicId - The epic task ID to compute waves for. * @param cwd - Optional project root (falls back to `getTaskAccessor` default). * @param accessor - Optional pre-constructed data accessor (useful in tests). * @param parentIds - Containment parents to select; defaults to the requested epic. * @param ranking - Shared ranking context; when absent, the project-wide one * `cleo next` and `orchestrate waves` use is loaded once (`loadRankingContext`), * so every wave surface orders members identically (T12692). Pass it in when * planning several waves or epics in one call. * @returns Selected task counts and waves with current dependency readiness. * * @example * ```ts * const plan = await getEnrichedWaves(sagaId, root, accessor, memberEpicIds); * ``` */ export declare function getEnrichedWaves(epicId: string, cwd?: string, accessor?: DataAccessor, parentIds?: readonly string[], ranking?: ScoreTaskContext): Promise<{ epicId: string; waves: EnrichedWave[]; totalWaves: number; totalTasks: number; }>; //# sourceMappingURL=waves.d.ts.map