// Evidence-only DOM measurement: never changes renderer, goldens or acceptance policy. const fs = require('node:fs'); const path = require('node:path'); const assert = require('node:assert/strict'); const crypto = require('node:crypto'); const req = require('node:module').createRequire(path.resolve(__dirname, '../../job-tracker-ui/package.json')); const { chromium } = req('playwright'); const ts = req('typescript'); const hash = bytes => crypto.createHash('sha256').update(bytes).digest('hex'); const previewFile = path.resolve(__dirname, '../../job-tracker-ui/src/cvPreview.ts'); const previewSource = fs.readFileSync(previewFile); const compiled = ts.transpileModule(previewSource.toString('utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText; const copy = { exports: {} }; new Function('exports', 'module', compiled)(copy.exports, copy); async function main() { const [source, target] = process.argv.slice(2); assert.ok(source && target, 'Usage: node measure-baselines.cjs '); assert.ok(!fs.existsSync(target), 'Keep earlier measurements immutable'); const input = fs.readFileSync(path.join(source, 'measurements.json')); const fixtures = JSON.parse(input).fixtures; assert.equal(fixtures.length, 36); const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 794, height: 1123 }, serviceWorkers: 'block', offline: true }); await page.route('**/*', route => route.abort()); const rows = []; try { for (const fixture of fixtures) { assert.match(fixture.fixture, /^(?:short-en|medium-nb|long-en|dense-nb)-[a-z-]+$/); const html = fs.readFileSync(path.join(source, fixture.fixture, 'render.html')); assert.ok(html.length <= 8 * 1024 * 1024, 'Excessive synthetic HTML'); await page.setContent(copy.exports.previewDocumentHtml(html.toString('utf8'), 297 * 96 / 25.4)); await page.waitForFunction(() => document.documentElement.dataset.cvPreviewReady === 'true'); const measured = await page.evaluate(() => { const name = document.querySelector('.name'); const node = name?.firstChild; if (node?.nodeType !== Node.TEXT_NODE || !node.textContent.startsWith('S01 ')) throw new Error('Unexpected synthetic name fixture'); const range = document.createRange(); range.setStart(node, 0); range.setEnd(node, 3); const rect = range.getBoundingClientRect(), style = getComputedStyle(name); const sentinel = document.createElement('span'); sentinel.style.cssText = 'display:inline-block;width:0;height:0;padding:0;margin:0;border:0;vertical-align:baseline'; name.prepend(sentinel); const baseline = sentinel.getBoundingClientRect().top; sentinel.remove(); const after = range.getBoundingClientRect(); const context = document.createElement('canvas').getContext('2d'); context.font = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`; const metrics = context.measureText('S01'); return { rangeX: rect.x, rangeTop: rect.y, rangeHeight: rect.height, rangeWidth: rect.width, sentinelBaseline: baseline, canvasAscent: metrics.fontBoundingBoxAscent, canvasDescent: metrics.fontBoundingBoxDescent, canvasBaseline: rect.y + metrics.fontBoundingBoxAscent, sentinelChangedGeometry: rect.x !== after.x || rect.y !== after.y || rect.width !== after.width || rect.height !== after.height, font: context.font, fontFamily: style.fontFamily, fontSize: style.fontSize, fontWeight: style.fontWeight, fontLoaded: document.fonts.check(context.font, 'S01'), pages: Number(document.documentElement.dataset.cvPreviewPages) }; }); const original = fixture.measured.tokens.find(token => token.token === 'S01'); assert.ok(measured.fontLoaded && !measured.sentinelChangedGeometry); assert.ok(Math.abs(measured.sentinelBaseline - measured.canvasBaseline) < 0.01, 'Independent baseline measurements disagree'); assert.ok(Math.abs(measured.rangeX - original.x) < 0.01 && Math.abs(measured.rangeTop - original.y) < 0.01, 'Preview source/geometry drift'); assert.equal(measured.pages, fixture.previewPages); rows.push({ fixture: fixture.fixture, htmlSha256: hash(html), pdfSha256: hash(fs.readFileSync(path.join(source, fixture.fixture, 'export.pdf'))), ...measured }); } fs.writeFileSync(target, JSON.stringify({ evidenceOnly: true, policy: 'PROPOSED_DIAGNOSTIC_NOT_ORIGINAL_GATE_REPLACEMENT', browser: browser.version(), measurementsSha256: hash(input), previewSourceSha256: hash(previewSource), rows }, null, 2)); console.log(`Measured ${rows.length} synthetic DOM baselines; sentinel/canvas agree; geometry unchanged`); } finally { await browser.close(); } } main().catch(error => { console.error(error.message); process.exitCode = 1; });