fix(k1): stabilize repeated acquisition and live viewer recovery

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 01:55:12 +03:00
parent 37b8930527
commit 2a97cf28c0
28 changed files with 2776 additions and 286 deletions
@@ -439,6 +439,11 @@ test("live source is confirmed only by an acquiring acquisition", () => {
assert.equal(lifecycle.sourceStatusLabel(waiting), "Ожидание реальных данных");
assert.equal(lifecycle.isConfirmedLiveState(acquiring), true);
assert.equal(lifecycle.confirmedRuntimeSourceMode(acquiring), "live");
assert.equal(lifecycle.liveStartPlan(acquiring), "already-running");
assert.equal(
lifecycle.controlSessionEntryPlan("scanning", false, false),
"continue",
);
});
test("prepared acquisition resumes without another prepare and remains recoverable", () => {
@@ -0,0 +1,94 @@
import assert from "node:assert/strict";
import { after, before, test } from "node:test";
import { createServer } from "vite";
let server;
let advanceLiveReceiverWatchdog;
let initialLiveReceiverWatchdogState;
let initialLiveReceiverRecoveryState;
let requestLiveReceiverRecovery;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
advanceLiveReceiverWatchdog,
initialLiveReceiverRecoveryState,
initialLiveReceiverWatchdogState,
requestLiveReceiverRecovery,
} = await server.ssrLoadModule("/src/core/observation/liveReceiverWatchdog.ts"));
});
after(async () => {
await server?.close();
});
test("watchdog ignores healthy live progress", () => {
let state = initialLiveReceiverWatchdogState();
for (let index = 0; index < 20; index += 1) {
const observed = advanceLiveReceiverWatchdog(state, {
nowMs: index * 500,
backendActivitySequence: index * 2,
viewerRangeMaxNs: index * 1_000_000_000,
});
state = observed.state;
assert.notEqual(observed.signal, "stalled");
}
});
test("watchdog detects a frozen receiver while backend publication advances", () => {
let state = initialLiveReceiverWatchdogState();
let signal = "none";
let stalledForMs = 0;
for (let index = 0; index <= 13; index += 1) {
const observed = advanceLiveReceiverWatchdog(state, {
nowMs: index * 500,
backendActivitySequence: 100 + index,
viewerRangeMaxNs: 42_000_000_000,
});
state = observed.state;
signal = observed.signal === "stalled" ? observed.signal : signal;
stalledForMs = Math.max(stalledForMs, observed.stalledForMs);
}
assert.equal(signal, "stalled");
assert.ok(stalledForMs >= 5_000);
});
test("one backend increment at stream finalization does not create a false stall", () => {
let state = initialLiveReceiverWatchdogState();
state = advanceLiveReceiverWatchdog(state, {
nowMs: 0,
backendActivitySequence: 10,
viewerRangeMaxNs: 20_000_000_000,
}).state;
state = advanceLiveReceiverWatchdog(state, {
nowMs: 500,
backendActivitySequence: 11,
viewerRangeMaxNs: 20_000_000_000,
}).state;
const observed = advanceLiveReceiverWatchdog(state, {
nowMs: 10_000,
backendActivitySequence: 11,
viewerRangeMaxNs: 20_000_000_000,
});
assert.equal(observed.signal, "none");
});
test("startup failures request only three bounded viewer restarts", () => {
let state = initialLiveReceiverRecoveryState();
for (let attempt = 1; attempt <= 3; attempt += 1) {
const recovery = requestLiveReceiverRecovery(state);
assert.equal(recovery.signal, "retry");
assert.equal(recovery.attempt, attempt);
assert.equal(recovery.state.awaitingRecovery, true);
state = recovery.state;
}
const exhausted = requestLiveReceiverRecovery(state);
assert.equal(exhausted.signal, "exhausted");
assert.equal(exhausted.attempt, 3);
assert.equal(exhausted.state.awaitingRecovery, false);
});
@@ -129,7 +129,11 @@ 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]*if \(!isRecordedSource\) clearLiveRecordingOpenTimer\(\);/,
/recordingOpened = true;[\s\S]*clearLiveRecordingOpenTimer\(\);[\s\S]*clearLiveRecordingDiscoveryTimer\(\);/,
);
assert.match(
source,
/viewer\.get_active_recording_id\(\)[\s\S]*eventCode: "live_receiver_active_store_admitted"[\s\S]*admitRecording\(\{[\s\S]*application_id: "nodedc_mission_core_spatial"/,
);
assert.match(
source,
@@ -141,6 +145,14 @@ test("recorded RRD bytes are never split across LogChannel.send_rrd calls", asyn
);
});
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\}/);
});
test("the complete vendor canvas host is hidden during partial and failed admission", async () => {
const css = await readFile(new URL("../src/styles/spatial.css", import.meta.url), "utf8");
assert.match(