const { test } = require('node:test'); const assert = require('node:assert/strict'); const { selectTop } = require('./diversity'); function item(id, score, group, excludedFromTop10) { return { ticket: { id }, score, group, excludedFromTop10: Boolean(excludedFromTop10), aiClassification: {} }; } test('Top final nunca ultrapassa topN', () => { const scored = Array.from({ length: 20 }, (_, i) => item(i, 100 - i, 'ranking_geral', false)); const { selected } = selectTop(scored, 10, {}); assert.equal(selected.length, 10); }); test('itens excluidos do Top10 nunca aparecem selecionados', () => { const scored = [item(1, 500, 'critico_acionavel', true), item(2, 10, 'ranking_geral', false)]; const { selected } = selectTop(scored, 10, {}); assert.ok(!selected.some((s) => s.ticket.id === 1)); }); test('10 criticos legitimos no mesmo grupo entram todos (diversidade nao bloqueia emergencia real)', () => { const scored = Array.from({ length: 10 }, (_, i) => item(i, 500 - i, 'critico_acionavel', false)); const { selected } = selectTop(scored, 10, {}); assert.equal(selected.length, 10); assert.deepEqual(selected.map((s) => s.ticket.id).sort(), scored.map((s) => s.ticket.id).sort()); }); test('BUG REAL comprovado em execucao real: mesmo conjunto de itens empatados em score, em ordens de chegada diferentes, produz o MESMO Top10 -- missao "correcao final" secao 14/15', () => { // Simula o que aconteceu de verdade: 12 itens com o MESMO score, chegando em duas ordens // diferentes (n8n nao garante ordem entre branches paralelos). Sem desempate deterministico // por ticket.id, cada execucao escolhia um subconjunto de 10 diferente -> mensagens // diferentes -> hash diferente -> idempotencia nunca detectava como "mesmo dia, mesmo digest". const ids = [38413, 38476, 38477, 38509, 36925, 37691, 37389, 38657, 75, 38611, 38583, 38658]; const ordemA = ids.map((id) => item(id, 200, 'ranking_geral', false)); const ordemB = [...ordemA].reverse(); const resultA = selectTop(ordemA, 10, {}); const resultB = selectTop(ordemB, 10, {}); const idsA = resultA.selected.map((s) => s.ticket.id); const idsB = resultB.selected.map((s) => s.ticket.id); assert.deepEqual(idsA, idsB, 'a mesma composicao de candidatos deveria produzir o mesmo Top10, independente da ordem de chegada'); }); test('desempate por ticket.id nao muda QUEM vence quando os scores sao diferentes (so desempata igualdade)', () => { const scored = [item(2, 100, 'ranking_geral', false), item(1, 200, 'ranking_geral', false)]; const { selected } = selectTop(scored, 10, {}); assert.equal(selected[0].ticket.id, 1, 'score maior continua vencendo, desempate so entra quando ha empate real'); }); test('com grupos variados, ordena por score respeitando diversidade leve', () => { const scored = [ ...Array.from({ length: 8 }, (_, i) => item(`c${i}`, 300 - i, 'critico_acionavel', false)), item('t1', 250, 'sem_tecnico', false), item('t2', 240, 'quick_win', false), ]; const { selected } = selectTop(scored, 10, {}); assert.equal(selected.length, 10); assert.ok(selected.some((s) => s.ticket.id === 't1')); });