P7/P8: add topology proxies and recovery reports

This commit is contained in:
2026-08-02 17:24:50 -04:00
parent 4cc349a589
commit 9c76f33f3d
11 changed files with 156 additions and 16 deletions

View File

@@ -6,7 +6,7 @@ import { PROJECT_SCHEMA_MIGRATIONS, PROJECT_SCHEMA_SQL, PROJECT_SCHEMA_VERSION }
import { PersistenceWriteQueue, ProjectAutosaveScheduler } from '../src/facade/projectStore'
import { DependencyGraph } from '../src/facade/dependencyGraph'
import { evaluateQuantityExpression, quantityFromNumber } from '../src/facade/units'
import { createSubshapeRefs, matchSubshapes, signatureForFace } from '../src/facade/topologyNaming'
import { createEdgeSubshapeRefs, createSubshapeRefs, createVertexSubshapeRefs, matchSubshapes, signatureForEdge, signatureForFace, signatureForVertex } from '../src/facade/topologyNaming'
import { createSketch, solveSketch } from '../src/facade/sketcher'
import { RecomputeCoordinator } from '../src/facade/recomputeEngine'
import { inspectFcstdArchive } from '../src/facade/fcstd'
@@ -142,6 +142,19 @@ test('topology signatures are independent of transient face indexes and flag amb
assert.equal(matches[0].previousId, first.refs[0].persistentId)
})
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)
assert.equal(signatureForVertex([1, 2, 3]).hash, signatureForVertex([1.000001, 2, 3], 1e-5).hash)
const face = { vertexCoord: [0, 0, 0, 2, 0, 0, 2, 0, 2, 0, 0, 2], normalCoord: [], triIndexes: [0, 1, 2, 0, 2, 3] }
const edges = createEdgeSubshapeRefs('shape-topology', 3, [face])
const vertices = createVertexSubshapeRefs('shape-topology', 3, [face])
assert.equal(edges.refs.length, 5)
assert.equal(vertices.refs.length, 4)
assert.ok(edges.refs.every((ref) => ref.kind === 'edge' && ref.persistentId.startsWith('topo-edge-')))
assert.ok(vertices.refs.every((ref) => ref.kind === 'vertex' && ref.persistentId.startsWith('topo-vertex-')))
})
test('basic sketch solver applies geometric constraints and reports remaining degrees of freedom', () => {
const sketch = createSketch('sketch-test', [{ id: 'line-1', type: 'line', start: { x: 0, y: 0 }, end: { x: 1, y: 0 } }], [
{ id: 'horizontal-1', type: 'horizontal', geometryId: 'line-1' },
@@ -432,6 +445,17 @@ test('project persistence remains behind the facade contract', async () => {
assert.equal(loaded?.label, 'Pump Housing')
assert.equal(loaded?.objects.find((object) => object.id === 'pad')?.properties.find((property) => property.name === 'Length')?.value, 55)
assert.equal(facade.project.capabilities().mode, 'sqlite-memory')
const recovery = await facade.project.recovery('doc-pump-housing')
assert.equal(recovery.integrity, 'ok')
assert.equal(recovery.lastSavedVersion, loaded?.version)
})
test('recovery report identifies missing snapshots in the transient fallback store', async () => {
const facade = createMockFacade()
const recovery = await facade.project.recovery('missing-document')
assert.equal(recovery.integrity, 'unavailable')
assert.equal(recovery.lastSavedVersion, null)
assert.ok(recovery.warnings.some((warning) => /No saved snapshot/.test(warning)))
})
test('FCStd inspection reports recognized, proxy, and Python-backed objects without executing code', () => {
@@ -465,6 +489,9 @@ test('FCStd inspection reports recognized, proxy, and Python-backed objects with
assert.equal(inspection.compatibility.codeExecutionBlocked, true)
assert.deepEqual(inspection.compatibility.unknownTypeIds, ['Vendor::CustomFeature'])
assert.ok(inspection.entries.some((entry) => entry.role === 'script'))
assert.equal(inspection.proxyDocument.readOnly, true)
assert.equal(inspection.proxyDocument.objects.length, 3)
assert.equal(inspection.proxyDocument.objects[1].properties.find((property) => property.name === 'ImportSupport')?.value, 'proxy')
})
test('FCStd inspection rejects missing metadata, traversal paths, and suspicious compression ratios', () => {