From 6edc39c4ebc6b498bf03c2bc0901814bb4b699bb Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 8 Jun 2026 22:51:43 -0400 Subject: [PATCH] chore(#893): remove dead loadConfig from configuration.cts (#912) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `loadConfig` in configuration.cts was superseded by config-loader.cts (ADR-857 phase 2e, #885). Exhaustive grep confirms no caller imports loadConfig from configuration.cjs — all live callers use config-loader.cjs or the core.cjs back-compat re-export. configuration.cts now provides only the pure normalization and defaults primitives (normalizeLegacyKeys, mergeDefaults, migrateOnDisk, CONFIG_DEFAULTS) that config-loader.cts depends on. Updated CONTEXT.md and docs/INVENTORY.md to reflect the narrowed module surface. Co-authored-by: Claude Opus 4.8 --- ...move-dead-loadconfig-from-configuration.md | 7 +++ CONTEXT.md | 2 +- docs/INVENTORY.md | 2 +- src/configuration.cts | 44 ++----------------- 4 files changed, 13 insertions(+), 42 deletions(-) create mode 100644 .changeset/893-remove-dead-loadconfig-from-configuration.md diff --git a/.changeset/893-remove-dead-loadconfig-from-configuration.md b/.changeset/893-remove-dead-loadconfig-from-configuration.md new file mode 100644 index 000000000..6a4280650 --- /dev/null +++ b/.changeset/893-remove-dead-loadconfig-from-configuration.md @@ -0,0 +1,7 @@ +--- +type: Changed +pr: 893 +--- +Remove dead `loadConfig` export from `configuration.cts` — superseded by `config-loader.cts` (ADR-857 phase 2e, #885). All live callers already import `loadConfig` from `config-loader.cjs` or the `core.cjs` back-compat re-export; exhaustive grep confirms zero callers importing it from `configuration.cjs`. `configuration.cjs` now provides only the pure normalization and defaults primitives (`normalizeLegacyKeys`, `mergeDefaults`, `migrateOnDisk`, `CONFIG_DEFAULTS`) that `config-loader.cjs` depends on. (#893) + + diff --git a/CONTEXT.md b/CONTEXT.md index 607d884d1..a4c408654 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -80,7 +80,7 @@ Module owning dispatch-event creation, redaction, and logger behavior for the Co Module policy that defines query-time behavior when `.planning/config.json` is absent: use built-in defaults for parity-sensitive query Interfaces, and emit parity-aligned empty model ids for pre-project model resolution surfaces. ### Configuration Module -Module owning config load, legacy-key normalization, defaults merge, and explicit on-disk migration for `.planning/config.json`. Interface: `loadConfig(cwd) → MergedConfig` (pure read, never writes disk), `normalizeLegacyKeys(parsed) → { parsed, normalizations[] }` (idempotent, pure, returns the list of normalizations applied), `mergeDefaults(parsed) → MergedConfig` (deep-merge of parsed config over canonical defaults), `migrateOnDisk(cwd) → MigrationReport` (explicit, opt-in, called by the installer and by `gsd-tools migrate-config`). Invariants: never mutates disk inside `loadConfig`; legacy top-level keys (`branching_strategy`, `sub_repos`, `multiRepo`, `depth`) are normalized into their canonical nested locations in the returned value; defaults come from the shared `gsd-core/bin/shared/config-defaults.manifest.json`; schema (`VALID_CONFIG_KEYS`, `RUNTIME_STATE_KEYS`, `DYNAMIC_KEY_PATTERNS`) comes from `gsd-core/bin/shared/config-schema.manifest.json`. Source of truth: `gsd-core/bin/lib/configuration.cjs`, consumed via the thin Adapters at `bin/lib/core.cjs:loadConfig` and `bin/lib/config-schema.cjs`. Eliminates the recurring #3523-class drift bug structurally. +Module owning legacy-key normalization, defaults merge, and explicit on-disk migration for `.planning/config.json`. Interface: `normalizeLegacyKeys(parsed) → { parsed, normalizations[] }` (idempotent, pure, returns the list of normalizations applied), `mergeDefaults(parsed) → MergedConfig` (deep-merge of parsed config over canonical defaults), `migrateOnDisk(cwd) → MigrationReport` (explicit, opt-in, called by the installer and by `gsd-tools migrate-config`). Invariants: legacy top-level keys (`branching_strategy`, `sub_repos`, `multiRepo`, `depth`) are normalized into their canonical nested locations in the returned value; defaults come from the shared `gsd-core/bin/shared/config-defaults.manifest.json`; schema (`VALID_CONFIG_KEYS`, `RUNTIME_STATE_KEYS`, `DYNAMIC_KEY_PATTERNS`) comes from `gsd-core/bin/shared/config-schema.manifest.json`. Note: `loadConfig` (project config read + merge) was extracted to the Config Loader Module (`config-loader.cjs`) per ADR-857 phase 2e (#885); `configuration.cjs` now provides only the pure normalization and defaults primitives that `config-loader.cjs` depends on. Source of truth: `gsd-core/bin/lib/configuration.cjs`, consumed via `bin/lib/config-loader.cjs` and `bin/lib/config-schema.cjs`. Eliminates the recurring #3523-class drift bug structurally. ### Planning Workspace Module Module owning `.planning` path resolution, active workstream pointer policy (`session-scoped > shared`), pointer self-heal behavior, and planning lock semantics for workstream-aware execution. diff --git a/docs/INVENTORY.md b/docs/INVENTORY.md index af2581eef..481e84a93 100644 --- a/docs/INVENTORY.md +++ b/docs/INVENTORY.md @@ -396,7 +396,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`. | `config-schema.cjs` | Single source of truth for `VALID_CONFIG_KEYS` and dynamic key patterns; imported by both the validator and the config-schema-docs parity test | | `config-types.cjs` | TypeScript type definitions for the `model_policy` config block — `ModelPolicyConfig`, `TierEntry`, `RuntimeTiers`; compiled from `src/config-types.cts` at publish time (ADR-457) | | `config.cjs` | `config.json` read/write, section initialization; imports validator from `config-schema.cjs` | -| `configuration.cjs` | Configuration Module — canonical config loading, legacy-key normalization, defaults merge, and explicit on-disk migration; source of truth for both SDK and CJS consumers | +| `configuration.cjs` | Configuration Module — legacy-key normalization, defaults merge, and explicit on-disk migration; pure normalization primitives consumed by `config-loader.cjs` and `config-schema.cjs` (loadConfig extracted to config-loader per ADR-857 #885) | | `context-utilization.cjs` | Pure classifier for `gsd-health --context` — turns (tokensUsed, contextWindow) into a `{ percent, state }` triage result against the 60%/70% fracture-point thresholds (#2792) | | `core-utils.cjs` | Shared low-level utilities — POSIX path normalization, sub-repo/subdirectory scanning, phase file stats, slug/one-liner/plan-id helpers, time-ago (extracted from `core.cjs`, ADR-857) | | `core.cjs` | Shared utilities and runtime fallbacks; compatibility re-exports for planning-workspace and I/O (`io.cjs`) helpers | diff --git a/src/configuration.cts b/src/configuration.cts index 55be605d5..36e5c4268 100644 --- a/src/configuration.cts +++ b/src/configuration.cts @@ -1,6 +1,8 @@ /** - * Configuration Module — single source of truth for config loading, - * legacy-key normalization, defaults merge, and explicit on-disk migration. + * Configuration Module — legacy-key normalization, defaults merge, and explicit + * on-disk migration. Pure normalization primitives consumed by config-loader.cjs + * and config-schema.cjs. `loadConfig` was extracted to config-loader.cjs per + * ADR-857 phase 2e (#885) and removed from this module per #893. * * ADR-457 build-at-publish: the hand-written bin/lib/configuration.cjs collapsed * to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour @@ -132,11 +134,6 @@ interface NormalizeLegacyKeysResult { normalizations: Normalization[]; } -interface LoadConfigOptions { - workstream?: string; - onNormalizations?: (normalizations: Normalization[]) => void; -} - interface MigrateOnDiskResult { migrated: boolean; normalizations: Normalization[]; @@ -197,38 +194,6 @@ function mergeDefaults(parsed: Record): Record return deepMergeConfig(defaults, parsed); } -function loadConfig(cwd: string, options?: LoadConfigOptions): Record { - const configPath = join(planningDir(cwd, options?.workstream), 'config.json'); - let raw: string; - try { - raw = readFileSync(configPath, 'utf-8'); - } - catch { - // File missing — return defaults - return mergeDefaults({}); - } - const trimmed = raw.trim(); - if (trimmed === '') { - return mergeDefaults({}); - } - let parsed: unknown; - try { - parsed = JSON.parse(trimmed); - } - catch (err) { - const msg = err instanceof Error ? err.message : String(err); - throw new Error(`Failed to parse config at ${configPath}: ${msg}`); - } - if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { - throw new Error(`Config at ${configPath} must be a JSON object`); - } - const { parsed: normalized, normalizations } = normalizeLegacyKeys(parsed as Record); - if (options?.onNormalizations && normalizations.length > 0) { - options.onNormalizations(normalizations); - } - return mergeDefaults(normalized); -} - function migrateOnDisk(cwd: string, workstream?: string): MigrateOnDiskResult { const configPath = join(planningDir(cwd, workstream), 'config.json'); let raw: string; @@ -277,7 +242,6 @@ function migrateOnDisk(cwd: string, workstream?: string): MigrateOnDiskResult { } export { - loadConfig, normalizeLegacyKeys, mergeDefaults, migrateOnDisk,