fix(v2): AI_FALLBACK replaces the ACTIONABLE_NOW-with-confidence-0 lie, normalize null-like strings
Fallback (ai_disabled, ai_error, invalid_json, ai_max_candidates_cap -- any candidate the AI never actually analyzed) now produces classification 'AI_FALLBACK', an explicit technical state that is never part of the 11-class enum sent to OpenAI (the AI itself can never legitimately return it). Previously it silently claimed ACTIONABLE_NOW with confidence 0, which made unanalyzed tickets indistinguishable from genuinely confirmed ones at the classification-label level. Also normalizes blocker_type/waiting_for when the model returns the literal string "null"/"none"/"n/a"/"" instead of JSON null -- done once, in the validation layer (logic/classification.js), not scattered around the workflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
db7a261a10
commit
00a42db269
+15
-3
@@ -4,6 +4,18 @@ const VALID_CLASSIFICATIONS = [
|
||||
'PROJECT_LONG_TERM', 'DUPLICATE_OR_OBSOLETE', 'INSUFFICIENT_CONTEXT',
|
||||
];
|
||||
|
||||
// O modelo, apesar do schema permitir null de verdade em blocker_type/waiting_for, as vezes
|
||||
// devolve a STRING "null" (ou variantes equivalentes) em vez do valor JSON null. Normaliza
|
||||
// aqui, na camada de validacao -- unico lugar que toca a resposta crua da IA.
|
||||
const NULL_LIKE_STRINGS = new Set(['null', 'none', 'n/a', 'na', '']);
|
||||
|
||||
function normalizeNullableString(value) {
|
||||
if (value === null || value === undefined) return null;
|
||||
const trimmed = String(value).trim();
|
||||
if (NULL_LIKE_STRINGS.has(trimmed.toLowerCase())) return null;
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function validateAiClassification(raw) {
|
||||
const errors = [];
|
||||
if (!raw || typeof raw !== 'object') {
|
||||
@@ -28,8 +40,8 @@ function validateAiClassification(raw) {
|
||||
classification: raw.classification,
|
||||
actionable_today: raw.actionable_today,
|
||||
confidence,
|
||||
blocker_type: raw.blocker_type ?? null,
|
||||
waiting_for: raw.waiting_for ?? null,
|
||||
blocker_type: normalizeNullableString(raw.blocker_type),
|
||||
waiting_for: normalizeNullableString(raw.waiting_for),
|
||||
next_action: raw.next_action,
|
||||
suggested_action_type: raw.suggested_action_type ?? 'technical_action',
|
||||
business_risk: raw.business_risk ?? 'medium',
|
||||
@@ -41,4 +53,4 @@ function validateAiClassification(raw) {
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { VALID_CLASSIFICATIONS, validateAiClassification };
|
||||
module.exports = { VALID_CLASSIFICATIONS, validateAiClassification, normalizeNullableString };
|
||||
|
||||
Reference in New Issue
Block a user