wip(k1): checkpoint connection recovery rewrite

Capture the current unreleased K1 connection, recovery, lifecycle, viewer, and test work as a single known-bad baseline for subsequent fixes.
This commit is contained in:
DCCONSTRUCTIONS
2026-08-14 14:57:50 +03:00
parent aff331082f
commit 0ca7316a24
157 changed files with 152962 additions and 4036 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,219 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { after, before, test } from "node:test";
import React, { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { createServer } from "vite";
let server;
let DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY;
let DevicePluginHostProvider;
let commitPersistedDeviceModelId;
let restorePersistedDeviceModelId;
const hostSourceUrl = new URL(
"../src/core/device-plugins/DevicePluginHost.tsx",
import.meta.url,
);
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY,
DevicePluginHostProvider,
commitPersistedDeviceModelId,
restorePersistedDeviceModelId,
} = await server.ssrLoadModule("/src/core/device-plugins/DevicePluginHost.tsx"));
});
after(async () => {
await server?.close();
});
function memoryStorage(seed = {}) {
const values = new Map(Object.entries(seed));
const calls = [];
return {
calls,
getItem(key) {
calls.push(["get", key]);
return values.get(key) ?? null;
},
setItem(key, value) {
calls.push(["set", key, value]);
values.set(key, value);
},
removeItem(key) {
calls.push(["remove", key]);
values.delete(key);
},
value(key) {
return values.get(key) ?? null;
},
};
}
function registryWith(...modelIds) {
const registered = new Set(modelIds);
return {
resolveModel(modelId) {
return registered.has(modelId) ? { model: { id: modelId } } : null;
},
};
}
function fakePlugin(modelId) {
function RuntimeProvider({ activeModel, children }) {
return createElement(
"div",
{ "data-active-model": activeModel?.id ?? "" },
children,
);
}
function ConnectionView() {
return null;
}
return {
manifest: {
apiVersion: "missioncore.nodedc/v1alpha1",
kind: "DevicePlugin",
metadata: {
id: "test.device.plugin",
version: "1.0.0",
displayName: "Test device",
},
spec: {
hostApiRange: "v1alpha1",
runtime: {
backendEntrypoint: "test.device:plugin",
isolation: "transitional-in-process",
},
permissions: [],
actions: [{ id: "state.read", mutating: false, secretFields: [] }],
models: [{
id: modelId,
vendor: "Test",
displayName: "Test model",
category: "test",
description: "test",
verified: true,
capabilities: [],
ui: {
slot: "device.connection",
componentKey: "test.connection",
},
}],
},
},
RuntimeProvider,
connectionViews: { "test.connection": ConnectionView },
};
}
test("persisted model restore admits only an id in the current plugin registry", () => {
const key = DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY;
const registry = registryWith("xgrids.lixelkity-k1");
const valid = memoryStorage({ [key]: " xgrids.lixelkity-k1 " });
assert.equal(
restorePersistedDeviceModelId(registry, valid),
"xgrids.lixelkity-k1",
);
assert.equal(valid.calls.some(([operation]) => operation === "remove"), false);
for (const staleValue of ["removed.model", " "]) {
const stale = memoryStorage({ [key]: staleValue });
assert.equal(restorePersistedDeviceModelId(registry, stale), null);
assert.equal(stale.value(key), null, "a stale model id must be cleared");
}
assert.equal(restorePersistedDeviceModelId(registry, null), null);
});
test("fresh provider mount immediately activates the registry-validated persisted model", () => {
const modelId = "test.model.one";
const storage = memoryStorage({
[DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY]: modelId,
});
const previousWindow = globalThis.window;
globalThis.window = { localStorage: storage };
try {
const markup = renderToStaticMarkup(createElement(
DevicePluginHostProvider,
{ plugins: [fakePlugin(modelId)] },
createElement("span", null, "runtime child"),
));
assert.match(markup, /data-active-model="test\.model\.one"/);
} finally {
if (previousWindow === undefined) delete globalThis.window;
else globalThis.window = previousWindow;
}
});
test("successful selection commits and explicit clear removes the same durable key", () => {
const storage = memoryStorage();
commitPersistedDeviceModelId("xgrids.lixelkity-k1", storage);
assert.equal(
storage.value(DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY),
"xgrids.lixelkity-k1",
);
commitPersistedDeviceModelId(null, storage);
assert.equal(storage.value(DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY), null);
assert.deepEqual(
storage.calls.slice(-1)[0],
["remove", DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY],
);
});
test("unavailable browser storage fails closed without blocking host state", () => {
const denied = {
getItem() {
throw new Error("storage denied");
},
setItem() {
throw new Error("storage denied");
},
removeItem() {
throw new Error("storage denied");
},
};
assert.equal(
restorePersistedDeviceModelId(registryWith("xgrids.lixelkity-k1"), denied),
null,
);
assert.doesNotThrow(() =>
commitPersistedDeviceModelId("xgrids.lixelkity-k1", denied)
);
assert.doesNotThrow(() => commitPersistedDeviceModelId(null, denied));
});
test("host writes persistence only after plugin deactivation succeeds", () => {
const source = readFileSync(hostSourceUrl, "utf8");
const failedDeactivation = source.indexOf("if (!(await deactivate()))");
const admittedState = source.indexOf("setSelectedModelId(nextModelId);");
const durableCommit = source.indexOf(
"commitPersistedDeviceModelId(nextModelId, selectionStorage);",
admittedState,
);
assert.ok(failedDeactivation >= 0);
assert.ok(
failedDeactivation < admittedState && admittedState < durableCommit,
"failed deactivation branches must return before in-memory and durable commit",
);
assert.match(
source,
/if \(nextModelId === selectedModelId\) \{[\s\S]*?commitPersistedDeviceModelId\(nextModelId, selectionStorage\);[\s\S]*?return true;/,
"explicit clear must remove stale persistence even from an already-empty host",
);
assert.match(
source,
/useState<string \| null>\(\(\) =>\s*restorePersistedDeviceModelId\(registry, selectionStorage\)/,
"a fresh provider mount must restore before runtime providers receive activeModel",
);
});
@@ -0,0 +1,977 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { after, before, test } from "node:test";
import React, { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { createServer } from "vite";
let server;
let activeStreamForceFinishAuthority;
let activeStreamForceFinishAuthorityMatches;
let activeStreamRecoveredBrowserAuthority;
let activeStreamRecoveryPresentation;
let activeStreamRecoveryPresentationAuthority;
let activeStreamRecoveryOwnsPresentationDecision;
let exactActiveStreamRecoveryLineage;
let formatActiveStreamRecoveryElapsed;
let suppressGenericErrorDuringActiveStreamRecovery;
let isXgridsActiveStreamRecovery;
let K1AcquisitionPipeline;
let K1SpatialControlsView;
let runSpatialActiveStreamForceFinish;
let shouldRenderK1GenericRuntimeError;
let shouldRenderK1OperationalPanels;
let xgridsK1Actions;
let xgridsK1Api;
const hookSourceUrl = new URL(
"../../../plugins/xgrids-k1/frontend/src/useXgridsK1Runtime.ts",
import.meta.url,
);
const acquisitionSourceUrl = new URL(
"../../../plugins/xgrids-k1/frontend/src/components/K1AcquisitionPipeline.tsx",
import.meta.url,
);
const recoverySurfaceSourceUrl = new URL(
"../../../plugins/xgrids-k1/frontend/src/components/ActiveStreamRecoverySurface.tsx",
import.meta.url,
);
const spatialControlsSourceUrl = new URL(
"../../../plugins/xgrids-k1/frontend/src/components/K1SpatialControls.tsx",
import.meta.url,
);
const connectionSourceUrl = new URL(
"../../../plugins/xgrids-k1/frontend/src/XgridsK1Connection.tsx",
import.meta.url,
);
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
activeStreamForceFinishAuthority,
activeStreamForceFinishAuthorityMatches,
activeStreamRecoveredBrowserAuthority,
activeStreamRecoveryPresentation,
activeStreamRecoveryPresentationAuthority,
activeStreamRecoveryOwnsPresentationDecision,
exactActiveStreamRecoveryLineage,
formatActiveStreamRecoveryElapsed,
suppressGenericErrorDuringActiveStreamRecovery,
} = await server.ssrLoadModule("@xgrids-k1/frontend/activeStreamRecovery.ts"));
({ isXgridsActiveStreamRecovery, xgridsK1Api } = await server.ssrLoadModule(
"@xgrids-k1/frontend/api.ts",
));
({ xgridsK1Actions } = await server.ssrLoadModule(
"@xgrids-k1/frontend/manifest.ts",
));
({ K1AcquisitionPipeline } = await server.ssrLoadModule(
"@xgrids-k1/frontend/components/K1AcquisitionPipeline.tsx",
));
({
K1SpatialControlsView,
runSpatialActiveStreamForceFinish,
} = await server.ssrLoadModule(
"@xgrids-k1/frontend/components/K1SpatialControls.tsx",
));
({
shouldRenderK1GenericRuntimeError,
shouldRenderK1OperationalPanels,
} = await server.ssrLoadModule(
"@xgrids-k1/frontend/XgridsK1Connection.tsx",
));
});
after(async () => {
await server?.close();
});
function recoveryContract(overrides = {}) {
return {
schema_version: "missioncore.xgrids-k1-active-stream-recovery/v1",
state: "reconnecting",
generation: 7,
acquisition_id: "acquisition-recovery-001",
attempt: 3,
started_at_utc: "2026-08-11T19:31:00Z",
elapsed_ms: 12_400,
reason_code: "read-only-rebind-in-progress",
force_finish_allowed: true,
automatic_read_only_rebind: true,
automatic_command_retry: false,
start_performed: false,
stop_performed: false,
ble_operation_performed: false,
network_mutation_performed: false,
runtime_producer_generation: 11,
camera_recovery: "owned",
camera_media_state: "pending-first-media",
camera_media_ready: false,
camera_epoch: {
generation: 7,
init_committed: true,
init_committed_age_ms: 250,
first_media_committed: false,
first_media_committed_age_ms: null,
committed_media_segment_count: 0,
last_media_segment_age_ms: null,
},
...overrides,
};
}
function recoveryState(recoveryOverrides = {}, stateOverrides = {}) {
return {
snapshot_runtime_id: "snapshot-runtime-recovery-001",
snapshot_revision: 43,
producer_generation: 11,
phase: "reconnecting",
source_mode: "live",
acquisition: {
acquisition_id: "acquisition-recovery-001",
device_id: "device-k1-001",
device_session_id: "device-session-001",
compatibility_profile_id: "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2",
control_mode: "plugin-commanded",
requested_streams: ["spatial.point-cloud.live"],
target_host: "127.0.0.1",
duration_seconds: 0,
evidence_policy: "required",
state: "acquiring",
state_revision: 9,
cleanup_pending: false,
},
connection_recovery: recoveryContract(recoveryOverrides),
...stateOverrides,
};
}
function coldRestartPrePclState() {
const state = recoveryState({
generation: 1,
acquisition_id: "acquisition-before-backend-restart-001",
attempt: 0,
started_at_utc: "2026-08-14T00:31:00Z",
elapsed_ms: 450,
reason_code: "restart-receiver-awaiting-first-pcl",
runtime_producer_generation: 1,
camera_recovery: "inactive",
camera_media_state: "inactive",
camera_media_ready: false,
camera_epoch: null,
}, {
snapshot_runtime_id: "snapshot-runtime-after-cold-restart-001",
snapshot_revision: 2,
producer_generation: 1,
acquisition: {
...recoveryState().acquisition,
acquisition_id: "acquisition-before-backend-restart-001",
state: "awaiting_external_start",
state_revision: 4,
},
camera_preview: {
activation_admission: {
state: "waiting-for-first-authoritative-pcl",
basis: "post-rerun-publish-pcl-frame",
runtime_producer_generation: 1,
device_command_sent: false,
},
},
});
return state;
}
function coldRestartRecoveredState() {
const state = coldRestartPrePclState();
return {
...state,
snapshot_revision: state.snapshot_revision + 1,
phase: "live",
acquisition: {
...state.acquisition,
state: "acquiring",
state_revision: state.acquisition.state_revision + 1,
},
connection_recovery: {
...state.connection_recovery,
state: "recovered",
elapsed_ms: null,
reason_code: null,
force_finish_allowed: false,
camera_recovery: "owned",
camera_media_state: "pending-epoch",
camera_media_ready: false,
camera_epoch: null,
},
camera_preview: {
activation_admission: {
state: "activating",
basis: "post-rerun-publish-pcl-frame",
runtime_producer_generation: 1,
device_command_sent: false,
},
},
};
}
function controller(state, overrides = {}) {
return {
state,
pendingAction: null,
error: null,
physicalStopIntentSpent: false,
physicalStopInFlight: false,
closeApplicationControlSession: async () => false,
prepareCanonicalAcquisition: async () => false,
startPreparedAcquisition: async () => false,
startReplay: async () => false,
stop: async () => false,
stopLocalReceiver: async () => false,
forceFinishActiveStreamLocally: async () => false,
abort: async () => false,
...overrides,
};
}
function renderPipeline(state, overrides = {}) {
return renderToStaticMarkup(createElement(K1AcquisitionPipeline, {
controller: controller(state, overrides),
desiredConnectionMode: "bridge",
openSpatialScene() {},
activateAutomaticSpatialSource() {},
}));
}
function renderSpatialControls(state, overrides = {}) {
return renderToStaticMarkup(createElement(K1SpatialControlsView, {
controller: controller(state, overrides),
}));
}
function buttonsWithText(markup, text) {
return (markup.match(/<button\b[\s\S]*?<\/button>/g) ?? [])
.filter((button) => button.includes(text));
}
function sourceSlice(source, startMarker, endMarker) {
const start = source.indexOf(startMarker);
const end = source.indexOf(endMarker, start + startMarker.length);
assert.notEqual(start, -1, `missing source marker: ${startMarker}`);
assert.notEqual(end, -1, `missing source marker: ${endMarker}`);
return source.slice(start, end);
}
test("active recovery contract is strict about all no-write invariants", () => {
assert.equal(isXgridsActiveStreamRecovery(recoveryContract()), true);
for (const field of [
"automatic_command_retry",
"start_performed",
"stop_performed",
"ble_operation_performed",
"network_mutation_performed",
]) {
assert.equal(
isXgridsActiveStreamRecovery(recoveryContract({ [field]: true })),
false,
field,
);
}
assert.equal(
isXgridsActiveStreamRecovery(recoveryContract({ state: "retrying-command" })),
false,
);
assert.equal(
isXgridsActiveStreamRecovery(recoveryContract({ elapsed_ms: -1 })),
false,
);
const missingMediaState = recoveryContract();
delete missingMediaState.camera_media_state;
assert.equal(isXgridsActiveStreamRecovery(missingMediaState), false);
assert.equal(
isXgridsActiveStreamRecovery(recoveryContract({ camera_media_ready: true })),
false,
);
assert.equal(
isXgridsActiveStreamRecovery(recoveryContract({
camera_media_state: "ready",
camera_media_ready: true,
camera_epoch: {
...recoveryContract().camera_epoch,
generation: 0,
first_media_committed: true,
first_media_committed_age_ms: 1,
committed_media_segment_count: 1,
last_media_segment_age_ms: 1,
},
})),
false,
);
});
test("cold restart before first PCL owns exact reconnect UI without camera or physical actions", () => {
const state = coldRestartPrePclState();
assert.equal(isXgridsActiveStreamRecovery(state.connection_recovery), true);
const lineage = exactActiveStreamRecoveryLineage(state);
assert.deepEqual(lineage && {
runtime: lineage.snapshotRuntimeId,
acquisition: lineage.acquisitionId,
revision: lineage.acquisitionStateRevision,
recovery: lineage.recoveryGeneration,
producer: lineage.runtimeProducerGeneration,
}, {
runtime: "snapshot-runtime-after-cold-restart-001",
acquisition: "acquisition-before-backend-restart-001",
revision: 4,
recovery: 1,
producer: 1,
});
assert.notEqual(activeStreamRecoveryPresentationAuthority(state), null);
assert.notEqual(activeStreamForceFinishAuthority(state), null);
assert.equal(activeStreamRecoveredBrowserAuthority(state), null);
assert.equal(state.connection_recovery.camera_recovery, "inactive");
assert.equal(state.connection_recovery.camera_media_state, "inactive");
assert.equal(state.connection_recovery.camera_media_ready, false);
assert.equal(state.connection_recovery.camera_epoch, null);
assert.deepEqual(state.camera_preview.activation_admission, {
state: "waiting-for-first-authoritative-pcl",
basis: "post-rerun-publish-pcl-frame",
runtime_producer_generation: 1,
device_command_sent: false,
});
const pipeline = renderPipeline(state);
assert.match(pipeline, /Восстанавливаем соединение/);
assert.match(pipeline, /START, STOP, Bluetooth и настройки устройства не отправляются/);
assert.equal(buttonsWithText(pipeline, "Прервать соединение").length, 1);
assert.equal(buttonsWithText(pipeline, "Запустить приём").length, 0);
assert.equal(buttonsWithText(pipeline, "Остановить устройство и запись").length, 0);
assert.equal(buttonsWithText(pipeline, "Остановить сканирование").length, 0);
assert.doesNotMatch(
pipeline,
/СВЯЗЬ ВОССТАНОВЛЕНА|Связь восстановлена · приём продолжается|Продолжаем тот же приём/,
);
const spatial = renderSpatialControls(state);
assert.match(spatial, /Восстанавливаем соединение/);
assert.equal(buttonsWithText(spatial, "Прервать соединение").length, 1);
assert.doesNotMatch(
spatial,
/Остановить устройство|Остановить K1|Завершить локальный приём/,
);
});
test("cold restart first PCL preserves lineage and renders recovered continuation copy", () => {
const beforePcl = coldRestartPrePclState();
const state = coldRestartRecoveredState();
assert.equal(isXgridsActiveStreamRecovery(state.connection_recovery), true);
assert.equal(
state.connection_recovery.acquisition_id,
beforePcl.connection_recovery.acquisition_id,
);
assert.equal(
state.connection_recovery.generation,
beforePcl.connection_recovery.generation,
);
assert.equal(
state.connection_recovery.runtime_producer_generation,
beforePcl.connection_recovery.runtime_producer_generation,
);
const lineage = exactActiveStreamRecoveryLineage(state);
const browserAuthority = activeStreamRecoveredBrowserAuthority(state);
assert.deepEqual(lineage && {
runtime: lineage.snapshotRuntimeId,
acquisition: lineage.acquisitionId,
revision: lineage.acquisitionStateRevision,
recovery: lineage.recoveryGeneration,
producer: lineage.runtimeProducerGeneration,
}, {
runtime: "snapshot-runtime-after-cold-restart-001",
acquisition: "acquisition-before-backend-restart-001",
revision: 5,
recovery: 1,
producer: 1,
});
assert.deepEqual(browserAuthority, lineage);
assert.equal(activeStreamRecoveryPresentationAuthority(state), null);
assert.equal(activeStreamForceFinishAuthority(state), null);
assert.equal(state.connection_recovery.camera_recovery, "owned");
assert.equal(state.camera_preview.activation_admission.device_command_sent, false);
const pipeline = renderPipeline(state);
assert.doesNotMatch(pipeline, /Восстанавливаем соединение|Прервать соединение/);
assert.match(pipeline, /СВЯЗЬ ВОССТАНОВЛЕНА · АКТИВНЫЙ ПРИЁМ/);
assert.match(pipeline, /Связь восстановлена · приём продолжается/);
assert.match(pipeline, /Продолжаем тот же приём без нового START/);
assert.doesNotMatch(pipeline, /Назовите проект и запустите приём|Запустить приём/);
});
test("force-finish authority requires exact runtime, acquisition, revision and generations", () => {
const state = recoveryState();
const authority = activeStreamForceFinishAuthority(state);
assert.deepEqual(authority && {
snapshotRuntimeId: authority.snapshotRuntimeId,
acquisitionId: authority.acquisitionId,
acquisitionStateRevision: authority.acquisitionStateRevision,
recoveryGeneration: authority.recoveryGeneration,
runtimeProducerGeneration: authority.runtimeProducerGeneration,
}, {
snapshotRuntimeId: "snapshot-runtime-recovery-001",
acquisitionId: "acquisition-recovery-001",
acquisitionStateRevision: 9,
recoveryGeneration: 7,
runtimeProducerGeneration: 11,
});
assert.equal(activeStreamForceFinishAuthorityMatches(authority, state), true);
const staleCases = [
(() => {
const value = structuredClone(state);
value.snapshot_runtime_id = "snapshot-runtime-recovery-002";
return value;
})(),
(() => {
const value = structuredClone(state);
value.acquisition.acquisition_id = "acquisition-recovery-002";
return value;
})(),
(() => {
const value = structuredClone(state);
value.acquisition.state_revision += 1;
return value;
})(),
(() => {
const value = structuredClone(state);
value.connection_recovery.generation += 1;
return value;
})(),
(() => {
const value = structuredClone(state);
value.producer_generation += 1;
return value;
})(),
];
for (const stale of staleCases) {
assert.equal(activeStreamForceFinishAuthorityMatches(authority, stale), false);
}
assert.equal(
activeStreamForceFinishAuthority(recoveryState({ state: "recovered", force_finish_allowed: false })),
null,
);
assert.equal(
activeStreamForceFinishAuthority(recoveryState({ force_finish_allowed: false })),
null,
);
});
test("reconnecting presentation is exact and owns stale supervisor projection", () => {
const state = recoveryState({ force_finish_allowed: false });
const authority = activeStreamRecoveryPresentationAuthority(state);
assert.deepEqual(authority && {
runtime: authority.snapshotRuntimeId,
acquisition: authority.acquisitionId,
producer: authority.runtimeProducerGeneration,
recovery: authority.recoveryGeneration,
}, {
runtime: "snapshot-runtime-recovery-001",
acquisition: "acquisition-recovery-001",
producer: 11,
recovery: 7,
});
assert.equal(activeStreamRecoveryOwnsPresentationDecision(state), true);
const wrongProducer = structuredClone(state);
wrongProducer.producer_generation += 1;
assert.equal(activeStreamRecoveryPresentationAuthority(wrongProducer), null);
assert.equal(
activeStreamRecoveryOwnsPresentationDecision(wrongProducer),
true,
"a valid reconnect contract must block stale ordinary data projection",
);
for (const recoveryStateName of [
"blocked",
"standby",
"fault",
"force-finishing",
"force-finished",
]) {
const terminal = recoveryState({ state: recoveryStateName });
assert.equal(activeStreamRecoveryPresentationAuthority(terminal), null);
assert.equal(activeStreamRecoveryOwnsPresentationDecision(terminal), true);
}
assert.equal(
activeStreamRecoveryOwnsPresentationDecision(recoveryState({ state: "recovered" })),
false,
);
});
test("recovered browser carryover keeps exact lineage without restoring recovery controls", () => {
const state = recoveryState({
state: "recovered",
force_finish_allowed: false,
elapsed_ms: null,
reason_code: null,
}, {
phase: "live",
});
const authority = activeStreamRecoveredBrowserAuthority(state);
assert.deepEqual(authority && {
runtime: authority.snapshotRuntimeId,
acquisition: authority.acquisitionId,
revision: authority.acquisitionStateRevision,
producer: authority.runtimeProducerGeneration,
recovery: authority.recoveryGeneration,
}, {
runtime: "snapshot-runtime-recovery-001",
acquisition: "acquisition-recovery-001",
revision: 9,
producer: 11,
recovery: 7,
});
assert.equal(activeStreamRecoveryPresentation(state), null);
assert.equal(activeStreamForceFinishAuthority(state), null);
const staleProducer = structuredClone(state);
staleProducer.producer_generation += 1;
assert.equal(activeStreamRecoveredBrowserAuthority(staleProducer), null);
assert.equal(
activeStreamRecoveredBrowserAuthority(recoveryState({
state: "recovered",
camera_recovery: "blocked",
force_finish_allowed: false,
}, { phase: "live" })),
null,
);
});
test("only an exact reconnecting lineage suppresses the generic red error", () => {
const state = recoveryState();
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(state, null), true);
assert.equal(
shouldRenderK1GenericRuntimeError("Ошибка локального приёмника", false, state, null),
false,
);
assert.equal(
suppressGenericErrorDuringActiveStreamRecovery(state, "force-finish"),
false,
);
assert.equal(
shouldRenderK1GenericRuntimeError(
"Локальное завершение не выполнено",
false,
state,
"force-finish",
),
true,
"a failed explicit local finish must keep the generic error banner visible",
);
const wrongProducer = structuredClone(state);
wrongProducer.producer_generation += 1;
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(wrongProducer), false);
const wrongAcquisition = structuredClone(state);
wrongAcquisition.connection_recovery.acquisition_id = "acquisition-stale";
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(wrongAcquisition), false);
const missingRuntime = structuredClone(state);
delete missingRuntime.snapshot_runtime_id;
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(missingRuntime), false);
const blocked = recoveryState({ state: "blocked" });
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(blocked), false);
const nonOwned = recoveryState({ automatic_read_only_rebind: false });
assert.equal(suppressGenericErrorDuringActiveStreamRecovery(nonOwned), false);
const inactiveCases = [
recoveryState({}, { phase: "error" }),
recoveryState({}, { source_mode: "idle" }),
recoveryState({}, {
acquisition: {
...state.acquisition,
state: "failed",
},
}),
];
for (const inactive of inactiveCases) {
assert.equal(
suppressGenericErrorDuringActiveStreamRecovery(inactive, null),
false,
"stale recovery projection must fail open to the error banner",
);
}
});
test("reconnecting presentation is neutral, timed and exposes explicit local finish", () => {
const state = recoveryState();
const presentation = activeStreamRecoveryPresentation(state);
assert.equal(presentation?.state, "reconnecting");
assert.equal(presentation?.tone, "neutral");
assert.equal(presentation?.progressLabel, "Попытка 3 · 12 с");
assert.equal(presentation?.forceFinishAvailable, true);
const markup = renderPipeline(state);
assert.match(markup, /Восстанавливаем соединение/);
assert.match(markup, /Попытка 3 · 12 с/);
assert.match(markup, /class="nodedc-activity-indicator/);
assert.equal(buttonsWithText(markup, "Прервать соединение").length, 1);
assert.match(markup, /START, STOP, Bluetooth и настройки устройства не отправляются/);
assert.doesNotMatch(markup, /Ошибка локального приёмника/);
assert.equal(shouldRenderK1OperationalPanels(state), true);
});
test("spatial scene owns the same recovery spinner and explicit local finish", () => {
const markup = renderSpatialControls(recoveryState());
assert.match(markup, /Восстанавливаем соединение/);
assert.match(markup, /Попытка 3 · 12 с/);
assert.match(markup, /class="nodedc-activity-indicator/);
assert.match(markup, /data-recovery-state="reconnecting"/);
assert.equal(buttonsWithText(markup, "Прервать соединение").length, 1);
assert.match(markup, /локальный front\/back-приём/);
assert.doesNotMatch(
markup,
/Остановить устройство|Остановить K1|Завершить локальный приём/,
"recovery must not expose canonical STOP or the generic receiver stop",
);
});
test("spatial blocked and fault recovery copy is terminal and truthful", () => {
const blocked = renderSpatialControls(recoveryState({
state: "blocked",
reason_code: "exact-binding-changed",
}));
assert.match(blocked, /Связь не восстановлена/);
assert.match(blocked, /Восстановление остановлено/);
assert.doesNotMatch(blocked, /class="nodedc-activity-indicator/);
assert.equal(buttonsWithText(blocked, "Прервать соединение").length, 1);
const fault = renderSpatialControls(recoveryState({
state: "fault",
force_finish_allowed: false,
reason_code: "active-stream-recovery-system-error",
}));
assert.match(fault, /K1 сообщил об ошибке/);
assert.match(fault, /Автоматических команд и повторов нет/);
assert.equal(buttonsWithText(fault, "Прервать соединение").length, 0);
});
test("spatial recovery interaction routes only to exact local force-finish", async () => {
let forceFinishCalls = 0;
const current = recoveryState();
const invoked = await runSpatialActiveStreamForceFinish({
state: current,
forceFinishActiveStreamLocally: async () => {
forceFinishCalls += 1;
return true;
},
});
assert.equal(invoked, true);
assert.equal(forceFinishCalls, 1);
const stale = structuredClone(current);
stale.connection_recovery.runtime_producer_generation += 1;
const rejected = await runSpatialActiveStreamForceFinish({
state: stale,
forceFinishActiveStreamLocally: async () => {
forceFinishCalls += 1;
return true;
},
});
assert.equal(rejected, false);
assert.equal(forceFinishCalls, 1, "stale lineage must not dispatch any action");
});
test("spatial force-finish pending owns the surface without a second action", () => {
const markup = renderSpatialControls(
recoveryState({
state: "force-finishing",
acquisition_id: null,
force_finish_allowed: false,
automatic_read_only_rebind: false,
camera_recovery: "inactive",
}),
{ pendingAction: "force-finish" },
);
assert.match(markup, /Завершаем локальный приём/);
assert.match(markup, /data-recovery-state="force-finishing"/);
assert.match(markup, /Команда STOP устройству не отправляется/);
assert.equal(buttonsWithText(markup, "Прервать соединение").length, 0);
});
test("blocked, camera-blocked, standby and fault copy stay truthful", () => {
const blocked = recoveryState({ state: "blocked", reason_code: "exact-binding-changed" });
const blockedMarkup = renderPipeline(blocked);
assert.match(blockedMarkup, /Связь не восстановлена/);
assert.match(blockedMarkup, /Восстановление остановлено/);
assert.doesNotMatch(blockedMarkup, /class="nodedc-activity-indicator/);
assert.equal(buttonsWithText(blockedMarkup, "Прервать соединение").length, 1);
const cameraBlocked = recoveryState({
state: "blocked",
camera_recovery: "blocked",
reason_code: "camera-recovery-failed",
});
assert.match(renderPipeline(cameraBlocked), /Видеопоток не восстановлен/);
const standby = recoveryState({
state: "standby",
force_finish_allowed: false,
reason_code: "device-reported-standby",
});
const standbyMarkup = renderPipeline(standby);
assert.match(standbyMarkup, /Устройство перешло в ожидание/);
assert.match(standbyMarkup, /без команды STOP/);
assert.equal(buttonsWithText(standbyMarkup, "Прервать соединение").length, 0);
assert.equal(shouldRenderK1OperationalPanels(standby), true);
const fault = recoveryState({
state: "fault",
force_finish_allowed: false,
reason_code: "active-stream-recovery-system-error",
});
const faultMarkup = renderPipeline(fault);
assert.match(faultMarkup, /K1 сообщил об ошибке/);
assert.match(faultMarkup, /Автоматических команд и повторов нет/);
assert.equal(buttonsWithText(faultMarkup, "Прервать соединение").length, 0);
assert.equal(shouldRenderK1OperationalPanels(fault), true);
});
test("recovered active lineage renders the continued session and one exact STOP", () => {
const state = recoveryState({
state: "recovered",
force_finish_allowed: false,
elapsed_ms: null,
reason_code: null,
}, {
phase: "live",
compatibility: {
vendor_writes_enabled: true,
permitted_mode: "active-control",
},
application_control_session: {
session_generation: 5,
state_revision: 8,
state: "scanning",
can_stop: true,
control_socket_open: true,
},
connection_policy: {
schema_version: "missioncore.xgrids-k1-connection-policy/v1",
facts: { retained_context_is_presence: false },
allowed_actions: ["stop-acquisition"],
actions: {
"stop-acquisition": {
allowed: true,
reason_codes: [],
target_source: "connection-supervisor",
required_transport_ref: null,
required_connection_mode: null,
requires_live_gatt_validation: false,
automatic_retry: false,
},
},
},
});
assert.equal(activeStreamRecoveryPresentation(state), null);
const markup = renderPipeline(state);
assert.doesNotMatch(markup, /Восстанавливаем соединение|Прервать соединение/);
assert.match(markup, /СВЯЗЬ ВОССТАНОВЛЕНА · АКТИВНЫЙ ПРИЁМ/);
assert.match(markup, /Связь восстановлена · приём продолжается/);
assert.match(markup, /Продолжаем тот же приём без нового START/);
assert.doesNotMatch(markup, /Назовите проект и запустите приём|Запустить приём/);
const stopButtons = buttonsWithText(markup, "Остановить устройство и запись");
assert.equal(stopButtons.length, 1);
assert.doesNotMatch(stopButtons[0], /\bdisabled(?:=|\s|>)/);
});
test("stale recovered marker on an idle released runtime fails closed to idle UI", () => {
const state = recoveryState({
state: "recovered",
force_finish_allowed: false,
elapsed_ms: null,
reason_code: null,
}, {
phase: "idle",
source_mode: "idle",
acquisition: {
...recoveryState().acquisition,
state: "completed",
cleanup_pending: false,
},
application_control_session: {
session_generation: 5,
state_revision: 9,
state: "completed",
can_stop: false,
control_socket_open: false,
},
});
assert.equal(activeStreamRecoveryPresentation(state), null);
const markup = renderPipeline(state);
assert.doesNotMatch(
markup,
/СВЯЗЬ ВОССТАНОВЛЕНА|Связь восстановлена · приём продолжается|Продолжаем тот же приём/,
);
assert.match(markup, /Назовите проект и запустите приём/);
assert.equal(buttonsWithText(markup, "Остановить устройство и запись").length, 0);
assert.equal(buttonsWithText(markup, "Остановить сканирование").length, 0);
});
test("force-finishing shows one local-only pending owner and no second action", () => {
const state = recoveryState({
state: "force-finishing",
acquisition_id: null,
force_finish_allowed: false,
automatic_read_only_rebind: false,
runtime_producer_generation: 11,
camera_recovery: "inactive",
});
const markup = renderPipeline(state, { pendingAction: "force-finish" });
assert.match(markup, /Завершаем локальный приём/);
assert.match(markup, /Команда STOP устройству не отправляется/);
assert.match(markup, /class="nodedc-activity-indicator/);
assert.equal(buttonsWithText(markup, "Прервать соединение").length, 0);
});
test("elapsed presentation is deterministic", () => {
assert.equal(formatActiveStreamRecoveryElapsed(null), null);
assert.equal(formatActiveStreamRecoveryElapsed(-1), null);
assert.equal(formatActiveStreamRecoveryElapsed(999), "0 с");
assert.equal(formatActiveStreamRecoveryElapsed(59_999), "59 с");
assert.equal(formatActiveStreamRecoveryElapsed(60_000), "1 мин");
assert.equal(formatActiveStreamRecoveryElapsed(125_900), "2 мин 5 с");
});
test("force-finish manifest/API sends the exact fenced local-only request", async () => {
assert.equal(
xgridsK1Actions.acquisitionForceFinishLocal,
"acquisition.force-finish-local",
);
const request = {
expected_snapshot_runtime_id: "snapshot-runtime-recovery-001",
acquisition_id: "acquisition-recovery-001",
expected_state_revision: 9,
expected_recovery_generation: 7,
operator_confirmed: true,
operation_id: "op-00000000-0000-4000-8000-000000000321",
idempotency_key:
"acquisition.force-finish-local:op-00000000-0000-4000-8000-000000000321",
deadline_seconds: 30,
};
let capturedUrl = null;
let capturedInit = null;
const originalFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
capturedUrl = String(input);
capturedInit = init;
return new Response(JSON.stringify({ state: recoveryState() }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
try {
await xgridsK1Api.forceFinishAcquisitionLocally(request);
} finally {
globalThis.fetch = originalFetch;
}
assert.match(
capturedUrl,
/\/actions\/acquisition\.force-finish-local$/,
);
assert.equal(capturedInit.method, "POST");
assert.deepEqual(JSON.parse(capturedInit.body), { input: request });
});
test("state API rejects a drifted active recovery contract", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => new Response(JSON.stringify({
state: recoveryState({ stop_performed: true }),
}), {
status: 200,
headers: { "Content-Type": "application/json" },
});
try {
await assert.rejects(
() => xgridsK1Api.getState(),
/некорректное состояние/,
);
} finally {
globalThis.fetch = originalFetch;
}
});
test("frontend boundary keeps recovery automatic work read-only and local finish explicit", () => {
const hookSource = readFileSync(hookSourceUrl, "utf8");
const forceFinish = sourceSlice(
hookSource,
"const forceFinishActiveStreamLocally",
"const abort",
);
assert.match(forceFinish, /run\("force-finish"/);
assert.match(forceFinish, /activeStreamForceFinishAuthority\(latestState\.current\)/);
assert.match(forceFinish, /expected_snapshot_runtime_id:\s*authority\.snapshotRuntimeId/);
assert.match(forceFinish, /acquisition_id:\s*authority\.acquisitionId/);
assert.match(forceFinish, /expected_state_revision:\s*authority\.acquisitionStateRevision/);
assert.match(forceFinish, /expected_recovery_generation:\s*authority\.recoveryGeneration/);
assert.match(forceFinish, /operator_confirmed:\s*true/);
assert.match(
forceFinish,
/newMutationContext\("acquisition\.force-finish-local"\)/,
);
assert.equal(
(forceFinish.match(/forceFinishAcquisitionLocally\(/g) ?? []).length,
1,
);
assert.doesNotMatch(
forceFinish,
/startAcquisition|stopAcquisition|scanBle|selectCameraPreview|connect\(/,
);
const acquisitionSource = readFileSync(acquisitionSourceUrl, "utf8");
assert.equal(
(acquisitionSource.match(/forceFinishActiveStreamLocally\(\)/g) ?? []).length,
1,
"the explicit recovery button is the only frontend caller",
);
const recoverySurface = readFileSync(recoverySurfaceSourceUrl, "utf8");
assert.match(recoverySurface, /<ActivityIndicator/);
assert.match(recoverySurface, /<Button[\s\S]*?variant="secondary"/);
assert.doesNotMatch(recoverySurface, /<button\b|style=\{/);
const spatialSource = readFileSync(spatialControlsSourceUrl, "utf8");
assert.match(spatialSource, /variant="compact"/);
assert.match(
spatialSource,
/runSpatialActiveStreamForceFinish\(\{[\s\S]*?forceFinishActiveStreamLocally/,
);
const spatialForceFinish = sourceSlice(
spatialSource,
"export function runSpatialActiveStreamForceFinish",
"export function K1SpatialControlsView",
);
assert.match(spatialForceFinish, /activeStreamForceFinishAuthority\(controller\.state\)/);
assert.equal(
(spatialForceFinish.match(/controller\.forceFinishActiveStreamLocally\(\)/g) ?? []).length,
1,
);
assert.doesNotMatch(spatialForceFinish, /\bstop\(|stopLocalReceiver|start|connect|scanBle/);
const connectionSource = readFileSync(connectionSourceUrl, "utf8");
assert.match(
connectionSource,
/shouldRenderK1GenericRuntimeError\([\s\S]*?errorCorrelation\?\.action/,
);
assert.match(
connectionSource,
/\{showGenericRuntimeError && error \? \([\s\S]*?<K1OperatorError/,
);
});
File diff suppressed because it is too large Load Diff
@@ -4,9 +4,14 @@ import { after, before, test } from "node:test";
import { createServer } from "vite";
let server;
let advanceLiveReceiverOpenWatchdog;
let advanceLiveReceiverWatchdog;
let initialLiveReceiverOpenWatchdogState;
let initialLiveReceiverWatchdogState;
let initialLiveReceiverRecoveryState;
let liveReceiverRecoveryAuthorityIsCurrent;
let liveReceiverRecoveryRetryDelay;
let liveRerunRecoveryAuthorityIdentity;
let requestLiveReceiverRecovery;
before(async () => {
@@ -16,9 +21,14 @@ before(async () => {
server: { middlewareMode: true },
});
({
advanceLiveReceiverOpenWatchdog,
advanceLiveReceiverWatchdog,
initialLiveReceiverOpenWatchdogState,
initialLiveReceiverRecoveryState,
initialLiveReceiverWatchdogState,
liveReceiverRecoveryAuthorityIsCurrent,
liveReceiverRecoveryRetryDelay,
liveRerunRecoveryAuthorityIdentity,
requestLiveReceiverRecovery,
} = await server.ssrLoadModule("/src/core/observation/liveReceiverWatchdog.ts"));
});
@@ -92,3 +102,217 @@ test("startup failures request only three bounded viewer restarts", () => {
assert.equal(exhausted.attempt, 3);
assert.equal(exhausted.state.awaitingRecovery, false);
});
function livePointCloudDescriptor(overrides = {}) {
return {
id: "xgrids-k1:lixelkity-k1:sensor.lidar.primary",
sourceId: "sensor.lidar.primary",
semanticChannelId: "spatial.point-cloud.live",
label: "K1 point cloud",
description: "live",
modality: "point-cloud",
role: "primary",
availability: "streaming",
transport: "rerun-grpc",
endpointLabel: "Rerun gRPC",
previewUrl: "rerun+http://127.0.0.1:9877/proxy",
delivery: null,
activation: null,
presentationLease: null,
provider: {
pluginId: "xgrids-k1",
pluginVersion: "0.1.0",
modelId: "lixelkity-k1",
compatibilityProfileId: "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2",
},
binding: {
deviceId: "device-k1-001",
deviceSessionId: "device-session-001",
acquisitionId: "acquisition-001",
},
capabilities: {
overlay: false,
fullscreen: true,
resizable: false,
defaultVisible: true,
timelineMode: "live-only",
seekable: false,
sessionRecording: false,
clockId: "acquisition-001",
spatialRegistration: "native",
},
...overrides,
};
}
const liveSpatialSource = {
id: "acquisition-001",
url: "rerun+http://127.0.0.1:9877/proxy",
label: "Live",
kind: "rerun-grpc",
};
test("exact live Rerun authority gets durable retries with capped delay", () => {
const authority = liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor(),
liveSpatialSource,
);
assert.ok(authority);
assert.equal(liveReceiverRecoveryAuthorityIsCurrent(authority, authority), true);
let state = initialLiveReceiverRecoveryState();
const delays = [];
for (let attempt = 1; attempt <= 8; attempt += 1) {
const recovery = requestLiveReceiverRecovery(state, {
activeAuthorityIdentity: authority,
expectedAuthorityIdentity: authority,
});
assert.equal(recovery.signal, "retry");
assert.equal(recovery.attempt, attempt);
delays.push(recovery.delayMs);
state = recovery.state;
}
assert.deepEqual(delays, [400, 1_000, 2_000, 5_000, 5_000, 5_000, 5_000, 5_000]);
assert.equal(state.attempts, 8);
assert.equal(liveReceiverRecoveryRetryDelay(100), 5_000);
});
test("Rerun durable retry fails closed when exact authority is replaced", () => {
const authority = liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor(),
liveSpatialSource,
);
assert.ok(authority);
const replacement = liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor({
binding: {
deviceId: "device-k1-001",
deviceSessionId: "device-session-002",
acquisitionId: "acquisition-002",
},
capabilities: {
...livePointCloudDescriptor().capabilities,
clockId: "acquisition-002",
},
}),
{ ...liveSpatialSource, id: "acquisition-002" },
);
assert.ok(replacement);
const stale = requestLiveReceiverRecovery(initialLiveReceiverRecoveryState(), {
activeAuthorityIdentity: replacement,
expectedAuthorityIdentity: authority,
});
assert.equal(stale.signal, "stale");
assert.equal(stale.delayMs, null);
assert.deepEqual(stale.state, initialLiveReceiverRecoveryState());
});
test("connecting Rerun authority requires an exact recovery generation lease", () => {
const recoveryLease = {
kind: "active-stream-recovery",
runtimeId: "runtime-recovery-001",
acquisitionId: "acquisition-001",
acquisitionStateRevision: 4,
producerGeneration: 17,
recoveryGeneration: 6,
};
const recoveredAuthority = liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor({
availability: "connecting",
presentationLease: recoveryLease,
}),
liveSpatialSource,
);
assert.ok(recoveredAuthority);
assert.equal(
liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor({ availability: "connecting" }),
liveSpatialSource,
),
null,
);
assert.equal(
liveRerunRecoveryAuthorityIdentity(
livePointCloudDescriptor({
availability: "connecting",
presentationLease: { ...recoveryLease, producerGeneration: 0 },
}),
liveSpatialSource,
),
null,
);
});
test("opening receiver gets bounded rolling patience while backend publication advances", () => {
let openState = initialLiveReceiverOpenWatchdogState(0, 0);
let recoveryState = initialLiveReceiverRecoveryState();
const samples = [
[134, 3_999, "wait-for-store"],
[266, 4_000, "refresh-receiver"],
];
for (const [backendActivitySequence, nowMs, expectedSignal] of samples) {
const observed = advanceLiveReceiverOpenWatchdog(
openState,
recoveryState,
backendActivitySequence,
nowMs,
);
assert.equal(observed.signal, expectedSignal);
assert.equal(observed.state.lastBackendActivitySequence, backendActivitySequence);
assert.deepEqual(observed.recoveryState, {
attempts: 0,
awaitingRecovery: false,
});
openState = observed.state;
recoveryState = observed.recoveryState;
}
});
test("unchanged opening sequence delegates to bounded receiver restart", () => {
const openState = initialLiveReceiverOpenWatchdogState(486);
const recoveryState = initialLiveReceiverRecoveryState();
const unchanged = advanceLiveReceiverOpenWatchdog(
openState,
recoveryState,
486,
);
assert.equal(unchanged.signal, "restart-receiver");
const restart = requestLiveReceiverRecovery(unchanged.recoveryState);
assert.equal(restart.signal, "retry");
assert.equal(restart.attempt, 1);
});
test("fresh backend progress preserves earlier restart debt until viewer admission", () => {
const openState = initialLiveReceiverOpenWatchdogState(486, 0);
const consumedRestart = requestLiveReceiverRecovery(initialLiveReceiverRecoveryState());
const observed = advanceLiveReceiverOpenWatchdog(
openState,
consumedRestart.state,
600,
3_999,
);
assert.equal(observed.signal, "wait-for-store");
assert.deepEqual(observed.recoveryState, {
attempts: 1,
awaitingRecovery: true,
});
});
test("aged active receiver refresh does not spend or erase restart debt", () => {
const openState = initialLiveReceiverOpenWatchdogState(486, 0);
const consumedRestart = requestLiveReceiverRecovery(initialLiveReceiverRecoveryState());
const observed = advanceLiveReceiverOpenWatchdog(
openState,
consumedRestart.state,
900,
4_000,
);
assert.equal(observed.signal, "refresh-receiver");
assert.deepEqual(observed.recoveryState, consumedRestart.state);
assert.equal(observed.openForMs, 4_000);
});
@@ -0,0 +1,216 @@
import assert from "node:assert/strict";
import { after, before, test } from "node:test";
import { createServer } from "vite";
let createLiveViewerDiagnosticLifecycle;
let createAbortFencedBuildVerifier;
let createUiBuildStaleCoordinator;
let liveViewerDiagnosticBody;
let server;
let uiBuildIdFromModuleScripts;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
createAbortFencedBuildVerifier,
createLiveViewerDiagnosticLifecycle,
createUiBuildStaleCoordinator,
liveViewerDiagnosticBody,
uiBuildIdFromModuleScripts,
} = await server.ssrLoadModule("/src/core/observation/liveViewerDiagnostics.ts"));
});
after(async () => {
await server?.close();
});
function createFakeScheduler() {
let now = 0;
let nextHandle = 1;
const jobs = new Map();
const schedule = (callback, delay, interval) => {
const handle = nextHandle;
nextHandle += 1;
jobs.set(handle, { callback, due: now + delay, interval });
return handle;
};
const clear = (handle) => jobs.delete(handle);
return {
scheduler: {
setTimeout: (callback, delay) => schedule(callback, delay, null),
clearTimeout: clear,
setInterval: (callback, delay) => schedule(callback, delay, delay),
clearInterval: clear,
},
advance(milliseconds) {
const target = now + milliseconds;
while (true) {
const next = [...jobs.entries()]
.filter(([, job]) => job.due <= target)
.sort((left, right) => left[1].due - right[1].due)[0];
if (!next) break;
const [handle, job] = next;
now = job.due;
if (job.interval === null) jobs.delete(handle);
else job.due += job.interval;
job.callback();
}
now = target;
},
pending: () => jobs.size,
};
}
const lineage = (viewerInstanceId, lifecycleGeneration = 1) => ({
uiBuildId: "/assets/index-abcdefgh.js",
documentInstanceId: "00000000-0000-4000-8000-000000000001",
viewerInstanceId,
lifecycleGeneration,
});
test("mounted viewer admission terminally fences 60 seconds of stale timers", () => {
const clock = createFakeScheduler();
const callbacks = [];
const posts = [];
const lifecycle = createLiveViewerDiagnosticLifecycle({
lineage: lineage("00000000-0000-4000-8000-000000000011"),
scheduler: clock.scheduler,
diagnosticPoster: (event, eventLineage) => posts.push({ event, eventLineage }),
buildVerifier: () => undefined,
});
lifecycle.armAdmissionTimeout(() => callbacks.push("timeout"), 12_000);
lifecycle.armAdmissionInterval(() => callbacks.push("discovery"), 100);
lifecycle.markAdmitted();
lifecycle.post({ eventCode: "live_receiver_active_store_admitted" });
clock.advance(60_000);
assert.deepEqual(callbacks, []);
assert.equal(clock.pending(), 0);
assert.equal(posts.length, 1);
assert.equal(posts[0].eventLineage.lifecycleGeneration, 1);
});
test("two mounted viewers keep timer and diagnostic lineage isolated", () => {
const clock = createFakeScheduler();
const posts = [];
const first = createLiveViewerDiagnosticLifecycle({
lineage: lineage("00000000-0000-4000-8000-000000000021"),
scheduler: clock.scheduler,
diagnosticPoster: (event, eventLineage) => posts.push({ event, eventLineage }),
buildVerifier: () => undefined,
});
const second = createLiveViewerDiagnosticLifecycle({
lineage: lineage("00000000-0000-4000-8000-000000000022", 7),
scheduler: clock.scheduler,
diagnosticPoster: (event, eventLineage) => posts.push({ event, eventLineage }),
buildVerifier: () => undefined,
});
first.armAdmissionTimeout(() => {
first.post({ eventCode: "live_receiver_error" });
}, 12_000);
second.armAdmissionTimeout(() => {
second.post({ eventCode: "live_receiver_error" });
}, 12_000);
first.markAdmitted();
clock.advance(12_000);
assert.equal(posts.length, 1);
assert.equal(
posts[0].eventLineage.viewerInstanceId,
"00000000-0000-4000-8000-000000000022",
);
assert.equal(posts[0].eventLineage.lifecycleGeneration, 7);
});
test("stale-build and unmount fence callbacks before one reload", () => {
const clock = createFakeScheduler();
const order = [];
const posts = [];
const lifecycle = createLiveViewerDiagnosticLifecycle({
lineage: lineage("00000000-0000-4000-8000-000000000031"),
scheduler: clock.scheduler,
diagnosticPoster: (event) => posts.push(event),
buildVerifier: () => undefined,
});
lifecycle.armAdmissionTimeout(() => {
lifecycle.post({ eventCode: "live_receiver_error" });
}, 12_000);
const coordinator = createUiBuildStaleCoordinator({
scheduleReload: (callback, delay) => {
order.push(`scheduled:${delay}`);
clock.scheduler.setTimeout(callback, delay);
},
reload: () => order.push("reload"),
});
coordinator.subscribe(() => {
order.push("local-transports-closed");
lifecycle.dispose();
});
coordinator.report({
loadedUiBuildId: "/assets/index-abcdefgh.js",
expectedUiBuildId: "/assets/index-ijklmnop.js",
});
coordinator.report({
loadedUiBuildId: "/assets/index-abcdefgh.js",
expectedUiBuildId: "/assets/index-qrstuvwx.js",
});
clock.advance(60_000);
lifecycle.post({ eventCode: "live_receiver_error" });
assert.deepEqual(order, ["local-transports-closed", "scheduled:50", "reload"]);
assert.deepEqual(posts, []);
assert.equal(lifecycle.active(), false);
});
test("last unsubscribe fences an already queued build verification callback", () => {
const controller = new AbortController();
const observedSignals = [];
const queuedVerify = createAbortFencedBuildVerifier(
controller.signal,
(signal) => observedSignals.push(signal),
);
queuedVerify();
// stopBuildMonitor aborts the locally captured controller when the last
// mounted viewer unsubscribes. A browser callback already queued before the
// interval/listener removal can still run once, but cannot start a fetch.
controller.abort();
queuedVerify();
assert.deepEqual(observedSignals, [controller.signal]);
assert.equal(observedSignals[0].aborted, true);
});
test("diagnostic body and build id retain exact document/viewer/build lineage", () => {
const eventLineage = lineage("00000000-0000-4000-8000-000000000041", 9);
assert.deepEqual(
liveViewerDiagnosticBody(
{ eventCode: "live_receiver_recovered", streamId: "acquisition-42" },
eventLineage,
),
{
schema_version: "missioncore.live-viewer-diagnostic/v2",
event_code: "live_receiver_recovered",
ui_build_id: "/assets/index-abcdefgh.js",
document_instance_id: "00000000-0000-4000-8000-000000000001",
viewer_instance_id: "00000000-0000-4000-8000-000000000041",
lifecycle_generation: 9,
stream_id: "acquisition-42",
},
);
assert.equal(
uiBuildIdFromModuleScripts(
["https://mission.local/assets/index-dT7dN-y4.js"],
"https://mission.local/park",
),
"/assets/index-dT7dN-y4.js",
);
});
File diff suppressed because it is too large Load Diff
@@ -5,7 +5,9 @@ import { after, before, test } from "node:test";
import { createServer } from "vite";
let server;
let claimExclusiveLiveViewer;
let createRecordedOpenWatchdog;
let createReentrantViewerDisposer;
let recordedOpenWatchdogTimeoutMs;
let rerunViewerInitialSource;
let resolveRecordedViewerSourceUrl;
@@ -17,7 +19,9 @@ before(async () => {
server: { middlewareMode: true },
});
({
claimExclusiveLiveViewer,
createRecordedOpenWatchdog,
createReentrantViewerDisposer,
recordedOpenWatchdogTimeoutMs,
rerunViewerInitialSource,
resolveRecordedViewerSourceUrl,
@@ -118,6 +122,45 @@ test("complete recorded admission clears its watchdog", () => {
assert.deepEqual(cancelled, [23]);
});
test("deferred viewer start cannot reopen after stale unmount", async () => {
let resolveStart;
const start = new Promise((resolve) => {
resolveStart = resolve;
});
let disposed = false;
let cleanupCount = 0;
let closeCount = 0;
let stopCount = 0;
const diagnostics = [];
const disposeViewer = createReentrantViewerDisposer(
() => {
cleanupCount += 1;
},
() => {
closeCount += 1;
stopCount += 1;
},
);
const pendingMount = (async () => {
await start;
if (disposed) {
disposeViewer();
return;
}
diagnostics.push("admitted");
})();
disposed = true;
disposeViewer();
resolveStart();
await pendingMount;
assert.equal(cleanupCount, 1);
assert.equal(closeCount, 2);
assert.equal(stopCount, 2);
assert.deepEqual(diagnostics, []);
});
test("recorded RRD bytes are never split across LogChannel.send_rrd calls", async () => {
const source = await readFile(
new URL("../src/components/RerunViewport.tsx", import.meta.url),
@@ -129,7 +172,7 @@ test("recorded RRD bytes are never split across LogChannel.send_rrd calls", asyn
assert.match(source, /viewer\.start\(\s*rerunViewerInitialSource\(resolvedSource\)/s);
assert.match(
source,
/recordingOpened = true;[\s\S]*clearLiveRecordingOpenTimer\(\);[\s\S]*clearLiveRecordingDiscoveryTimer\(\);/,
/recordingOpened = true;[\s\S]*diagnosticLifecycle\.markAdmitted\(\);/,
);
assert.match(
source,
@@ -145,12 +188,31 @@ test("recorded RRD bytes are never split across LogChannel.send_rrd calls", asyn
);
});
test("one live document owns one native Rerun receiver", async () => {
const releases = [];
const releaseFirstClaim = claimExclusiveLiveViewer(() => releases.push("first"));
const releaseSecondClaim = claimExclusiveLiveViewer(() => releases.push("second"));
assert.deepEqual(releases, ["first"]);
releaseFirstClaim();
assert.deepEqual(releases, ["first"]);
releaseSecondClaim();
const releaseThirdClaim = claimExclusiveLiveViewer(() => releases.push("third"));
assert.deepEqual(releases, ["first"]);
releaseThirdClaim();
});
test("raw replay exercises the same streaming receiver lifecycle as a live scan", async () => {
const source = await readFile(
new URL("../src/workspaces/Workspaces.tsx", import.meta.url),
"utf8",
);
assert.match(source, /followLive=\{!recordedReplay && streamActive\}/);
assert.match(
source,
/sourceUrl\.trim\(\) && pointCloudVisible && !intentionalSourceEnd/,
);
});
test("the complete vendor canvas host is hidden during partial and failed admission", async () => {
@@ -42,6 +42,113 @@ function snapshot(revision, generation, phase = "streaming", sessionId = "device
};
}
function stampedSnapshot({
runtimeStartedAt = "2026-08-06T10:00:00Z",
runtimeStartedMonotonicNs = "1000000",
runtimeId = "runtime-a",
snapshotRevision = 1,
cameraRevision = snapshotRevision,
generation = 1,
} = {}) {
return {
...snapshot(cameraRevision, generation),
snapshot_runtime_started_at_utc: runtimeStartedAt,
snapshot_runtime_started_monotonic_ns: runtimeStartedMonotonicNs,
snapshot_runtime_id: runtimeId,
snapshot_revision: snapshotRevision,
};
}
test("uses the process snapshot revision before camera-local counters", () => {
const current = stampedSnapshot({ snapshotRevision: 8, cameraRevision: 2 });
const stale = stampedSnapshot({ snapshotRevision: 7, cameraRevision: 99 });
const newer = stampedSnapshot({ snapshotRevision: 9, cameraRevision: 1 });
assert.equal(selectMonotonicXgridsState(current, stale), current);
assert.equal(selectMonotonicXgridsState(current, newer), newer);
});
test("accepts a newer runtime and rejects a delayed snapshot from the old runtime", () => {
const oldRuntime = stampedSnapshot({
runtimeStartedAt: "2026-08-06T10:00:00Z",
runtimeStartedMonotonicNs: "1000000",
runtimeId: "runtime-old",
snapshotRevision: 300,
});
const newRuntime = stampedSnapshot({
runtimeStartedAt: "2026-08-06T10:05:00Z",
runtimeStartedMonotonicNs: "2000000",
runtimeId: "runtime-new",
snapshotRevision: 1,
});
const delayedOldRuntime = stampedSnapshot({
runtimeStartedAt: "2026-08-06T10:00:00Z",
runtimeStartedMonotonicNs: "1000000",
runtimeId: "runtime-old",
snapshotRevision: 301,
});
assert.equal(selectMonotonicXgridsState(oldRuntime, newRuntime), newRuntime);
assert.equal(
selectMonotonicXgridsState(newRuntime, delayedOldRuntime),
newRuntime,
);
});
test("orders restarts by monotonic time even when UTC moves backwards", () => {
const oldRuntime = stampedSnapshot({
runtimeStartedAt: "2026-08-06T10:05:00Z",
runtimeStartedMonotonicNs: "2000000",
runtimeId: "runtime-old",
snapshotRevision: 900,
});
const newRuntime = stampedSnapshot({
runtimeStartedAt: "2026-08-06T09:55:00Z",
runtimeStartedMonotonicNs: "3000000",
runtimeId: "runtime-new",
snapshotRevision: 1,
});
assert.equal(selectMonotonicXgridsState(oldRuntime, newRuntime), newRuntime);
assert.equal(selectMonotonicXgridsState(newRuntime, oldRuntime), newRuntime);
});
test("orders two runtimes sharing the same UTC millisecond", () => {
const first = stampedSnapshot({
runtimeStartedMonotonicNs: "4000000",
runtimeId: "runtime-first",
});
const second = stampedSnapshot({
runtimeStartedMonotonicNs: "4000001",
runtimeId: "runtime-second",
});
assert.equal(selectMonotonicXgridsState(first, second), second);
});
test("a malformed monotonic stamp cannot replace valid runtime authority", () => {
const current = stampedSnapshot({
runtimeStartedMonotonicNs: "5000000",
runtimeId: "runtime-current",
});
const malformed = stampedSnapshot({
runtimeStartedAt: "2026-08-06T11:00:00Z",
runtimeStartedMonotonicNs: "not-a-number",
runtimeId: "runtime-malformed",
snapshotRevision: 9999,
});
assert.equal(selectMonotonicXgridsState(current, malformed), current);
});
test("does not let an unstamped legacy response replace stamped authority", () => {
const current = stampedSnapshot({ snapshotRevision: 8 });
const legacy = snapshot(99, 99);
assert.equal(selectMonotonicXgridsState(current, legacy), current);
assert.equal(selectMonotonicXgridsState(legacy, current), current);
});
test("accepts the first camera preview snapshot", () => {
const incoming = snapshot(1, 1);
assert.equal(selectMonotonicXgridsState(null, incoming), incoming);
@@ -13,6 +13,9 @@ let projectObservationLayoutSnapshot;
let saveObservationWorkspaceLayoutProfile;
let WorkspaceLayoutApiError;
let WorkspaceLayoutContractError;
let admitLiveDefaultPresentations;
let automaticLivePresentationIdentity;
let livePresentationCloseFence;
let observationPresentationSourceAfterLayoutApply;
let visibleSourceIdsAfterRecordedCatalogActivation;
@@ -33,6 +36,9 @@ before(async () => {
WorkspaceLayoutContractError,
} = await server.ssrLoadModule("/src/core/observation/workspaceLayout.ts"));
({
admitLiveDefaultPresentations,
automaticLivePresentationIdentity,
livePresentationCloseFence,
observationPresentationSourceAfterLayoutApply,
visibleSourceIdsAfterRecordedCatalogActivation,
} = await server.ssrLoadModule("/src/core/observation/useObservationLayout.ts"));
@@ -213,6 +219,95 @@ test("opening a recorded catalog reveals its sealed cameras beside the point clo
);
});
test("a sequential live acquisition re-arms the same camera without reopening a deliberate close", () => {
const pointCloud = {
id: "k1:sensor.lidar.primary",
sourceId: "sensor.lidar.primary",
modality: "point-cloud",
availability: "streaming",
transport: "rerun-grpc",
previewUrl: "grpc://127.0.0.1:9876/proxy",
delivery: null,
activation: null,
binding: {
deviceId: "k1-a",
deviceSessionId: "device-session-reused",
acquisitionId: "acquisition-a",
},
capabilities: { defaultVisible: true, overlay: false },
};
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/reused",
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 firstCamera = camera("acquisition-a", "camera-preview-2");
const first = admitLiveDefaultPresentations(
[pointCloud.id],
[pointCloud, firstCamera],
new Set(),
new Set(),
);
assert.deepEqual(first.visibleIds, [pointCloud.id, firstCamera.id]);
assert.deepEqual(first.admittedIdentities, [
automaticLivePresentationIdentity(firstCamera),
]);
const sameAcquisitionNewDelivery = camera("acquisition-a", "camera-preview-3");
const closedInFirstAcquisition = new Set([
livePresentationCloseFence(firstCamera),
]);
const afterDeliberateClose = admitLiveDefaultPresentations(
[pointCloud.id],
[pointCloud, sameAcquisitionNewDelivery],
new Set(first.admittedIdentities),
closedInFirstAcquisition,
);
assert.deepEqual(afterDeliberateClose.visibleIds, [pointCloud.id]);
assert.deepEqual(afterDeliberateClose.admittedIdentities, []);
const nextAcquisitionSameDelivery = camera("acquisition-b", "camera-preview-3");
assert.notEqual(
automaticLivePresentationIdentity(nextAcquisitionSameDelivery),
automaticLivePresentationIdentity(sameAcquisitionNewDelivery),
);
const second = admitLiveDefaultPresentations(
[pointCloud.id],
[
{ ...pointCloud, binding: { ...pointCloud.binding, acquisitionId: "acquisition-b" } },
nextAcquisitionSameDelivery,
],
new Set(first.admittedIdentities),
closedInFirstAcquisition,
);
assert.deepEqual(second.visibleIds, [pointCloud.id, nextAcquisitionSameDelivery.id]);
assert.deepEqual(second.admittedIdentities, [
automaticLivePresentationIdentity(nextAcquisitionSameDelivery),
]);
});
test("workspace layout API uses the canonical endpoint and optimistic revision", async () => {
const calls = [];
const current = decodeObservationWorkspaceLayoutProfile(wireProfile());