Files
claudetools/projects/dataforth-dos/tools/enrich-8b5bscm.js
Mike Swanson 316c6f67e0 dataforth(datasheet): converge 8B/5B/SCM onto the DSCA template machinery (gated; WIP)
Generalized the shared renderer (datasheet-exact.js) so the per-model template path is
no longer DSCA-only — 8B/SCM5B now route through the same templates/slotMap/fround path
as DSCA. SCM7B stays on its separate parse7BRawData/legacy path (excluded). Changes
(all behind the per-model `validated` gate; non-templated families byte-unchanged, and
DSCA verified non-regressed at 54/56 + staged-92 still render):
- Load 8b5bscm-templates.json (MINED_8B5BSCM); for family 8B/SCM5B, a mined template
  takes the template path (else falls through to the legacy DATA_LINES path).
- Final-Test header is now the verbatim captured `ftHeader` (8B/5B use two schemes —
  legacy "Measured Value" vs DSCA "Measured Value*"); enrich-8b5bscm.js captured it for
  all 136 from the Hoffman originals.
- Accuracy data formatter chosen by input type detected from accHeader: frequency(Hz)/
  AC(AAC/VAC) -> formatAccuracyLineDSCA3345 (now takes inputType, not model prefix);
  standard voltage/current/temp -> legacy formatAccuracyLine.
- parseRawData step-skip generalized to any templated model (skipStepIfStatus).
- Footer 240VAC/Hi-Pot family blocks skipped for templated models (rows carry them).
- Templated SCM5B prepends "SCM" to the printed model name.
- slotmap-from-hoffman.js parameterized (DSCA_TPL) — derived 80 slotMaps for 8b5bscm.

Validation vs live Hoffman originals (validate-mined.js): 37/136 pass and are marked
validated -> 13 real 8B/SCM5B render live via the template path; 24 SCM7B already match
via the unchanged legacy path. Everything else stays null (gated, safe) — nothing
published.

Remaining long tail (well-characterized, next session): ~66 render-null need slotMaps
the Hoffman-oracle derivation couldn't get (vintage / parse); ~33 multi-nuance fails:
Final-Test sign handling on some 8B/5B measured values, accuracy-precision fround in the
legacy std formatter, "Packing Check List" vs "Check List" variants, and other per-model
footer/format quirks. Each failing model stacks several, so single fixes don't flip them.

Tools: enrich-8b5bscm.js, validate-mined.js (generalized validator), slotmap-from-hoffman.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 18:45:44 -07:00

31 lines
2.5 KiB
JavaScript

// Enrich 8b5bscm-templates.json: capture each model's verbatim Final-Test HEADER line
// (the "Parameter ... Measured Value[*] ... Specification ... Status" line) from its
// _srcSerial Hoffman original, since 8B/5B use two different header schemes (legacy
// "Measured Value" vs DSCA-style "Measured Value*"). Stored as `ftHeader`. --apply writes.
const fs = require('fs'), https = require('https');
const TPL = './8b5bscm-templates.json';
const c = JSON.parse(fs.readFileSync('C:\\ProgramData\\dataforth-uploader\\credentials.json', 'utf8'));
const APPLY = process.argv.includes('--apply');
function req(m, uri, h, b) { return new Promise((res, rej) => { const u = new URL(uri); const r = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: m, headers: h, timeout: 30000 }, x => { let d = ''; x.on('data', c => d += c); x.on('end', () => { try { res(JSON.parse(d)); } catch { res({ _raw: d }); } }); }); r.on('error', rej); if (b) r.write(b); r.end(); }); }
(async () => {
const tpl = JSON.parse(fs.readFileSync(TPL, 'utf8'));
const form = Object.entries({ grant_type: 'client_credentials', client_id: c.CF_CLIENT_ID, client_secret: c.CF_CLIENT_SECRET, scope: c.CF_SCOPE }).map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v)).join('&');
const t = (await req('POST', c.CF_TOKEN_URL, { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(form) }, form)).access_token;
let done = 0; const schemes = {};
for (const m of Object.keys(tpl)) {
const sn = tpl[m]._srcSerial; if (!sn) continue;
const g = await req('GET', c.CF_API_BASE + '/api/v1/TestReportDataFiles/' + encodeURIComponent(sn), { Authorization: 'Bearer ' + t });
if (!g.Content) continue;
const L = g.Content.replace(/\r/g, '').split('\n');
const fi = L.findIndex(l => /FINAL TEST RESULTS/.test(l)); if (fi < 0) continue;
const hi = L.findIndex((l, i) => i > fi && /Parameter\s+Measured/.test(l)); if (hi < 0) continue;
tpl[m].ftHeader = L[hi];
const star = /Measured Value\*/.test(L[hi]) ? 'star' : 'plain';
schemes[star] = (schemes[star] || 0) + 1;
done++;
}
console.log('captured ftHeader for ' + done + ' models; header schemes: ' + JSON.stringify(schemes));
if (APPLY) { fs.writeFileSync(TPL, JSON.stringify(tpl)); console.log('[APPLY] wrote ' + TPL); }
else console.log('(dry run — pass --apply)');
})().catch(e => { console.error('ERR', e.message); process.exit(1); });