fix(secretary): срез впечённой метки «[зачёркнуто]» из текста записей
Модель копировала служебный префикс «[зачёркнуто] » (которым запрос помечает зачёркнутые строки) в поле text, и он компаундился ([зачёркнуто] [зачёркнуто] …), плодя марочные клоны. canonicalClauses теперь срезает ведущий маркер перед сборкой канона: метка не персистится, клоны сливаются с чистой записью (ходы объединяются). Только ведущий наш маркер — реальный текст с него не начинается. Дедуп/История/провенанс/Шаги не тронуты. Свод секретаря 113/113. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,7 +92,11 @@ function allTexts(p) {
|
||||
|
||||
/** Куски записи без дословных повторов: split(' — ') от «text — why», dedup по первому вхождению. */
|
||||
function canonicalClauses(text, why) {
|
||||
const raw = (why != null && String(why).trim() !== '') ? `${text}${SEP}${why}` : String(text || '');
|
||||
// Срез служебной метки зачёркивания, впечённой моделью в текст (запрос рисует «[зачёркнуто] X»,
|
||||
// слабая модель копирует строку в поле text). Только ведущий наш маркер — реальный текст с него
|
||||
// не начинается; марочные клоны после среза дают тот же канон и сливаются с чистой записью.
|
||||
const cleanText = String(text || '').replace(/^(?:\[зачёркнуто\]\s*)+/, '');
|
||||
const raw = (why != null && String(why).trim() !== '') ? `${cleanText}${SEP}${why}` : cleanText;
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const part of raw.split(SEP).map((s) => s.trim()).filter(Boolean)) {
|
||||
|
||||
@@ -231,6 +231,17 @@ describe('collapseProtocol — детерминированное схлопыв
|
||||
const p = { open: [{ text: 'Хайку или Sonnet? — Хайку или Sonnet?', struck: false, turns: [1] }] };
|
||||
expect(collapseProtocol(p).open[0].text).toBe('Хайку или Sonnet?');
|
||||
});
|
||||
it('срезает впечённую метку «[зачёркнуто]» из текста и сливает с чистой записью', () => {
|
||||
const p = { decisions: [
|
||||
{ text: 'Выбрано X', why: 'причина', struck: true, turns: [3] },
|
||||
{ text: '[зачёркнуто] [зачёркнуто] Выбрано X', why: 'причина', struck: true, turns: [31] },
|
||||
] };
|
||||
const out = collapseProtocol(p);
|
||||
expect(out.decisions).toHaveLength(1);
|
||||
expect(out.decisions[0].text).toBe('Выбрано X');
|
||||
expect(out.decisions[0].turns).toEqual([3, 31]);
|
||||
expect(JSON.stringify(out)).not.toContain('[зачёркнуто]');
|
||||
});
|
||||
it('hidden / steps / nextSvId не трогаются', () => {
|
||||
const p = { decisions: [], hidden: [{ id: 'СВ-1' }], steps: [{ turn: 1 }], nextSvId: 5 };
|
||||
const out = collapseProtocol(p);
|
||||
|
||||
Reference in New Issue
Block a user