Files
Web_FreeCAD_Bitbybit/scripts/freecad-production-drift-classification.mjs
wangdequan 83cbc80971
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: advance TSN drift and ordered pair evidence
2026-08-15 04:44:23 -04:00

103 lines
6.1 KiB
JavaScript

const sha256 = (value) => typeof value === 'string' && /^[0-9a-f]{64}$/.test(value)
const canonical = (value) => Array.isArray(value)
? value.map(canonical)
: value && typeof value === 'object'
? Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonical(entry)]))
: value
export const productionDriftDecisions = [
{
taskId: 'TSN-PROD-DRIFT-000',
operation: 'cut',
classification: 'allowed_evolution',
reasonCode: 'native-downstream-topology-stabilizes-after-edit-restore',
rationale: 'FreeCAD deterministically evolves the downstream Fillet, Mirrored, and LinearPattern semantic topology after a Pocket Length edit/restore while restoring their geometry; the evolved topology and mapped names remain stable through save, reopen, and resave.',
},
{
taskId: 'TSN-PROD-DRIFT-001',
operation: 'rotate',
classification: 'allowed_evolution',
reasonCode: 'native-downstream-topology-stabilizes-after-edit-restore',
rationale: 'FreeCAD deterministically evolves the downstream Mirrored and LinearPattern semantic topology after a Rotate Angle edit/restore while restoring their geometry; the evolved topology and mapped names remain stable through save, reopen, and resave.',
},
]
export const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify(canonical(right))
const stageFingerprint = (driftReplay, ordinal, phase) => {
const mutation = driftReplay.mutation
const persistence = driftReplay.persistence?.[phase]?.[ordinal]
if (!persistence) throw new Error(`${driftReplay.operation}/${ordinal} lacks ${phase} persistence evidence.`)
return {
geometrySignature: persistence.geometrySignature,
semanticTopologyDigest: persistence.semanticTopologyDigest,
mappedNames: persistence.mappedNames,
mappedNameDigest: persistence.mappedNameDigest,
}
}
export const buildProductionDriftSnapshot = (report, operation) => {
const driftReplay = report?.driftReplays?.find((entry) => entry.operation === operation)
if (!driftReplay) throw new Error(`${operation} has no isolated production drift replay.`)
const mutation = driftReplay.mutation
const ordinals = mutation.restoreTopologyDriftOrdinals
if (!Array.isArray(ordinals) || ordinals.length === 0) throw new Error(`${operation} has no recovered production topology drift.`)
const stages = ordinals.map((ordinal) => ({
ordinal,
operation: driftReplay.persistence.initial[ordinal].operation,
name: driftReplay.persistence.initial[ordinal].name,
before: {
geometrySignature: mutation.beforeGeometrySignatures[ordinal],
semanticTopologyDigest: mutation.beforeTopologyDigests[ordinal],
},
edited: {
geometrySignature: mutation.editedGeometrySignatures[ordinal],
semanticTopologyDigest: mutation.editedTopologyDigests[ordinal],
},
restored: {
geometrySignature: mutation.restoredGeometrySignatures[ordinal],
semanticTopologyDigest: mutation.restoredTopologyDigests[ordinal],
},
persistence: Object.fromEntries(['initial', 'reopened', 'resaved'].map((phase) => [phase, stageFingerprint(driftReplay, ordinal, phase)])),
}))
return {
operation,
contract: {
featureName: mutation.featureName,
typeId: mutation.typeId,
propertyPath: mutation.propertyPath,
},
values: {
before: mutation.beforeParameter,
edited: mutation.editedParameter,
restored: mutation.restoredParameter,
},
driftOrdinals: ordinals,
stages,
checks: {
parameterRestored: mutation.parameterChanged === true && same(mutation.beforeParameter, mutation.restoredParameter),
geometryRestored: mutation.restoredGeometrically === true && mutation.restoredExactly === true && same(mutation.beforeGeometrySignatures, mutation.restoredGeometrySignatures),
topologyEvolved: stages.every(({ before, restored }) => before.semanticTopologyDigest !== restored.semanticTopologyDigest),
restoredMatchesInitial: driftReplay.checks?.restoredMatchesInitial === true && stages.every(({ restored, persistence }) => same(restored.geometrySignature, persistence.initial.geometrySignature) && restored.semanticTopologyDigest === persistence.initial.semanticTopologyDigest),
persistenceStable: driftReplay.checks?.geometryStable === true && driftReplay.checks?.topologyStable === true && driftReplay.checks?.mappedNamesStable === true && stages.every(({ persistence }) => ['reopened', 'resaved'].every((phase) => same(persistence.initial, persistence[phase]))),
},
}
}
export const validateProductionDriftSnapshot = (snapshot) => {
if (!snapshot || typeof snapshot.operation !== 'string' || !snapshot.operation) throw new Error('production drift snapshot has no operation identity.')
if (!Array.isArray(snapshot.driftOrdinals) || snapshot.driftOrdinals.length === 0 || snapshot.stages?.length !== snapshot.driftOrdinals.length) throw new Error(`${snapshot.operation} has an invalid drift-stage set.`)
if (!same(snapshot.stages.map(({ ordinal }) => ordinal), snapshot.driftOrdinals)) throw new Error(`${snapshot.operation} drift-stage identities are inconsistent.`)
for (const stage of snapshot.stages) {
if (!Number.isInteger(stage.ordinal) || !stage.operation || !stage.name) throw new Error(`${snapshot.operation} has an invalid stage identity.`)
for (const phase of ['before', 'edited', 'restored']) {
if (!Array.isArray(stage[phase]?.geometrySignature) || !sha256(stage[phase]?.semanticTopologyDigest)) throw new Error(`${snapshot.operation}/${stage.name}/${phase} has an invalid fingerprint.`)
}
for (const phase of ['initial', 'reopened', 'resaved']) {
const value = stage.persistence?.[phase]
if (!Array.isArray(value?.geometrySignature) || !value?.mappedNames || typeof value.mappedNames !== 'object' || !sha256(value?.semanticTopologyDigest) || !sha256(value?.mappedNameDigest)) throw new Error(`${snapshot.operation}/${stage.name}/${phase} has invalid persistence evidence.`)
}
}
if (!Object.values(snapshot.checks ?? {}).every((value) => value === true)) throw new Error(`${snapshot.operation} does not satisfy the allowed-evolution evidence contract.`)
}