/*
Desired-state composition types for RFC-1038. Defines the declarative target
(DesiredState), the runtime actual state (ActualState, replacing KernelRegistry),
component/command/pipeline declarations, and the module export shape that
replaces KernelModule.register().
- Does not implement reconciliation logic — see reconciler.ts.
- Does not implement overlay resolution — see overlay.ts.
- Does not define Zod schemas — see component/schemas.ts.
- RFC-1038: initial implementation — desired-state composition types replacing ComponentManifestV1, KernelModule, KernelRegistry.
- RFC-1144: run read-only steps to completion in collect-errors pipeline mode
Scheduler: collectErrors option on executeScheduledSteps — read-only steps (ScheduledStep.readOnly, executor-resolved from mutatesState === false) run after dependency failures with ranAfterFailedDependency annotation; ranTainted set propagates taint transitively so mutating dependents still skip. Executor: mergeCollectErrorsOption OR-merges PipelineDeclaration.collectErrors with the CLI flag at registry resolution; readOnly annotated post-buildSchedule; taint flag copied to step reports; tainted failures marked in pretty output. Contracts: PipelineDeclaration.collectErrors, KernelExecutionReport.ranAfterFailedDependency, pipelines maps store full declarations. Declarations: collectErrors on validation-gate registrations (build.post, check, build.check, compass, integrity.release in the workpiece template; packages.check in checks module). Tests: 10 new cases covering AC-1..AC-6 plus transitive taint.
*/
import type { Sha256Digest } from "../fingerprint/primitives.ts";
import type { ComponentScope, ScopeContext, ComponentDeclaration } from "../component/contracts.ts";
import type {
KernelFlagSpec,
GeneratedArtifactSpec,
KernelPipelineStep,
KernelCommandMetadata,
KernelCommandInput,
KernelRuntimeContext,
KernelCommandResult,
ModuleFiberState,
} from "./types.ts";
/**
* Unified component type — replaces ComponentManifestV1.
* Re-exported from contracts.ts for convenience.
*/
export type { ComponentDeclaration };
export interface DesiredState {
/** Stable component declarations keyed by componentId. Map for O(1) lookup. */
components: Map;
/** Capability contracts that must be satisfied. */
requiredCapabilities: string[];
/** Available artifacts for resolution. */
availableArtifacts: ReadonlyMap;
/** Admitted grants for resolution. */
admittedGrants: ReadonlyArray<{ scope: string; resource: string }>;
/** Profile ID for resolution. */
profileId: string;
}
export interface ReconciliationDelta {
/** Components to activate (present in desired, absent in actual). */
toActivate: ComponentDeclaration[];
/** Components to deactivate (absent in desired, present in actual). */
toDeactivate: string[];
/** Components to reconfigure (present in both, but config changed). */
toReconfigure: Array<{
id: string;
oldConfig: Record;
newConfig: Record;
}>;
/** Components unchanged (present in both, config identical). */
unchanged: string[];
/** Missing dependencies — required capabilities with no provider. */
missingDependencies: Array<{ capability: string; requiredBy: string }>;
}
export interface ReconciliationResult {
delta: ReconciliationDelta;
applied: boolean;
/** Components that failed to activate. */
failures: Array<{ id: string; reason: string }>;
/** Time taken to reconcile, in milliseconds. */
durationMs: number;
}
/**
* Command declaration — replaces KernelCommandDefinition for registration.
* Carries ALL metadata fields from KernelCommandDefinition plus the execute function.
* Type safety is preserved: execute receives typed KernelCommandInput and KernelRuntimeContext.
*/
export interface CommandDeclaration extends KernelCommandMetadata {
/** Command name — e.g. "sternsystem.validate". */
name: string;
/** RFC-0260: declared flag schema. */
flags?: Record;
/** RFC-0266: workspace-root-relative path globs this command reads. */
reads?: string[];
/** RFC-0266: workspace-root-relative path globs this command writes. */
writes?: string[];
/** RFC-0637 + RFC-1194: paths relative to dirname(modulePath) for cache hashing. */
modulePaths?: string[];
/** RFC-0687: command names whose outputs this validator checks. */
validatesOutputs?: string[];
/** RFC-0960: repo-relative path to the implementing source file. */
modulePath?: string;
/** RFC-0960: declared generated artifacts. */
generates?: GeneratedArtifactSpec[];
/** RFC-0963: the single contract this validator enforces. */
contract?: string;
/** RFC-0963: the rule IDs this validator enforces. */
rules?: string[];
/** The execute function — typed, same signature as KernelCommandDefinition.execute. */
execute: (
input: KernelCommandInput,
context: KernelRuntimeContext,
) => Promise | void | KernelCommandResult;
}
/**
* Pipeline declaration — replaces registerPipeline() calls.
* Carries the pipeline name and steps with all KernelPipelineStep fields.
*/
export interface PipelineDeclaration {
/** Pipeline name — e.g. "packages.check". */
name: string;
/** Pipeline steps with command references, args, timeouts, and dependsOn (RFC-0686). */
steps: KernelPipelineStep[];
/**
* RFC-1144: when true, the executor behaves as if `--collect-errors` was
* passed — read-only steps (`mutatesState === false`) run to completion
* after dependency failures instead of being cascade-skipped. OR-merged
* with the CLI flag; there is no opt-out flag. Declare on validation-gate
* pipelines only — deployment/mutation pipelines keep fail-fast.
*/
collectErrors?: boolean;
}
/**
* Module export — replaces KernelModule.
* Each *.module.ts file exports this object instead of calling register().
* The reconciler reads declarations, commands, and pipelines from this export.
*/
export interface ModuleExport {
/** Module name — e.g. "sternsystem". */
name: string;
/** Module version. */
version: string;
/** Component declarations for desired-state composition. */
declarations: ComponentDeclaration[];
/**
* Command declarations — replaces registerCommand() calls.
* execute functions may lazy-load implementations via `await import()`
* inside the execute body, preserving the current lazy-loading pattern.
*/
commands: CommandDeclaration[];
/** Pipeline declarations — replaces registerPipeline() calls. */
pipelines: PipelineDeclaration[];
/**
* Optional conditional declaration builder.
* Replaces conditional registration logic in register() bodies.
* Receives the runtime context (env vars, profile, etc.) and returns
* additional or modified declarations/commands/pipelines.
* This runs at startup before reconciliation, not at registration time.
*/
conditionalBuilder?: (context: ModuleBuildContext) => {
declarations?: ComponentDeclaration[];
commands?: CommandDeclaration[];
pipelines?: PipelineDeclaration[];
};
}
/**
* Build context passed to conditionalBuilder.
* Provides environment and profile information for conditional declarations.
*/
export interface ModuleBuildContext {
/** Environment variables (process.env snapshot). */
env: Record;
/** Profile ID from kernel config. */
profileId: string;
/** Whether this is a long-running process (dev server, watch mode). */
longRunning: boolean;
}
/**
* Actual state — replaces KernelRegistry entirely.
* The desired state is the declarative target; the actual state is what's
* currently running. The reconciler updates actual state to match desired state.
* Command execution reads from actual state — no separate registry needed.
*
* Commands and pipelines are always available — they're the module's interface,
* not dynamically activated. They're populated once at startup from ModuleExport[]
* and never change. The reconciler only manages components (capabilities and effects).
* A command may check component state at execution time if it depends on a capability.
*/
export interface ActualState {
/** Active components with their runtime fiber state, keyed by componentId. */
components: ReadonlyMap;
/**
* All declared commands from all ModuleExport[], keyed by command name.
* Populated once at startup, never changes.
*/
commands: ReadonlyMap;
/**
* All declared pipelines from all ModuleExport[], keyed by pipeline name.
* Populated once at startup, never changes. RFC-1144: values are full
* PipelineDeclaration objects (steps + pipeline-level options).
*/
pipelines: ReadonlyMap;
/**
* Map from command name to module name — used for command manifest generation.
* Populated once at startup alongside commands.
*/
commandModules?: ReadonlyMap;
}
/**
* Mutable version of ActualState — used by the reconciler for component mutations.
* Commands and pipelines are still readonly (populated once at startup).
*/
export interface MutableActualState {
components: Map;
commands: ReadonlyMap;
pipelines: ReadonlyMap;
}
/**
* Overlay — layered patch on the base desired state.
* Allows scope-specific modifications without rewriting the base.
*/
export interface DesiredStateOverlay {
/** Overlay ID — stable and unique within the scope. */
id: string;
/** Scope this overlay applies to (RFC-1036). */
scope: ComponentScope;
/** Scope context (e.g., missionId for per-mission overlays). */
context: ScopeContext;
/** Components to add or replace in the base desired state. */
addOrReplace: Map;
/** Component IDs to remove from the base desired state. */
remove: string[];
/** Priority — higher priority overlays override lower ones. */
priority: number;
}