#!/usr/bin/env node // Diagnostic: check alignment between counts history dates and anomaly log dates // Usage: node backend/scripts/diagnose-chart-alignment.js const path = require('path'); const sqlite3 = require('sqlite3').verbose(); const DB_PATH = path.join(__dirname, '..', 'cve_database.db'); function dbAll(db, sql, params = []) { return new Promise((resolve, reject) => { db.all(sql, params, (err, rows) => { if (err) reject(err); else resolve(rows || []); }); }); } function fmtDate(d) { if (!d) return ''; const p = d.split('-'); if (p.length === 3) return `${p[1]}/${p[2]}/${p[0].slice(2)}`; return d; } function extractDate(ts) { if (!ts) return ''; return ts.split('T')[0].split(' ')[0]; } async function main() { const db = new sqlite3.Database(DB_PATH); // Get counts history dates (same query as the API) const countsRows = await dbAll(db, `SELECT date FROM ( SELECT DATE(recorded_at) AS date, ROW_NUMBER() OVER (PARTITION BY DATE(recorded_at) ORDER BY recorded_at DESC) AS rn FROM ivanti_counts_history ) WHERE rn = 1 ORDER BY date ASC` ); const countsDates = new Set(countsRows.map(r => fmtDate(r.date))); // Get anomaly history (same query as the API) const anomalyRows = await dbAll(db, `SELECT sync_timestamp, newly_archived_count, returned_count, return_classification_json FROM ivanti_sync_anomaly_log ORDER BY sync_timestamp DESC LIMIT 30` ); console.log('=== Counts History Dates (last 10) ==='); const lastTen = countsRows.slice(-10); for (const r of lastTen) { console.log(` ${r.date} → ${fmtDate(r.date)}`); } console.log('\n=== Anomaly Log Entries with Activity ==='); for (const a of anomalyRows) { if (a.newly_archived_count === 0 && a.returned_count === 0) continue; const rawDate = extractDate(a.sync_timestamp); const dateKey = fmtDate(rawDate); const inCounts = countsDates.has(dateKey); console.log(` ${a.sync_timestamp} → raw="${rawDate}" → key="${dateKey}" | archived=${a.newly_archived_count} returned=${a.returned_count} | in counts: ${inCounts ? 'YES' : '*** NO ***'}`); } console.log('\n=== All Anomaly Dates NOT in Counts History ==='); let missingCount = 0; for (const a of anomalyRows) { const rawDate = extractDate(a.sync_timestamp); const dateKey = fmtDate(rawDate); if (!countsDates.has(dateKey)) { console.log(` MISSING: ${a.sync_timestamp} → "${dateKey}" (archived=${a.newly_archived_count}, returned=${a.returned_count})`); missingCount++; } } if (missingCount === 0) console.log(' (none — all anomaly dates have matching counts history)'); db.close(); } main().catch(err => { console.error('Fatal error:', err); process.exit(1); });