/** * scope — scope / read_scope / write_scope / artifact_scope resolution. * * G-026 M2 (ADR-0004 #13/#16): * - scope is the *declared target* (task author intent); * - write_scope is the *resolved authoritative write set* computed by the * orchestrator from scope + repo map; * - read_scope / artifact_scope default to write_scope when absent. * Parallel safety requires every task's write_scope to land in a SINGLE * repository boundary and non-overlapping write sets across concurrent tasks. */ import type { PathIdentity, RepoBoundary, SubmoduleInfo } from "./path-identity.js"; /** Fields a task may declare (subset of TaskEntry relevant to scoping). */ export interface ScopedTask { id: string; scope?: string; read_scope?: string; write_scope?: string; artifact_scope?: string; } /** Resolved write set of a task. */ export interface ResolvedWriteScope { taskId: string; /** Identity per declared write path (or scope paths when write_scope absent). */ identities: PathIdentity[]; /** Distinct repository boundaries touched; >1 → mixed (non parallel-safe). */ boundaries: RepoBoundary[]; /** boundary === 'submodule' && exactly one distinct submodule */ singleSubmodule?: string; /** True when the set is an unresolved/mixed target. */ mixed: boolean; /** True when any path is unknown (fail-closed). */ hasUnknown: boolean; /** True when the task declared NO write paths AND no explicit read-only read_scope. * Empty-without-declaration is NOT read-only: the writer may touch anything → * conservative serial. Only explicit read_scope tasks are parallel-safe writers-free. */ unresolved: boolean; /** True when the task explicitly declared read_scope (read-only by declaration). */ readOnly: boolean; } /** Parse declared scoping fields from a task. */ export declare function parseTaskScopes(task: ScopedTask): { scope: string[]; readScope: string[]; writeScope: string[]; artifactScope: string[]; }; /** * Resolve a task's authoritative write set against the repo map. * Mixed root+submodule or unknown paths → mixed/unknown (caller must not parallel). */ export declare function resolveWriteScope(task: ScopedTask, repoMap: { workspace: string; submodules: SubmoduleInfo[]; }): ResolvedWriteScope; /** * Whether task A and task B may run concurrently without write conflicts. * Both must be single-boundary, non-unknown, and their write sets must not overlap. * Explicitly declared read-only tasks (no write paths) never conflict. */ export declare function tasksAreParallelSafeTaskwise(a: ResolvedWriteScope, b: ResolvedWriteScope): boolean; /** Overall parallel-safety check over a set of ready tasks (D4 extension). */ export declare function tasksAreParallelSafeResolved(resolved: ResolvedWriteScope[]): boolean; /** * Orchestrator-level check used by change-tasks-execute parallel gate (M2). * Collects the repo map (root + .gitmodules submodules) and resolves every * ready task's write scope; safe only when all tasks resolve clean and are * pairwise parallel-safe (ADR #22: same boundary serial, distinct submodule ok, * mixed/unknown fail closed). */ export declare function scopeParallelSafeFor(tasks: ScopedTask[], workspace: string, execSyncImpl?: (cmd: string, opts: { encoding: string; cwd: string; }) => { toString(): string; }): Promise;