feat(v2): add safe AI fallback and cache/reanalysis decision
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c445e00fc5
commit
efba7792fa
@@ -0,0 +1,8 @@
|
||||
function needsReanalysis({ memory, currentHash, now }) {
|
||||
if (!memory) return { needsAi: true, reason: 'no_cache' };
|
||||
if (memory.last_context_hash !== currentHash) return { needsAi: true, reason: 'context_changed' };
|
||||
if (memory.next_review_at != null && now >= memory.next_review_at) return { needsAi: true, reason: 'review_due' };
|
||||
return { needsAi: false, reason: 'cache_valid' };
|
||||
}
|
||||
|
||||
module.exports = { needsReanalysis };
|
||||
@@ -0,0 +1,30 @@
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { needsReanalysis } = require('./cache');
|
||||
|
||||
test('sem memoria previa, sempre precisa de IA', () => {
|
||||
const result = needsReanalysis({ memory: null, currentHash: 'abc', now: 1000 });
|
||||
assert.equal(result.needsAi, true);
|
||||
assert.equal(result.reason, 'no_cache');
|
||||
});
|
||||
|
||||
test('hash igual e sem next_review_at vencido usa cache', () => {
|
||||
const memory = { last_context_hash: 'abc', next_review_at: null };
|
||||
const result = needsReanalysis({ memory, currentHash: 'abc', now: 1000 });
|
||||
assert.equal(result.needsAi, false);
|
||||
assert.equal(result.reason, 'cache_valid');
|
||||
});
|
||||
|
||||
test('hash diferente forca reavaliacao (mudanca significativa)', () => {
|
||||
const memory = { last_context_hash: 'abc', next_review_at: null };
|
||||
const result = needsReanalysis({ memory, currentHash: 'xyz', now: 1000 });
|
||||
assert.equal(result.needsAi, true);
|
||||
assert.equal(result.reason, 'context_changed');
|
||||
});
|
||||
|
||||
test('next_review_at vencido forca reavaliacao mesmo com hash igual', () => {
|
||||
const memory = { last_context_hash: 'abc', next_review_at: 500 };
|
||||
const result = needsReanalysis({ memory, currentHash: 'abc', now: 1000 });
|
||||
assert.equal(result.needsAi, true);
|
||||
assert.equal(result.reason, 'review_due');
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
function buildFallbackClassification(reason) {
|
||||
return {
|
||||
classification: 'ACTIONABLE_NOW',
|
||||
actionable_today: true,
|
||||
confidence: 0,
|
||||
blocker_type: null,
|
||||
waiting_for: null,
|
||||
next_action: 'Revisar chamado manualmente',
|
||||
suggested_action_type: 'manual_review',
|
||||
business_risk: 'medium',
|
||||
reason: `Fallback deterministico: ${reason}`,
|
||||
evidence: [],
|
||||
is_fallback: true,
|
||||
fallback_reason: reason,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { buildFallbackClassification };
|
||||
@@ -0,0 +1,12 @@
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { buildFallbackClassification } = require('./fallback');
|
||||
|
||||
test('fallback e sempre seguro e marcado como tal', () => {
|
||||
const result = buildFallbackClassification('ai_timeout');
|
||||
assert.equal(result.is_fallback, true);
|
||||
assert.equal(result.fallback_reason, 'ai_timeout');
|
||||
assert.equal(result.confidence, 0);
|
||||
assert.equal(result.classification, 'ACTIONABLE_NOW');
|
||||
assert.ok(result.reason.includes('Fallback'));
|
||||
});
|
||||
Reference in New Issue
Block a user