From 8f25ce32e16aad23982f815f1e2b48027a7242b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 16 Jun 2026 16:12:48 +0300 Subject: [PATCH] =?UTF-8?q?feat(round-memory):=20recordArtifact=20?= =?UTF-8?q?=E2=80=94=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=81=D0=B8=D0=B8=20+=20=D0=B4=D0=BE=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D0=BE=D0=B2=20M/J=20(SP2c-1=20helper)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- tools/round-memory-record.mjs | 22 ++++++++++++++++++ tools/round-memory-record.test.mjs | 37 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tools/round-memory-record.mjs create mode 100644 tools/round-memory-record.test.mjs diff --git a/tools/round-memory-record.mjs b/tools/round-memory-record.mjs new file mode 100644 index 0000000..97f63c0 --- /dev/null +++ b/tools/round-memory-record.mjs @@ -0,0 +1,22 @@ +#!/usr/bin/env node +/** round-memory-record — orchestration-помощник записи памяти кругов (SP2c-1). + * Цель — минимизировать врезки в discipline-source: одна точка пишет снимок версии артефакта + * и доводы контроллера последнего круга «## Переговоры» по дорожкам M/J. Объекция стороны + * (NO-GO) пишется отдельным вызовом recordObjection прямо из стора. Fail-quiet. */ +import { recordVersion, recordArg } from './round-memory-store.mjs'; +import { parseNegotiationSection } from './negotiation-section.mjs'; + +/** На запись артефакта: снимок версии + доводы ПОСЛЕДНЕГО круга по дорожкам M/J. + * Пустые доводы не пишутся. Любая ошибка → no-op (false), не кидает. */ +export function recordArtifact(taskId, stage, content, baseDir) { + try { + recordVersion(taskId, stage, content, baseDir); + const rounds = parseNegotiationSection(content); + const last = rounds[rounds.length - 1]; + if (last) { + if (last.mentor) recordArg(taskId, stage, 'M', last.mentor, baseDir); + if (last.judge) recordArg(taskId, stage, 'J', last.judge, baseDir); + } + return true; + } catch { return false; } +} diff --git a/tools/round-memory-record.test.mjs b/tools/round-memory-record.test.mjs new file mode 100644 index 0000000..a014344 --- /dev/null +++ b/tools/round-memory-record.test.mjs @@ -0,0 +1,37 @@ +import { describe, it, expect } from 'vitest'; +import { mkdtempSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { recordArtifact } from './round-memory-record.mjs'; +import { getVersions, getArgs } from './round-memory-store.mjs'; + +const dir = () => mkdtempSync(join(tmpdir(), 'rmrec-')); + +describe('recordArtifact', () => { + it('пишет версию артефакта', () => { + const d = dir(); + recordArtifact('t1', 'plan', '# План\nтело', d); + expect(getVersions('t1', 'plan', d)).toEqual(['# План\nтело']); + }); + it('пишет доводы последнего круга по дорожкам M/J', () => { + const d = dir(); + const content = `# План +## Переговоры +### Круг 1 +**Наставнику:** довод M +**Судье:** довод J +## Шаги`; + recordArtifact('t1', 'plan', content, d); + expect(getArgs('t1', 'plan', 'M', d)).toEqual(['довод M']); + expect(getArgs('t1', 'plan', 'J', d)).toEqual(['довод J']); + }); + it('нет переговоров → версия есть, доводов нет', () => { + const d = dir(); + recordArtifact('t1', 'spec', '# Спека', d); + expect(getVersions('t1', 'spec', d)).toEqual(['# Спека']); + expect(getArgs('t1', 'spec', 'M', d)).toEqual([]); + }); + it('fail-quiet на мусоре не кидает', () => { + expect(() => recordArtifact('t1', 'plan', null, '\0bad')).not.toThrow(); + }); +});