Files
claudetools/projects/dataforth-dos/database/notify.js
Mike Swanson 2ae7d6a0ac fix: dataforth API upload — unregistered model skip list, batch-500 fallback, FAIL filter
- UNREGISTERED_MODELS set: 9 model numbers not in Hoffman API catalog; skipped
  silently instead of generating errors
- batch-500 fallback: when a bulk batch returns HTTP 500, retry each record
  individually so good records get stamped and only truly-bad records count
  as errors
- FAIL-parameter filter: records with any FAIL on a parameter line are excluded
  from the push before the batch is assembled
- notify.js integration: wired in existing notification module

Files added:
- projects/dataforth-dos/database/upload-to-api.js
- projects/dataforth-dos/database/notify.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 12:25:33 -07:00

72 lines
2.2 KiB
JavaScript

/**
* Fire-and-forget alert notification module.
* Email sending is not yet implemented (Entra app pending).
* Logs a formatted preview of what would be emailed to stderr.
* Never throws — callers do not need to guard this.
*/
const os = require('os');
const TO = 'mike@azcomputerguru.com';
const FROM = 'sysadmin@dataforth.com';
const HOST = os.hostname();
const PREFIX = '[NOTIFY]';
const SEP_EQ = '='.repeat(60);
const SEP_DAS = '-'.repeat(60);
/**
* Log a formatted email preview to stderr.
*
* @param {string} subject - Email subject line (prefixed with [TestDataDB] automatically)
* @param {object} [context={}]
* @param {string} [context.stage] - Pipeline stage where the alert fired
* @param {string} [context.error] - Error message or description
* @param {string[]} [context.details] - Additional detail lines
* @param {object} [context.stats] - Arbitrary stats object, serialized as JSON
*/
function alert(subject, context) {
context = context || {};
const lines = [];
lines.push(`${PREFIX} ${SEP_EQ}`);
lines.push(`${PREFIX} TO: ${TO}`);
lines.push(`${PREFIX} FROM: ${FROM} (pending Entra app)`);
lines.push(`${PREFIX} SUBJECT: [TestDataDB] ${subject}`);
lines.push(`${PREFIX} ${SEP_DAS}`);
lines.push(`${PREFIX} Host: ${HOST}`);
lines.push(`${PREFIX} Time: ${new Date().toISOString()}`);
if (context.stage !== undefined) {
lines.push(`${PREFIX} Stage: ${context.stage}`);
}
if (context.error !== undefined) {
lines.push(`${PREFIX}`);
lines.push(`${PREFIX} ${context.error}`);
}
if (Array.isArray(context.details) && context.details.length > 0) {
lines.push(`${PREFIX}`);
for (const line of context.details) {
lines.push(`${PREFIX} ${line}`);
}
}
if (context.stats !== undefined) {
lines.push(`${PREFIX} Stats: ${JSON.stringify(context.stats)}`);
}
lines.push(`${PREFIX} ${SEP_EQ}`);
lines.push(`${PREFIX} (email not sent — Entra app pending)`);
try {
for (const line of lines) {
process.stderr.write(line + '\n');
}
} catch (_) {
// stderr write failure — nothing we can do
}
}
module.exports = { alert };