fix(k1): stabilize live recovery and media admission

This commit is contained in:
DCCONSTRUCTIONS
2026-08-22 00:03:01 +03:00
parent 7217244886
commit eaad9deda1
29 changed files with 1645 additions and 199 deletions
@@ -16,6 +16,7 @@ let WorkspaceLayoutContractError;
let admitLiveDefaultPresentations;
let automaticLivePresentationIdentity;
let livePresentationCloseFence;
let restoredLayoutMayAdmitLiveDefault;
let observationPresentationSourceAfterLayoutApply;
let visibleSourceIdsAfterRecordedCatalogActivation;
@@ -39,6 +40,7 @@ before(async () => {
admitLiveDefaultPresentations,
automaticLivePresentationIdentity,
livePresentationCloseFence,
restoredLayoutMayAdmitLiveDefault,
observationPresentationSourceAfterLayoutApply,
visibleSourceIdsAfterRecordedCatalogActivation,
} = await server.ssrLoadModule("/src/core/observation/useObservationLayout.ts"));
@@ -308,6 +310,67 @@ test("a sequential live acquisition re-arms the same camera without reopening a
]);
});
test("a restored layout admits a selected delivery after reload and only same-acquisition successors", () => {
const camera = (acquisitionId, deliveryId) => ({
id: "k1:sensor.camera.right",
sourceId: "sensor.camera.right",
modality: "video",
availability: "streaming",
transport: "websocket",
previewUrl: null,
delivery: {
id: deliveryId,
kind: "mse-fmp4-websocket",
url: `/camera-preview/${deliveryId}`,
mediaType: 'video/mp4; codecs="avc1.641028"',
},
activation: {
groupId: "k1:device-session-reused:camera.preview.decoder",
maxActive: 1,
selected: true,
controllable: true,
},
binding: {
deviceId: "k1-a",
deviceSessionId: "device-session-reused",
acquisitionId,
},
capabilities: { defaultVisible: true, overlay: true },
});
const original = camera("acquisition-a", "camera-preview-2");
const successor = camera("acquisition-a", "camera-preview-3");
const unrelated = camera("acquisition-b", "camera-preview-3");
const presented = new Set([livePresentationCloseFence(original)]);
assert.equal(restoredLayoutMayAdmitLiveDefault([original], new Set()), true);
assert.equal(restoredLayoutMayAdmitLiveDefault([successor], presented), true);
assert.equal(restoredLayoutMayAdmitLiveDefault([unrelated], presented), false);
assert.equal(restoredLayoutMayAdmitLiveDefault([{
...original,
activation: { ...original.activation, selected: false },
}], new Set()), false);
const admitted = admitLiveDefaultPresentations(
[],
[successor],
new Set([automaticLivePresentationIdentity(original)]),
new Set(),
);
assert.deepEqual(admitted.visibleIds, [successor.id]);
assert.deepEqual(admitted.admittedIdentities, [
automaticLivePresentationIdentity(successor),
]);
const deliberatelyClosed = admitLiveDefaultPresentations(
[],
[successor],
new Set([automaticLivePresentationIdentity(original)]),
presented,
);
assert.deepEqual(deliberatelyClosed.visibleIds, []);
assert.deepEqual(deliberatelyClosed.admittedIdentities, []);
});
test("workspace layout API uses the canonical endpoint and optimistic revision", async () => {
const calls = [];
const current = decodeObservationWorkspaceLayoutProfile(wireProfile());