feat: round-memory buildRoundMemory загрузка памяти кругов SP2c-2 инкремент 1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-16 16:54:39 +03:00
parent 0b19c86fed
commit 3fb98fa51c
2 changed files with 60 additions and 0 deletions
+22
View File
@@ -77,3 +77,25 @@ export function clearRoundMemory(taskId, baseDir) {
return true;
} catch { return false; }
}
/** SP2c-2: собрать память кругов для построителя промпта (судья J-side / наставник M-side).
* side='judge' → дорожка J, свои judge-замечания, БЕЗ замечания-при-возврате (судья холодный);
* side='mentor' → дорожка M, свои mentor-замечания + ПОСЛЕДНЕЕ замечание судьи (при возврате).
* versionDiff = diff(последняя сохранённая версия, текущая); пусто пока прошлой версии нет
* (круг 1 слеп). Fail-quiet → пустая память. */
export function buildRoundMemory({ taskId, stage, side, currentContent = '', baseDir } = {}) {
try {
const track = side === 'judge' ? 'J' : 'M';
const versions = getVersions(taskId, stage, baseDir);
const prev = versions.length ? versions[versions.length - 1] : null;
const versionDiff = prev != null ? diffLines(prev, String(currentContent ?? '')) : '';
const objections = getObjections(taskId, stage, side, baseDir);
const args = getArgs(taskId, stage, track, baseDir);
let judgeObjectionOnReturn = '';
if (side === 'mentor') {
const jo = getObjections(taskId, stage, 'judge', baseDir);
if (jo.length) judgeObjectionOnReturn = jo[jo.length - 1];
}
return { objections, args, versionDiff, judgeObjectionOnReturn };
} catch { return { objections: [], args: [], versionDiff: '', judgeObjectionOnReturn: '' }; }
}
+38
View File
@@ -6,6 +6,7 @@ import {
recordVersion, getVersions, diffVersions,
recordObjection, getObjections,
recordArg, getArgs, clearRoundMemory,
buildRoundMemory,
} from './round-memory-store.mjs';
const dir = () => mkdtempSync(join(tmpdir(), 'rmem-'));
@@ -56,3 +57,40 @@ describe('round-memory-store', () => {
expect(getVersions('t1', 'spec', '\0bad')).toEqual([]);
});
});
describe('buildRoundMemory (SP2c-2)', () => {
it('круг 1 слеп: нет версий → versionDiff пуст, объекции/доводы пусты', () => {
const d = dir();
const m = buildRoundMemory({ taskId: 't1', stage: 'plan', side: 'judge', currentContent: 'v1', baseDir: d });
expect(m).toEqual({ objections: [], args: [], versionDiff: '', judgeObjectionOnReturn: '' });
});
it('judge: только J-дорожка + свои judge-замечания + diff против текущей, без замечания-при-возврате', () => {
const d = dir();
recordVersion('t1', 'plan', 'строка1\nстрока2', d);
recordObjection('t1', 'plan', 'judge', 'замечание судьи 1', d);
recordObjection('t1', 'plan', 'mentor', 'замечание наставника', d);
recordArg('t1', 'plan', 'J', 'довод судье', d);
recordArg('t1', 'plan', 'M', 'довод наставнику', d);
const m = buildRoundMemory({ taskId: 't1', stage: 'plan', side: 'judge', currentContent: 'строка1\nстрока2-изм', baseDir: d });
expect(m.objections).toEqual(['замечание судьи 1']);
expect(m.args).toEqual(['довод судье']);
expect(m.versionDiff).toContain('строка2');
expect(m.judgeObjectionOnReturn).toBe('');
});
it('mentor: M-дорожка + свои mentor-замечания + ПОСЛЕДНЕЕ замечание судьи', () => {
const d = dir();
recordVersion('t1', 'spec', 'тело', d);
recordObjection('t1', 'spec', 'mentor', 'замечание наставника 1', d);
recordObjection('t1', 'spec', 'judge', 'замечание судьи A', d);
recordObjection('t1', 'spec', 'judge', 'замечание судьи B', d);
recordArg('t1', 'spec', 'M', 'довод наставнику', d);
const m = buildRoundMemory({ taskId: 't1', stage: 'spec', side: 'mentor', currentContent: 'тело2', baseDir: d });
expect(m.objections).toEqual(['замечание наставника 1']);
expect(m.args).toEqual(['довод наставнику']);
expect(m.judgeObjectionOnReturn).toBe('замечание судьи B');
});
it('fail-quiet на битом baseDir → пустая память', () => {
const m = buildRoundMemory({ taskId: 't1', stage: 'plan', side: 'judge', currentContent: 'x', baseDir: '\0bad' });
expect(m).toEqual({ objections: [], args: [], versionDiff: '', judgeObjectionOnReturn: '' });
});
});