/** * Deterministic schema validation for `.openlore/config.json` * (change: add-config-schema-validation). * * `readOpenLoreConfig` parses the file with a bare `JSON.parse(...) as OpenLoreConfig` * — a type *assertion* checked by nothing at runtime. A typo'd key (`pancResponse`, * `embeding`) is silently dropped and the default wins, so the user believes a feature * is configured when it is not. This module closes that gap the way the rest of the * substrate already does (the decision store validates on load, the index attests * integrity): a shallow, allocation-light, dependency-free validator that DISCLOSES * unknown keys, type mismatches, and version skew — never a hard failure, and never a * behavior change for a currently-valid config. * * Two honesty invariants: * - Forward-compatible: an unknown key (including one written by a *newer* OpenLore) is * disclosed and then ignored, so a newer config under an older openlore degrades * gracefully rather than crashing. * - Bound to the type: {@link CONFIG_FIELD_KINDS} is `Record`, * so adding a field to `OpenLoreConfig` without a validator entry fails the build; a * completeness test names any residual drift. */ import type { OpenLoreConfig } from '../../types/index.js'; /** The current config-schema version stamped into `.openlore/config.json`. */ export declare const CONFIG_SCHEMA_VERSION = "1.0.0"; /** * Top-level value shapes the validator checks. Deliberately shallow — validation runs * on every read of a ~45-caller hub, so it stays allocation-light and does not recurse * into nested objects (a mistyped nested field is out of scope, disclosed as such). */ export type ConfigFieldKind = 'string' | 'string-or-null' | 'object'; /** * The known keys of `OpenLoreConfig` and the shape each holds. Typed as * `Record` so a field added to the interface without an entry * here fails `tsc` (and CI); {@link config-schema.test.ts} binds it at runtime too. */ export declare const CONFIG_FIELD_KINDS: Record; /** The known top-level config keys, derived from the type-bound field map. */ export declare const KNOWN_CONFIG_KEYS: readonly string[]; /** * A registered non-additive config-schema change: reading a config stamped *before* * `since` should disclose that `fields` need attention (rename/removal). Empty today — * the schema has only ever grown with optional, forward- and backward-compatible fields, * so no older config is misread. An entry is added here (and {@link CONFIG_SCHEMA_VERSION} * bumped) only when a breaking shape change lands. */ export interface ConfigMigration { /** The version at which the breaking change landed (semver). */ since: string; /** The affected fields, for the recovery message. */ fields: string[]; /** Human recovery guidance. */ note: string; } export declare const CONFIG_MIGRATIONS: readonly ConfigMigration[]; /** A single deterministic finding from validating a config object. */ export interface ConfigValidationFinding { kind: 'unknown-key' | 'type-mismatch' | 'version-older' | 'version-newer'; /** The offending key, when the finding is about one. */ key?: string; /** Human-readable message. */ message: string; /** For unknown-key: the closest known key within the edit-distance bound, if any. */ suggestion?: string; } /** * Check the `version` stamp against the running schema version. A newer stamp is * disclosed (unknown content is handled by the unknown-key path); an older stamp is * reported only when a registered {@link ConfigMigration} affects the (stamp, current] * range — a purely additive gap stays silent because the config is still forward- and * backward-compatible. Never a hard failure. Exported so the pure version logic is * testable with an injected current version / migration set. */ export declare function checkConfigVersion(stamp: unknown, opts?: { current?: string; migrations?: readonly ConfigMigration[]; }): ConfigValidationFinding[]; /** * Validate a parsed config object against the type-derived schema. Pure and * deterministic: returns findings ordered as unknown-keys (in file order), then * type-mismatches, then version skew. Never throws, never mutates, never a hard failure. * A non-object input yields no findings (the JSON parse already reported a syntax error). */ export declare function validateOpenLoreConfig(parsed: unknown, opts?: { current?: string; migrations?: readonly ConfigMigration[]; }): ConfigValidationFinding[]; //# sourceMappingURL=config-schema.d.ts.map