/** * Architecture invariant rules (spec-23; change: widen-architecture-rule-vocabulary). * * A small, opt-in, fully declarative rule format for dependency / layer / * module-boundary constraints. Rules are author-declared in * `.openlore/architecture.json` (and optionally sourced from synced ADR files), * NEVER inferred by an LLM. Parsing is total: malformed entries become warnings * and are skipped — loading rules never throws. * * The checker ([check.ts](./check.ts)) compiles these down to deterministic * passes over the file-level dependency graph, reusing the canonical * `classifyLayerEdge` primitive from the call-graph analyzer for the `layers` kind. */ /** Where a rule came from — an author's config file, or a recorded decision (spec-16). */ export type RuleSource = 'config' | 'decision'; export interface DecisionRuleReceipt { id: string; title: string; rationale: string; servedContentMetadata?: { provenance: 'reviewed-corpus' | 'local-unreviewed'; }; } interface RuleProvenance { /** Stable decision-local id; absent on config and legacy Invariant rules. */ ruleId?: string; /** Repository-relative source-path boundary for decision-carried rules. */ scope?: string; /** Governing decision receipt, attached by the trusted corpus loader. */ decision?: DecisionRuleReceipt; } /** * Ordered layering: key order is top → bottom, so a lower layer depending on an * upper layer is a violation. Each layer maps to one or more path prefixes. */ export interface LayersRule extends RuleProvenance { kind: 'layers'; layers: Record; source: RuleSource; } /** "Files under `from` must not depend on files under `to`." */ export interface ForbiddenRule extends RuleProvenance { kind: 'forbidden'; from: string; to: string; reason?: string; source: RuleSource; } /** Module boundary: "files under `module` may depend ONLY on `mayDependOn` (plus themselves)." */ export interface AllowedOnlyRule extends RuleProvenance { kind: 'allowedOnly'; module: string; mayDependOn: string[]; reason?: string; source: RuleSource; } /** "Every file under `from` must directly depend on at least one file under `to`." */ export interface RequiredRule extends RuleProvenance { kind: 'required'; from: string; to: string; reason?: string; source: RuleSource; } /** "Dependency cycles under `scope` are forbidden except within allowed prefixes." */ export interface CircularRule extends RuleProvenance { kind: 'circular'; scope: string; allowed: string[]; reason?: string; source: RuleSource; } /** "Files outside `from` must not transitively reach files under `to`." */ export interface ReachableRule extends RuleProvenance { kind: 'reachable'; from: string; to: string; reason?: string; source: RuleSource; } /** "Files under `scope` must have at least one incoming dependency." */ export interface OrphanRule extends RuleProvenance { kind: 'orphan'; scope: string; reason?: string; source: RuleSource; } /** "Files under `scope` must not depend on a strictly more-unstable file." */ export interface MoreUnstableRule extends RuleProvenance { kind: 'moreUnstable'; scope: string; reason?: string; source: RuleSource; } export type ArchitectureRule = LayersRule | ForbiddenRule | AllowedOnlyRule | RequiredRule | CircularRule | ReachableRule | OrphanRule | MoreUnstableRule; /** The parsed rule set plus warnings and whether declared config was fully assessed. */ export interface ArchitectureRules { rules: ArchitectureRule[]; warnings: string[]; /** False when a declared config could not be read or fully parsed. */ assessmentComplete?: boolean; } /** * Parse a raw config object into validated rules. Total: every malformed entry is * recorded as a warning and skipped; this never throws. `source` tags provenance. */ export declare function parseArchitectureRules(raw: unknown, source: RuleSource): ArchitectureRules; /** * Parse `Invariant:` markers out of synced ADR files. We read SYNCED files only — * never `pending.json` fields, which are purged on sync (spec-16 edge case). * Supported single-line grammar (deterministic, no LLM): * * Invariant: forbidden -> [(reason)] * Invariant: allowedOnly -> , [(reason)] * * Anything else is ignored. Returns rules tagged `source: 'decision'`. */ export declare function parseInvariantMarkers(adrText: string): ArchitectureRule[]; /** * Load the effective architecture rules for a project: the opt-in config file * merged with any decision-sourced invariants. Absent config is NOT an error — * returns an empty, inert rule set. Never throws. */ export declare function loadArchitectureRules(absDir: string, opts?: { includeDecisions?: boolean; openspecPath?: string; }): Promise; /** True when no rules are declared — the instrument is fully inert. */ export declare function rulesAreInert(rules: ArchitectureRules): boolean; export {}; //# sourceMappingURL=rules.d.ts.map