diff --git a/scripts/lib/context-profiles.js b/scripts/lib/context-profiles.js index de80d1142..57a0db2c3 100644 --- a/scripts/lib/context-profiles.js +++ b/scripts/lib/context-profiles.js @@ -86,13 +86,26 @@ function estimateMetadata(entries, target, profile) { }; } -function compileContextProfile({ +function validatePlanOptions({ selectionMode = 'manual', target = 'codex' }) { + validateTarget(target); + if (!MODES.includes(selectionMode)) throw new Error(`Unknown selection mode: ${selectionMode}`); +} + +function compileContextProfile(options = {}) { + validatePlanOptions(options); + return compileContextPlan(loadContextRegistry({ repoRoot: options.repoRoot || DEFAULT_REPO_ROOT }), options); +} + +/** + * Compile a plan against a registry the caller loaded in the same call, so a + * caller that also needs the registry hashes its sources once. Callers pass + * the result of `loadContextRegistry` directly; nothing keeps one across calls. + */ +function compileContextPlan(registry, { repoRoot = DEFAULT_REPO_ROOT, profileId = 'lean@1', selectionMode = 'manual', target = 'codex', include = [], exclude = [], } = {}) { - validateTarget(target); - if (!MODES.includes(selectionMode)) throw new Error(`Unknown selection mode: ${selectionMode}`); - const registry = loadContextRegistry({ repoRoot }); + validatePlanOptions({ selectionMode, target }); const profile = loadContextProfile(profileId, { repoRoot }); if (profile.registryId !== registry.id) throw new Error('Profile registry ID mismatch'); const selected = resolveSelection(registry, profile, include, exclude); @@ -130,4 +143,4 @@ function compileContextProfile({ return plan; } -module.exports = { compileContextProfile, explainContextEntry, loadContextProfile }; +module.exports = { compileContextProfile, compileContextPlan, explainContextEntry, loadContextProfile }; diff --git a/scripts/lib/context-selection.js b/scripts/lib/context-selection.js index 5a642d455..eeef1d406 100644 --- a/scripts/lib/context-selection.js +++ b/scripts/lib/context-selection.js @@ -2,7 +2,7 @@ const yaml = require('js-yaml'); const { loadContextRegistry, loadSkillTriggers } = require('./context-pack-registry'); -const { compileContextProfile } = require('./context-profiles'); +const { compileContextPlan } = require('./context-profiles'); const { buildRetrievalIndex, searchRetrieval } = require('./context-retrieval'); const { DEFAULT_REPO_ROOT, createSourceReader, digestObject } = require('./context-profile-support'); @@ -310,10 +310,10 @@ function admissibility(byId, excluded, reader) { * without explicit selection. Metadata only; bodies are never returned. */ function routingEntries({ repoRoot = DEFAULT_REPO_ROOT, profileId = 'lean@1', target = 'codex', selectionMode = 'auto', include = [], exclude = [] } = {}) { - const plan = compileContextProfile({ repoRoot, profileId, target, selectionMode, include, exclude }); + // One registry load serves the plan and the routing entries. const registry = loadContextRegistry({ repoRoot }); + const plan = compileContextPlan(registry, { repoRoot, profileId, target, selectionMode, include, exclude }); const { triggers } = loadSkillTriggers({ repoRoot }); - if (registry.registryDigest !== plan.registryDigest) throw new Error('Registry changed during routing index build'); const byId = new Map(registry.entries.map(entry => [entry.id, entry])); const excluded = new Set(plan.excludedIds); const admissible = admissibility(byId, excluded, createSourceReader(repoRoot)); @@ -335,10 +335,11 @@ function resolveTaskContext({ repoRoot = DEFAULT_REPO_ROOT, task, profileId = 'l selectionMode = 'auto', include = [], exclude = [], load = false, previous = null, expectedDigest = null } = {}) { validateTask(task); validatePrevious(previous); - const plan = compileContextProfile({ repoRoot, profileId, target, selectionMode, include, exclude }); + // One registry load serves the plan and the selection; skill bytes are + // still verified against it when they are read. const registry = loadContextRegistry({ repoRoot }); + const plan = compileContextPlan(registry, { repoRoot, profileId, target, selectionMode, include, exclude }); const { triggers } = loadSkillTriggers({ repoRoot }); - if (registry.registryDigest !== plan.registryDigest) throw new Error('Registry changed during task selection'); const reader = createSourceReader(repoRoot); const byId = new Map(registry.entries.map(entry => [entry.id, entry])); const excluded = new Set(plan.excludedIds);