/** * Reopen planning and application (FR4). * * `planReopen` is pure — no I/O — so every refusal branch is testable without a * filesystem. `applyReopen` is the single writing function in the module. * * **Why the range is contiguous.** Reopening only the phases an author named * would leave a `complete` phase sitting behind an `in-progress` one, and two * shipped behaviours then misfire: `findNextPendingPhase` * (`core/lifecycle.ts:244-269`) jumps forward over the intermediates writing a * `type: 'normal'` record with no skip recorded, and `checkDeploymentEntry` * (`:491-505`) keys on template adjacency rather than the actual target, so a * reopened `design` whose next pending phase is `deployment` would enter * deployment with that gate never evaluated. A contiguous range fixes both * without touching `evaluateTransition`, which is what lets this feature add no * gate at all. * * **Why validation is an allowlist AND a character check.** Membership in * `phasesForScope` serves three jobs — traversal guard, Gate-1 correctness guard * (`lifecycle.ts:310-318` skips the required-artifacts gate entirely when * `current_phase` is not in the list, so a typo silently switches the gate * *off*), and scope guard. But membership alone is not enough: * `validateTemplate` (`core/template-resolver.ts:323-326`) accepts any non-empty * string as a phase name, so a project-local template declaring * `- name: ../../evil` puts a traversal token *inside* the allowlist, and * `saveSnapshot`'s `join` has no containment (`state/snapshot-store.ts:129-133`). * This repo already treats `.aidlc/templates/` as hostile for exactly this * reason (`traceability/gate-criterion.ts:64-71`). * * Requirements: change-management/AC-27, AC-50, AC-82, AC-83, AC-84, AC-85, * AC-87, AC-89, AC-92; amend-cannot-reopen-current-phase/AC-7, AC-8 */ import type { InstanceState, PhaseState, WorkflowTemplate } from '../core/types.js'; import type { Amendment, ReopenPlan } from './types.js'; export interface PlanInput { amendment: Amendment; instanceState: InstanceState; phaseStates: Map; resolvedTemplate: WorkflowTemplate; /** Actor identity for the record's `by` (AC-83). */ actor: string; /** Injected so tests are deterministic. */ now: Date; } /** * Plan a reopen. Pure: one of five variants out, no writes, no reads. */ export declare function planReopen(input: PlanInput): ReopenPlan; export interface ApplyInput { projectRoot: string; instance: string; plan: Extract; instanceState: InstanceState; phaseStates: Map; resolvedTemplate: WorkflowTemplate; amendment: Amendment; now: Date; } /** * Apply a reopen plan. * * **Write order is deliberate** (AC-89): every phase state file first, then * `instance.yaml` (`current_phase` and `applied_amendments` in one write), then * the appended record last. A failure part-way therefore leaves phases reopened * with the amendment unrecorded, which a re-run completes; the reverse order * would leave the amendment recorded with phases untouched, which a re-run would * refuse to fix. */ export declare function applyReopen(input: ApplyInput): void; /** * Record an amendment as applied without touching phase state — the no-op path * (AC-87). An accounted-for amendment must not become destructive later when * `current_phase` moves on its own. */ export declare function recordApplied(projectRoot: string, instance: string, instanceState: InstanceState, amendmentNumber: number): void; /** Sorted, deduplicated union — so a repeat run is stable rather than growing. */ export declare function mergeApplied(existing: number[] | undefined, n: number): number[]; //# sourceMappingURL=reopen.d.ts.map