Found while syncing this cycle's fixes to the live DEV workflow and
preparing Run A: tools/build-workflow.js's readLogicSource() only inlines
whatever a node's own `@requires` header lists -- it does not resolve
transitive dependencies. context.js started doing `require('./normalize')`
earlier this cycle, but the three node drivers that need normalizeTicket/
buildAiContextText (which call normalizeGlpiText internally) still only
declared `@requires context.js`, never `normalize.js` itself.
The result compiles fine (new Function(...) syntax-checks pass -- a
ReferenceError is a runtime error, not a syntax error) but would throw
"normalizeGlpiText is not defined" the moment any of these three nodes
actually ran:
- Code - Mesclar Contexto e Calcular Hash (merge-context-hash.node.js)
- Code - Normalizar Candidatos Base (normalize-candidates.node.js)
- Code - Preparar Prompt IA (prepare-ai-prompt.node.js)
This never surfaced in Run 1 (prior session) because normalize.js/the
descricao field didn't exist yet at that point, and it didn't surface in
this cycle's local test suite because node--test only exercises the pure
logic/*.js modules directly (with real requires), never the inlined,
concatenated jsCode a node actually runs in n8n.
Fixed by adding normalize.js explicitly to each of the three headers,
matching the codebase's existing convention for multi-file deps (e.g.
compute-score.node.js already lists `@requires cooldown.js score.js`
together instead of relying on any transitive resolution).
Added a regression test that scans every generated Code node for calls to
normalizeGlpiText/normalizeTicket/buildAiContextText and asserts the
normalizeGlpiText function definition is actually present in that same
inlined source -- would have caught this before it ever reached DEV.
102/102 tests passing (was 101/101 -- +1 new regression test).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
29 lines
1.1 KiB
JavaScript
29 lines
1.1 KiB
JavaScript
// @requires normalize.js context.js hash.js
|
|
const candidatosBase = $('Code - Normalizar Candidatos Base').all().map((item) => item.json);
|
|
const contextRows = $input.all().map((item) => item.json);
|
|
|
|
function groupBy(rows, key) {
|
|
const map = {};
|
|
for (const row of rows) {
|
|
const k = String(row[key]);
|
|
if (!map[k]) map[k] = [];
|
|
map[k].push(row);
|
|
}
|
|
return map;
|
|
}
|
|
|
|
const followupRows = contextRows.filter((row) => row.tipo === 'followup');
|
|
const taskRows = contextRows.filter((row) => row.tipo === 'task');
|
|
|
|
const followupsByTicket = groupBy(followupRows, 'tickets_id');
|
|
const tasksByTicket = groupBy(taskRows, 'tickets_id');
|
|
|
|
return candidatosBase.map((base) => {
|
|
const idKey = String(base.id);
|
|
const followups = (followupsByTicket[idKey] || []).map((f) => ({ id: f.id, date: f.date, texto: f.texto }));
|
|
const tasks = (tasksByTicket[idKey] || []).map((t) => ({ id: t.id, date: t.date, status: t.status, texto: t.texto }));
|
|
const ticket = normalizeTicket(base, { followups, tasks });
|
|
const contextHash = buildContextFingerprint(ticket);
|
|
return { json: { ticket, contextHash } };
|
|
});
|