feat(v2): normalize GLPI text before context/hash, add real ticket description
context.normalizeTicket now runs normalizeGlpiText on titulo, descricao (new field, sourced from glpi_tickets.content -- never fetched before), and every followup/task texto. buildAiContextText restructured into delimited sections (TITULO / DESCRICAO ORIGINAL / STATUS-TECNICO-GRUPO / FOLLOW-UPS / TAREFAS) instead of one flat string. hash.buildContextFingerprint now includes titulo/descricao and the normalized followup/task texto (previously only id/date/status), so: (a) the same content encoded differently (HTML vs escaped entities) produces the same hash, and (b) editing a followup's actual content (same id/date) is now detected as a real context change -- previously silently invisible to the hash. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d7650308a9
commit
db7a261a10
+7
-3
@@ -13,11 +13,15 @@ function djb2Hash(str) {
|
||||
return hash.toString(16).padStart(8, '0');
|
||||
}
|
||||
|
||||
const FINGERPRINT_FIELDS = ['status', 'tecnico_atribuido', 'categoria', 'entidade'];
|
||||
const FINGERPRINT_FIELDS = ['status', 'tecnico_atribuido', 'categoria', 'entidade', 'titulo', 'descricao'];
|
||||
|
||||
// Campos textuais (titulo, descricao, followups[].texto, tasks[].texto) entram no fingerprint
|
||||
// já normalizados (normalizeTicket roda normalizeGlpiText antes disso) -- por isso a mesma
|
||||
// informação escrita com HTML puro ou com entidades escapadas produz o mesmo hash. Nunca
|
||||
// inclui dias_aberto/dias_sem_interacao/idade: o hash só muda por evento real de contexto.
|
||||
function buildContextFingerprint(ticket) {
|
||||
const followups = (ticket.followups || []).map((f) => `${f.id}:${f.date}`).sort();
|
||||
const tasks = (ticket.tasks || []).map((t) => `${t.id}:${t.status}:${t.date}`).sort();
|
||||
const followups = (ticket.followups || []).map((f) => `${f.id}:${f.date}:${f.texto || ''}`).sort();
|
||||
const tasks = (ticket.tasks || []).map((t) => `${t.id}:${t.status}:${t.date}:${t.texto || ''}`).sort();
|
||||
const picked = {};
|
||||
for (const field of FINGERPRINT_FIELDS) picked[field] = ticket[field];
|
||||
picked.followups = followups;
|
||||
|
||||
Reference in New Issue
Block a user