/ __quarantined_tests__ / agents / triage-supplement.test.js
triage-supplement.test.js
  1  /**
  2   * Triage Agent Supplement — Priority Calculation Branch Coverage
  3   *
  4   * Covers branches in calculatePriority() not hit by existing tests:
  5   * - Line 723: frequency > 10 (but <= 100) → score -= 2
  6   * - Lines 725-726: frequency > 1 (but <= 10) → score -= 1
  7   * - Line 731: severity === 'high' → score -= 2
  8   * - Lines 740-741: ageHours > 24 → score -= 1 (old task)
  9   * - Lines 748-749: stage in criticalStages → score -= 2 (assets, rescoring, proposals)
 10   * - Lines 756-757: errorType includes 'auth', 'data_loss' → score -= 1
 11   * - Lines 824-825: getStageFile returns null for unknown stage
 12   */
 13  
 14  import { describe, test, before, after } from 'node:test';
 15  import assert from 'node:assert/strict';
 16  import Database from 'better-sqlite3';
 17  import { TriageAgent } from '../../src/agents/triage.js';
 18  import { resetDb as resetBaseDb } from '../../src/agents/base-agent.js';
 19  import { resetDb as resetTaskDb } from '../../src/agents/utils/task-manager.js';
 20  import { resetDb as resetMessageDb } from '../../src/agents/utils/message-manager.js';
 21  import { tmpdir } from 'os';
 22  import { join } from 'path';
 23  import { existsSync, unlinkSync } from 'fs';
 24  
 25  const TEST_DB = join(tmpdir(), `triage-supplement-${Date.now()}.db`);
 26  
 27  let agent;
 28  let db;
 29  
 30  before(async () => {
 31    process.env.DATABASE_PATH = TEST_DB;
 32    process.env.AGENT_REALTIME_NOTIFICATIONS = 'false';
 33    process.env.AGENT_IMMEDIATE_INVOCATION = 'false';
 34  
 35    db = new Database(TEST_DB);
 36    db.exec(`
 37      CREATE TABLE IF NOT EXISTS agent_tasks (
 38        id INTEGER PRIMARY KEY AUTOINCREMENT,
 39        task_type TEXT NOT NULL,
 40        assigned_to TEXT NOT NULL,
 41        created_by TEXT,
 42        status TEXT DEFAULT 'pending',
 43        priority INTEGER DEFAULT 5,
 44        context_json TEXT,
 45        result_json TEXT,
 46        parent_task_id INTEGER,
 47        error_message TEXT,
 48        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
 49        started_at DATETIME,
 50        completed_at DATETIME,
 51        retry_count INTEGER DEFAULT 0
 52      );
 53      CREATE TABLE IF NOT EXISTS agent_messages (
 54        id INTEGER PRIMARY KEY AUTOINCREMENT,
 55        task_id INTEGER, from_agent TEXT NOT NULL, to_agent TEXT NOT NULL,
 56        message_type TEXT, content TEXT NOT NULL, metadata_json TEXT,
 57        created_at DATETIME DEFAULT CURRENT_TIMESTAMP, read_at DATETIME
 58      );
 59      CREATE TABLE IF NOT EXISTS agent_logs (
 60        id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER,
 61        agent_name TEXT NOT NULL, log_level TEXT, message TEXT,
 62        data_json TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP
 63      );
 64      CREATE TABLE IF NOT EXISTS agent_state (
 65        agent_name TEXT PRIMARY KEY,
 66        last_active DATETIME DEFAULT CURRENT_TIMESTAMP,
 67        current_task_id INTEGER, status TEXT DEFAULT 'idle', metrics_json TEXT
 68      );
 69      CREATE TABLE IF NOT EXISTS agent_outcomes (
 70        id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL,
 71        agent_name TEXT NOT NULL, task_type TEXT NOT NULL, outcome TEXT NOT NULL,
 72        context_json TEXT, result_json TEXT, duration_ms INTEGER,
 73        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
 74      );
 75      CREATE TABLE IF NOT EXISTS agent_llm_usage (
 76        id INTEGER PRIMARY KEY AUTOINCREMENT, agent_name TEXT NOT NULL,
 77        task_id INTEGER, model TEXT NOT NULL, prompt_tokens INTEGER NOT NULL,
 78        completion_tokens INTEGER NOT NULL, cost_usd DECIMAL(10,6) NOT NULL,
 79        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
 80      );
 81      CREATE TABLE IF NOT EXISTS structured_logs (
 82        id INTEGER PRIMARY KEY AUTOINCREMENT, agent_name TEXT, task_id INTEGER,
 83        level TEXT, message TEXT, data_json TEXT,
 84        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
 85      );
 86      CREATE TABLE IF NOT EXISTS cron_locks (
 87        lock_key TEXT PRIMARY KEY,
 88        acquired_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 89        updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 90        description TEXT
 91      );
 92    `);
 93  
 94    agent = new TriageAgent();
 95    await agent.initialize();
 96  });
 97  
 98  after(() => {
 99    resetBaseDb();
100    resetTaskDb();
101    resetMessageDb();
102    try {
103      db.close();
104    } catch {
105      /* ignore */
106    }
107    if (existsSync(TEST_DB)) {
108      try {
109        unlinkSync(TEST_DB);
110      } catch {
111        /* ignore */
112      }
113    }
114  });
115  
116  describe('TriageAgent - calculatePriority branch coverage', () => {
117    const freshTask = () => ({ id: 1, created_at: new Date().toISOString() });
118    const oldTask = () => ({
119      id: 2,
120      created_at: new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString(),
121    });
122  
123    test('frequency > 10 (not > 100) reduces score by 2', () => {
124      const p = agent.calculatePriority(freshTask(), { frequency: 50, severity: 'low', stage: '' });
125      // base 5 - 2 (freq > 10) = 3
126      assert.strictEqual(p, 3);
127    });
128  
129    test('frequency > 1 (not > 10) reduces score by 1', () => {
130      const p = agent.calculatePriority(freshTask(), { frequency: 5, severity: 'low', stage: '' });
131      // base 5 - 1 (freq > 1) = 4
132      assert.strictEqual(p, 4);
133    });
134  
135    test('severity === high reduces score by 2', () => {
136      const p = agent.calculatePriority(freshTask(), { frequency: 1, severity: 'high', stage: '' });
137      // base 5 - 2 (high severity) = 3
138      assert.strictEqual(p, 3);
139    });
140  
141    test('age > 24h reduces score by 1', () => {
142      const p = agent.calculatePriority(oldTask(), { frequency: 1, severity: 'low', stage: '' });
143      // base 5 - 1 (age > 24h) = 4
144      assert.strictEqual(p, 4);
145    });
146  
147    test('assets stage is critical → reduces score by 2', () => {
148      const p = agent.calculatePriority(freshTask(), {
149        frequency: 1,
150        severity: 'low',
151        stage: 'assets',
152      });
153      // base 5 - 2 (critical stage) = 3
154      assert.strictEqual(p, 3);
155    });
156  
157    test('rescoring stage is critical → reduces score by 2', () => {
158      const p = agent.calculatePriority(freshTask(), {
159        frequency: 1,
160        severity: 'low',
161        stage: 'rescoring',
162      });
163      assert.strictEqual(p, 3);
164    });
165  
166    test('proposals stage is critical → reduces score by 2', () => {
167      const p = agent.calculatePriority(freshTask(), {
168        frequency: 1,
169        severity: 'low',
170        stage: 'proposals',
171      });
172      assert.strictEqual(p, 3);
173    });
174  
175    test('auth error type reduces score by 1', () => {
176      const p = agent.calculatePriority(freshTask(), {
177        frequency: 1,
178        severity: 'low',
179        stage: '',
180        error_type: 'auth_failure',
181      });
182      // base 5 - 1 (auth) = 4
183      assert.strictEqual(p, 4);
184    });
185  
186    test('data_loss error type reduces score by 1', () => {
187      const p = agent.calculatePriority(freshTask(), {
188        frequency: 1,
189        severity: 'low',
190        stage: '',
191        error_type: 'data_loss',
192      });
193      assert.strictEqual(p, 4);
194    });
195  
196    test('database error type reduces score by 1', () => {
197      const p = agent.calculatePriority(freshTask(), {
198        frequency: 1,
199        severity: 'low',
200        stage: '',
201        error_type: 'database_constraint',
202      });
203      assert.strictEqual(p, 4);
204    });
205  });
206  
207  describe('TriageAgent - resolveFilePath null return (unknown stage)', () => {
208    test('returns null for unknown stage name with no stack trace', () => {
209      // No src/ path in error, no pattern match, unknown stage
210      const result = agent.resolveFilePath('generic error occurred', '', 'unknown_stage_xyz');
211      assert.strictEqual(result, null);
212    });
213  
214    test('returns null when error, stackTrace, and stage have no matches', () => {
215      const result = agent.resolveFilePath('something totally unrecognized', '', 'custom_stage');
216      assert.strictEqual(result, null);
217    });
218  
219    test('returns stage file for known stage even with unknown error', () => {
220      const result = agent.resolveFilePath('generic error', '', 'scoring');
221      assert.ok(result && result.includes('scoring'), 'Should resolve to scoring file');
222    });
223  });