import { describe, it, expect } from 'vitest'; import { detectMethodDirected, loadKnownNodes } from './observer-routing-detector.mjs'; const NODES = ['brainstorming', 'discovery-interview', 'systematic-debugging']; describe('detectMethodDirected', () => { it('detects a directive verb followed by a node name', () => { expect(detectMethodDirected('запусти discovery-interview по этой фиче', NODES)).toEqual({ directed: true, node: 'discovery-interview', }); }); it('detects "используй X"', () => { expect(detectMethodDirected('используй systematic-debugging здесь', NODES).directed).toBe(true); }); it('detects a /slash-command form', () => { expect(detectMethodDirected('сделай это через /brainstorming', NODES)).toEqual({ directed: true, node: 'brainstorming', }); }); it('does NOT flag a bare node mention without a directive verb', () => { expect(detectMethodDirected('почему ты выбрал brainstorming, а не план?', NODES).directed).toBe(false); }); it('does NOT flag a prompt with no node reference', () => { expect(detectMethodDirected('добавь колонку Город в таблицу', NODES).directed).toBe(false); }); it('is empty-input safe', () => { expect(detectMethodDirected('', NODES).directed).toBe(false); expect(detectMethodDirected(null, []).directed).toBe(false); }); }); describe('loadKnownNodes', () => { it('loads names, skips comments and blank lines', () => { const nodes = loadKnownNodes('tools/observer-known-nodes.txt'); expect(nodes).toContain('brainstorming'); expect(nodes).toContain('discovery-interview'); expect(nodes.every((n) => !n.startsWith('#') && n.length > 0)).toBe(true); }); it('returns an empty array for a missing file', () => { expect(loadKnownNodes('tools/does-not-exist.txt')).toEqual([]); }); }); import { stripPastedContext } from './observer-routing-detector.mjs'; describe('stripPastedContext (узкий: fenced + blockquote)', () => { it('removes fenced blocks', () => { expect(stripPastedContext('a\n```\n/x here\n```\nb')).not.toContain('/x'); }); it('removes blockquote lines', () => { expect(stripPastedContext('> /x cited\nkeep')).not.toContain('/x'); }); it('keeps inline backticks (FP-safe bias)', () => { expect(stripPastedContext('use `/x` now')).toContain('/x'); }); it('is non-string safe', () => { expect(stripPastedContext(null)).toBe(''); }); }); describe('detectMethodDirected — PASTED-context guard (4-й FP-класс)', () => { it('does NOT flag a /node inside a fenced code block', () => { const t = 'смотри лог:\n```\nуже использовал /brainstorming тут\n```\nчто думаешь?'; expect(detectMethodDirected(t, NODES).directed).toBe(false); }); it('does NOT flag a blockquote-cited directive', () => { const t = '> используй systematic-debugging здесь\nэто цитата из старого чата'; expect(detectMethodDirected(t, NODES).directed).toBe(false); }); it('STILL flags an inline /slash directive (FP-safe bias preserved)', () => { expect(detectMethodDirected('сделай через `/brainstorming`', NODES).directed).toBe(true); }); it('STILL flags a plain-prose directive', () => { expect(detectMethodDirected('запусти discovery-interview', NODES).directed).toBe(true); }); });