/** * Dependency checking - validate task dependency graphs. * Ported from lib/tasks/dependency-check.sh * * @epic T4454 * @task T4529 */ import type { Task } from '@cleocode/contracts'; import type { DataAccessor } from '../store/data-accessor.js'; /** Result of a dependency validation check. */ export interface DependencyCheckResult { valid: boolean; errors: DependencyError[]; warnings: DependencyWarning[]; } /** A dependency error. */ export interface DependencyError { code: string; taskId: string; message: string; relatedIds?: string[]; } /** A dependency warning. */ export interface DependencyWarning { code: string; taskId: string; message: string; } /** * Test whether an observed dependency status satisfies execution readiness. * * @remarks * Only done and archived records satisfy the spawn contract. Cancelled work, * missing status and unrecognized input remain unsatisfied. Completion waivers * are a separate policy and are not applied by this predicate. * * @param status - Status observed from a dependency record, if available. * @returns Whether the dependency supplies satisfactory readiness evidence. * @example * ```ts * isReadinessDependencySatisfied('archived'); // true * isReadinessDependencySatisfied('cancelled'); // false * ``` */ export declare function isReadinessDependencySatisfied(status: string | undefined): boolean; /** * Return dependencies that prevent a task from being spawned. * * @remarks * Readiness follows the spawn contract: only done and archived dependencies * satisfy it. Missing tasks and cancelled work remain blockers. Completion * waivers apply to completion validation, not to this readiness decision. * The caller owns loading the dependency population and surfacing read failures. * * @param depends - The task's explicit hard dependency identifiers. * @param taskLookup - Successfully loaded dependency records, keyed by identity. * @returns Blocking identifiers in their original dependency order. * * @example * ```ts * const blockers = getReadinessDependencyBlockers(['T1'], new Map()); * // blockers is ['T1']: absence is not evidence of completed work. * ``` */ export declare function getReadinessDependencyBlockers(depends: readonly string[] | undefined, taskLookup: ReadonlyMap): string[]; /** * Resolve explicit hard dependency evidence beyond a selected task population. * * @remarks * The returned lookup includes the selected rows and canonically loaded external * dependencies, including archived records. It is evidence for readiness, not a * replacement selection for counts, containment, scoring, or candidate discovery. * Missing records remain absent so the readiness policy can report their IDs as * blockers. Read failures propagate and never become a successful empty lookup. * * @param selected - Successfully loaded tasks whose dependencies will be assessed. * @param accessor - Canonical accessor bound to the owning project. * @returns A separate identity lookup containing selected and external evidence. * @throws Error when the required canonical dependency read fails. * @example * ```ts * const lookup = await loadReadinessDependencyLookup(selectedTasks, accessor); * const blockers = getReadinessDependencyBlockers(selectedTasks[0]?.depends, lookup); * ``` */ export declare function loadReadinessDependencyLookup(selected: readonly Task[], accessor: DataAccessor): Promise>; /** * Detect circular dependencies using DFS. * Returns the cycle path if found, empty array otherwise. */ export declare function detectCircularDeps(taskId: string, tasks: Task[]): string[]; /** * Check if adding a dependency would create a cycle. */ export declare function wouldCreateCycle(fromId: string, toId: string, tasks: Task[]): boolean; /** * Get tasks that are blocked (have unmet dependencies). * * Excludes tasks in terminal states (`done`, `cancelled`, `archived`) and the * Tier 2 proposal queue (`proposed`) — `proposed` tasks are not part of the * active execution dependency graph. * * `archived` tasks satisfy dependencies (treated equivalent to done) — T1954. */ export declare function getBlockedTasks(tasks: Task[]): Task[]; /** * Get tasks that are ready (all dependencies met). * * Excludes tasks in terminal states (`done`, `cancelled`, `archived`) and the * Tier 2 proposal queue (`proposed`). `proposed` tasks represent agent-suggested * work pending owner review and must never be auto-picked by the sentient loop * or orchestrator (T946 / Round 2 audit §8). * * `archived` tasks satisfy dependencies (treated equivalent to done) — T1954. */ export declare function getReadyTasks(tasks: Task[]): Task[]; /** * Get tasks that depend on a given task. */ export declare function getDependents(taskId: string, tasks: Task[]): Task[]; /** * Get dependent IDs. */ export declare function getDependentIds(taskId: string, tasks: Task[]): string[]; /** * Get unresolved dependencies for a task (deps that are not done/cancelled/archived). * * `archived` tasks satisfy dependencies (treated equivalent to done) — T1954. */ export declare function getUnresolvedDeps(taskId: string, tasks: Task[]): string[]; /** * Validate dependencies for missing references. */ export declare function validateDependencyRefs(tasks: Task[]): DependencyError[]; /** * Full dependency graph validation. */ export declare function validateDependencies(tasks: Task[]): DependencyCheckResult; /** * Topological sort of tasks by dependencies. * Returns sorted task IDs or null if cycle detected. */ export declare function topologicalSort(tasks: Task[]): string[] | null; /** * Walk upstream recursively through a task's dependency chain. * Returns all non-done/non-cancelled/non-archived dependency IDs (deduplicated). * Uses a visited set for cycle protection. * * `archived` tasks satisfy dependencies (treated equivalent to done) — T1954. */ export declare function getTransitiveBlockers(taskId: string, tasks: Task[]): string[]; /** * From the transitive blockers, return only "leaf" blockers — those whose * own dependencies are all resolved (done/cancelled/archived) or that have no * dependencies at all. These are the root-cause tasks that need action first. * * `archived` tasks satisfy dependencies (treated equivalent to done) — T1954. */ export declare function getLeafBlockers(taskId: string, tasks: Task[]): string[]; //# sourceMappingURL=dependency-check.d.ts.map