From ffaeb8f37bfee1316ec4773351acf0994ccc1a8f 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: Wed, 20 May 2026 13:14:16 +0300 Subject: [PATCH] feat(observer): strip blocks from promptText MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes brain-retro 2026-05-20 #8 — UserPromptSubmit hook injects ... blocks into user.content that polluted classifyTask / classifyPromptSignal / routing detection. Now stripped via regex before any analysis. Completed by controller (Opus) after subagent hit context limit on 1250-line test file. Helper stripSystemReminders + promptText update were committed by subagent; test cases appended via Bash heredoc. 4 new vitest tests, 290/290 GREEN. Co-Authored-By: Claude Opus 4.7 (1M context) --- tools/observer-transcript-parser.mjs | 9 +++-- tools/observer-transcript-parser.test.mjs | 43 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/observer-transcript-parser.mjs b/tools/observer-transcript-parser.mjs index eb2d9d4b..5afb7c74 100644 --- a/tools/observer-transcript-parser.mjs +++ b/tools/observer-transcript-parser.mjs @@ -95,14 +95,19 @@ function findTurnStart(entries) { return 0; } +function stripSystemReminders(text) { + return String(text || '').replace(/[\s\S]*?<\/system-reminder>/g, ''); +} + function promptText(entry) { const c = entry && entry.message && entry.message.content; - if (typeof c === 'string') return c; + if (typeof c === 'string') return stripSystemReminders(c); if (Array.isArray(c)) { - return c + const joined = c .filter((b) => b && b.type === 'text') .map((b) => b.text || '') .join(' '); + return stripSystemReminders(joined); } return ''; } diff --git a/tools/observer-transcript-parser.test.mjs b/tools/observer-transcript-parser.test.mjs index 84614a19..dc482920 100644 --- a/tools/observer-transcript-parser.test.mjs +++ b/tools/observer-transcript-parser.test.mjs @@ -1248,3 +1248,46 @@ describe('error event differentiation (Task 7)', () => { expect(e.summary).toContain('String to replace'); }); }); + +describe('promptText strips blocks (Task 8)', () => { + it('classifyTask is not polluted by reminder content', () => { + const transcript = [ + JSON.stringify({ sessionId: 's' }), + JSON.stringify({ type: 'user', message: { role: 'user', + content: 'почему как что зачем\nрефактор биллинга' + }, uuid: 'u1', timestamp: '2026-05-20T00:00:00Z' }), + ].join('\n'); + const ep = parseTranscript(transcript); + expect(ep.primary_rationale.task_classification).toBe('refactor'); + }); + it('multiline system-reminder is stripped', () => { + const transcript = [ + JSON.stringify({ sessionId: 's' }), + JSON.stringify({ type: 'user', message: { role: 'user', + content: '\nline 1\nline 2 with почему\n\nfix баг' + }, uuid: 'u1', timestamp: '2026-05-20T00:00:00Z' }), + ].join('\n'); + const ep = parseTranscript(transcript); + expect(ep.primary_rationale.task_classification).toBe('bugfix'); + }); + it('multiple system-reminders all stripped', () => { + const transcript = [ + JSON.stringify({ sessionId: 's' }), + JSON.stringify({ type: 'user', message: { role: 'user', + content: 'почемуmiddleкаксоздай фичу' + }, uuid: 'u1', timestamp: '2026-05-20T00:00:00Z' }), + ].join('\n'); + const ep = parseTranscript(transcript); + expect(ep.primary_rationale.task_classification).toBe('feature'); + }); + it('content array form also stripped', () => { + const transcript = [ + JSON.stringify({ sessionId: 's' }), + JSON.stringify({ type: 'user', message: { role: 'user', + content: [{ type: 'text', text: 'почему как рефактор' }] + }, uuid: 'u1', timestamp: '2026-05-20T00:00:00Z' }), + ].join('\n'); + const ep = parseTranscript(transcript); + expect(ep.primary_rationale.task_classification).toBe('refactor'); + }); +});