import assert from 'node:assert/strict'; import test from 'node:test'; import { buildExecutionPatternAggregate, environmentMatchBoost, groupTaskOutcomesByProblem, planExperienceReflection, problemFingerprint, } from './experience-reflect.mjs'; test('problemFingerprint normalizes punctuation and spacing', () => { assert.equal(problemFingerprint(' SSE connection!!! '), 'sse connection'); }); test('groupTaskOutcomesByProblem groups active task outcomes by problem', () => { const groups = groupTaskOutcomesByProblem([ { id: '1', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'A' }, { id: '2', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'B' }, { id: '3', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'C' }, { id: '4', kind: 'task_outcome', status: 'active', problem: 'Other', title: 'D' }, { id: '5', kind: 'lesson', status: 'active', problem: 'SSE 断线', title: 'E' }, ], 3); assert.equal(groups.length, 1); assert.equal(groups[0].length, 3); }); test('environmentMatchBoost rewards component matches', () => { const boost = environmentMatchBoost( { environment_json: JSON.stringify({ runtime: 'goosed', components: ['docker', 'postgres'] }) }, ['goosed', 'docker'], ); assert.equal(boost, 1); }); test('buildExecutionPatternAggregate merges structured fields', () => { const payload = buildExecutionPatternAggregate([ { id: '1', title: 'SSE 修复', body: '改 server.rs', problem: 'SSE connection instability', result: 'success', confidence: 0.8, updated_at: 100, environment_json: JSON.stringify({ runtime: 'goosed', components: ['docker'] }), action_json: JSON.stringify({ executor: 'goose', steps: ['edit server.rs'] }), evidence_json: JSON.stringify({ sources: [{ source_id: 'run:1' }] }), }, { id: '2', title: 'SSE 再修', body: '补 replay 映射', problem: 'SSE connection instability', result: 'success', confidence: 0.9, updated_at: 200, environment_json: JSON.stringify({ components: ['portal'] }), action_json: JSON.stringify({ executor: 'goose', steps: ['replay mapping'] }), evidence_json: JSON.stringify({ sources: [{ source_id: 'run:2' }] }), }, { id: '3', title: 'SSE 第三次', body: '终态恢复', problem: 'SSE connection instability', result: 'partial', confidence: 0.7, updated_at: 300, environment_json: JSON.stringify({ components: ['sse'] }), action_json: JSON.stringify({ executor: 'goose', steps: ['finish sync'] }), evidence_json: JSON.stringify({ sources: [{ source_id: 'run:1' }] }), }, ]); assert.equal(payload.kind, 'execution_pattern'); assert.equal(payload.result, 'success'); assert.equal(payload.confidence, 0.8); assert.deepEqual(payload.environment.components.sort(), ['docker', 'portal', 'sse']); assert.equal(payload.evidence.sources.length, 2); assert.deepEqual(payload.evidence.provenance.aggregated_from, ['3', '2', '1']); }); test('planExperienceReflection skips groups with existing execution_pattern', () => { const plans = planExperienceReflection([ { id: '1', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'A' }, { id: '2', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'B' }, { id: '3', kind: 'task_outcome', status: 'active', problem: 'SSE 断线', title: 'C' }, { id: 'p1', kind: 'execution_pattern', status: 'active', problem: 'SSE 断线', title: 'pattern' }, ], { minGroupSize: 3 }); assert.equal(plans.length, 0); });