feat: add conservative topology history fallback

This commit is contained in:
2026-08-02 23:46:29 -04:00
parent d3d88b297b
commit 4d94109627
6 changed files with 83 additions and 3 deletions

View File

@@ -8,6 +8,7 @@ import { DependencyGraph } from '../src/facade/dependencyGraph'
import { evaluateQuantityExpression, quantityFromNumber } from '../src/facade/units'
import { createEdgeSubshapeRefs, createSubshapeRefs, createVertexSubshapeRefs, matchSubshapes, signatureForEdge, signatureForFace, signatureForVertex } from '../src/facade/topologyNaming'
import { createPersistedTopoRef, migrateTopoRefs, parseTopoRef, resolveTopoRef, serializeTopoRef } from '../src/facade/topologyReferences'
import { captureSignatureTopologyHistory } from '../src/facade/topologyHistory'
import { createSketch, solveSketch } from '../src/facade/sketcher'
import { createFacadeGeometryRecomputeExecutor, executeFacadeRecomputeNode, RecomputeCoordinator, type RecomputeGeometryRuntime } from '../src/facade/recomputeEngine'
import { inspectFcstdArchive } from '../src/facade/fcstd'
@@ -182,6 +183,27 @@ test('versioned TopoRefs serialize without transient indexes and resolve migrati
assert.equal(resolveTopoRef(restored, split.refs).status, 'ambiguous')
})
test('signature topology history conservatively classifies boolean fallback relations', () => {
const square = { vertexCoord: [0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], normalCoord: [], triIndexes: [0, 1, 2, 0, 2, 3] }
const translated = { ...square, vertexCoord: square.vertexCoord.map((value, index) => index % 3 === 0 ? value + 5 : value) }
const triangle = { vertexCoord: [0, 0, 1, 1, 0, 1, 0, 1, 1], normalCoord: [], triIndexes: [0, 1, 2] }
const before = createSubshapeRefs('base-shape', 1, [square])
const after = createSubshapeRefs('result-shape', 2, [translated, triangle])
const history = captureSignatureTopologyHistory('boolean-1', [{ objectId: 'base', entries: before.refs.map((ref, index) => ({ ref, signature: before.signatures[index] })) }], after.refs.map((ref, index) => ({ ref, signature: after.signatures[index] })))
assert.equal(history.provider, 'signature-fallback')
assert.equal(history.counts.modified, 1)
assert.equal(history.counts.generated, 1)
const deleted = captureSignatureTopologyHistory('boolean-2', [{ objectId: 'base', entries: before.refs.map((ref, index) => ({ ref, signature: before.signatures[index] })) }], [])
assert.equal(deleted.counts.deleted, 1)
const ambiguous = captureSignatureTopologyHistory('boolean-3', [
{ objectId: 'base', entries: before.refs.map((ref, index) => ({ ref, signature: before.signatures[index] })) },
{ objectId: 'tool', entries: before.refs.map((ref, index) => ({ ref, signature: before.signatures[index] })) },
], before.refs.map((ref, index) => ({ ref, signature: before.signatures[index] })))
assert.equal(ambiguous.counts.ambiguous, 1)
assert.deepEqual(new Set(ambiguous.relations[0].candidates?.map((candidate) => candidate.sourceObjectId)), new Set(['base', 'tool']))
})
test('edge and vertex topology signatures are orientation/index independent', () => {
const edge = signatureForEdge([0, 0, 0], [2, 0, 0])
assert.equal(edge.hash, signatureForEdge([2, 0, 0], [0, 0, 0]).hash)