fix(v2): centralize AI_FALLBACK/INSUFFICIENT_CONTEXT eligibility policy in cooldown.js

applyFallbackPolicy (new, in logic/cooldown.js alongside the isCriticalOverride
it reuses) is now the single place that decides whether an AI_FALLBACK or
INSUFFICIENT_CONTEXT ticket can enter the Top10: blocked by default, let
through only via an explicit critical override (SLA vencido + prioridade/
urgencia alta, OR sem_tecnico + prioridade/urgencia alta -- isCriticalOverride
extended to cover both, previously only covered SLA+priority). score.js
calls this policy and sets excludedFromTop10/exclusionReason/decisionReason
accordingly, with an auditable *_critical_override or *_no_override reason.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Gustavo
2026-08-24 16:51:17 -03:00
co-authored by Claude Sonnet 5
parent 00a42db269
commit 34f61abc3b
4 changed files with 118 additions and 7 deletions
+27 -1
View File
@@ -60,6 +60,32 @@ test('NEEDS_COORDINATION e excluido do Top10 diario', () => {
});
test('fallback nao recebe bonus de acionabilidade (comportamento seguro tipo V1)', () => {
const result = computeScore({ ticket: ticket({}), aiClassification: ai({ is_fallback: true }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
const result = computeScore({ ticket: ticket({}), aiClassification: ai({ classification: 'AI_FALLBACK', is_fallback: true }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
assert.equal(result.breakdown.actionabilityPoints, 0);
});
test('AI_FALLBACK comum e excluido do Top10 (nao pode competir como se fosse acionavel confirmado)', () => {
const result = computeScore({ ticket: ticket({}), aiClassification: ai({ classification: 'AI_FALLBACK', is_fallback: true, confidence: 0 }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
assert.equal(result.excludedFromTop10, true);
assert.equal(result.exclusionReason, 'ai_fallback_no_override');
});
test('AI_FALLBACK em chamado critico (SLA vencido + prioridade alta) entra por excecao explicita', () => {
const critico = ticket({ sla_vencido: true, prioridade: 5, urgencia: 5 });
const result = computeScore({ ticket: critico, aiClassification: ai({ classification: 'AI_FALLBACK', is_fallback: true, confidence: 0 }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
assert.equal(result.excludedFromTop10, false);
assert.equal(result.decisionReason, 'ai_fallback_critical_override');
});
test('INSUFFICIENT_CONTEXT comum fica fora da competicao operacional normal (excluido do Top10)', () => {
const result = computeScore({ ticket: ticket({}), aiClassification: ai({ classification: 'INSUFFICIENT_CONTEXT', confidence: 0.3 }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
assert.equal(result.excludedFromTop10, true);
assert.equal(result.exclusionReason, 'insufficient_context_no_override');
});
test('INSUFFICIENT_CONTEXT critico entra somente pela excecao definida', () => {
const critico = ticket({ sem_tecnico: true, prioridade: 4 });
const result = computeScore({ ticket: critico, aiClassification: ai({ classification: 'INSUFFICIENT_CONTEXT', confidence: 0.3 }), memory: null, contextChanged: true, config: CONFIG, now: NOW });
assert.equal(result.excludedFromTop10, false);
assert.equal(result.decisionReason, 'insufficient_context_critical_override');
});