/** * Pure lifecycle engine functions — completionPercent, isStalled, nextStep, evaluateTransition. * * These are stateless computations over typed state objects used for * progress tracking, observability, continuation resolution, and gate evaluation. * (Requirements 3.6, 6.6, 9.3, 11.2, 11.3, 24.6, 26.1, 26.5). */ import type { PhaseState, WorkflowTemplate, InstanceState, NextStep, FindingsIndex, TransitionResult } from './types.js'; /** * Calculate completion percentage for a lifecycle instance. * * Integer 0-100, floor of: (completed required artifacts) / (total required artifacts) * across all applicable phases (filtered by scope). * * Algorithm: * 1. Get applicable phases from the template (accounting for scope via phasesForScope) * 2. Count total required artifacts across all applicable phases * 3. Count completed artifacts (status === 'complete') from phase states * 4. Return Math.floor((completed / total) * 100), or 0 if total is 0 * * @param phaseStates - Map of phase name to PhaseState for this instance. * @param template - The resolved workflow template (no `extends`). * @param scope - The cycle scope to determine applicable phases. * @returns Integer 0-100 representing completion percentage. */ export declare function completionPercent(phaseStates: Map, template: WorkflowTemplate, scope?: InstanceState['scope']): number; /** * Determine if an instance is stalled. * * Stalled = current phase has been active longer than thresholdDays * AND completionPercent < 100%. * * "Active since" is the current phase's `reopened_at` when it has one, else its * `entered_at` (change-management/AC-93). * Never stalled at 100% — a completed instance is never flagged regardless * of how long its current phase has been active. * * @param state - The instance state (provides current_phase and scope). * @param phaseStates - Map of phase name to PhaseState for this instance. * @param template - The resolved workflow template. * @param now - Current time for age calculation. * @param thresholdDays - Number of days before a phase is considered stalled. * @returns true if the instance is stalled, false otherwise. */ /** * Elapsed seconds to record when a phase completes, or `null` when it cannot be * measured. * * Lives here, beside `isStalled`, because that function has had the anchor right * since change-management/AC-93 and the two transition call sites did not. Both * now call this, so the anchor is chosen in one place. * * Three rules, one per criterion: * * - **`reopened_at` beats `entered_at`** (first-run-gaps/AC-9). A reopen leaves * `entered_at` alone deliberately (`change/reopen.ts:256`), so anchoring there * bills every hour the phase sat *complete* as phase time. Measured: two * minutes of rework turned 1200 seconds into 1335. * - **A reopened visit adds to the figure already recorded** (first-run-gaps/AC-10), * so a phase's total covers all its visits and never decreases. A first visit * has no prior figure, so it is unaffected; `Math.max` on the other branch * holds the same invariant if a completion is ever computed twice. * - **`instanceCreatedAt` is the last resort** (first-run-gaps/AC-11). Every * instance created before `aidlc start` began stamping the initial phase has * `entered_at: null` there, and 57 of them exist. Without the fallback their * first phase records zero forever, and `metrics/report.ts` drops any phase * with no `entered_at` from lead time — so Requirements and Ideation have never * appeared in a single lead-time figure this project has produced. * * Returning `null` rather than `0` is the signature's whole point: callers keep * their `> 0` guard, so an unmeasurable phase stays absent instead of becoming a * zero that reads as measured. `artifact_count` was exactly that mistake. */ export declare function elapsedForCompletion(state: PhaseState, nowIso: string, instanceCreatedAt?: string | null): number | null; export declare function isStalled(state: InstanceState, phaseStates: Map, template: WorkflowTemplate, now: Date, thresholdDays: number): boolean; /** * Continuation resolver — deterministic function of template and state. * * Returns the next action the instance should take: * - `{ kind: 'artifact', phase, artifact }` — produce this artifact next * - `{ kind: 'phase', phase }` — enter this phase next * - `{ kind: 'complete' }` — all phases and artifacts are done * * Algorithm: * 1. Get the resolved phases for the current scope from the template. * 2. Find the current phase in the resolved list. * 3. In the current phase, find the first required artifact with status !== 'complete'. * → return `{ kind: 'artifact', phase: currentPhase, artifact: artifactName }` * 4. If all required artifacts in the current phase are complete, find the next * pending phase (status not 'complete' and not 'skipped'). * → return `{ kind: 'phase', phase: nextPhaseName }` * 5. If no pending phases remain, return `{ kind: 'complete' }`. * * @param state - The current instance state. * @param phaseStates - Map of phase name → PhaseState for all tracked phases. * @param template - The fully resolved workflow template (no `extends`). * @returns The next step the instance should take. */ export declare function nextStep(state: InstanceState, phaseStates: Map, template: WorkflowTemplate): NextStep; /** * Gate chain — evaluates whether a phase transition is allowed. * Returns Allowed or Blocked (with EVERY unsatisfied condition). * * Gate evaluation order: * 1. Required artifacts of the current phase all "complete" * 2. Review gate (if template configures one for this phase): no critical+open findings * 3. Ownership guard: warn + require override if actor ≠ recorded owner * 4. Deployment entry: every preceding required phase has recorded status "complete" (from state only) * 5. Blocking actions (placeholder — currently no-op) * * A blocked attempt reports every unsatisfied condition (Req 4.4). * * @param state - Current instance state. * @param phaseStates - Map of phase name → PhaseState for all phases in the instance. * @param template - The resolved workflow template (no `extends`). * @param actor - Identity of the user/agent attempting the transition. * @param findings - Findings index keyed by artifact name. * @param override - If true, suppresses the ownership violation. * @returns TransitionResult — `{ allowed: true }` or `{ allowed: false, violations: [...] }`. */ export declare function evaluateTransition(state: InstanceState, phaseStates: Map, template: WorkflowTemplate, actor: string, findings: FindingsIndex, override?: boolean): TransitionResult; //# sourceMappingURL=lifecycle.d.ts.map