Files
Web_FreeCAD_Bitbybit/scripts/check-freecad-naming-production.mjs
wangdequan f64b78865c
Some checks failed
real-verification / chrome (push) Has been cancelled
real-verification / freecad-oracle (push) Has been cancelled
real-verification / wasm (push) Has been cancelled
feat: complete production naming and reference lifecycle gates
2026-08-14 10:10:30 -04:00

55 lines
5.1 KiB
JavaScript

import { createHash } from 'node:crypto'
import { readFile, stat } from 'node:fs/promises'
import { resolve } from 'node:path'
import { FREECAD_NAMING_CALLBACKS, FREECAD_NAMING_OPERATIONS } from './freecad-naming-production-matrix.mjs'
const root = resolve(new URL('..', import.meta.url).pathname)
const fail = (message) => { throw new Error(`FreeCAD production naming verification failed: ${message}`) }
const checkReport = async (reportName, runtime, artifactRoot) => {
const report = JSON.parse(await readFile(resolve(root, 'config', reportName), 'utf8'))
if (report.status !== 'pass' || report.runtime !== runtime || report.implementation !== 'freecad-linked' || report.productionWorkerLinked !== true || report.systemExact !== false) fail(`${reportName} has an invalid production boundary.`)
if (JSON.stringify(report.callbacks) !== JSON.stringify(FREECAD_NAMING_CALLBACKS)) fail(`${reportName} callback list is incomplete.`)
if (JSON.stringify(report.operations) !== JSON.stringify(FREECAD_NAMING_OPERATIONS) || report.cases?.length !== FREECAD_NAMING_OPERATIONS.length) fail(`${reportName} operation matrix is incomplete.`)
if (report.cases.some((entry, index) => {
const native = entry.selectedRecords > 0
return entry.operation !== FREECAD_NAMING_OPERATIONS[index]
|| entry.status !== 'pass'
|| entry.provenanceResults < 1
|| entry.provenanceResults !== entry.selectedRecords + entry.ambiguousResults
|| entry.externallySourcedRecords < 1
|| entry.internalRecordsExcluded < 0
|| entry.externallySourcedRecords + entry.internalRecordsExcluded !== entry.historyRecords
|| entry.duplicateRecordsCollapsed < 0
|| entry.modifiedRelationPrecedence < 0
|| entry.callbackExecuted !== native
|| entry.mappedNames !== entry.selectedRecords
|| (native && (entry.stringHasherEntries < 0 || entry.elementMaps < 1 || !['native-evidence', 'mixed-native-and-ambiguous'].includes(entry.namingStatus)))
|| (!native && (entry.ambiguousResults < 1 || entry.stringHasherEntries !== 0 || entry.elementMaps !== 0 || entry.namingStatus !== 'ambiguous'))
})) fail(`${reportName} contains an invalid operation result.`)
const callbackCases = report.cases.filter(({ callbackExecuted }) => callbackExecuted).length
const ambiguityOnlyCases = report.cases.filter(({ namingStatus }) => namingStatus === 'ambiguous').length
if (report.callbackExecutedCases !== callbackCases || report.ambiguityOnlyCases !== ambiguityOnlyCases || callbackCases < 1 || callbackCases + ambiguityOnlyCases !== FREECAD_NAMING_OPERATIONS.length) fail(`${reportName} has invalid callback/ambiguity partitioning.`)
if (report.isomorphicCorpus?.status !== 'pass' || report.isomorphicCorpus.fixture !== 'coincident-equal-boxes' || report.isomorphicCorpus.uniqueResults !== 0 || report.isomorphicCorpus.ambiguousResults < 1 || report.isomorphicCorpus.arrayOrderFallbackUsed !== false || report.isomorphicCorpus.candidateSets?.some(({ candidates }) => candidates.length < 2)) fail(`${reportName} is missing its symmetric native-provenance corpus.`)
if (report.invalidHistoryRejected !== true || report.chainedStage?.mappedNames < 1 || report.chainedStage?.stringHasherEntries < 2) fail(`${reportName} is missing chained or fail-closed evidence.`)
for (const artifact of report.artifacts ?? []) {
const path = resolve(root, artifactRoot, artifact.name)
const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)])
if (bytes !== artifact.bytes || createHash('sha256').update(content).digest('hex') !== artifact.sha256) fail(`${reportName} is stale for ${artifact.name}.`)
}
if (report.artifacts?.length !== 3) fail(`${reportName} must lock JS, WASM and DATA.`)
const harnessPath = resolve(root, report.harness?.path ?? '')
const [harnessContent, harnessBytes] = await Promise.all([readFile(harnessPath), stat(harnessPath).then(({ size }) => size)])
if (report.harness?.path !== 'scripts/freecad-naming-production-matrix.mjs' || harnessBytes !== report.harness.bytes || createHash('sha256').update(harnessContent).digest('hex') !== report.harness.sha256) fail(`${reportName} is stale for the shared production harness.`)
return { runtime, cases: report.cases.length, generatedAt: report.generatedAt }
}
const requestedRuntime = process.argv.find((argument) => argument.startsWith('--runtime='))?.slice('--runtime='.length) ?? 'all'
if (!['all', 'node', 'chrome'].includes(requestedRuntime)) fail(`unsupported runtime ${requestedRuntime}.`)
const specs = [
['freecad-naming-production-verification.json', 'node', 'native/occt-history/dist'],
['chrome-freecad-naming-production-verification.json', 'chrome', 'public/native/occt-history'],
].filter(([, runtime]) => requestedRuntime === 'all' || runtime === requestedRuntime)
const reports = []
for (const [reportName, runtime, artifactRoot] of specs) reports.push(await checkReport(reportName, runtime, artifactRoot))
console.log(JSON.stringify({ status: 'freecad-production-naming-pass', implementation: 'freecad-linked', callbacks: FREECAD_NAMING_CALLBACKS, operations: FREECAD_NAMING_OPERATIONS.length, reports, systemExact: false }, null, 2))