import test from 'node:test'; import assert from 'node:assert/strict'; import { SearchMeasurement, measuredFailure, spanDepth, briefMs } from '../src/search-performance.ts'; const finish = (trace, lane, start, end, metrics, failed) => trace.completed(trace.begin(lane, start), end, metrics, failed); const native = { total_ms: 12, result_count: 2, trace: [], dropped_spans: 0 }; test('separates debounce, intentional semantic delay, queue, invoke and DOM update', () => { const trace = new SearchMeasurement(100, 165, true); trace.submitted('lexical', 165); finish(trace, 'lexical', 180, 200, native, false); trace.displayed('lexical', 200, 203, 2); trace.submitted('hybrid', 515); finish(trace, 'hybrid', 520, 550, native, false); trace.displayed('hybrid', 550, 554, 3); const report = trace.export(); assert.equal(report.debounce_ms, 65); assert.equal(report.lane_schedule_ms.hybrid, 350); assert.equal(report.attempts[0].queued_ms, 15); assert.equal(report.attempts[0].invoke_ms, 20); assert.equal(report.attempts[0].transport_estimate_ms, 8); assert.equal(report.displays[0].dom_update_ms, 3); assert.equal(report.first_results_ms, 103); assert.equal(report.hybrid_final_results_ms, 454); }); test('failed attempt timings survive retry and lexical response does not pretend hybrid completion', () => { const trace = new SearchMeasurement(0, 0, true); trace.submitted('lexical', 0); finish(trace, 'lexical', 0, 2, native, true); finish(trace, 'lexical', 402, 414, native, false); trace.displayed('lexical', 414, 415, 2); const report = trace.export(); assert.equal(report.attempts[1].retry_wait_ms, 400); assert.equal(report.attempts[0].failed, true); assert.equal(report.attempts[0].transport_estimate_ms, 0); assert.equal(report.hybrid_final_results_ms, null); assert.equal(report.latest_displayed_ms, 415); assert.equal(measuredFailure({message: 'worker busy', metrics: native}).message, 'worker busy'); assert.equal(measuredFailure('legacy failure'), null); }); test('debug history is bounded and first response survives dropped displays', () => { const context = { device: 'cpu', threads: 1 }; const trace = new SearchMeasurement(0, 0, true, context); context.threads = 8; for (let i = 0; i < 40; i++) { finish(trace, 'hybrid', i, i + 1, native, false); trace.displayed('hybrid', i, i + 1, 1); } const report = trace.export(); assert.equal(report.attempts.length, 32); assert.equal(report.displays.length, 16); assert.equal(report.dropped_attempts, 8); assert.equal(report.dropped_displays, 24); assert.equal(report.first_results_ms, 1); assert.equal(report.context.threads, 1); assert.doesNotMatch(JSON.stringify(report), /query|filename|snippet|ended_at/); }); test('cyclic or invalid native span parents cannot hang hierarchy rendering', () => { const spans = [{parent: 1}, {parent: 0}, {parent: 99}]; assert.equal(spanDepth(spans, 0), 1); assert.equal(spanDepth(spans, 2), 0); }); test('a later refresh has queue timing rather than being misreported as a busy retry', () => { const trace = new SearchMeasurement(0, 0, true); trace.submitted('hybrid', 350); finish(trace, 'hybrid', 350, 360, native, false); trace.submitted('hybrid', 1000); finish(trace, 'hybrid', 1010, 1020, native, false); assert.equal(trace.export().attempts[1].queued_ms, 10); assert.equal(trace.export().attempts[1].retry_wait_ms, 0); assert.equal(briefMs(.44), '<1'); assert.equal(briefMs(3.14), '3.1'); }); test('new submission after a failure measures pending queue rather than retry wait', () => { const trace = new SearchMeasurement(0, 0, true); trace.submitted('hybrid', 350); finish(trace, 'hybrid', 350, 360, native, true); trace.submitted('hybrid', 1000); finish(trace, 'hybrid', 1010, 1020, native, false); assert.equal(trace.export().attempts[1].queued_ms, 10); assert.equal(trace.export().attempts[1].retry_wait_ms, 0); }); test('an in-flight attempt keeps its captured submission when a refresh queues', () => { const trace = new SearchMeasurement(0, 0, true); trace.submitted('hybrid', 350); const active = trace.begin('hybrid', 355); trace.submitted('hybrid', 1000); trace.completed(active, 1005, native, true); finish(trace, 'hybrid', 1010, 1020, native, false); const attempts = trace.export().attempts; assert.equal(attempts[0].queued_ms, 5); assert.equal(attempts[1].queued_ms, 10); assert.equal(attempts[1].retry_wait_ms, 0); assert.notEqual(attempts[0].submission, attempts[1].submission); }); test('filesystem refresh excludes long idle time and retains original input timings separately', () => { const original = new SearchMeasurement(100, 160, true, { device: 'cpu' }); original.submitted('lexical', 160); finish(original, 'lexical', 165, 177, native, false); original.displayed('lexical', 177, 180, 2); original.submitted('hybrid', 510); finish(original, 'hybrid', 510, 522, native, false); original.displayed('hybrid', 522, 524, 3); const before = original.export(); const refreshed = original.freshForRefresh(83500); refreshed.submitted('lexical', 83500); finish(refreshed, 'lexical', 83502, 83514, native, false); refreshed.displayed('lexical', 83514, 83515, 3); const report = refreshed.export(); assert.equal(report.trigger, 'filesystem_refresh'); assert.equal(report.first_results_ms, 15); assert.equal(report.latest_displayed_ms, 15); assert.equal(report.debounce_ms, 0); assert.equal(report.hybrid_final_results_ms, null); assert.deepEqual(report.original_input, { debounce_ms: 60, first_results_ms: 80, latest_displayed_ms: 424, hybrid_final_results_ms: 424, }); assert.equal(report.attempts.length, 1); assert.equal(report.attempts[0].attempt, 1); assert.equal(report.attempts[0].queued_ms, 2); assert.deepEqual(original.export(), before); }); test('repeated refreshes retain a bounded immutable numeric origin without replaying failures or private spans', () => { const original = new SearchMeasurement(0, 60, false); original.submitted('lexical', 60); finish(original, 'lexical', 60, 70, { ...native, trace: [{ name: 'private-path-and-snippet', start_ms: 0, duration_ms: 1, parent: null, counters: {} }], }, true); original.displayed('lexical', 70, 72, 1); let refreshed = original.freshForRefresh(10000); const origin = refreshed.export().original_input; original.displayed('hybrid', 10001, 10002, 5); for (let i = 0; i < 100; i++) { const now = 20000 + i * 10000; refreshed = refreshed.freshForRefresh(now); assert.equal(refreshed.export().attempts.length, 0); assert.equal(refreshed.export().displays.length, 0); refreshed.submitted('lexical', now); finish(refreshed, 'lexical', now + 2, now + 14, native, false); refreshed.displayed('lexical', now + 14, now + 15, 2); const report = refreshed.export(); assert.equal(report.latest_displayed_ms, 15); assert.equal(report.attempts[0].retry_wait_ms, 0); assert.equal(report.attempts[0].attempt, 1); assert.deepEqual(report.original_input, origin); report.original_input.first_results_ms = 999; assert.deepEqual(refreshed.export().original_input, origin); assert.doesNotMatch(JSON.stringify(report), /private-path-and-snippet|ended_at/); assert.ok(JSON.stringify(report).length < 1500); } assert.equal(origin.first_results_ms, 72); assert.equal(origin.hybrid_final_results_ms, null); });