import assert from 'node:assert/strict' import { createHash } from 'node:crypto' import fs from 'node:fs/promises' import os from 'node:os' import path from 'node:path' import { createRequire } from 'node:module' import { spawn } from 'node:child_process' import { pathToFileURL } from 'node:url' const require = createRequire(import.meta.url) const electronExecutable = require('electron') const runtime = path.resolve('.tmp/rea-css-runtime/dist') const hash = bytes => createHash('sha256').update(bytes).digest('hex') const evidenceIdPattern = /^ev_[a-f0-9]{64}$/ const electronHelperSource = String.raw` const fs = require('node:fs') const path = require('node:path') const { app, nativeImage } = require('electron') const jobPath = process.env.YCODE_PIXEL_JOB const resultPath = process.env.YCODE_PIXEL_RESULT const finish = (value, code = 0) => { try { fs.writeFileSync(resultPath, JSON.stringify(value)) } catch {} app.exit(code) } const fail = error => finish({ ok: false, error: String(error && (error.stack || error.message) || error) }, 1) try { const job = JSON.parse(fs.readFileSync(jobPath, 'utf8')) const isolated = path.join(path.dirname(jobPath), 'electron-data') for (const name of ['userData', 'sessionData', 'logs']) { try { app.setPath(name, path.join(isolated, name)) } catch {} } app.disableHardwareAcceleration() app.whenReady().then(() => { try { if (job.mode === 'fixtures') { const createPng = (file, width, height, changed) => { const bitmap = Buffer.alloc(width * height * 4) for (let offset = 0; offset < bitmap.length; offset += 4) bitmap.set([20, 40, 60, 255], offset) if (changed) bitmap[0] += 1 const image = nativeImage.createFromBitmap(bitmap, { width, height, scaleFactor: 1 }) if (image.isEmpty()) throw new Error('nativeImage could not encode self-test fixture') fs.writeFileSync(file, image.toPNG()) } createPng(job.files.reference, 2, 2, false) createPng(job.files.changed, 2, 2, true) createPng(job.files.wide, 3, 2, false) finish({ ok: true }) return } if (job.mode !== 'compare') throw new Error('Unknown nativeImage helper mode') const output = [] for (const pair of job.pairs) { const reference = nativeImage.createFromBuffer(fs.readFileSync(pair.reference)) const candidate = nativeImage.createFromBuffer(fs.readFileSync(pair.candidate)) if (reference.isEmpty() || candidate.isEmpty()) throw new Error('A screenshot could not be decoded by nativeImage') const beforeSize = reference.getSize(1) const afterSize = candidate.getSize(1) const base = { name: pair.name, before: beforeSize, after: afterSize, channel_tolerance: job.channelTolerance, } if (beforeSize.width !== afterSize.width || beforeSize.height !== afterSize.height) { output.push({ ...base, status: 'dimension_mismatch', compared_pixels: 0, changed_pixels: null, changed_ratio: null, mean_absolute_channel_delta: null, maximum_channel_delta: null, diff_width: null, diff_height: null }) continue } const region = pair.region || { x: 0, y: 0, width: beforeSize.width, height: beforeSize.height } if (!Number.isInteger(region.x) || !Number.isInteger(region.y) || !Number.isInteger(region.width) || !Number.isInteger(region.height) || region.x < 0 || region.y < 0 || region.width < 1 || region.height < 1 || region.x + region.width > beforeSize.width || region.y + region.height > beforeSize.height) { throw new Error('Comparison region must be a positive integer rectangle inside both screenshots') } const beforeBitmap = reference.toBitmap({ scaleFactor: 1 }) const afterBitmap = candidate.toBitmap({ scaleFactor: 1 }) const expectedBeforeBytes = beforeSize.width * beforeSize.height * 4 const expectedAfterBytes = afterSize.width * afterSize.height * 4 if (beforeBitmap.length !== expectedBeforeBytes || afterBitmap.length !== expectedAfterBytes) throw new Error('nativeImage returned an unexpected bitmap byte count') const diffBitmap = Buffer.alloc(region.width * region.height * 4) const comparedPixels = region.width * region.height let changedPixels = 0 let maximumChannelDelta = 0 let absoluteChannelDelta = 0 for (let y = 0; y < region.height; y += 1) { for (let x = 0; x < region.width; x += 1) { const beforeOffset = ((region.y + y) * beforeSize.width + region.x + x) * 4 const afterOffset = ((region.y + y) * afterSize.width + region.x + x) * 4 const diffOffset = (y * region.width + x) * 4 let pixelMaximum = 0 for (let channel = 0; channel < 4; channel += 1) { const delta = Math.abs(beforeBitmap[beforeOffset + channel] - afterBitmap[afterOffset + channel]) absoluteChannelDelta += delta pixelMaximum = Math.max(pixelMaximum, delta) maximumChannelDelta = Math.max(maximumChannelDelta, delta) } if (pixelMaximum > job.channelTolerance) { changedPixels += 1 diffBitmap.fill(255, diffOffset, diffOffset + 4) } } } const diffImage = nativeImage.createFromBitmap(diffBitmap, { width: region.width, height: region.height, scaleFactor: 1 }) if (diffImage.isEmpty()) throw new Error('nativeImage could not encode the diff bitmap') fs.writeFileSync(pair.diffPath, diffImage.toPNG()) output.push({ ...base, region, status: changedPixels === 0 ? 'identical' : 'different', compared_pixels: comparedPixels, changed_pixels: changedPixels, changed_ratio: changedPixels / comparedPixels, mean_absolute_channel_delta: absoluteChannelDelta / (comparedPixels * 4), maximum_channel_delta: maximumChannelDelta, diff_width: region.width, diff_height: region.height, }) } finish({ ok: true, pairs: output }) } catch (error) { fail(error) } }).catch(fail) } catch (error) { fail(error) } ` function parseManifest(value) { if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Manifest must be a JSON object') const source = value.source ?? { kind: 'local-fixture' } if (!source || typeof source !== 'object' || !['rea-workbuddy', 'local-fixture'].includes(source.kind)) throw new Error('source.kind must be rea-workbuddy or local-fixture') if (!Array.isArray(value.requiredStates) || value.requiredStates.length === 0 || value.requiredStates.some(state => typeof state !== 'string' || !state.trim()) || new Set(value.requiredStates).size !== value.requiredStates.length) throw new Error('requiredStates must be a non-empty array of unique non-empty names') if (!Array.isArray(value.pairs)) throw new Error('pairs must be an array') const names = new Set() const pairs = value.pairs.map((pair, index) => { if (!pair || typeof pair !== 'object' || Array.isArray(pair)) throw new Error(`pairs[${index}] must be an object`) if (typeof pair.name !== 'string' || !pair.name.trim() || names.has(pair.name)) throw new Error(`pairs[${index}].name must be unique and non-empty`) names.add(pair.name) if (typeof pair.reference !== 'string' || !pair.reference || typeof pair.candidate !== 'string' || !pair.candidate) throw new Error(`pairs[${index}] requires reference and candidate PNG paths`) if (pair.region !== undefined) { const { x, y, width, height } = pair.region ?? {} if (![x, y, width, height].every(Number.isInteger) || x < 0 || y < 0 || width < 1 || height < 1) throw new Error(`pairs[${index}].region must be a positive integer rectangle`) } if (source.kind === 'rea-workbuddy') { const evidence = pair.referenceEvidence if (!evidence || typeof evidence !== 'object' || !evidenceIdPattern.test(evidence.id) || typeof evidence.archive !== 'string' || !evidence.archive) throw new Error(`pairs[${index}] requires referenceEvidence with a valid Evidence id and archive`) } return { ...pair } }) const channelTolerance = value.channelTolerance ?? 0 if (!Number.isInteger(channelTolerance) || channelTolerance < 0 || channelTolerance > 255) throw new Error('channelTolerance must be an integer from 0 to 255') return { source, requiredStates: [...value.requiredStates], pairs, channelTolerance } } async function authenticateEvidence(evidencePath) { const modulePath = pathToFileURL(path.join(runtime, 'domain/evidence.js')) let parseEvidence try { ({ parseEvidence } = await import(modulePath)) } catch (error) { throw new Error(`Prepared REA runtime is required to authenticate Evidence: ${error.message}`) } return parseEvidence(evidencePath) } function screenshotArtifacts(evidence) { const visuals = evidence.normalized_result?.visuals const artifacts = [] if (visuals?.artifact) artifacts.push({ location: 'visuals.artifact', artifact: visuals.artifact }) for (let index = 0; index < (visuals?.probe?.frames?.length ?? 0); index += 1) { const artifact = visuals.probe.frames[index]?.artifact if (artifact) artifacts.push({ location: `visuals.probe.frames[${index}].artifact`, artifact }) } return artifacts } function checkedArtifactHash(artifact) { if (!artifact || artifact.media_type !== 'image/png' || typeof artifact.data_base64 !== 'string' || typeof artifact.sha256 !== 'string') return undefined const bytes = Buffer.from(artifact.data_base64, 'base64') if (!bytes.length || bytes.toString('base64') !== artifact.data_base64 || (artifact.bytes !== undefined && artifact.bytes !== bytes.length)) return undefined const actualHash = hash(bytes) return actualHash === artifact.sha256 ? actualHash : undefined } async function verifyReferenceEvidence(pair, manifestDirectory, referenceHash) { const archive = path.resolve(manifestDirectory, pair.referenceEvidence.archive) let raw try { raw = JSON.parse(await fs.readFile(archive, 'utf8')) } catch (error) { throw new Error(`Cannot read reference Evidence archive for ${pair.name}: ${error.message}`) } if (raw.evidence_id !== pair.referenceEvidence.id) throw new Error(`Evidence id does not match its archive for ${pair.name}`) let evidence try { evidence = await authenticateEvidence(raw) } catch (error) { throw new Error(`Reference Evidence archive failed authentication for ${pair.name}: ${error.message}`) } if (evidence.operation !== 'inspect_electron_page') throw new Error(`Reference Evidence is not an Electron page inspection for ${pair.name}`) if (evidence.provider?.id !== 'rea-cdp-electron') throw new Error(`Reference Evidence provider is not rea-cdp-electron for ${pair.name}`) const targetPath = evidence.normalized_result?.target?.file_path if (typeof targetPath !== 'string' || !/WorkBuddy[\\/]resources[\\/]app\.asar[\\/]renderer[\\/]index\.html$/i.test(targetPath)) { throw new Error(`Reference Evidence target is not the WorkBuddy renderer for ${pair.name}`) } const visualProbe = evidence.parameters?.visual_probe if (visualProbe !== undefined && (!visualProbe || typeof visualProbe !== 'object' || Array.isArray(visualProbe) || !Array.isArray(visualProbe.actions))) { throw new Error(`Reference Evidence visual_probe.actions is malformed for ${pair.name}`) } const visualProbeActions = visualProbe?.actions ?? [] const hasVisualProbeActions = visualProbeActions.length > 0 const expectedAuthority = hasVisualProbeActions ? 'controlled-replay' : 'external-service' if (evidence.authority !== expectedAuthority) throw new Error(`Reference Evidence authority does not match visual_probe.actions for ${pair.name}`) const userAgent = evidence.normalized_result?.browser?.user_agent const version = typeof userAgent === 'string' ? userAgent.match(/WorkBuddy[ /]([\d.]+)/i)?.[1] ?? 'unobserved' : 'unobserved' const matching = screenshotArtifacts(evidence).filter(({ artifact }) => checkedArtifactHash(artifact) === referenceHash) if (!matching.length) throw new Error(`Reference PNG SHA is absent from authenticated REA baseline/probe artifacts for ${pair.name}`) return { id: evidence.evidence_id, archive, artifact_locations: matching.map(item => item.location), sha256: referenceHash, target_file_path: targetPath, authority: evidence.authority, version, version_observed: version !== 'unobserved', } } function safeDiffName(name) { const stem = name.normalize('NFKD').replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48) || 'state' return `${stem}-${hash(Buffer.from(name, 'utf8')).slice(0, 12)}-diff.png` } async function runElectronHelper(job) { const helperDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'ycode-visual-pixel-helper-')) const helperPath = path.join(helperDirectory, 'helper.cjs') const packagePath = path.join(helperDirectory, 'package.json') const jobPath = path.join(helperDirectory, 'job.json') const resultPath = path.join(helperDirectory, 'result.json') await fs.writeFile(helperPath, electronHelperSource, 'utf8') await fs.writeFile(packagePath, JSON.stringify({ name: 'ycode-visual-pixel-helper', version: '1.0.0', main: 'helper.cjs' }), 'utf8') await fs.writeFile(jobPath, JSON.stringify(job), 'utf8') const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => name.toUpperCase() !== 'ELECTRON_RUN_AS_NODE')) env.YCODE_PIXEL_JOB = jobPath env.YCODE_PIXEL_RESULT = resultPath try { const completion = await new Promise((resolve, reject) => { const child = spawn(electronExecutable, ['--no-sandbox', '--disable-gpu', '--disable-extensions', helperDirectory], { cwd: helperDirectory, env, windowsHide: true, stdio: ['ignore', 'ignore', 'pipe'], }) let stderr = '' let settled = false const timer = setTimeout(() => { child.kill() if (!settled) { settled = true reject(new Error('Hidden Electron nativeImage helper timed out')) } }, 45000) timer.unref() child.stderr.on('data', chunk => { stderr += chunk.toString() }) child.once('error', error => { clearTimeout(timer) if (!settled) { settled = true; reject(error) } }) child.once('close', (code, signal) => { clearTimeout(timer) if (settled) return settled = true resolve({ code, signal, stderr }) }) }) let result try { result = JSON.parse(await fs.readFile(resultPath, 'utf8')) } catch { throw new Error(`Hidden Electron nativeImage helper exited without a result (code ${completion.code}${completion.stderr ? `): ${completion.stderr.trim()}` : ')'}`) } if (!result.ok || completion.code !== 0) throw new Error(result.error || `Hidden Electron nativeImage helper failed (code ${completion.code})`) return result } finally { await fs.rm(helperDirectory, { recursive: true, force: true, maxRetries: 8, retryDelay: 200 }) } } async function compareManifest(manifest, manifestDirectory, outputDirectory) { const parsed = parseManifest(manifest) const prepared = [] for (const pair of parsed.pairs) { const referencePath = path.resolve(manifestDirectory, pair.reference) const candidatePath = path.resolve(manifestDirectory, pair.candidate) let referenceBytes, candidateBytes try { [referenceBytes, candidateBytes] = await Promise.all([fs.readFile(referencePath), fs.readFile(candidatePath)]) } catch (error) { throw new Error(`Cannot read screenshot pair ${pair.name}: ${error.message}`) } const referenceSha = hash(referenceBytes) const candidateSha = hash(candidateBytes) const referenceEvidence = parsed.source.kind === 'rea-workbuddy' ? await verifyReferenceEvidence(pair, manifestDirectory, referenceSha) : undefined prepared.push({ name: pair.name, reference: referencePath, candidate: candidatePath, reference_sha256: referenceSha, candidate_sha256: candidateSha, region: pair.region, reference_evidence: referenceEvidence, }) } await fs.mkdir(outputDirectory, { recursive: true }) const helperPairs = prepared.map(pair => ({ name: pair.name, reference: pair.reference, candidate: pair.candidate, region: pair.region, diffPath: path.join(outputDirectory, safeDiffName(pair.name)), })) const nativeResult = await runElectronHelper({ mode: 'compare', channelTolerance: parsed.channelTolerance, pairs: helperPairs }) const nativeByName = new Map(nativeResult.pairs.map(pair => [pair.name, pair])) const results = prepared.map(pair => { const compared = nativeByName.get(pair.name) if (!compared) throw new Error(`nativeImage helper omitted comparison ${pair.name}`) const dimensions = { width: compared.before.width, height: compared.before.height } const afterDimensions = { width: compared.after.width, height: compared.after.height } const diffPath = compared.diff_width === null ? undefined : helperPairs.find(item => item.name === pair.name).diffPath return { name: pair.name, status: compared.status, reference: { path: pair.reference, sha256: pair.reference_sha256, dimensions }, candidate: { path: pair.candidate, sha256: pair.candidate_sha256, dimensions: afterDimensions }, ...(compared.region ? { region: compared.region } : {}), channel_tolerance: compared.channel_tolerance, compared_pixels: compared.compared_pixels, changed_pixels: compared.changed_pixels, changed_ratio: compared.changed_ratio, mean_absolute_channel_delta: compared.mean_absolute_channel_delta, maximum_channel_delta: compared.maximum_channel_delta, diff_png: diffPath ? { path: diffPath, sha256: undefined, dimensions: { width: compared.diff_width, height: compared.diff_height } } : null, ...(pair.reference_evidence ? { reference_evidence: pair.reference_evidence } : {}), } }) for (const pair of results) { if (pair.diff_png) pair.diff_png.sha256 = hash(await fs.readFile(pair.diff_png.path)) } const missingRequiredStates = parsed.requiredStates.filter(name => !parsed.pairs.some(pair => pair.name === name)) const status = missingRequiredStates.length ? 'incomplete' : results.some(pair => pair.status !== 'identical') ? 'different' : 'identical' const observedVersions = results.flatMap(pair => pair.reference_evidence ? [{ state: pair.name, evidence_id: pair.reference_evidence.id, version: pair.reference_evidence.version, observed: pair.reference_evidence.version_observed, }] : []) let originalParity if (parsed.source.kind !== 'rea-workbuddy') { originalParity = { status: 'not_assessed', exactOriginalParity: false, versions: [], reasons: ['Source is local fixture data, not authenticated WorkBuddy Evidence.'] } } else { const reasons = [] if (missingRequiredStates.length) reasons.push('One or more required states are missing.') if (observedVersions.length !== results.length || observedVersions.some(item => !item.observed)) reasons.push('A WorkBuddy version was not observed in browser.user_agent.') if (reasons.length) originalParity = { status: 'incomplete', exactOriginalParity: false, versions: observedVersions, reasons } else if (results.some(pair => pair.status !== 'identical')) originalParity = { status: 'different', exactOriginalParity: false, versions: observedVersions, reasons: ['At least one declared state differs beyond channel tolerance.'] } else if (parsed.channelTolerance !== 0) originalParity = { status: 'not_exact', exactOriginalParity: false, versions: observedVersions, reasons: ['Non-zero channel tolerance does not establish exact pixel parity.'] } else originalParity = { status: 'exact_for_declared_states', exactOriginalParity: true, versions: observedVersions, reasons: [] } } const reportStatus = parsed.source.kind === 'rea-workbuddy' && originalParity.status === 'incomplete' ? 'incomplete' : parsed.source.kind === 'rea-workbuddy' && originalParity.status === 'not_exact' ? 'approximate' : status return { status: reportStatus, source: parsed.source, originalParity, scope: { assessment: 'declared_state_set_only', required_states: parsed.requiredStates, full_1to1: 'not_assessed', }, missing_required_states: missingRequiredStates, channel_tolerance: parsed.channelTolerance, metric_definition: 'Changed pixels have at least one of four decoded bitmap components above tolerance. Mean absolute channel delta is averaged across all four components in the compared region.', limitations: [ 'Only the manifest state set is assessed; this output is not a complete 1:1 product acceptance.', 'Images are decoded to nativeImage 8-bit bitmaps; their platform-specific byte order is compared consistently within this run. No registration, OCR, or semantic layout analysis is performed.', 'Diff PNG marks changed pixels white and unchanged pixels transparent.', ], pairs: results, } } async function runSelfTest() { const fixture = await fs.mkdtemp(path.join(os.tmpdir(), 'ycode-visual-pixels-self-test-')) try { assert.throws(() => parseManifest({ source: { kind: 'local-fixture' }, requiredStates: [], pairs: [] }), /non-empty array/) const files = { reference: path.join(fixture, 'reference.png'), changed: path.join(fixture, 'changed.png'), wide: path.join(fixture, 'wide.png'), } await runElectronHelper({ mode: 'fixtures', files }) const manifest = { source: { kind: 'local-fixture' }, requiredStates: ['same', 'one-pixel', 'dimension-mismatch'], pairs: [ { name: 'same', reference: files.reference, candidate: files.reference }, { name: 'one-pixel', reference: files.reference, candidate: files.changed, region: { x: 0, y: 0, width: 1, height: 1 } }, { name: 'dimension-mismatch', reference: files.reference, candidate: files.wide }, ], } const report = await compareManifest(manifest, fixture, path.join(fixture, 'diffs')) assert.equal(report.status, 'different') assert.equal(report.scope.full_1to1, 'not_assessed') assert.equal(report.originalParity.status, 'not_assessed') assert.equal(report.originalParity.exactOriginalParity, false) const same = report.pairs.find(pair => pair.name === 'same') assert.equal(same.status, 'identical') assert.equal(same.compared_pixels, 4) assert.equal(same.changed_pixels, 0) assert.equal(same.changed_ratio, 0) assert.equal(same.maximum_channel_delta, 0) assert.equal(same.mean_absolute_channel_delta, 0) const changed = report.pairs.find(pair => pair.name === 'one-pixel') assert.equal(changed.status, 'different') assert.equal(changed.changed_pixels, 1) assert.equal(changed.changed_ratio, 1) assert.equal(changed.maximum_channel_delta, 1) assert.equal(changed.mean_absolute_channel_delta, 0.25) assert.deepEqual(changed.diff_png.dimensions, { width: 1, height: 1 }) assert.match(changed.diff_png.sha256, /^[a-f0-9]{64}$/) assert.ok((await fs.stat(changed.diff_png.path)).size > 0) const mismatch = report.pairs.find(pair => pair.name === 'dimension-mismatch') assert.equal(mismatch.status, 'dimension_mismatch') assert.deepEqual(mismatch.reference.dimensions, { width: 2, height: 2 }) assert.deepEqual(mismatch.candidate.dimensions, { width: 3, height: 2 }) assert.equal(mismatch.changed_pixels, null) assert.equal(mismatch.diff_png, null) const incomplete = await compareManifest({ source: { kind: 'local-fixture' }, requiredStates: ['present', 'missing'], pairs: [{ name: 'present', reference: files.reference, candidate: files.reference }], }, fixture, path.join(fixture, 'incomplete-diffs')) assert.equal(incomplete.status, 'incomplete') assert.deepEqual(incomplete.missing_required_states, ['missing']) const { createEvidence } = await import(pathToFileURL(path.join(runtime, 'domain/evidence.js'))) const referenceBytes = await fs.readFile(files.reference) const changedBytes = await fs.readFile(files.changed) const asArtifact = bytes => ({ sha256: hash(bytes), bytes: bytes.length, media_type: 'image/png', data_base64: bytes.toString('base64') }) const baselineArtifact = asArtifact(referenceBytes) const probeArtifact = asArtifact(changedBytes) const workbuddyTargetPath = 'C:\\Program Files\\WorkBuddy\\resources\\app.asar\\renderer\\index.html' const syntheticEvidence = ({ visuals, targetFilePath = workbuddyTargetPath, userAgent = 'WorkBuddy/5.7.0 Electron/37.10.3', actions = [], authority = actions.length ? 'controlled-replay' : 'external-service' }) => createEvidence(undefined, { id: 'rea-cdp-electron', name: 'Synthetic WorkBuddy REA fixture provider', version: 'self-test', }, { predicateType: 'rea.electron-page-inspection', operation: 'inspect_electron_page', parameters: actions.length ? { visual_probe: { actions } } : {}, result: { browser: { user_agent: userAgent }, target: { file_path: targetFilePath }, visuals }, confidence: 'observed', authority, limitations: ['Synthetic self-test fixture only; not captured from WorkBuddy.'], }) const authenticatedEvidence = syntheticEvidence({ visuals: { artifact: baselineArtifact, probe: { frames: [{ step_id: 'probe-step', at_ms: 0, artifact: probeArtifact }] } }, actions: [{ kind: 'click', step_id: 'synthetic-probe-step' }], }) const archivePath = path.join(fixture, 'synthetic-evidence.json') await fs.writeFile(archivePath, JSON.stringify(authenticatedEvidence), 'utf8') const evidenced = await compareManifest({ source: { kind: 'rea-workbuddy' }, requiredStates: ['baseline', 'probe'], pairs: [ { name: 'baseline', reference: files.reference, candidate: files.reference, referenceEvidence: { id: authenticatedEvidence.evidence_id, archive: archivePath } }, { name: 'probe', reference: files.changed, candidate: files.changed, referenceEvidence: { id: authenticatedEvidence.evidence_id, archive: archivePath } }, ], }, fixture, path.join(fixture, 'evidenced-diffs')) assert.equal(evidenced.status, 'identical') assert.equal(evidenced.originalParity.status, 'exact_for_declared_states') assert.equal(evidenced.originalParity.exactOriginalParity, true) assert.equal(evidenced.originalParity.versions[0].version, '5.7.0') assert.equal(evidenced.pairs[0].reference_evidence.authority, 'controlled-replay') assert.equal(evidenced.scope.assessment, 'declared_state_set_only') assert.equal(evidenced.scope.full_1to1, 'not_assessed') assert.deepEqual(evidenced.pairs[0].reference_evidence.artifact_locations, ['visuals.artifact']) assert.deepEqual(evidenced.pairs[1].reference_evidence.artifact_locations, ['visuals.probe.frames[0].artifact']) const localFixtureEvidence = syntheticEvidence({ visuals: { artifact: baselineArtifact }, targetFilePath: path.join(fixture, 'renderer', 'index.html'), }) await fs.writeFile(archivePath, JSON.stringify(localFixtureEvidence), 'utf8') const localMasqueradeManifest = { source: { kind: 'rea-workbuddy' }, requiredStates: ['local-fixture'], pairs: [{ name: 'local-fixture', reference: files.reference, candidate: files.reference, referenceEvidence: { id: localFixtureEvidence.evidence_id, archive: archivePath } }], } await assert.rejects(compareManifest(localMasqueradeManifest, fixture, path.join(fixture, 'local-masquerade-diffs')), /target is not the WorkBuddy renderer/) const falseBindingEvidence = syntheticEvidence({ visuals: { artifact: probeArtifact } }) const workbuddyManifest = { source: { kind: 'rea-workbuddy' }, requiredStates: ['forged'], pairs: [{ name: 'forged', reference: files.reference, candidate: files.reference, referenceEvidence: { id: falseBindingEvidence.evidence_id, archive: archivePath } }], } const forgedEvidenceId = `ev_${'0'.repeat(64)}` await fs.writeFile(archivePath, JSON.stringify({ ...falseBindingEvidence, evidence_id: forgedEvidenceId }), 'utf8') const forgedIdManifest = { ...workbuddyManifest, pairs: [{ ...workbuddyManifest.pairs[0], referenceEvidence: { id: forgedEvidenceId, archive: archivePath } }], } await assert.rejects(compareManifest(forgedIdManifest, fixture, path.join(fixture, 'forged-id-diffs')), /authentication|identifier|digest|Evidence/i) await fs.writeFile(archivePath, JSON.stringify(falseBindingEvidence), 'utf8') await assert.rejects(compareManifest(workbuddyManifest, fixture, path.join(fixture, 'unclaimed-reference-diffs')), /SHA is absent/) const unversionedEvidence = syntheticEvidence({ visuals: { artifact: baselineArtifact }, userAgent: 'Chromium/123.0' }) await fs.writeFile(archivePath, JSON.stringify(unversionedEvidence), 'utf8') const unversioned = await compareManifest({ source: { kind: 'rea-workbuddy' }, requiredStates: ['unversioned'], pairs: [{ name: 'unversioned', reference: files.reference, candidate: files.reference, referenceEvidence: { id: unversionedEvidence.evidence_id, archive: archivePath } }], }, fixture, path.join(fixture, 'unversioned-diffs')) assert.equal(unversioned.status, 'incomplete') assert.equal(unversioned.originalParity.status, 'incomplete') assert.equal(unversioned.originalParity.exactOriginalParity, false) assert.equal(unversioned.originalParity.versions[0].version, 'unobserved') await fs.writeFile(archivePath, JSON.stringify(authenticatedEvidence), 'utf8') const approximate = await compareManifest({ source: { kind: 'rea-workbuddy' }, requiredStates: ['tolerant'], channelTolerance: 1, pairs: [{ name: 'tolerant', reference: files.reference, candidate: files.reference, referenceEvidence: { id: authenticatedEvidence.evidence_id, archive: path.join(fixture, 'synthetic-evidence.json') } }], }, fixture, path.join(fixture, 'tolerant-diffs')) assert.equal(approximate.status, 'approximate') assert.equal(approximate.originalParity.status, 'not_exact') assert.equal(approximate.originalParity.exactOriginalParity, false) const mismatchedAuthority = syntheticEvidence({ visuals: { artifact: baselineArtifact }, actions: [{ kind: 'click', step_id: 'synthetic-action' }], authority: 'external-service', }) await fs.writeFile(archivePath, JSON.stringify(mismatchedAuthority), 'utf8') await assert.rejects(compareManifest({ source: { kind: 'rea-workbuddy' }, requiredStates: ['authority'], pairs: [{ name: 'authority', reference: files.reference, candidate: files.reference, referenceEvidence: { id: mismatchedAuthority.evidence_id, archive: archivePath } }], }, fixture, path.join(fixture, 'authority-diffs')), /authority does not match visual_probe.actions/) console.log('Visual pixel self-test passed: pixel comparison, incomplete required states, authenticated synthetic baseline/probe binding, local-target masquerade rejection, observed-version and authority checks, nonzero-tolerance exactness rejection, and forged Evidence rejection') } finally { await fs.rm(fixture, { recursive: true, force: true }) } } async function main() { const args = process.argv.slice(2) if (args.length === 1 && args[0] === '--self-test') { await runSelfTest() return } const manifestPath = args[0] if (!manifestPath || manifestPath.startsWith('--')) throw new Error('Usage: node scripts/rea/compare-visual-pixels.mjs [--output ] | --self-test') let outputDirectory for (let index = 1; index < args.length; index += 1) { if (args[index] !== '--output' || !args[index + 1]) throw new Error('Expected --output followed by a directory') outputDirectory = path.resolve(args[++index]) } const absoluteManifest = path.resolve(manifestPath) const raw = JSON.parse(await fs.readFile(absoluteManifest, 'utf8')) const parsed = parseManifest(raw) const report = await compareManifest(parsed, path.dirname(absoluteManifest), outputDirectory ?? path.join(path.dirname(absoluteManifest), 'visual-pixel-diffs')) process.stdout.write(`${JSON.stringify(report, null, 2)}\n`) if (report.status !== 'identical') process.exitCode = 1 } main().catch(error => { process.stderr.write(`${error.stack || error.message || error}\n`) process.exitCode = 1 })