Files
claudetools/projects/dataforth-dos/datasheet-pipeline/implementation-upload/database/_sanity_check.js
Mike Swanson 733d87f20e Dataforth UI push + dedup + refactor, GuruRMM roadmap evolution, Azure signing setup
Dataforth (projects/dataforth-dos/):
- UI feature: row coloring + PUSH/RE-PUSH buttons + Website Status filter
- Database dedup to one row per SN (2.89M -> 469K rows, UNIQUE constraint added)
- Import logic handles FAIL -> PASS retest transition
- Refactored upload-to-api.js to render datasheets in-memory (dropped For_Web filesystem dep)
- Bulk pushed 170,984 records to Hoffman API
- Statistical sanity check: 100/100 stamped SNs verified on Hoffman

GuruRMM (projects/msp-tools/guru-rmm/):
- ROADMAP.md: added Terminology (5-tier hierarchy), Tunnel Channels Phase 2,
  Logging/Audit/Observability, Multi-tenancy, Modular Architecture,
  Protocol Versioning, Certificates sections + Decisions Log
- CONTEXT.md: hierarchy table, new anti-patterns (bootstrap sacred,
  no cross-module imports), revised next-steps priorities

Session logs for both projects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:39:32 -07:00

80 lines
3.4 KiB
JavaScript

const fs = require('fs');
const https = require('https');
const { URL } = require('url');
const db = require('./db');
const CREDS = JSON.parse(fs.readFileSync('C:/ProgramData/dataforth-uploader/credentials.json', 'utf8'));
function req(method, uri, headers) {
return new Promise((res, rej) => {
const u = new URL(uri);
const r = https.request({
hostname: u.hostname, port: u.port || 443, path: u.pathname + u.search,
method, headers, timeout: 20000,
}, rs => {
let d = '';
rs.on('data', c => d += c);
rs.on('end', () => res({ status: rs.statusCode, body: d }));
});
const t = setTimeout(() => { r.destroy(); rej(new Error('timeout')); }, 20000);
r.on('error', rej);
r.on('close', () => clearTimeout(t));
r.end();
});
}
(async () => {
const form = 'grant_type=client_credentials&client_id=' + encodeURIComponent(CREDS.CF_CLIENT_ID) +
'&client_secret=' + encodeURIComponent(CREDS.CF_CLIENT_SECRET) + '&scope=' + encodeURIComponent(CREDS.CF_SCOPE);
const tokR = await new Promise((r, j) => {
const u = new URL(CREDS.CF_TOKEN_URL);
const rq = https.request({
hostname: u.hostname, port: 443, path: u.pathname, method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(form) },
}, rs => {
let d = '';
rs.on('data', c => d += c);
rs.on('end', () => r({ status: rs.statusCode, body: d }));
});
rq.on('error', j);
rq.write(form);
rq.end();
});
const token = JSON.parse(tokR.body).access_token;
async function sample(label, sql, expect) {
console.log('=== ' + label + ' ===');
const rows = await db.query(sql);
let hit = 0, miss = 0, err = 0;
for (const r of rows) {
try {
const rr = await req('GET',
CREDS.CF_API_BASE + '/api/v1/TestReportDataFiles/' + encodeURIComponent(r.serial_number),
{ 'Authorization': 'Bearer ' + token });
if (rr.status === 200) hit++;
else if (rr.status === 404) miss++;
else { err++; console.log(' HTTP ' + rr.status + ' ' + r.serial_number); }
} catch (e) { err++; console.log(' ERR ' + r.serial_number + ' ' + e.message); }
}
console.log(' hit=' + hit + ' miss=' + miss + ' err=' + err + ' (' + expect + ')');
return { hit, miss, err };
}
await sample(
'Sample 1: 100 random stamped api_uploaded_at IS NOT NULL',
"SELECT serial_number FROM test_records WHERE api_uploaded_at IS NOT NULL ORDER BY random() LIMIT 100",
'expect hit=100',
);
await sample(
'Sample 2: 100 random unpushable PASS (NULL api_uploaded_at, PASS)',
"SELECT serial_number FROM test_records WHERE api_uploaded_at IS NULL AND overall_result='PASS' ORDER BY random() LIMIT 100",
'expect mostly miss (these are the 10K unpushables)',
);
await sample(
'Sample 3: 50 random FAIL',
"SELECT serial_number FROM test_records WHERE overall_result='FAIL' ORDER BY random() LIMIT 50",
'expect miss=50 (FAILs never reach Hoffman)',
);
await db.close();
})().catch(e => { console.error('FATAL', e.message); process.exit(1); });