// tools/missed-activations.test.mjs import { describe, it, expect } from 'vitest'; import { detectMissedActivations } from './missed-activations.mjs'; const map = { refactor: ['#11', '#12', '#43'], bugfix: ['#18', '#34'], feature: ['#19'], other: [], }; const dormancy = { '#11': false, '#12': false, '#43': false, '#18': false, '#34': false, '#19': false }; function ep(classification, node_chosen) { return { schema_version: 2, primary_rationale: { task_classification: classification, node_chosen }, }; } describe('detectMissedActivations', () => { it('counts an episode with profile classification + node_chosen=direct as missed', () => { const result = detectMissedActivations([ep('refactor', 'direct')], map, dormancy); expect(result.totalMissed).toBe(1); expect(result.byNode).toEqual({ '#11': 1, '#12': 1, '#43': 1 }); }); it('does NOT count episode when the recommended node IS chosen', () => { const result = detectMissedActivations([ep('refactor', '#11')], map, dormancy); expect(result.totalMissed).toBe(0); }); it('does NOT count episode when classification=other (empty list)', () => { const result = detectMissedActivations([ep('other', 'direct')], map, dormancy); expect(result.totalMissed).toBe(0); }); it('excludes dormant (DEFERRED) nodes from recommendations', () => { const dorm = { ...dormancy, '#43': true }; const result = detectMissedActivations([ep('refactor', 'direct')], map, dorm); expect(result.byNode).toEqual({ '#11': 1, '#12': 1 }); expect(result.totalMissed).toBe(1); }); it('returns totalMissed=0 when ALL recommended nodes are dormant', () => { const dorm = { '#11': true, '#12': true, '#43': true }; const result = detectMissedActivations([ep('refactor', 'direct')], map, dorm); expect(result.totalMissed).toBe(0); expect(result.byNode).toEqual({}); }); it('ignores schema v1 episodes (no factor analysis)', () => { const v1 = { schema_version: 1, primary_rationale: { task_classification: 'refactor', node_chosen: 'direct' } }; const result = detectMissedActivations([v1], map, dormancy); expect(result.totalMissed).toBe(0); }); it('ignores observer_error markers', () => { const err = { observer_error: true }; const result = detectMissedActivations([err], map, dormancy); expect(result.totalMissed).toBe(0); }); it('ignores unknown classification (not in map)', () => { const result = detectMissedActivations([ep('unknown-bucket', 'direct')], map, dormancy); expect(result.totalMissed).toBe(0); }); it('aggregates byClassification breakdown for the report', () => { const eps = [ ep('refactor', 'direct'), ep('refactor', 'direct'), ep('bugfix', 'direct'), ]; const result = detectMissedActivations(eps, map, dormancy); expect(result.byClassification).toEqual({ refactor: 2, bugfix: 1 }); expect(result.totalMissed).toBe(3); }); it('detects missed activation on v3 episode', () => { const v3 = { schema_version: 3, primary_rationale: { node_chosen: 'direct', task_classification: 'feature', recommended_node: '#19' } }; const result = detectMissedActivations([v3], { feature: ['#19'] }, { '#19': false }); expect(result.totalMissed).toBe(1); }); }); describe('detectMissedActivations — §17 v4 path (Phase 2 Task 11)', () => { it('flags direct on non-conversation v4 episode with recommended_node', () => { const r = detectMissedActivations([{ schema_version: 4, classifier_output: { task_type: 'feature', recommended_node: '#19', no_skill_found: false }, execution_trace: { actual_node_invoked_first: 'direct' }, }]); expect(r.totalMissed).toBe(1); expect(r.byNode).toEqual({ '#19': 1 }); expect(r.byClassification).toEqual({ feature: 1 }); }); it('does not flag conversation task_type (§17 exempt)', () => { const r = detectMissedActivations([{ schema_version: 4, classifier_output: { task_type: 'conversation', recommended_node: null }, }]); expect(r.totalMissed).toBe(0); }); it('does not flag micro / manual_override (§17 exempt)', () => { const r = detectMissedActivations([ { schema_version: 4, classifier_output: { task_type: 'micro', recommended_node: null }, execution_trace: { actual_node_invoked_first: 'direct' } }, { schema_version: 4, classifier_output: { task_type: 'manual_override', recommended_node: 'tdd' }, execution_trace: { actual_node_invoked_first: 'direct' } }, ]); expect(r.totalMissed).toBe(0); }); it('does not flag when no_skill_found=true (classifier honestly admits no match)', () => { const r = detectMissedActivations([{ schema_version: 4, classifier_output: { task_type: 'feature', recommended_node: null, no_skill_found: true }, execution_trace: { actual_node_invoked_first: 'direct' }, }]); expect(r.totalMissed).toBe(0); }); it('does not flag when a real node fired (not direct)', () => { const r = detectMissedActivations([{ schema_version: 4, classifier_output: { task_type: 'feature', recommended_node: '#19', no_skill_found: false }, execution_trace: { actual_node_invoked_first: 'superpowers:test-driven-development' }, }]); expect(r.totalMissed).toBe(0); }); it('does not flag when recommended_node is dormant', () => { const r = detectMissedActivations( [{ schema_version: 4, classifier_output: { task_type: 'feature', recommended_node: '#50', no_skill_found: false }, execution_trace: { actual_node_invoked_first: 'direct' }, }], {}, { '#50': true }, ); expect(r.totalMissed).toBe(0); }); });