feat: round-memory загрузка roundMemory M-side в хуке наставника SP2c-2 инкремент 2b
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,9 @@ import { bumpMentorNoGo, MENTOR_ESCALATE_AFTER } from './mentor-nogo-counter.mjs
|
||||
import { buildMentorGo, persistMentorGo } from './mentor-go-store.mjs';
|
||||
import { classifyJudgeOutcome } from './verdict-outcome-line.mjs';
|
||||
import { pushVerdict } from './verdict-surface-store.mjs';
|
||||
// SP2c-2: загрузчик памяти кругов M-side (свои замечания + M-доводы + diff + замечание судьи
|
||||
// при возврате) — инъектируется в runMentorOnPlanWrite, протягивается до построителя вердикта.
|
||||
import { buildRoundMemory } from './round-memory-store.mjs';
|
||||
|
||||
/**
|
||||
* Волна 7 (§6): сообщение арбитража при 3 NO-GO наставника — дословное замечание +
|
||||
@@ -101,11 +104,13 @@ export function buildLlmCall({ apiKey, model = CLASSIFIER_MODEL, transport = cal
|
||||
* Чистый производитель: inert → {ran:false}; не план-Write → {ran:false}; план без
|
||||
* steps-json → {ran:false, reason} (вердикт НЕ фабрикуется — печать всё равно fail-CLOSE
|
||||
* у судьи [enforce-judge-gate.mjs:79]); иначе onPlanWrite + персист. ВСЕ deps инъектируются.
|
||||
* roundMemoryImpl (SP2c-2): загрузчик памяти кругов M-side ({stage,content,taskId}→roundMemory);
|
||||
* null → круг слеп (память пуста, backward-compat).
|
||||
*/
|
||||
export async function runMentorOnPlanWrite(event, {
|
||||
mentorActiveImpl, llmCall, loadJournalImpl, persistJournalImpl, persistVerdictImpl,
|
||||
loadTaskIdImpl, persistTaskIdImpl, journalKey, graphSectionImpl, nowMs = null,
|
||||
classifyImpl = null, registryImpl = null,
|
||||
classifyImpl = null, registryImpl = null, roundMemoryImpl = null,
|
||||
} = {}) {
|
||||
if (!mentorActiveImpl()) return { ran: false, reason: 'mentor inert ($0)' };
|
||||
const tool = event && event.tool_name;
|
||||
@@ -126,6 +131,8 @@ export async function runMentorOnPlanWrite(event, {
|
||||
let graphSectionS = null;
|
||||
try { graphSectionS = graphSectionImpl(); } catch { graphSectionS = null; }
|
||||
const verifiedContextS = parseVerifiedContext(content);
|
||||
// SP2c-2: память кругов M-side спеки (свои замечания + M-доводы + diff + замечание судьи).
|
||||
const roundMemoryS = roundMemoryImpl ? roundMemoryImpl({ stage: 'spec', content, taskId: taskIdForPromptS }) : {};
|
||||
const rs = await onSpecWrite({
|
||||
specContent: content,
|
||||
specHash,
|
||||
@@ -138,6 +145,7 @@ export async function runMentorOnPlanWrite(event, {
|
||||
verifiedContext: verifiedContextS,
|
||||
negotiationLog: negotiationLogS,
|
||||
graphSection: graphSectionS,
|
||||
roundMemory: roundMemoryS,
|
||||
});
|
||||
try { persistVerdictImpl({ ok: rs.ok, wired: rs.wired, reason: rs.reason ?? null, planHash: specHash, verdict: rs.verdict }); } catch { /* best-effort */ }
|
||||
if (rs.journalOk && rs.journal) { try { persistJournalImpl(rs.journal); } catch { /* best-effort (SE10) */ } }
|
||||
@@ -165,6 +173,8 @@ export async function runMentorOnPlanWrite(event, {
|
||||
const planGoal = extractPlanGoal(content);
|
||||
let registry = null;
|
||||
try { registry = typeof registryImpl === 'function' ? registryImpl() : null; } catch { registry = null; }
|
||||
// SP2c-2: память кругов M-side плана (свои замечания + M-доводы + diff + замечание судьи).
|
||||
const roundMemoryP = roundMemoryImpl ? roundMemoryImpl({ stage: 'plan', content, taskId: taskIdForPrompt }) : {};
|
||||
const r = await onPlanWrite({
|
||||
planSteps: steps,
|
||||
existingTaskId: loadTaskIdImpl(),
|
||||
@@ -180,6 +190,7 @@ export async function runMentorOnPlanWrite(event, {
|
||||
registry,
|
||||
declaredSkills,
|
||||
planGoal,
|
||||
roundMemory: roundMemoryP,
|
||||
});
|
||||
const planHash = planId(steps);
|
||||
try { persistVerdictImpl({ ok: r.ok, wired: r.wired, reason: r.reason ?? null, planHash, verdict: r.verdict }); } catch { /* best-effort */ }
|
||||
@@ -211,6 +222,9 @@ async function main() {
|
||||
// ключ/транспорт; сбой ловит onPlanWrite → fail-safe (план без скил-сверки, §5).
|
||||
classifyImpl: async (goal, registry) => classify(goal, registry, { skipPrefilter: true }),
|
||||
registryImpl: () => { try { return loadRegistry({ useCache: false }); } catch { return null; } },
|
||||
// SP2c-2: реальный загрузчик памяти кругов M-side из стора (fail-quiet внутри
|
||||
// buildRoundMemory). baseDir = runtime; side='mentor' → M-дорожка + замечание судьи при возврате.
|
||||
roundMemoryImpl: ({ stage, content, taskId }) => buildRoundMemory({ taskId, stage, side: 'mentor', currentContent: content, baseDir: dir }),
|
||||
});
|
||||
if (res && res.ran) {
|
||||
// SP1: громкая видимость вердикта наставника (best-effort, fail-quiet).
|
||||
|
||||
@@ -116,6 +116,29 @@ describe('runMentorOnPlanWrite (обёртка-производитель W7)',
|
||||
expect(r.ran).toBe(true);
|
||||
expect(classifyCalled).toBe(true);
|
||||
});
|
||||
|
||||
// SP2c-2: хук грузит память кругов M-side через roundMemoryImpl и протягивает её до
|
||||
// построителя вердикта наставника (план и спека). stage прокидывается верно.
|
||||
it('SP2c-2: roundMemoryImpl (план) → память доходит до промпта наставника', async () => {
|
||||
let capturedUser = null;
|
||||
const d = deps({
|
||||
roundMemoryImpl: ({ stage }) => ({ objections: [`память дорожки ${stage}`] }),
|
||||
llmCall: async ({ buildPrompt }) => { capturedUser = buildPrompt().user; return GOOD_VERDICT; },
|
||||
});
|
||||
const r = await runMentorOnPlanWrite(planEvent, d);
|
||||
expect(r.ran).toBe(true);
|
||||
expect(capturedUser).toContain('память дорожки plan');
|
||||
});
|
||||
it('SP2c-2: roundMemoryImpl (спека) → stage=spec в памяти промпта', async () => {
|
||||
let capturedUser = null;
|
||||
const d = deps({
|
||||
roundMemoryImpl: ({ stage }) => ({ objections: [`память дорожки ${stage}`] }),
|
||||
llmCall: async ({ buildPrompt }) => { capturedUser = buildPrompt().user; return GOOD_VERDICT; },
|
||||
});
|
||||
const r = await runMentorOnPlanWrite(specEvent, d);
|
||||
expect(r.ran).toBe(true);
|
||||
expect(capturedUser).toContain('память дорожки spec');
|
||||
});
|
||||
});
|
||||
|
||||
describe('decideMentorObjection (Фаза 1 — канал замечаний наставника контроллеру)', () => {
|
||||
|
||||
Reference in New Issue
Block a user