mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 18:22:42 +00:00
fix(process): coalesce delayed capture progress
Retain one pending intermediate observation and drop stale live status before terminal cleanup. Preserve monotonic counts and final delivery while an observer is slow or rejects an update. Verify the send rate at its controlled-clock owner and lifecycle notification density at the CLI/MCP boundary, where receive timestamps include buffering and scheduling.
This commit is contained in:
1 parent
706bba6e13
commit
6cd5ea0fb2
5 files changed
+203
-32
No files matched your search
@@ -0,0 +1,113 @@
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
createProcessCaptureProgressTracker,
|
||||
type ProcessCaptureProgress,
|
||||
} from "./ProcessCaptureProgress.js";
|
||||
|
||||
const blockedProgress = () => {
|
||||
let release: () => void = () => undefined;
|
||||
const blocked = new Promise<void>((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
const delivered: Parameters<ProcessCaptureProgress["report"]>[0][] = [];
|
||||
const progress: ProcessCaptureProgress = {
|
||||
async report(update) {
|
||||
delivered.push(update);
|
||||
if (delivered.length === 1) await blocked;
|
||||
},
|
||||
};
|
||||
return { progress, delivered, release: () => release() };
|
||||
};
|
||||
|
||||
it("coalesces intermediate observations while the progress receiver is blocked", async () => {
|
||||
const receiver = blockedProgress();
|
||||
const tracker = createProcessCaptureProgressTracker(receiver.progress);
|
||||
void tracker.report({
|
||||
phase: "running",
|
||||
counts: { frames: 1, samples: 0, interactions: 0 },
|
||||
});
|
||||
await Promise.resolve();
|
||||
let latest: Promise<void> | undefined;
|
||||
for (let frames = 2; frames <= 1_000; frames += 1) {
|
||||
latest = tracker.report({
|
||||
phase: "running",
|
||||
counts: { frames, samples: 0, interactions: 0 },
|
||||
});
|
||||
}
|
||||
expect(receiver.delivered).toHaveLength(1);
|
||||
receiver.release();
|
||||
await latest;
|
||||
expect(receiver.delivered.map((update) => update.completed)).toEqual([
|
||||
1, 1_000,
|
||||
]);
|
||||
expect(receiver.delivered[1]?.message).toContain("frames=1000");
|
||||
});
|
||||
|
||||
it("discards stale live observations before delivering final cleanup", async () => {
|
||||
const receiver = blockedProgress();
|
||||
const tracker = createProcessCaptureProgressTracker(receiver.progress);
|
||||
void tracker.report({
|
||||
phase: "running",
|
||||
counts: { frames: 1, samples: 0, interactions: 0 },
|
||||
});
|
||||
await Promise.resolve();
|
||||
void tracker.report({
|
||||
phase: "running",
|
||||
counts: { frames: 2, samples: 0, interactions: 0 },
|
||||
});
|
||||
void tracker.report({
|
||||
phase: "settling",
|
||||
counts: { frames: 2, samples: 1, interactions: 0 },
|
||||
});
|
||||
tracker.closeLive();
|
||||
await tracker.report({
|
||||
phase: "running",
|
||||
counts: { frames: 10, samples: 10, interactions: 10 },
|
||||
});
|
||||
const terminal = tracker.report({
|
||||
phase: "cleanup",
|
||||
counts: { frames: 2, samples: 2, interactions: 0 },
|
||||
disposition: "exited",
|
||||
terminal: true,
|
||||
});
|
||||
receiver.release();
|
||||
await terminal;
|
||||
expect(receiver.delivered.map((update) => update.phase)).toEqual([
|
||||
"running",
|
||||
"cleanup",
|
||||
]);
|
||||
expect(receiver.delivered.at(-1)).toMatchObject({
|
||||
completed: 4,
|
||||
total: null,
|
||||
terminal: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("still delivers terminal status after an observer rejects an update", async () => {
|
||||
const delivered: Parameters<ProcessCaptureProgress["report"]>[0][] = [];
|
||||
const tracker = createProcessCaptureProgressTracker({
|
||||
async report(update) {
|
||||
delivered.push(update);
|
||||
if (delivered.length === 1) throw new Error("Observer disconnected");
|
||||
},
|
||||
});
|
||||
await tracker.report({
|
||||
phase: "prepare",
|
||||
counts: { frames: 0, samples: 0, interactions: 0 },
|
||||
});
|
||||
tracker.closeLive();
|
||||
await expect(
|
||||
tracker.report({
|
||||
phase: "cleanup",
|
||||
counts: { frames: 1, samples: 1, interactions: 0 },
|
||||
disposition: "failed",
|
||||
terminal: true,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
expect(delivered.at(-1)).toMatchObject({
|
||||
phase: "cleanup",
|
||||
completed: 2,
|
||||
terminal: true,
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user