feat(router): пининг совета роутера по goalHash (переписка шагов не зовёт LLM заново)
Новый router-pin-store: пин совета роутера по (task_id, goalHash) пер-сессионно. on-plan-write пин-aware: пин-попадание по неизменной цели → совет переиспользуется, classifyImpl НЕ зовётся; промах/смена цели → classify + сохранение пина. Проводка в активный наставник-хук инъекцией реального стора с sessionId (инъекция-выкл по умолчанию, старое поведение/тесты целы). Хвост спеки роутера §4 (пининг по goalHash), эпик роутер-реестр этап 3, item 2. Граница не тронута (recommended_chain, цепочки, observer-stop-hook, owner-seal). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,38 @@ describe('onPlanWrite возвращает результат роутера н
|
||||
});
|
||||
});
|
||||
|
||||
describe('пининг роутера по goalHash (D2)', () => {
|
||||
it('пин-попадание → classifyImpl НЕ зовётся, routerClassification = пин', async () => {
|
||||
let called = false;
|
||||
const r = await onPlanWrite({
|
||||
planSteps: STEPS, llmCall: llmOk, journalKey: 'k', nowMs: 1, planGoal: 'g',
|
||||
classifyImpl: async () => { called = true; return { recommended_chain: ['fresh'] }; },
|
||||
pinLoadImpl: () => ({ recommended_chain: ['pinned'] }),
|
||||
});
|
||||
expect(called).toBe(false);
|
||||
expect(r.routerClassification).toEqual({ recommended_chain: ['pinned'] });
|
||||
});
|
||||
it('промах пина → classifyImpl зовётся и pinSaveImpl получает результат', async () => {
|
||||
let saved = null;
|
||||
const r = await onPlanWrite({
|
||||
planSteps: STEPS, llmCall: llmOk, journalKey: 'k', nowMs: 1, planGoal: 'g',
|
||||
classifyImpl: async () => ({ recommended_chain: ['fresh'] }),
|
||||
pinLoadImpl: () => null,
|
||||
pinSaveImpl: (rec) => { saved = rec; },
|
||||
});
|
||||
expect(r.routerClassification).toEqual({ recommended_chain: ['fresh'] });
|
||||
expect(saved && saved.classification).toEqual({ recommended_chain: ['fresh'] });
|
||||
});
|
||||
it('без пин-имплов → classifyImpl зовётся (старое поведение)', async () => {
|
||||
let called = false;
|
||||
await onPlanWrite({
|
||||
planSteps: STEPS, llmCall: llmOk, journalKey: 'k', nowMs: 1, planGoal: 'g',
|
||||
classifyImpl: async () => { called = true; return { recommended_chain: ['x'] }; },
|
||||
});
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('оркестратор протягивает roundMemory до построителя (SP2c-2)', () => {
|
||||
it('onPlanWrite → roundMemory доходит до промпта вердикта', async () => {
|
||||
let capturedUser = null;
|
||||
|
||||
Reference in New Issue
Block a user