/** * The `compliance:` section of `.aidlc/config.yaml`. * * Owns one section and nothing else. There is no central config loader in this * codebase — ten call sites each join the path and parse it inline — and unifying * them is out of scope here, so this module is deliberately narrow rather than an * eleventh ad-hoc parse pretending to be general. * * The record shape exists to answer three questions no other state can: * * - **Is this layer locally edited?** By comparing the on-disk hash against the * hash recorded *at install*. Comparing against the currently bundled body — * what the framework path does, correctly, for its own layers — would make every * installed layer read as edited the moment pack content is updated upstream, so * `remove` would refuse to delete anything and corrected control text would never * land. * - **Which instances does a report cover?** By comparing each instance's * completion moment against `installed_at`. A pack cannot evidence a change that * predates it. * - **Is an installed pack stale?** By comparing `version` against the resolvable * one. Reported, never silently upgraded. * * Requirements: compliance-packs/AC-70, AC-71 */ import type { ModifiedDetector } from '../compile/layer-install.js'; /** One installed file, with the hash it had when it was written. */ export interface InstalledFile { /** Filename within `.aidlc/guidance/`, as registered. */ path: string; /** Hex sha256 of the bytes written at install. */ sha256: string; } /** One installed pack, as recorded in the project config. */ export interface InstalledPack { id: string; /** Pack content version at the time of install. */ version: string; /** ISO 8601 UTC. Bounds the report's default scope. */ installed_at: string; files: InstalledFile[]; } /** The `compliance:` section. */ export interface ComplianceConfig { /** * Whether a critical control finding blocks a phase transition. * * Governs transitions only. The diff check takes `--enforce` per invocation, so * a team can have a failing continuous-integration check without also blocking * every local phase transition. */ enforce: boolean; packs: InstalledPack[]; } /** The empty state: no packs, no enforcement. Distinct from "no section at all". */ export declare const EMPTY_COMPLIANCE: ComplianceConfig; /** Hex sha256 of a string, as written to disk. */ export declare function hashContent(content: string): string; /** * Read the `compliance:` section. * * A malformed section reads as empty rather than throwing, because every consumer * of this — the gate criterion, the report, the check — must degrade to "no packs * installed" rather than break an unrelated command. A malformed section is * reported by `aidlc doctor`, which is where a repair belongs. */ export declare function readComplianceConfig(projectRoot: string): ComplianceConfig; /** * Whether the `compliance:` section is absent, readable, or present-but-broken. * * `readComplianceConfig` collapses the last two into "no packs installed", which is * right for every consumer that only wants to know what governs the project — and * dangerous for the one consumer that acts on the *absence* of a record. `doctor`'s * unowned-registration check drops an index entry precisely because no installed pack * claims its file; if a pack record silently failed to narrow, the check would read a * live pack as uninstalled and deregister a layer that is still governing the project. * * So the distinction lives here rather than in the migration: this module already owns * every rule about what a well-formed record looks like, and a second implementation of * those rules in `doctor/` would drift from this one the first time a field is added. * * `malformed` deliberately includes a *partially* readable section. One unnarrowable * element among five means the list is no longer a complete account of what is * installed, and completeness is the only property the caller needs. */ export declare function complianceSectionState(projectRoot: string): 'absent' | 'ok' | 'malformed'; /** * Write the `compliance:` section, leaving every other section untouched. * * The whole document is read, one key is replaced, and the document is written * back — so a hand-added section survives, the same guarantee `computeSetup` gives * for the sections it does not own. */ export declare function writeComplianceConfig(projectRoot: string, config: ComplianceConfig): void; /** The record for one installed pack, or null when it is not installed. */ export declare function findInstalledPack(config: ComplianceConfig, id: string): InstalledPack | null; /** * A modified-detector that compares against the hash recorded at install. * * This is the pack rule, and it is the reason `installLayers` takes the detector * as a parameter rather than hard-coding one. `bundledBodyDiffers` answers "does * this differ from what we ship *now*", which for a pack conflates "the user * edited it" with "we published a new version". * * A file with no recorded hash counts as modified: we have no evidence we wrote * it, so it is not ours to delete. */ export declare function recordedHashDiffers(pack: InstalledPack | null, guidanceDir: string): ModifiedDetector; /** True when the pack is installed and its recorded version differs from `available`. */ export declare function isStale(pack: InstalledPack | null, available: string): boolean; //# sourceMappingURL=config.d.ts.map