fix(observation): admit bounded LAB chunk coverage

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 22:34:07 +03:00
parent 082b7057da
commit 5a29a536a2
4 changed files with 104 additions and 14 deletions
@@ -46,6 +46,8 @@ export interface RerunPlaybackState {
playing: boolean;
/** Latest session-time value currently available to the browser receiver. */
bufferedEndNs: number | null;
/** Declared first session-time value, when the archive descriptor provides it. */
expectedStartNs: number | null;
/** Declared final session-time value, when the archive descriptor provides it. */
expectedEndNs: number | null;
/** Download progress in the closed interval 0..1, or null without a valid expectation. */
@@ -182,6 +184,7 @@ export function createRecordedOpenWatchdog<T>({
export interface RecordedPlaybackBufferState {
bufferedEndNs: number | null;
expectedStartNs: number | null;
expectedEndNs: number | null;
bufferProgress: number | null;
fullyBuffered: boolean;
@@ -214,6 +217,7 @@ export function recordedPlaybackBufferState(
if (expectedTimelineEndSeconds === undefined) {
return {
bufferedEndNs,
expectedStartNs: null,
expectedEndNs: null,
bufferProgress: null,
fullyBuffered: usableRange !== null,
@@ -222,6 +226,7 @@ export function recordedPlaybackBufferState(
if (!Number.isFinite(expectedTimelineEndSeconds) || expectedTimelineEndSeconds < 0) {
return {
bufferedEndNs,
expectedStartNs: null,
expectedEndNs: null,
bufferProgress: null,
fullyBuffered: false,
@@ -240,21 +245,32 @@ export function recordedPlaybackBufferState(
) {
return {
bufferedEndNs,
expectedStartNs: null,
expectedEndNs: null,
bufferProgress: null,
fullyBuffered: false,
};
}
// Rerun split preserves whole boundary chunks so that all generated splits
// still sum exactly to the source recording. A verified bounded artifact can
// therefore begin slightly before its declared operator window. Admission
// requires coverage of the declared window, not byte-chunk boundary equality.
const fullyBuffered = usableRange !== null &&
Math.abs(usableRange.min - expectedStartNs) <= BUFFER_END_TOLERANCE_NS &&
Math.abs(usableRange.max - expectedEndNs) <= BUFFER_END_TOLERANCE_NS;
usableRange.min <= expectedStartNs + BUFFER_END_TOLERANCE_NS &&
usableRange.max >= expectedEndNs - BUFFER_END_TOLERANCE_NS;
const expectedDurationNs = expectedEndNs - expectedStartNs;
const bufferProgress = bufferedEndNs === null
? 0
: expectedDurationNs <= 0
? (fullyBuffered ? 1 : 0)
: Math.min(1, Math.max(0, (bufferedEndNs - expectedStartNs) / expectedDurationNs));
return { bufferedEndNs, expectedEndNs, bufferProgress, fullyBuffered };
return {
bufferedEndNs,
expectedStartNs,
expectedEndNs,
bufferProgress,
fullyBuffered,
};
}
/** A recorded viewport is publishable only after its declared range is complete. */
@@ -272,9 +288,19 @@ export function recordedPlaybackRangeWhenReady(
buffer: RecordedPlaybackBufferState,
artifactVerified: boolean,
): { min: number; max: number } | null {
return artifactVerified && buffer.fullyBuffered && isUsableRecordedPlaybackRange(rangeNs)
? rangeNs
: null;
if (
!artifactVerified ||
!buffer.fullyBuffered ||
!isUsableRecordedPlaybackRange(rangeNs)
) return null;
return {
min: buffer.expectedStartNs === null
? rangeNs.min
: Math.max(rangeNs.min, buffer.expectedStartNs),
max: buffer.expectedEndNs === null
? rangeNs.max
: Math.min(rangeNs.max, buffer.expectedEndNs),
};
}
/** Do not mount host timeline controls while a recorded generation is partial. */
@@ -1076,6 +1102,7 @@ export function RerunViewport({
...(followLive
? {
bufferedEndNs: rangeNs?.max ?? null,
expectedStartNs: null,
expectedEndNs: null,
bufferProgress: null,
fullyBuffered: true,
@@ -1096,7 +1123,7 @@ export function RerunViewport({
emitPlayback({ playing });
},
jumpToEnd: () => {
const range = viewer.get_time_range(event.recording_id, timeline);
const range = playbackState?.rangeNs;
if (!range) return;
viewer.set_current_time(event.recording_id, timeline, range.max);
emitPlayback({ rangeNs: range, currentNs: range.max, playing: false });
@@ -1151,7 +1178,9 @@ export function RerunViewport({
viewer.set_playing(event.recording_id, true);
},
initialPlaybackStartSeconds === undefined
? undefined
? expectedTimelineStartSeconds === undefined
? undefined
: expectedTimelineStartSeconds * 1_000_000_000
: initialPlaybackStartSeconds * 1_000_000_000,
);
if (autoplayStarted) {
@@ -1167,6 +1196,7 @@ export function RerunViewport({
...(followLive
? {
bufferedEndNs: rangeNs?.max ?? null,
expectedStartNs: null,
expectedEndNs: null,
bufferProgress: null,
fullyBuffered: true,
@@ -133,6 +133,7 @@ test("session catalog decodes canonical snake_case into a path-free camelCase mo
durationSeconds: 1_450.744,
replayable: true,
preparation: null,
lab: null,
}]);
assert.equal("raw_capture" in catalog.items[0], false);
assert.equal("path" in catalog.items[0], false);
@@ -42,6 +42,7 @@ test("a first frame reports buffer telemetry but is not ready for presentation",
const firstFrame = recordedPlaybackBufferState({ min: 0, max: 0 }, 20);
assert.deepEqual(firstFrame, {
bufferedEndNs: 0,
expectedStartNs: 0,
expectedEndNs: 20_000_000_000,
bufferProgress: 0,
fullyBuffered: false,
@@ -58,6 +59,7 @@ test("host timeline remains unmounted until the verified recording is fully read
currentNs: 0,
playing: false,
bufferedEndNs: 5,
expectedStartNs: 0,
expectedEndNs: 10,
bufferProgress: 0.5,
fullyBuffered: false,
@@ -77,6 +79,7 @@ test("host timeline remains unmounted until the verified recording is fully read
test("buffer progress grows independently and preserves the full-buffer tolerance", () => {
assert.deepEqual(recordedPlaybackBufferState({ min: 0, max: 5_000_000_000 }, 20), {
bufferedEndNs: 5_000_000_000,
expectedStartNs: 0,
expectedEndNs: 20_000_000_000,
bufferProgress: 0.25,
fullyBuffered: false,
@@ -97,14 +100,37 @@ test("buffer progress grows independently and preserves the full-buffer toleranc
{ min: 0, max: 19_999_500_000 },
);
const wrongDeclaredStart = recordedPlaybackBufferState(
const missingDeclaredStart = recordedPlaybackBufferState(
{ min: 5_000_000_000, max: 20_000_000_000 },
20,
0,
);
assert.equal(wrongDeclaredStart.bufferProgress, 1);
assert.equal(wrongDeclaredStart.fullyBuffered, false);
assert.equal(isRecordedPlaybackReady(true, true, wrongDeclaredStart), false);
assert.equal(missingDeclaredStart.bufferProgress, 1);
assert.equal(missingDeclaredStart.fullyBuffered, false);
assert.equal(isRecordedPlaybackReady(true, true, missingDeclaredStart), false);
});
test("a verified split boundary spill covers and clamps the declared LAB window", () => {
const actualRange = {
min: 34_756_228_209,
max: 95_383_857_292,
};
const buffer = recordedPlaybackBufferState(
actualRange,
95.383857292,
35.421857292,
);
assert.equal(buffer.bufferProgress, 1);
assert.equal(buffer.fullyBuffered, true);
assert.equal(isRecordedPlaybackReady(true, true, buffer), true);
assert.deepEqual(
recordedPlaybackRangeWhenReady(actualRange, buffer, true),
{
min: 35_421_857_292,
max: 95_383_857_292,
},
);
});
test("recorded autoplay waits for the full range and then runs exactly once", () => {