Pre-submission checklist
Bug Description
Summary
In core/pipeline/deps.ts, attachSkillSubscriber is wired with llm: bgLlm (the main model), never bgReflectLlm (the dedicated client built from the skillEvolver config block). As a result the skill subscriber's LLM-backed work (crystallization evaluation, evolution) always runs on the main model regardless of skillEvolver.* config, and skillEvolver.lastOkAt never updates because the dedicated client is never invoked.
Root cause
// deps.ts, attachSkillSubscriber call
const skillHandle = attachSkillSubscriber({
repos: deps.repos,
embedder: bgEmbedder,
llm: bgLlm, // ← BUG: should be bgReflectLlm
bus: buses.skill,
l2Bus: buses.l2,
rewardBus: buses.reward,
log: log.child({ channel: "core.skill" }),
config: algorithm.skill,
...
});
bgReflectLlm is constructed earlier in the same file specifically from the skillEvolver config block, but is only read for metadata (health/overview endpoint), never passed into the skill subscriber itself.
Verified via git log -L on this call site: it has never been wired to bgReflectLlm since the v2.0 Reflect2Evolve rewrite (60b97444) — this is not a regression, it's never worked.
Relation to #2148
This is a distinct instance of the same wiring-bug class fixed in #2148 (PR #2151) — that issue was about captureRunner's reflectLlm slot getting the wrong client (skill-evolver client where main llm was needed). This issue is the opposite direction: the skill subscriber never gets the dedicated skillEvolver client it's supposed to have. Different call site, not fixed by #2151.
Impact
- Operators configuring a distinct
skillEvolver.* model (e.g. to isolate skill-evolution cost/quality from the main model) get silently ignored — the main llm handles it instead.
skillEvolver.lastOkAt in the overview/health endpoint reads null indefinitely on any install that relies on it as a liveness signal for skill evolution, even when skill evolution is running fine (just on the wrong model).
Suggested Fix
const skillHandle = attachSkillSubscriber({
...
llm: bgReflectLlm ?? bgLlm,
...
});
Pre-submission checklist
Bug Description
Summary
In
core/pipeline/deps.ts,attachSkillSubscriberis wired withllm: bgLlm(the main model), neverbgReflectLlm(the dedicated client built from theskillEvolverconfig block). As a result the skill subscriber's LLM-backed work (crystallization evaluation, evolution) always runs on the main model regardless ofskillEvolver.*config, andskillEvolver.lastOkAtnever updates because the dedicated client is never invoked.Root cause
bgReflectLlmis constructed earlier in the same file specifically from theskillEvolverconfig block, but is only read for metadata (health/overview endpoint), never passed into the skill subscriber itself.Verified via
git log -Lon this call site: it has never been wired tobgReflectLlmsince the v2.0 Reflect2Evolve rewrite (60b97444) — this is not a regression, it's never worked.Relation to #2148
This is a distinct instance of the same wiring-bug class fixed in #2148 (PR #2151) — that issue was about
captureRunner'sreflectLlmslot getting the wrong client (skill-evolver client where main llm was needed). This issue is the opposite direction: the skill subscriber never gets the dedicatedskillEvolverclient it's supposed to have. Different call site, not fixed by #2151.Impact
skillEvolver.*model (e.g. to isolate skill-evolution cost/quality from the main model) get silently ignored — the mainllmhandles it instead.skillEvolver.lastOkAtin the overview/health endpoint readsnullindefinitely on any install that relies on it as a liveness signal for skill evolution, even when skill evolution is running fine (just on the wrong model).Suggested Fix