mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-17 13:45:34 +02:00
perf(context): load the registry once per resolution and routing index build
compileContextProfile now validates its options, loads the registry and calls compileContextPlan(registry, options), which compiles against a registry the caller loaded in the same call. resolveTaskContext and routingEntries load the registry once and compile from it, so the sources are hashed once per call instead of twice. On this repository (full@1, Windows 11, median of 5): resolveTaskContext 1332 ms -> 645 ms, routingEntries 1321 ms -> 721 ms. The registry never comes from outside the call: nothing caches it or accepts one from a caller, so a stale or forged registry cannot be passed in. The two "Registry changed during ..." checks compared the two loads and are gone with the second load; each call now works from one snapshot, and skill bytes are still verified against it when read. compileContextProfile keeps its signature, output and error order. Split out of #2945, whose prompt hook is superseded by #3453.
This commit is contained in:
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user