diff --git a/docs/development/code-map.md b/docs/development/code-map.md index f77ba40..b628340 100644 --- a/docs/development/code-map.md +++ b/docs/development/code-map.md @@ -18,7 +18,7 @@ Entries: `src/index.ts`, `src/server/index.ts`, `src/dev-entry.ts`, `src/host-en | [src/engine/motion/timeline.ts](../../src/engine/motion/timeline.ts) | [src/engine/motion/README.md](../../src/engine/motion/README.md) | `AnimationAsset`, `AnimationFrame`, `Track`, `Clip`, `MotionPlan`, `nodeAnimations`, `visit`, `channelRange`, `values`, `tracks`, `sampleAnimation`, `motionPath`, `animationAssets`, `compileCatalogue`, `compile`, `samplePlan` | src/engine/motion/curves.ts, src/engine/motion/vector.ts, src/scenes/native-document.ts | src/engine/animations.ts, src/engine/motion/player.ts, src/engine/sound/catalogue.ts | tests/unit/motion.test.ts, tests/unit/sound.test.ts, tests/unit/vector-motion.test.ts | | [src/engine/motion/vector.ts](../../src/engine/motion/vector.ts) | [src/engine/motion/README.md](../../src/engine/motion/README.md) | `VectorPath`, `parseMorphPath`, `morphPath` | src/engine/motion/curves.ts | src/engine/motion/timeline.ts | tests/unit/vector-motion.test.ts | | [src/engine/native-composition-publisher.ts](../../src/engine/native-composition-publisher.ts) | [src/engine/README.md](../../src/engine/README.md) | `PeerOptions`, `NativeCompositionPeer`, `Peer`, `NativeCompositionPublishResult`, `NativeCompositionPeerFactory`, `PublisherOptions`, `Snapshot`, `Deferred`, `QueuedAction`, `deferred`, `record`, `isBaseMismatch`, `randomTransactionId`, `NativeCompositionPublisher`, `NativeCompositionPublisher.publish`, `NativeCompositionPublisher.clear`, `NativeCompositionPublisher.retire`, `NativeCompositionPublisher.discard`, `NativeCompositionPublisher.enqueueLatest`, `NativeCompositionPublisher.replacePending`, `NativeCompositionPublisher.pump`, `NativeCompositionPublisher.drain`, `NativeCompositionPublisher.receiveSnapshot`, `NativeCompositionPublisher.read`, `NativeCompositionPublisher.apply`, `NativeCompositionPublisher.write`, `NativeCompositionPublisher.clearOwnedGraph` | src/internal/native-tree.ts, src/scenes/native-composition-state.ts, src/scenes/native-composition.ts, src/types/index.ts, fast-json-patch | src/engine/native-composition-session.ts | tests/unit/native-composition-publisher.test.ts, tests/unit/native-composition-session.test.ts | -| [src/engine/native-composition-session.ts](../../src/engine/native-composition-session.ts) | [src/engine/README.md](../../src/engine/README.md) | `AcceptedPublication`, `NativeCompositionSession`, `NativeCompositionSession.start`, `NativeCompositionSession.project`, `NativeCompositionSession.use`, `NativeCompositionSession.publish`, `NativeCompositionSession.accept`, `NativeCompositionSession.acceptDocument`, `NativeCompositionSession.clear`, `NativeCompositionSession.retire`, `NativeCompositionSession.reportError`, `NativeCompositionSession.publishTo`, `NativeCompositionSession.clearOn`, `NativeCompositionSession.completeRecovery` | src/engine/native-composition-publisher.ts, src/engine/native-scene-frames.ts, src/engine/vision-contracts.ts, src/scenes/native-composition.ts, src/scenes/native-document.ts, src/types/index.ts | src/engine/native-lsdp-runtime.ts | tests/unit/native-composition-session.test.ts | +| [src/engine/native-composition-session.ts](../../src/engine/native-composition-session.ts) | [src/engine/README.md](../../src/engine/README.md) | `AcceptedPublication`, `NativeCompositionSession`, `NativeCompositionSession.start`, `NativeCompositionSession.project`, `NativeCompositionSession.use`, `NativeCompositionSession.publish`, `NativeCompositionSession.accept`, `NativeCompositionSession.acceptCurrent`, `NativeCompositionSession.acceptDocument`, `NativeCompositionSession.clear`, `NativeCompositionSession.retire`, `NativeCompositionSession.reportError`, `NativeCompositionSession.publishTo`, `NativeCompositionSession.clearOn`, `NativeCompositionSession.completeRecovery` | src/engine/native-composition-publisher.ts, src/engine/native-scene-frames.ts, src/engine/vision-contracts.ts, src/scenes/native-composition.ts, src/scenes/native-document.ts, src/types/index.ts | src/engine/native-lsdp-runtime.ts | tests/unit/native-composition-session.test.ts | | [src/engine/native-lsdp-reconnect.ts](../../src/engine/native-lsdp-reconnect.ts) | [src/engine/README.md](../../src/engine/README.md) | `NativeLsdpReconnectTarget`, `ReconnectActions`, `NativeLsdpReconnect`, `NativeLsdpReconnect.schedule`, `NativeLsdpReconnect.reset`, `NativeLsdpReconnect.recoverComposition`, `NativeLsdpReconnect.clear` | src/types/index.ts | src/engine/native-lsdp-runtime.ts | tests/unit/native-lsdp-runtime-composition.test.ts | | [src/engine/native-lsdp-runtime-support.ts](../../src/engine/native-lsdp-runtime-support.ts) | [src/engine/README.md](../../src/engine/README.md) | `selectNativeDocument`, `reportNativeLsdpError`, `measureNativeLsdpStage` | src/scenes/instances.ts, src/scenes/native-document.ts, src/types/index.ts | src/engine/native-lsdp-runtime.ts | via consuming boundary | | [src/engine/native-lsdp-runtime.ts](../../src/engine/native-lsdp-runtime.ts) | [src/engine/README.md](../../src/engine/README.md) | `Change`, `NativeLsdpRuntime`, `NativeLsdpRuntime.visual`, `NativeLsdpRuntime.start`, `NativeLsdpRuntime.disconnect`, `NativeLsdpRuntime.setToken`, `NativeLsdpRuntime.closePeer`, `NativeLsdpRuntime.connect`, `NativeLsdpRuntime.readSubscribe`, `NativeLsdpRuntime.fail`, `NativeLsdpRuntime.receive`, `NativeLsdpRuntime.transition`, `NativeLsdpRuntime.render`, `NativeLsdpRuntime.acceptComposition`, `NativeLsdpRuntime.reserved`, `NativeLsdpRuntime.updatePlayback`, `NativeLsdpRuntime.resumeAudio`, `NativeLsdpRuntime.audioStream`, `NativeLsdpRuntime.audioStatus`, `NativeLsdpRuntime.renderAudio`, `NativeLsdpRuntime.report` | src/engine/animations.ts, src/engine/control-feedback.ts, src/engine/frame-patches.ts, src/engine/live-media.ts, src/engine/native-composition-session.ts, src/engine/native-lsdp-reconnect.ts, src/engine/native-lsdp-runtime-support.ts, src/engine/native-scene-frames.ts, src/engine/native-worker-client.ts, src/engine/sound/controller.ts, src/engine/sound/offline.ts, src/engine/vision-presenter.ts, src/internal/native-state.ts, src/internal/native-stream.ts, src/internal/native-tree.ts, src/peer-viewer/injection.ts, src/scenes/native-composition.ts, src/scenes/native-document.ts, src/sources/capture.ts, src/sources/peers.ts, src/types/index.ts, @lumencast/runtime, fast-json-patch | src/mount.ts | tests/unit/native-lsdp-runtime-composition.test.ts, tests/unit/native-lsdp-runtime.test.ts | diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json new file mode 100644 index 0000000..3524733 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json @@ -0,0 +1,975 @@ +{ + "numTotalTestSuites": 10, + "numPassedTestSuites": 10, + "numFailedTestSuites": 0, + "numPendingTestSuites": 0, + "numTotalTests": 79, + "numPassedTests": 79, + "numFailedTests": 0, + "numPendingTests": 0, + "numTodoTests": 0, + "snapshot": { + "added": 0, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0, + "didUpdate": false + }, + "startTime": 1793299364653, + "success": true, + "testResults": [ + { + "assertionResults": [ + { + "ancestorTitles": [ + "frame-paced scalar presentation" + ], + "fullName": "frame-paced scalar presentation merges 512 ordered states into one frame while retaining every receipt", + "status": "passed", + "title": "merges 512 ordered states into one frame while retaining every receipt", + "duration": 12.643499999999676, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "frame-paced scalar presentation" + ], + "fullName": "frame-paced scalar presentation retains arrivals during a blocked GPU submission and drains before structure work", + "status": "passed", + "title": "retains arrivals during a blocked GPU submission and drains before structure work", + "duration": 3.9490999999998166, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "frame-paced scalar presentation" + ], + "fullName": "frame-paced scalar presentation propagates presentation failure and cancels unapplied work on disconnect", + "status": "passed", + "title": "propagates presentation failure and cancels unapplied work on disconnect", + "duration": 3.0979999999999563, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "frame-paced scalar presentation" + ], + "fullName": "frame-paced scalar presentation uses render completion to drain arrivals without an extra empty animation frame", + "status": "passed", + "title": "uses render completion to drain arrivals without an extra empty animation frame", + "duration": 1.5898999999999432, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299380540, + "endTime": 1793299380561.5898, + "status": "passed", + "message": "", + "name": "/tests/unit/frame-patches.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [], + "fullName": "updates and retires a coverage graph while preserving the other producer", + "status": "passed", + "title": "updates and retires a coverage graph while preserving the other producer", + "duration": 33.04160000000002, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "publishes the active physical graph with source hash and retries only a CAS conflict", + "status": "passed", + "title": "publishes the active physical graph with source hash and retries only a CAS conflict", + "duration": 7.418700000000172, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "deduplicates the same state but republishes an unchanged layout with a new source hash", + "status": "passed", + "title": "deduplicates the same state but republishes an unchanged layout with a new source hash", + "duration": 13.45959999999991, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not overwrite or retire a replacement producer after losing slot ownership", + "status": "passed", + "title": "does not overwrite or retire a replacement producer after losing slot ownership", + "duration": 3.5696000000000367, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "publishes a capture-only graph with no Solar surface bands", + "status": "passed", + "title": "publishes a capture-only graph with no Solar surface bands", + "duration": 5.976699999999937, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not let a delayed old first write replace the Main-claimed producer", + "status": "passed", + "title": "does not let a delayed old first write replace the Main-claimed producer", + "duration": 11.131900000000087, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "cannot claim an empty slot after Main revokes the previous host", + "status": "passed", + "title": "cannot claim an empty slot after Main revokes the previous host", + "duration": 8.29359999999997, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "bounds a slow publisher to one active write and the latest pending plan", + "status": "passed", + "title": "bounds a slow publisher to one active write and the latest pending plan", + "duration": 20.615999999999985, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "lets clear supersede a pending plan behind the active write", + "status": "passed", + "title": "lets clear supersede a pending plan behind the active write", + "duration": 5.509299999999939, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "makes retire a terminal clear barrier behind an active write", + "status": "passed", + "title": "makes retire a terminal clear barrier behind an active write", + "duration": 6.785200000000032, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "reports a terminal peer close and retires without attempting a remote clear", + "status": "passed", + "title": "reports a terminal peer close and retires without attempting a remote clear", + "duration": 2.3874000000000706, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299374334, + "endTime": 1793299374452.3875, + "status": "passed", + "message": "", + "name": "/tests/unit/native-composition-publisher.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [], + "fullName": "replays the latest accepted LSML composition after the peer was offline", + "status": "passed", + "title": "replays the latest accepted LSML composition after the peer was offline", + "duration": 202.51620000000003, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "accepts an empty current scene as a clear and does not replay the retired plan", + "status": "passed", + "title": "accepts an empty current scene as a clear and does not replay the retired plan", + "duration": 127.86190000000033, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "refuses to accept a receipt from a different scene identity", + "status": "passed", + "title": "refuses to accept a receipt from a different scene identity", + "duration": 2.3319000000001324, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299377940, + "endTime": 1793299378272.3318, + "status": "passed", + "message": "", + "name": "/tests/unit/native-composition-session.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [], + "fullName": "projects nested owners and interleaved global bands without applying owner affine twice", + "status": "passed", + "title": "projects nested owners and interleaved global bands without applying owner affine twice", + "duration": 6.808800000000019, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "preserves independent nested owner opacity and capture own opacity", + "status": "passed", + "title": "preserves independent nested owner opacity and capture own opacity", + "duration": 0.6696999999999207, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "uses a unique child id per capture occurrence and requires its base author id", + "status": "passed", + "title": "uses a unique child id per capture occurrence and requires its base author id", + "duration": 2.093399999999974, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "uses the required native root id for the receipt root occurrence", + "status": "passed", + "title": "uses the required native root id for the receipt root occurrence", + "duration": 3.583299999999781, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "preserves authored framing units separately from the bounded upload texture", + "status": "passed", + "title": "preserves authored framing units separately from the bounded upload texture", + "duration": 1.0743999999999687, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "supports capture-only and paint-only receipts, including the transparent one-pixel canvas", + "status": "passed", + "title": "supports capture-only and paint-only receipts, including the transparent one-pixel canvas", + "duration": 1.1204999999999927, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "keeps exact viewport scaling and maps full rotation/shear into native matrix order", + "status": "passed", + "title": "keeps exact viewport scaling and maps full rotation/shear into native matrix order", + "duration": 0.4616000000000895, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "accepts only producer-classified exact viewport and image-bound clips", + "status": "passed", + "title": "accepts only producer-classified exact viewport and image-bound clips", + "duration": 0.8975000000000364, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "refuses masks and unsupported blend modes without dropping their facts", + "status": "passed", + "title": "refuses masks and unsupported blend modes without dropping their facts", + "duration": 0.4496999999998934, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "refuses canvas-limit, stale-identity and invalid-clip receipts", + "status": "passed", + "title": "refuses canvas-limit, stale-identity and invalid-clip receipts", + "duration": 0.5995000000000346, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "binds the published projection to the exact LSDP hash and receipt geometry", + "status": "passed", + "title": "binds the published projection to the exact LSDP hash and receipt geometry", + "duration": 3.6667999999999665, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299375953, + "endTime": 1793299375974.6667, + "status": "passed", + "message": "", + "name": "/tests/unit/native-composition.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated prepare with identical layout", + "status": "passed", + "title": "renews the source hash on coordinated prepare with identical layout", + "duration": 65.03070000000002, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated commit with identical layout", + "status": "passed", + "title": "renews the source hash on coordinated commit with identical layout", + "duration": 41.04209999999989, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated finalize with identical layout", + "status": "passed", + "title": "renews the source hash on coordinated finalize with identical layout", + "duration": 52.74319999999989, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated cleanup with identical layout", + "status": "passed", + "title": "renews the source hash on coordinated cleanup with identical layout", + "duration": 34.36709999999994, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment binds the restored projection to the abort hash and replays only that state to a replacement peer", + "status": "passed", + "title": "binds the restored projection to the abort hash and replays only that state to a replacement peer", + "duration": 54.471000000000004, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated commit snapshot with its full resource hash", + "status": "passed", + "title": "publishes a joining coordinated commit snapshot with its full resource hash", + "duration": 34.462999999999965, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated finalize snapshot with its full resource hash", + "status": "passed", + "title": "publishes a joining coordinated finalize snapshot with its full resource hash", + "duration": 32.617899999999736, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated abort snapshot with its full resource hash", + "status": "passed", + "title": "publishes a joining coordinated abort snapshot with its full resource hash", + "duration": 33.68560000000025, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment keeps the accepted projection on failed staging and rejects invalid phases without publication", + "status": "passed", + "title": "keeps the accepted projection on failed staging and rejects invalid phases without publication", + "duration": 52.17309999999998, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment cannot publish a coordinated state after stopping during feedback", + "status": "passed", + "title": "cannot publish a coordinated state after stopping during feedback", + "duration": 38.26319999999987, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment refreshes the full resource hash when only another selected entry changes", + "status": "passed", + "title": "refreshes the full resource hash when only another selected entry changes", + "duration": 30.784300000000258, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes the accepted Vision receipt and refreshes it after a scalar patch", + "status": "passed", + "title": "publishes the accepted Vision receipt and refreshes it after a scalar patch", + "duration": 32.97509999999966, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment reconnects only the composition peer with a fresh token and the latest accepted state", + "status": "passed", + "title": "reconnects only the composition peer with a fresh token and the latest accepted state", + "duration": 45.53279999999995, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "gives primary reconnection priority over a pending composition retry", + "status": "passed", + "title": "gives primary reconnection priority over a pending composition retry", + "duration": 0.7233000000001084, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not reset composition backoff when peer construction returns", + "status": "passed", + "title": "does not reset composition backoff when peer construction returns", + "duration": 0.7201999999997497, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "rejects a composition token fetch superseded by primary token refresh", + "status": "passed", + "title": "rejects a composition token fetch superseded by primary token refresh", + "duration": 0.3362999999999374, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not admit a token fetch from a stopped composition lifetime", + "status": "passed", + "title": "does not admit a token fetch from a stopped composition lifetime", + "duration": 0.38200000000006185, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299372220, + "endTime": 1793299372772.382, + "status": "passed", + "message": "", + "name": "/tests/unit/native-lsdp-runtime-composition.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber receives all 512 states in order and confirms every identity after their covering frame", + "status": "passed", + "title": "receives all 512 states in order and confirms every identity after their covering frame", + "duration": 436.6414, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber catches up explicit native overflow on the same socket and retained canvas", + "status": "passed", + "title": "catches up explicit native overflow on the same socket and retained canvas", + "duration": 36.999299999999494, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber stages a new archive for an image absent from the current package and retains the media controller", + "status": "passed", + "title": "stages a new archive for an image absent from the current package and retains the media controller", + "duration": 30.526200000000244, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber keeps exact generation identity and ignores changes to another physical lane", + "status": "passed", + "title": "keeps exact generation identity and ignores changes to another physical lane", + "duration": 31.408800000000156, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber waits for a missing generation and clears a removed session instead of selecting another entry", + "status": "passed", + "title": "waits for a missing generation and clears a removed session instead of selecting another entry", + "duration": 31.7488000000003, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber subscribes to an unselected resource and renders the first real LSML received", + "status": "passed", + "title": "subscribes to an unselected resource and renders the first real LSML received", + "duration": 34.079099999999926, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber subscribes only after the fragmented snapshot is rendered", + "status": "passed", + "title": "subscribes only after the fragmented snapshot is rendered", + "duration": 26.88680000000022, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber reads and renders a fresh baseline when the scene advances before subscription", + "status": "passed", + "title": "reads and renders a fresh baseline when the scene advances before subscription", + "duration": 32.04819999999927, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber surfaces repeated baseline conflicts after four attempts", + "status": "passed", + "title": "surfaces repeated baseline conflicts after four attempts", + "duration": 31.055199999999786, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber applies and presents received mutations without producer feedback or projection", + "status": "passed", + "title": "applies and presents received mutations without producer feedback or projection", + "duration": 46.326100000000224, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber rebuilds a structural edit in memory while retaining the original source manifest", + "status": "passed", + "title": "rebuilds a structural edit in memory while retaining the original source manifest", + "duration": 35.35779999999977, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber rejects stale baselines and invalid receipts without touching Vision", + "status": "passed", + "title": "rejects stale baselines and invalid receipts without touching Vision", + "duration": 43.455299999999625, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber drains camera uploads before staging a structural replacement", + "status": "passed", + "title": "drains camera uploads before staging a structural replacement", + "duration": 47.612700000000586, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber rejects failed presentation and late work after disconnect", + "status": "passed", + "title": "rejects failed presentation and late work after disconnect", + "duration": 30.882000000000517, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber keeps the accepted scene alive when staging activation fails", + "status": "passed", + "title": "keeps the accepted scene alive when staging activation fails", + "duration": 31.635299999999916, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar subscriber" + ], + "fullName": "native Solar subscriber recovers subscription failures through a fresh native snapshot", + "status": "passed", + "title": "recovers subscription failures through a fresh native snapshot", + "duration": 33.13540000000012, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation reconstructs a fresh subscriber from a compact commit resource", + "status": "passed", + "title": "reconstructs a fresh subscriber from a compact commit resource", + "duration": 26.65059999999994, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation reconstructs a fresh subscriber from a compact finalize resource", + "status": "passed", + "title": "reconstructs a fresh subscriber from a compact finalize resource", + "duration": 31.70090000000073, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation fetches and mounts a fresh scene on A to B to A without retaining inactive frames", + "status": "passed", + "title": "fetches and mounts a fresh scene on A to B to A without retaining inactive frames", + "duration": 61.767800000000534, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation restores a fresh subscriber after an aborted Prism request", + "status": "passed", + "title": "restores a fresh subscriber after an aborted Prism request", + "duration": 56.21180000000004, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation acknowledges preparation, commit and abort on solar/lane-a as preview", + "status": "passed", + "title": "acknowledges preparation, commit and abort on solar/lane-a as preview", + "duration": 56.02739999999994, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation acknowledges preparation, commit and abort on solar/lane-a as program", + "status": "passed", + "title": "acknowledges preparation, commit and abort on solar/lane-a as program", + "duration": 39.621399999999994, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation acknowledges preparation, commit and abort on solar/lane-b as preview", + "status": "passed", + "title": "acknowledges preparation, commit and abort on solar/lane-b as preview", + "duration": 66.65179999999964, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation acknowledges preparation, commit and abort on solar/lane-b as program", + "status": "passed", + "title": "acknowledges preparation, commit and abort on solar/lane-b as program", + "duration": 56.94419999999991, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation finalizes and retires the previous frame on solar/lane-a", + "status": "passed", + "title": "finalizes and retires the previous frame on solar/lane-a", + "duration": 58.417599999999766, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation finalizes and retires the previous frame on solar/lane-b", + "status": "passed", + "title": "finalizes and retires the previous frame on solar/lane-b", + "duration": 76.32740000000013, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation rejects a physical transition without an explicit logical role", + "status": "passed", + "title": "rejects a physical transition without an explicit logical role", + "duration": 35.62010000000009, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation prepares invisibly, commits while retaining old frame, and aborts without recreating it", + "status": "passed", + "title": "prepares invisibly, commits while retaining old frame, and aborts without recreating it", + "duration": 39.30380000000059, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation finalizes once and re-acknowledges replay without another mount", + "status": "passed", + "title": "finalizes once and re-acknowledges replay without another mount", + "duration": 42.12209999999959, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation keeps a committed presentation alive through a null coordinator seed", + "status": "passed", + "title": "keeps a committed presentation alive through a null coordinator seed", + "duration": 69.02570000000014, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation honors a null authoritative clear after coordinated finalization", + "status": "passed", + "title": "honors a null authoritative clear after coordinated finalization", + "duration": 46.348399999999856, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation can compensate finalization while its receipt or cleanup is unresolved", + "status": "passed", + "title": "can compensate finalization while its receipt or cleanup is unresolved", + "duration": 40.22270000000026, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "coordinated physical lane presentation" + ], + "fullName": "coordinated physical lane presentation reports failed staging while preserving accepted frame", + "status": "passed", + "title": "reports failed staging while preserving accepted frame", + "duration": 44.11570000000029, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299368566, + "endTime": 1793299370376.1157, + "status": "passed", + "message": "", + "name": "/tests/unit/native-lsdp-runtime.test.ts" + } + ] +} diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.txt new file mode 100644 index 0000000..c4811c6 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.txt @@ -0,0 +1,17 @@ + + RUN v4.1.11 + + ✓ tests/unit/native-lsdp-runtime.test.ts (33 tests) 1814ms + ✓ receives all 512 states in order and confirms every identity after their covering frame 437ms + ✓ tests/unit/native-lsdp-runtime-composition.test.ts (17 tests) 554ms + ✓ tests/unit/native-composition-publisher.test.ts (11 tests) 121ms + ✓ tests/unit/native-composition.test.ts (11 tests) 24ms + ✓ tests/unit/native-composition-session.test.ts (3 tests) 335ms + ✓ tests/unit/frame-patches.test.ts (4 tests) 26ms + + Test Files 6 passed (6) + Tests 79 passed (79) + Start at 19:42:44 + Duration 15.87s (transform 1.92s, setup 0ms, import 2.74s, tests 2.87s, environment 7.81s) + +JSON report written to /evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.json b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.json new file mode 100644 index 0000000..03b70ca --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.json @@ -0,0 +1,254 @@ +{ + "numTotalTestSuites": 2, + "numPassedTestSuites": 0, + "numFailedTestSuites": 2, + "numPendingTestSuites": 0, + "numTotalTests": 17, + "numPassedTests": 8, + "numFailedTests": 9, + "numPendingTests": 0, + "numTodoTests": 0, + "snapshot": { + "added": 0, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0, + "didUpdate": false + }, + "startTime": 1793299359715, + "success": false, + "testResults": [ + { + "assertionResults": [ + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated prepare with identical layout", + "status": "failed", + "title": "renews the source hash on coordinated prepare with identical layout", + "duration": 98.19090000000006, + "failureMessages": [ + "AssertionError: expected 'tree-sha256:ba0b24717acfae4191052ff6f…' to be 'tree-sha256:9755c8f7e869869a8aef75fdb…' // Object.is equality\n at /tests/unit/native-lsdp-runtime-composition.test.ts:331:31\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated commit with identical layout", + "status": "failed", + "title": "renews the source hash on coordinated commit with identical layout", + "duration": 55.785699999999906, + "failureMessages": [ + "AssertionError: expected { lsml: '1.1', …(4) } to deeply equal { lsml: '1.1', …(4) }\n at /tests/unit/native-lsdp-runtime-composition.test.ts:328:31\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated finalize with identical layout", + "status": "failed", + "title": "renews the source hash on coordinated finalize with identical layout", + "duration": 40.247100000000046, + "failureMessages": [ + "AssertionError: expected { lsml: '1.1', …(4) } to deeply equal { lsml: '1.1', …(4) }\n at /tests/unit/native-lsdp-runtime-composition.test.ts:328:31\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment renews the source hash on coordinated cleanup with identical layout", + "status": "passed", + "title": "renews the source hash on coordinated cleanup with identical layout", + "duration": 47.65109999999959, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment binds the restored projection to the abort hash and replays only that state to a replacement peer", + "status": "failed", + "title": "binds the restored projection to the abort hash and replays only that state to a replacement peer", + "duration": 52.04710000000023, + "failureMessages": [ + "AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ]\n at /tests/unit/native-lsdp-runtime-composition.test.ts:357:59\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated commit snapshot with its full resource hash", + "status": "failed", + "title": "publishes a joining coordinated commit snapshot with its full resource hash", + "duration": 32.141599999999926, + "failureMessages": [ + "AssertionError: expected undefined to be 'tree-sha256:0556db0865bb51304224774e2…' // Object.is equality\n at /tests/unit/native-lsdp-runtime-composition.test.ts:383:66\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated finalize snapshot with its full resource hash", + "status": "failed", + "title": "publishes a joining coordinated finalize snapshot with its full resource hash", + "duration": 31.27669999999989, + "failureMessages": [ + "AssertionError: expected undefined to be 'tree-sha256:ee88fd96bf0e9a61d6b2718f4…' // Object.is equality\n at /tests/unit/native-lsdp-runtime-composition.test.ts:383:66\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes a joining coordinated abort snapshot with its full resource hash", + "status": "failed", + "title": "publishes a joining coordinated abort snapshot with its full resource hash", + "duration": 30.56989999999996, + "failureMessages": [ + "AssertionError: expected undefined to be 'tree-sha256:bdb3730bf78968d3d915f6c1f…' // Object.is equality\n at /tests/unit/native-lsdp-runtime-composition.test.ts:383:66\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment keeps the accepted projection on failed staging and rejects invalid phases without publication", + "status": "failed", + "title": "keeps the accepted projection on failed staging and rejects invalid phases without publication", + "duration": 38.52280000000019, + "failureMessages": [ + "AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ]\n at /tests/unit/native-lsdp-runtime-composition.test.ts:403:59\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment cannot publish a coordinated state after stopping during feedback", + "status": "passed", + "title": "cannot publish a coordinated state after stopping during feedback", + "duration": 45.08809999999994, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment refreshes the full resource hash when only another selected entry changes", + "status": "failed", + "title": "refreshes the full resource hash when only another selected entry changes", + "duration": 45.804999999999836, + "failureMessages": [ + "AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ]\n at /tests/unit/native-lsdp-runtime-composition.test.ts:455:59\n at file:///D:/Documents/Zab/Solar/.worktrees/eleven-local-20261019-complete-dev/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20" + ], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment publishes the accepted Vision receipt and refreshes it after a scalar patch", + "status": "passed", + "title": "publishes the accepted Vision receipt and refreshes it after a scalar patch", + "duration": 49.13850000000002, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [ + "native Solar composition attachment" + ], + "fullName": "native Solar composition attachment reconnects only the composition peer with a fresh token and the latest accepted state", + "status": "passed", + "title": "reconnects only the composition peer with a fresh token and the latest accepted state", + "duration": 46.63079999999991, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "gives primary reconnection priority over a pending composition retry", + "status": "passed", + "title": "gives primary reconnection priority over a pending composition retry", + "duration": 1.2721000000001368, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not reset composition backoff when peer construction returns", + "status": "passed", + "title": "does not reset composition backoff when peer construction returns", + "duration": 0.8575000000000728, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "rejects a composition token fetch superseded by primary token refresh", + "status": "passed", + "title": "rejects a composition token fetch superseded by primary token refresh", + "duration": 0.5010999999999513, + "failureMessages": [], + "meta": {}, + "tags": [] + }, + { + "ancestorTitles": [], + "fullName": "does not admit a token fetch from a stopped composition lifetime", + "status": "passed", + "title": "does not admit a token fetch from a stopped composition lifetime", + "duration": 0.4481999999998152, + "failureMessages": [], + "meta": {}, + "tags": [] + } + ], + "startTime": 1793299363011, + "endTime": 1793299363629.5012, + "status": "failed", + "message": "", + "name": "/tests/unit/native-lsdp-runtime-composition.test.ts" + } + ] +} diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.txt new file mode 100644 index 0000000..66ef5e5 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.txt @@ -0,0 +1,209 @@ + + RUN v4.1.11 + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts (17 tests | 9 failed) 621ms + × renews the source hash on coordinated prepare with identical layout 98ms + × renews the source hash on coordinated commit with identical layout 56ms + × renews the source hash on coordinated finalize with identical layout 40ms + ✓ renews the source hash on coordinated cleanup with identical layout 48ms + × binds the restored projection to the abort hash and replays only that state to a replacement peer 52ms + × publishes a joining coordinated commit snapshot with its full resource hash 32ms + × publishes a joining coordinated finalize snapshot with its full resource hash 31ms + × publishes a joining coordinated abort snapshot with its full resource hash 31ms + × keeps the accepted projection on failed staging and rejects invalid phases without publication 39ms + ✓ cannot publish a coordinated state after stopping during feedback 45ms + × refreshes the full resource hash when only another selected entry changes 46ms + ✓ publishes the accepted Vision receipt and refreshes it after a scalar patch 49ms + ✓ reconnects only the composition peer with a fresh token and the latest accepted state 47ms + ✓ gives primary reconnection priority over a pending composition retry 1ms + ✓ does not reset composition backoff when peer construction returns 1ms + ✓ rejects a composition token fetch superseded by primary token refresh 1ms + ✓ does not admit a token fetch from a stopped composition lifetime 0ms + + Test Files 1 failed (1) + Tests 9 failed | 8 passed (17) + Start at 19:42:39 + Duration 3.88s (transform 1.20s, setup 0ms, import 1.53s, tests 621ms, environment 1.22s) + +JSON report written to /evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.json + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 9 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > renews the source hash on coordinated prepare with identical layout +AssertionError: expected 'tree-sha256:ba0b24717acfae4191052ff6f…' to be 'tree-sha256:9755c8f7e869869a8aef75fdb…' // Object.is equality + +Expected: "tree-sha256:9755c8f7e869869a8aef75fdb82993b3b26f49bca099fdccac6437e8e86d3c91" +Received: "tree-sha256:ba0b24717acfae4191052ff6fb02e6d683c4651b38be9490cd0722b11878c885" + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:331:31 + 329| phase === "prepare" ? ready.initial : ready.candidate, + 330| ); + 331| expect(accepted[2]).toBe(hash); + | ^ + 332| expect(accepted[0]).toEqual(initialProjection); + 333| break; + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > renews the source hash on coordinated commit with identical layout + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > renews the source hash on coordinated finalize with identical layout +AssertionError: expected { lsml: '1.1', …(4) } to deeply equal { lsml: '1.1', …(4) } + +- Expected ++ Received + +@@ -1,8 +1,8 @@ + { + "defaults": { +- "__lit.text.title": "candidate", ++ "__lit.text.title": "before", + }, + "layout": { + "children": [], + "type": "frame", + }, + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:328:31 + 326| if (phase !== acceptedPhase) continue; + 327| const accepted = mocks.composition.publish.mock.calls.at(-1)… + 328| expect(accepted[1]).toEqual( + | ^ + 329| phase === "prepare" ? ready.initial : ready.candidate, + 330| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > binds the restored projection to the abort hash and replays only that state to a replacement peer +AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ] + +- Expected ++ Received + +@@ -130,7 +130,7 @@ + }, + "lsml": "1.1", + "scene_id": "real-source", + "scene_version": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + }, +- "tree-sha256:066d7ca89dc240c93412fe8f5f86d7385bf146da168c0b48285e513d5eb89170", ++ "tree-sha256:ba0b24717acfae4191052ff6fb02e6d683c4651b38be9490cd0722b11878c885", + ] + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:357:59 + 355| await vi.advanceTimersByTimeAsync(250); + 356| expect(mocks.compositionPublishers).toHaveLength(2); + 357| expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + | ^ + 358| initialProjection, + 359| ready.initial, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > publishes a joining coordinated commit snapshot with its full resource hash +AssertionError: expected undefined to be 'tree-sha256:0556db0865bb51304224774e2…' // Object.is equality + +- Expected: +"tree-sha256:0556db0865bb51304224774e28ce93a1ada12c1d047ccd495f4ff6236ecfc5a6" + ++ Received: +undefined + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:383:66 + 381| const ready = await setup(initial); + 382| try { + 383| expect(mocks.composition.publish.mock.calls.at(-1)?.[2]).toBe( + | ^ + 384| nativeTreeHash(initial), + 385| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > publishes a joining coordinated finalize snapshot with its full resource hash +AssertionError: expected undefined to be 'tree-sha256:ee88fd96bf0e9a61d6b2718f4…' // Object.is equality + +- Expected: +"tree-sha256:ee88fd96bf0e9a61d6b2718f432ffc08ee37b8c0f216384e9906f7b10679eba7" + ++ Received: +undefined + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:383:66 + 381| const ready = await setup(initial); + 382| try { + 383| expect(mocks.composition.publish.mock.calls.at(-1)?.[2]).toBe( + | ^ + 384| nativeTreeHash(initial), + 385| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > publishes a joining coordinated abort snapshot with its full resource hash +AssertionError: expected undefined to be 'tree-sha256:bdb3730bf78968d3d915f6c1f…' // Object.is equality + +- Expected: +"tree-sha256:bdb3730bf78968d3d915f6c1fde395c99e74293ca9deaf1872b20fe3c095e355" + ++ Received: +undefined + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:383:66 + 381| const ready = await setup(initial); + 382| try { + 383| expect(mocks.composition.publish.mock.calls.at(-1)?.[2]).toBe( + | ^ + 384| nativeTreeHash(initial), + 385| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > keeps the accepted projection on failed staging and rejects invalid phases without publication +AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ] + +- Expected ++ Received + +@@ -130,7 +130,7 @@ + }, + "lsml": "1.1", + "scene_id": "real-source", + "scene_version": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + }, +- "tree-sha256:9755c8f7e869869a8aef75fdb82993b3b26f49bca099fdccac6437e8e86d3c91", ++ "tree-sha256:ba0b24717acfae4191052ff6fb02e6d683c4651b38be9490cd0722b11878c885", + ] + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:403:59 + 401| phase: "failed", + 402| }); + 403| expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + | ^ + 404| initialProjection, + 405| ready.initial, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/9]⎯ + + FAIL tests/unit/native-lsdp-runtime-composition.test.ts > native Solar composition attachment > refreshes the full resource hash when only another selected entry changes +AssertionError: expected [ { …(7) }, …(2) ] to deeply equal [ { …(7) }, …(2) ] + +- Expected ++ Received + +@@ -130,7 +130,7 @@ + }, + "lsml": "1.1", + "scene_id": "real-source", + "scene_version": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + }, +- "tree-sha256:fe44cc74182a034a75937d4cf2fee69d7f03ab5bb0db2e60ec9b95f95aed5227", ++ "tree-sha256:e6f9c97ff1e0836f88d0c01040773bacc3a709a103898e4d90829934ecadcfb5", + ] + + ❯ tests/unit/native-lsdp-runtime-composition.test.ts:455:59 + 453| other: { ...document, defaults: { "__lit.text.title": "edited"… + 454| }; + 455| expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + | ^ + 456| projection, + 457| document, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/9]⎯ diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture-tests.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture-tests.txt new file mode 100644 index 0000000..0464db5 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture-tests.txt @@ -0,0 +1,25 @@ + +> @zablab/solar@3.0.1 test:architecture +> node --test tests/tooling/*.test.mjs + +✔ test imports cannot retain an orphan or an unused product export (4730.5636ms) +✔ worker is reached through its actual URL edge and disappears when that edge is removed (7572.4426ms) +✔ public type aliases/re-exports remain contracts and broken imports/dependencies fail (5504.8193ms) +✔ documentation detects broken links/headings, commands, paths and unowned tools (32.907ms) +✔ historical evidence and external repository commands stay outside Solar documentation checks (24.7382ms) +✔ emitted Solar host contract advertises native composition without changing v2 (6.8372ms) +✔ a complete old v2 host without only native composition is rejected (0.8267ms) +✔ release manifest declares the protocol actually packaged with Solar (580.7691ms) +✔ a different source revision refuses before changing the packaged binary or manifest (492.8701ms) +✔ an invalid existing manifest schema refuses before package mutation (176.2948ms) +✔ invalid arguments refuse without touching an existing package (269.4757ms) +✔ a missing source binary refuses before changing the packaged files (269.3214ms) +✔ matching source revision adds another platform and keeps the package verifiable (671.0015ms) +ℹ tests 13 +ℹ suites 0 +ℹ pass 13 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 19016.5801 diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture.txt new file mode 100644 index 0000000..34d0722 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture.txt @@ -0,0 +1,45 @@ + +> @zablab/solar@3.0.1 check:architecture +> npm run check:source-usage && npm run code:check && npm run check:docs && python scripts/check_file_sizes.py + + +> @zablab/solar@3.0.1 check:source-usage +> node scripts/check-source-usage.mjs + +{ + "schema": "solar.source-usage.v2", + "roots": [ + "src/index.ts", + "src/server/index.ts", + "src/dev-entry.ts", + "src/host-entry.ts" + ], + "source_files": 71, + "reachable_files": 71, + "unused": [], + "unusedExports": [], + "unusedDependencies": [], + "problems": [], + "limits": "AST module/export usage including public re-exports, literal dynamic imports and Worker URL edges. Types and local live helper calls count. Tests cannot retain unused product code. Symbol liveness inside methods uses tsc/eslint; opaque runtime behavior and upstream internals require their separate tests/pins." +} + +> @zablab/solar@3.0.1 code:check +> node scripts/code/cli.mjs check + +Code map is current: 71 files. + +> @zablab/solar@3.0.1 check:docs +> node scripts/check-documentation.mjs + +{ + "tools": 86, + "schema": "solar.documentation.v1", + "documents": 31, + "localLinks": 198, + "npmCommands": 92, + "pathReferences": 176, + "toolReferences": 84, + "failures": [], + "limits": "Current local Markdown links, paths, headings, named npm commands and Solar script references (including unquoted commands). Historical ADRs/evidence, explicitly other-repository commands and remote endpoints are excluded. Behavioral claims and integration boundaries require review/tests." +} +File-size guard: 319 text files, 5 reviewed exceptions, no growth. diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-lint.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-lint.txt new file mode 100644 index 0000000..6e7bd6f --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-lint.txt @@ -0,0 +1,3 @@ + +> @zablab/solar@3.0.1 lint +> eslint --max-warnings 0 . diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-typecheck.txt b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-typecheck.txt new file mode 100644 index 0000000..07e7ba5 --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-typecheck.txt @@ -0,0 +1,3 @@ + +> @zablab/solar@3.0.1 typecheck +> tsc -b --pretty diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-AGENT_REPORT.md b/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-AGENT_REPORT.md new file mode 100644 index 0000000..b0c050d --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-AGENT_REPORT.md @@ -0,0 +1,101 @@ +# Solar — publication du hash source après admission coordonnée + +Rapport du 29 octobre 2026, 18:45 UTC. Q-agent `code-debugging`, filiation informatique → code → code-debugging, contribution `solar-proof` de la Q-task parent `prism-debug-continuation`. Q-session parent `qs-cdf211ab9b25a9dedce2ce52`, conversation `01a11a8b-8f4f-7fc2-abc4-7983042e4f63`. Cette contribution poursuit la session parent. + +## Version et périmètre + +- Dépôt Solar, branche `realisateur/local-20261026-composition-publication`. +- Base observée : `caab7a2c3994b3954348ef6167de934e95a6677a`. +- Worktree attribué : `D:/Documents/Zab/Solar/.worktrees/realisateur-local-20261026-composition-publication`. +- Écriture limitée à ce worktree. Aucun changement Prism, service commun, checkout canonique, protocole, déploiement, push ou merge. Aucun Live/REC réel ni Computer Use. +- Paquet du mandat lu intégralement : `t24_prism-debug-continuation_s5_solar_n1.packet.json`, SHA256 `8ba6dd5b948a489a0138fb50611a947c4c636556f806b1f8e28ade40aed42eb6`. + +## Défaut reproduit et causalité + +`NativeCompositionSession.use` change uniquement la projection active. La publication acceptée et son hash source sont renouvelés par `accept` et les chemins `acceptDocument`/`acceptFrame`. Les admissions coordonnées dans `NativeLsdpRuntime` pouvaient préparer, activer ou restaurer une projection avec `use` sans renouveler la publication `solar/composition`. Le hash de la ressource LSDP changeait alors que la publication conservait le hash précédent. Une modification d'une autre entrée d'une collection sélectionnée avait le même problème. + +Le test hérité, fondé sur un espion d'acceptation et une projection nulle, échouait au prepare. Il a été conservé sous forme de patch dans le temporaire de la session avant remplacement par une preuve utilisant des projections issues de reçus Vision synthétiques. Sur le runtime de la base, avec les tests renforcés et le même runner, 9 tests échouent et 8 passent. Les échecs couvrent prepare, commit, finalize, abort/reconnexion, snapshots commit/finalize/abort, échec de staging et modification hors entrée sélectionnée. Cleanup utilisait déjà un chemin de patch qui publiait. + +Le contrôle avant correction remplace temporairement uniquement `src/engine/native-lsdp-runtime.ts` par son contenu de la base, puis restaure les octets candidats dans un bloc `finally`. Les tests et fixtures restent identiques. Le résultat rouge est donc attribuable au runtime de base. + +## Correction effectuée + +`NativeCompositionSession.acceptCurrent(document, stateHash)` réutilise le mécanisme existant d'acceptation et de publication pour la projection active ; une scène vide passe par `clear`. Le runtime l'appelle après admission d'un snapshot coordonné, d'une notification coordonnée, ou d'un nouvel état dont l'entrée sélectionnée n'a pas changé. Un contrôle de durée de vie suit les effets asynchrones avant cette acceptation. Le chemin de rendu utilise également ce point d'entrée après avoir activé la projection. + +La déduplication, le hash du plan, la coalescence du dernier état, le CAS et l'autorité du producer restent ceux du publisher existant. Aucun timer, cache produit ou contournement Prism n'est ajouté. Le README propriétaire décrit le contrat et la carte dérivée a été régénérée avec `node scripts/code/cli.mjs map`. + +Fichiers fonctionnels et documentaires : + +- `src/engine/native-composition-session.ts` : admission explicite de la projection courante. +- `src/engine/native-lsdp-runtime.ts` : publication après admission coordonnée et contrôles de durée de vie. +- `src/engine/README.md`, `docs/development/code-map.md` : contrat et découverte actualisés. +- `tests/unit/native-lsdp-runtime-composition.test.ts` : admission coordonnée, état/layout identiques, commit, restauration abort, snapshots, staging refusé, arrêt, reconnexion et sélection de collection. +- `tests/unit/native-composition-publisher.test.ts` : publisher réel, déduplication du même hash et publication d'un nouveau hash avec géométrie identique. +- `tests/unit/native-composition-session.test.ts` : scène vide, clear et absence de replay périmé après remplacement du peer. + +## Vérifications observées + +Environnement : Solar 3.0.1, Node 24.16.0, npm 11.16.0, TypeScript 5.9.3, ESLint 9.39.4, Vitest 4.1.11. Dépendances existantes utilisées sans installation ni modification du lockfile. + +| Contrôle | Résultat | +| --- | --- | +| Runtime de base, tests renforcés | 17 tests : 9 échecs, 8 réussites | +| Candidat, suite ciblée | 79/79 tests, 6 fichiers, aucun skip | +| `npm run typecheck` | Exit 0 | +| `npm run lint` | Exit 0 | +| `npm run check:architecture` | Exit 0 : 71 sources atteignables, carte courante, aucune référence documentaire invalide, garde de taille sans croissance | +| `npm run test:architecture` | 13/13 tests | +| Prettier sur les 5 fichiers TypeScript modifiés | Exit 0 | +| `git diff --check` | Exit 0 | + +La suite ciblée comprend `native-lsdp-runtime.test.ts` (33), `native-lsdp-runtime-composition.test.ts` (17), `native-composition-publisher.test.ts` (11), `native-composition.test.ts` (11), `native-composition-session.test.ts` (3), `frame-patches.test.ts` (4). Les tests existants du publisher couvrent aussi remplacement de producer, première écriture ancienne retardée, révocation, clear/retire, fermeture terminale et priorité du dernier état. + +Runner utilisé depuis le worktree pour éviter une écriture de cache dans les dépendances partagées : + +```javascript +// Exécuté par node --input-type=module -e, avec cette configuration. +import { startVitest } from 'vitest/node'; +const ctx = await startVitest('test', [ + 'tests/unit/native-lsdp-runtime-composition.test.ts', + 'tests/unit/native-lsdp-runtime.test.ts', + 'tests/unit/native-composition-publisher.test.ts', + 'tests/unit/native-composition-session.test.ts', + 'tests/unit/frame-patches.test.ts', + 'tests/unit/native-composition.test.ts' +], { + run: true, config: false, cache: false, environment: 'happy-dom', maxWorkers: 1, + reporters: ['default', 'json'], + outputFile: 'evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json' +}, { + cacheDir: process.cwd() + '/.cache/composition-publication/vite', + resolve: { alias: { + '@lumencast/runtime': process.cwd() + '/node_modules/@lumencast/runtime/dist/webrtc/index.js' + } } +}); +await ctx.close(); +``` + +L'environnement et l'alias reprennent la configuration existante. Le chargement alternatif de la configuration par le runner avait échoué sur `__dirname`/`ERR_AMBIGUOUS_MODULE_SYNTAX` ; l'API avec options explicites ci-dessus a exécuté les tests. Aucune couverture globale n'est revendiquée. + +## Preuves et conservation + +Tous les chemins suivants sont relatifs à ce dossier de preuve : + +- `20261029T184112Z-before-tests.txt` et `.json` : 9 échecs/8 réussites du runtime de base. +- `20261029T184112Z-after-tests.txt` et `.json` : 79 réussites du candidat ; dernière exécution commencée à 18:42:44 UTC. Le nom de fichier conserve l'identité de la première capture. +- `20261029T184258Z-typecheck.txt`, `20261029T184258Z-lint.txt`, `20261029T184258Z-architecture.txt`, `20261029T184258Z-architecture-tests.txt` : contrôles finaux. +- `20261029T184518Z-checksums.json` : SHA256 des sept fichiers modifiés et des huit sorties de contrôle, sans ce rapport ni le manifeste lui-même. + +Les chemins absolus du worktree ont été remplacés dans les sorties de test par ``. Aucune clé, authentification, donnée de session produit ni journal brut externe n'est inclus. + +Le reproducer hérité est sauvegardé dans `C:/Users/Mathias/AppData/Local/Temp/codex-zab/01a11a8b-8f4f-7fc2-abc4-7983042e4f63/debug-20261029/solar-inherited-reproducer.patch`. Son fichier d'origine `native-lsdp-runtime.test.ts` est revenu au contenu de HEAD après consolidation des tests. Le dossier local hérité `node_modules-cache/` a été préservé sous `.cache/composition-publication/inherited-node_modules-cache`, après contrôle des chemins et de l'absence de reparse point. La jonction `node_modules` vers le worktree commun reste inchangée. + +Une copie en octets identiques de ce rapport est remise à `C:/Users/Mathias/AppData/Local/Temp/codex-zab/01a11a8b-8f4f-7fc2-abc4-7983042e4f63/debug-20261029/solar-report.md` ; son SHA256 et le commit signé contenant cette version sont communiqués dans le retour à l'hôte. + +## Limites et remise + +La causalité locale et le contrat de publication sont établis par ces contrôles. Les tests runtime utilisent un publisher mocké et des reçus Vision synthétiques ; les tests du publisher utilisent son implémentation réelle et un faux peer CAS. Ils ne prouvent pas les pixels CEF, un transport natif réel, une intégration Prism de bout en bout ou la disparition du warning utilisateur. Aucun build, CI distante, Live, REC ou déploiement n'est revendiqué. + +Le script global attendu `D:/Documents/Zab/agents/_shared/zab-workspace-guard.ps1` est absent de l'installation observée. Les contrôles locaux de structure et d'architecture réussissent ; aucun gate global de clôture n'est déclaré vert. Le worktree reste disponible pour la revue et l'intégration de l'hôte. Aucun nettoyage des autres travaux n'a été entrepris. + +Remise : commit local signé, état suivi propre, revue requise par l'hôte avant intégration. Le retour exact communique le SHA du commit. Un rollback ultérieur peut utiliser `git revert` sur ce SHA ; aucun rollback n'a été effectué. diff --git a/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-checksums.json b/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-checksums.json new file mode 100644 index 0000000..3a7b11a --- /dev/null +++ b/evidence/local-20261026-composition-publication/realisateur/20261029T184518Z-checksums.json @@ -0,0 +1,66 @@ +{ + "schema": "solar.composition-publication.checksums.v1", + "base": "caab7a2c3994b3954348ef6167de934e95a6677a", + "files": [ + { + "path": "docs/development/code-map.md", + "sha256": "414ac331a2b85f4db0a4ca29db796f8c491b505405ac0551d6d47cc073e1ac0c" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.json", + "sha256": "6677212e26012cac835bab49b45c35a312ee08a5f181ac056216ae72d920f76d" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-after-tests.txt", + "sha256": "3cdeaadc495dae6cd413eb2f567e7aefc7ec2d89f07c6572468b7b9260398cb6" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.json", + "sha256": "ebcd950023de55e1bca5d55480108dbee05b210f75b44dc9522b8cc1b87f3a60" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184112Z-before-tests.txt", + "sha256": "01489208e7bc0949e0f11296e16b4e95f95c76f253c7e5227e6d00a5230328d6" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture-tests.txt", + "sha256": "5c98910b77b598e48a741483ccabdacddf14e4c2038dd69bf8a45940f82e323a" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-architecture.txt", + "sha256": "6ee1dd4cea964c8a8178ce35d805992dcae9cd06a62422abbc4cedb5ca366122" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-lint.txt", + "sha256": "e51b07f2f784e48d3ca441f93c962423fae97033a4254400cd677229188e7891" + }, + { + "path": "evidence/local-20261026-composition-publication/realisateur/20261029T184258Z-typecheck.txt", + "sha256": "a20f8cee9083300dda173863c9c9d7fb4d2c35f781bcb91e615f0f073f142078" + }, + { + "path": "src/engine/native-composition-session.ts", + "sha256": "f1bb341d484f345940bea43cedd7b4aabcc21e267f45422b3aafc068875240c9" + }, + { + "path": "src/engine/native-lsdp-runtime.ts", + "sha256": "48642597adcd5fab253b7d7e45fe4504e1593ef38c6ad3797f186946375a26f3" + }, + { + "path": "src/engine/README.md", + "sha256": "0158cfbba49b5b7c7dc4dea52b791c35f3c9aee9001e650d4adb076708bab1f7" + }, + { + "path": "tests/unit/native-composition-publisher.test.ts", + "sha256": "805a4ce4dd250a16dde9c0b7543ff493a104330f6b84b42c874adccb73ef7ab9" + }, + { + "path": "tests/unit/native-composition-session.test.ts", + "sha256": "16b22ed1afdc8dbd69cad32f70d0c9cc9be6a6c5579ea0c402d1daa75a44ccb8" + }, + { + "path": "tests/unit/native-lsdp-runtime-composition.test.ts", + "sha256": "ca6aace4e016936220f97523964ba3ac08390ccc60a6afccf1cfc4e241fa25ae" + } + ] +} diff --git a/src/engine/README.md b/src/engine/README.md index d5b1c08..a1ae64c 100644 --- a/src/engine/README.md +++ b/src/engine/README.md @@ -75,6 +75,14 @@ recovery takes priority and runtime disconnect cancels pending composition work. `NativeCompositionSession` stores accepted source state while the peer is absent and replays that latest state when a replacement peer starts; it reports retry success only after the replacement peer completes its first current publication. +Coordinated prepare/commit/finalize/abort admissions also bind the retained or +activated projection to the exact accepted resource hash, including joining +snapshots and source changes outside a selected entry. Identical geometry does +not imply an identical source hash. Runtime lifetime checks precede this binding; +rejected or stopped deliveries cannot replace the accepted publication. +`use` changes only the active projection during staging; `acceptCurrent` records +and publishes that projection after source admission, or clears an empty scene. +The existing publisher still owns plan hashing, latest-state coalescing and CAS. When the trusted host config enables `nativeCompositionLSDP`, the runtime projects compositor metadata from the accepted Vision receipt of that active scene and publishes it with the exact LSDP state hash to the separate `solar/composition` diff --git a/src/engine/native-composition-session.ts b/src/engine/native-composition-session.ts index 27a71d7..51f206a 100644 --- a/src/engine/native-composition-session.ts +++ b/src/engine/native-composition-session.ts @@ -114,6 +114,12 @@ export class NativeCompositionSession { this.publish(projection, document, stateHash); } + /** Bind a retained/committed projection to the newly accepted source state. */ + acceptCurrent(document: LSMLDocument | null, stateHash: unknown): void { + if (document) this.accept(this.activeProjection, document, stateHash); + else this.clear(); + } + acceptDocument( document: LSMLDocument, scene: VisionSceneHandle, diff --git a/src/engine/native-lsdp-runtime.ts b/src/engine/native-lsdp-runtime.ts index 67ad3a9..e33c854 100644 --- a/src/engine/native-lsdp-runtime.ts +++ b/src/engine/native-lsdp-runtime.ts @@ -460,6 +460,8 @@ export class NativeLsdpRuntime { this.presentedDocument = document; if (document) await this.updatePlayback(document); else this.sound.clear(); + check(); + if (handled) this.composition.acceptCurrent(document, hash); this.nativeState = state; this.hasSnapshot = true; this.hash = hash; @@ -657,6 +659,8 @@ export class NativeLsdpRuntime { this.presentedDocument = next; if (next && changed) await this.updatePlayback(next); else if (!next) this.sound.clear(); + check(); + if (coordinated || !changed) this.composition.acceptCurrent(next, hash); this.nativeState = state; this.hash = hash; this.sequence = event.sequence; @@ -957,11 +961,7 @@ export class NativeLsdpRuntime { media.resume(); if (previous && previous.media !== media) previous.media.dispose(); if (compositionStateHash !== undefined) - this.composition.accept( - frame.composition, - document, - compositionStateHash, - ); + this.composition.acceptCurrent(document, compositionStateHash); } catch (error) { if (!committed) { if (!reusedMedia) media?.dispose(); diff --git a/tests/unit/native-composition-publisher.test.ts b/tests/unit/native-composition-publisher.test.ts index 4a68cd4..a013ea4 100644 --- a/tests/unit/native-composition-publisher.test.ts +++ b/tests/unit/native-composition-publisher.test.ts @@ -319,6 +319,44 @@ it("publishes the active physical graph with source hash and retries only a CAS }); }); +it("deduplicates the same state but republishes an unchanged layout with a new source hash", async () => { + const shared: FakeShared = { + state: claimedState("host-a-incarnation-1"), + staleOnce: false, + applied: [], + }; + const publisher = new NativeCompositionPublisher( + options(), + vi.fn(), + fakePeerFactory(shared), + ); + const document = { scene_id: "scene-a", scene_version: "sha256:revision-a" }; + const layout = projection(); + await publisher.publish(layout, document, "tree-sha256:initial"); + const first = (shared.state.graphs as Record) + .A!; + await publisher.publish( + structuredClone(layout), + document, + "tree-sha256:initial", + ); + expect(shared.applied).toHaveLength(1); + await publisher.publish( + structuredClone(layout), + document, + "tree-sha256:committed", + ); + const committed = ( + shared.state.graphs as Record + ).A!; + expect(shared.applied).toHaveLength(2); + expect(committed.source.stateHash).toBe("tree-sha256:committed"); + expect(committed.planHash).not.toBe(first.planHash); + expect(committed.groups).toEqual(first.groups); + expect(committed.surfaces).toEqual(first.surfaces); + await publisher.retire(); +}); + it("does not overwrite or retire a replacement producer after losing slot ownership", async () => { const shared = { state: claimedState("host-a-incarnation-1") as Record, diff --git a/tests/unit/native-composition-session.test.ts b/tests/unit/native-composition-session.test.ts index 3502171..b95b606 100644 --- a/tests/unit/native-composition-session.test.ts +++ b/tests/unit/native-composition-session.test.ts @@ -201,6 +201,34 @@ it("replays the latest accepted LSML composition after the peer was offline", as await vi.waitFor(() => expect(state.graphs.A).toBeUndefined()); }); +it("accepts an empty current scene as a clear and does not replay the retired plan", async () => { + const state: SharedCompositionState = { + schema: "solar.native-composition.state/1", + producers: { A: "host-a-current" }, + graphs: {}, + }; + const peers: Array<{ authToken: string; onClose?: (error: Error) => void }> = + []; + const session = new NativeCompositionSession( + options(), + undefined, + undefined, + peerFactory(state, peers), + ); + const document = scene("scene-a", "a"); + session.start("token-a"); + session.accept(projection(640), document, nativeTreeHash(document)); + await vi.waitFor(() => expect(state.graphs.A).toBeDefined()); + session.acceptCurrent(null, nativeTreeHash(null)); + await vi.waitFor(() => expect(state.graphs.A).toBeUndefined()); + expect(session.currentProjection).toBeNull(); + peers[0]?.onClose?.(new Error("composition peer disconnected")); + session.start("token-b"); + await vi.waitFor(() => expect(peers).toHaveLength(2)); + expect(state.graphs.A).toBeUndefined(); + session.retire(); +}); + it("refuses to accept a receipt from a different scene identity", () => { const session = new NativeCompositionSession(options()); const documentA = scene("scene-a", "a"); diff --git a/tests/unit/native-lsdp-runtime-composition.test.ts b/tests/unit/native-lsdp-runtime-composition.test.ts index d2c3406..5d42e2d 100644 --- a/tests/unit/native-lsdp-runtime-composition.test.ts +++ b/tests/unit/native-lsdp-runtime-composition.test.ts @@ -25,7 +25,14 @@ const mocks = vi.hoisted(() => ({ prewarm: vi.fn(async () => {}), disconnectSession: vi.fn(), activate: vi.fn(), - feedback: vi.fn(async () => {}), + feedback: vi.fn( + async ( + _url: string, + _lane: string, + _value: unknown, + _signal: AbortSignal, + ) => {}, + ), media: { update: vi.fn(), refresh: vi.fn(), @@ -121,40 +128,39 @@ const origin: SceneSourceDelivery = { blueManifest: nativeManifest(document.scene_id, version), }; -async function setup(initial: unknown, token: MountOptions["token"] = "") { - let handleSceneId = ""; - let handleSceneVersion = ""; - let acceptedFrame: ReturnType | null = null; - const scene = { - get sceneId() { - return handleSceneId; - }, - get sceneVersion() { - return handleSceneVersion; - }, - get compositionFrame() { - return acceptedFrame; - }, - applyPatch: vi.fn(async () => { - if (acceptedFrame) - acceptedFrame = { - ...acceptedFrame, - pixelRevision: (BigInt(acceptedFrame.pixelRevision) + 1n).toString(), +async function setup( + initial: unknown, + token: MountOptions["token"] = "", + selector?: string, + varyProjection = false, +) { + const scenes: Array> = []; + function makeScene(frame: ReturnType) { + return { + sceneId: frame.sceneId, + sceneVersion: frame.sceneVersion, + get compositionFrame() { + return frame; + }, + applyPatch: vi.fn(async () => { + frame = { + ...frame, + pixelRevision: (BigInt(frame.pixelRevision) + 1n).toString(), }; - }), - clearMedia: vi.fn(async () => {}), - canApplyPatch: vi.fn(() => true), - dispose: vi.fn(), - mediaSources: [], - activate: vi.fn(), - feedback: vi.fn(async () => {}), - flush: vi.fn(async () => {}), - }; + }), + clearMedia: vi.fn(async () => {}), + canApplyPatch: vi.fn(() => true), + dispose: vi.fn(), + mediaSources: [], + activate: vi.fn(), + deactivate: vi.fn(), + feedback: vi.fn(async () => {}), + flush: vi.fn(async () => {}), + }; + } mocks.mount.mockImplementation(async (...args: unknown[]) => { const source = args[1] as SceneSourceDelivery; const renderPackage = args[5] as { sceneVersion: string }; - handleSceneId = source.sceneId; - handleSceneVersion = renderPackage.sceneVersion; const frame = compositionFrame(); frame.sceneId = source.sceneId; frame.sceneVersion = renderPackage.sceneVersion; @@ -164,10 +170,12 @@ async function setup(initial: unknown, token: MountOptions["token"] = "") { frame.canvasSize = [640, 480]; frame.owners[0]!.localSize = [640, 480]; frame.owners[0]!.localToWorld = [1, 0, 0, 1, 0, 0]; + if (varyProjection && scenes.length > 0) frame.owners[0]!.opacity = 0.5; frame.captures[0]!.localToWorld = [1, 0, 0, 1, 20, 30]; frame.surfaces[0]!.sceneRect = [0, 0, 640, 480]; frame.surfaces[0]!.atlasRect = [0, 0, 640, 480]; - acceptedFrame = frame; + const scene = makeScene(frame); + scenes.push(scene); return scene; }); const resource = "solar/lane-a"; @@ -176,6 +184,7 @@ async function setup(initial: unknown, token: MountOptions["token"] = "") { nativeLSDP: { url: "ws://127.0.0.1:4520/lsdp", resource, + selector, }, nativeComposition: { width: 640, height: 480 }, nativeCompositionLSDP: { @@ -213,7 +222,7 @@ async function setup(initial: unknown, token: MountOptions["token"] = "") { }); await receive(structuredClone(initial), context("lsdp.state.read/1")); await turn(); - return { runtime, scene, receive, context }; + return { runtime, scene: scenes[0]!, scenes, receive, context, options }; } function documentElement(): HTMLElement { @@ -258,6 +267,203 @@ describe("native Solar composition attachment", () => { mocks.compositionPublisherOptions = null; }); + async function coordinated(varyProjection = false) { + const initial = structuredClone(document); + const candidate = { + ...initial, + defaults: { "__lit.text.title": "candidate" }, + }; + const ready = await setup(initial, "", undefined, varyProjection); + let state: unknown = initial; + let sequence = 0; + const deliver = async (phase: string) => { + const value = + phase === "cleanup" + ? candidate + : { + ...(phase === "commit" || phase === "finalize" + ? candidate + : initial), + "x-solar-transition": { + request_id: "composition-selection", + phase, + lane: "preview", + ...(phase === "prepare" ? { source: candidate } : {}), + }, + }; + const transactionId = String(++sequence).padStart(32, "0"); + const receipt = await ready.receive( + { + kind: "applied_change", + sequence, + mutation: { + format: "lsdp.apply/1", + id: transactionId, + target: "solar/lane-a", + beforeHash: nativeTreeHash(state), + operations: [{ op: "replace", path: "", value }], + }, + receipt: { target: "solar/lane-a", transactionId, level: "applied" }, + }, + ready.context("lsdp.state.subscription/1"), + ); + state = value; + expect(receipt).toEqual({ level: "applied", transactionId }); + return nativeTreeHash(value); + }; + return { ...ready, initial, candidate, deliver }; + } + + it.each(["prepare", "commit", "finalize", "cleanup"])( + "renews the source hash on coordinated %s with identical layout", + async (acceptedPhase) => { + const ready = await coordinated(); + const initialProjection = + mocks.composition.publish.mock.calls.at(-1)?.[0]; + try { + for (const phase of ["prepare", "commit", "finalize", "cleanup"]) { + const hash = await ready.deliver(phase); + if (phase !== acceptedPhase) continue; + const accepted = mocks.composition.publish.mock.calls.at(-1)!; + expect(accepted[1]).toEqual( + phase === "prepare" ? ready.initial : ready.candidate, + ); + expect(accepted[2]).toBe(hash); + expect(accepted[0]).toEqual(initialProjection); + break; + } + // A repeated identical state still admits the exact hash without remounting. + await ready.deliver(acceptedPhase); + expect(mocks.mount).toHaveBeenCalledTimes(2); + expect(ready.options.onError).not.toHaveBeenCalled(); + } finally { + ready.runtime.disconnect(); + } + }, + ); + + it("binds the restored projection to the abort hash and replays only that state to a replacement peer", async () => { + const ready = await coordinated(true); + const initialProjection = mocks.composition.publish.mock.calls.at(-1)?.[0]; + try { + await ready.deliver("prepare"); + await ready.deliver("commit"); + expect(ready.scenes[1]!.compositionFrame.owners[0]!.opacity).toBe(0.5); + vi.useFakeTimers(); + mocks.compositionPublishers[0]!.onDisconnected(new Error("peer closed")); + const hash = await ready.deliver("abort"); + await vi.advanceTimersByTimeAsync(250); + expect(mocks.compositionPublishers).toHaveLength(2); + expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + initialProjection, + ready.initial, + hash, + ]); + expect(ready.scenes[0]!.activate).toHaveBeenCalledOnce(); + expect(ready.scenes[1]!.dispose).toHaveBeenCalledOnce(); + } finally { + vi.useRealTimers(); + ready.runtime.disconnect(); + } + }); + + it.each(["commit", "finalize", "abort"])( + "publishes a joining coordinated %s snapshot with its full resource hash", + async (phase) => { + const initial = { + ...document, + "x-solar-transition": { + request_id: "snapshot-selection", + phase, + lane: "preview", + }, + }; + const ready = await setup(initial); + try { + expect(mocks.composition.publish.mock.calls.at(-1)?.[2]).toBe( + nativeTreeHash(initial), + ); + expect(mocks.composition.publish.mock.calls.at(-1)?.[0]).toBeTruthy(); + expect(ready.options.onError).not.toHaveBeenCalled(); + } finally { + ready.runtime.disconnect(); + } + }, + ); + + it("keeps the accepted projection on failed staging and rejects invalid phases without publication", async () => { + const ready = await coordinated(); + const initialProjection = mocks.composition.publish.mock.calls.at(-1)?.[0]; + try { + mocks.mount.mockRejectedValueOnce(new Error("renderer refused")); + const hash = await ready.deliver("prepare"); + expect(mocks.feedback.mock.calls.at(-1)?.[2]).toMatchObject({ + phase: "failed", + }); + expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + initialProjection, + ready.initial, + hash, + ]); + const publications = mocks.composition.publish.mock.calls.length; + await expect(ready.deliver("invalid")).rejects.toThrow( + "SOLAR_TRANSITION_INVALID", + ); + expect(mocks.composition.publish).toHaveBeenCalledTimes(publications); + } finally { + ready.runtime.disconnect(); + } + }); + + it("cannot publish a coordinated state after stopping during feedback", async () => { + const ready = await coordinated(); + let release!: () => void; + let entered!: () => void; + const feedbackEntered = new Promise((resolve) => { + entered = resolve; + }); + mocks.feedback.mockImplementationOnce(async () => { + entered(); + await new Promise((resolve) => { + release = resolve; + }); + }); + const publications = mocks.composition.publish.mock.calls.length; + const pending = ready.deliver("prepare"); + const rejected = expect(pending).rejects.toThrow(); + await feedbackEntered; + ready.runtime.disconnect(); + release(); + await rejected; + expect(mocks.composition.publish).toHaveBeenCalledTimes(publications); + expect(mocks.composition.retire).toHaveBeenCalledOnce(); + }); + + it("refreshes the full resource hash when only another selected entry changes", async () => { + const initial = { selected: document, other: document }; + const ready = await setup(initial, "", "selected"); + const projection = mocks.composition.publish.mock.calls.at(-1)?.[0]; + try { + const event = change(); + event.mutation.beforeHash = nativeTreeHash(initial); + event.mutation.operations[0]!.path = "/other/defaults/__lit.text.title"; + await ready.receive(event, ready.context("lsdp.state.subscription/1")); + const expected = { + selected: document, + other: { ...document, defaults: { "__lit.text.title": "edited" } }, + }; + expect(mocks.composition.publish.mock.calls.at(-1)).toEqual([ + projection, + document, + nativeTreeHash(expected), + ]); + expect(ready.scene.applyPatch).not.toHaveBeenCalled(); + expect(mocks.mount).toHaveBeenCalledOnce(); + } finally { + ready.runtime.disconnect(); + } + }); + it("publishes the accepted Vision receipt and refreshes it after a scalar patch", async () => { const initial = { ...structuredClone(document),