1import type {
2 DesktopHostTelemetrySnapshot,
3 ResourceMonitorProcessSample,
4 ResourceMonitorSnapshotEvent,
5 ResourceTelemetryHealth,
6} from "@t3tools/contracts";
7import { describe, expect, it } from "@effect/vitest";
8import * as DateTime from "effect/DateTime";
9import * as Option from "effect/Option";
10
11import {
12 buildResourceTelemetryHistory,
13 normalizeResourceTelemetryHistoryInput,
14} from "./ResourceTelemetryHistory.ts";
15
16const SERVER_PID = 100;
17const ELECTRON_PID = 200;
18const CHILD_PID = 300;
19const STARTED_AT_MS = DateTime.toEpochMillis(DateTime.makeUnsafe("2026-06-17T12:00:00.000Z"));
20
21function processSample(
22 input: Partial<ResourceMonitorProcessSample> &
23 Pick<ResourceMonitorProcessSample, "pid" | "ppid" | "startTimeMs">,
24): ResourceMonitorProcessSample {
25 return {
26 runTimeMs: 1_000,
27 name: `process-${input.pid}`,
28 command: `process-${input.pid}`,
29 status: "Running",
30 cpuPercent: 0,
31 cpuTimeMs: 0,
32 residentBytes: 1_024,
33 virtualBytes: 2_048,
34 ioReadBytes: 0,
35 ioWriteBytes: 0,
36 ioSemantics: "storage",
37 ...input,
38 };
39}
40
41function snapshot(
42 sequence: number,
43 sampledAtUnixMs: number,
44 childCpuTimeMs: number,
45 childWriteBytes: number,
46): ResourceMonitorSnapshotEvent {
47 const processes = [
48 processSample({ pid: SERVER_PID, ppid: 1, startTimeMs: 10 }),
49 processSample({
50 pid: ELECTRON_PID,
51 ppid: 1,
52 startTimeMs: 20,
53 name: "electron",
54 command: "electron",
55 }),
56 processSample({
57 pid: CHILD_PID,
58 ppid: SERVER_PID,
59 startTimeMs: 30,
60 name: "codex",
61 command: "codex app-server",
62 cpuTimeMs: childCpuTimeMs,
63 ioWriteBytes: childWriteBytes,
64 }),
65 ];
66 return {
67 version: 3,
68 type: "snapshot",
69 sequence,
70 sampledAtUnixMs,
71 collectionDurationMicros: 100,
72 scannedProcessCount: processes.length,
73 retainedProcessCount: processes.length,
74 inaccessibleProcessCount: 0,
75 processes,
76 };
77}
78
79const health: ResourceTelemetryHealth = {
80 native: {
81 status: "healthy",
82 lastSampleAt: Option.none(),
83 lastError: Option.none(),
84 },
85 desktop: {
86 status: "healthy",
87 lastSampleAt: Option.none(),
88 lastError: Option.none(),
89 },
90 sidecarVersion: Option.some("0.1.0"),
91 sidecarPid: Option.some(400),
92 restartCount: 0,
93 collectionDurationMicros: 100,
94 scannedProcessCount: 3,
95 retainedProcessCount: 3,
96 inaccessibleProcessCount: 0,
97};
98
99function desktopSnapshot(): DesktopHostTelemetrySnapshot {
100 const sampledAt = DateTime.makeUnsafe(STARTED_AT_MS + 1_000);
101 return {
102 version: 1,
103 type: "desktopTelemetry",
104 sequence: 1,
105 sampledAtUnixMs: STARTED_AT_MS + 1_000,
106 electronPid: ELECTRON_PID,
107 power: {
108 source: "electron-main",
109 idle: "false",
110 idleSeconds: 0,
111 locked: "false",
112 suspended: false,
113 onBattery: "false",
114 lowPowerMode: "unknown",
115 thermalState: "nominal",
116 stale: false,
117 updatedAt: sampledAt,
118 },
119 speedLimitPercent: Option.none(),
120 electronProcesses: [
121 {
122 pid: ELECTRON_PID,
123 creationTimeMs: 20,
124 type: "Browser",
125 cpuPercent: 999,
126 idleWakeupsPerSecond: 999,
127 workingSetBytes: 999_999,
128 peakWorkingSetBytes: 999_999,
129 },
130 ],
131 };
132}
133
134describe("buildResourceTelemetryHistory", () => {
135 it("normalizes query bounds before requesting native history", () => {
136 expect(normalizeResourceTelemetryHistoryInput({ windowMs: 0, bucketMs: 0 })).toEqual({
137 windowMs: 1_000,
138 bucketMs: 1_000,
139 });
140 });
141
142 it("replays native snapshots on demand without applying current Electron metrics", () => {
143 const history = buildResourceTelemetryHistory({
144 readAt: DateTime.makeUnsafe(STARTED_AT_MS + 2_000),
145 windowMs: 10_000,
146 bucketMs: 10_000,
147 sampleIntervalMs: 1_000,
148 serverPid: SERVER_PID,
149 sidecarPid: Option.some(400),
150 desktopSnapshot: Option.some(desktopSnapshot()),
151 snapshots: [
152 snapshot(1, STARTED_AT_MS, 100, 1_000),
153 snapshot(2, STARTED_AT_MS + 1_000, 350, 5_000),
154 ],
155 health,
156 });
157
158 const child = history.topProcesses.find((process) => process.identity.pid === CHILD_PID);
159 const electron = history.topProcesses.find((process) => process.identity.pid === ELECTRON_PID);
160 expect(child?.sampleCount).toBe(2);
161 expect(child?.cpuTimeMs).toBe(250);
162 expect(child?.ioWriteBytes).toBe(4_000);
163 expect(electron?.category).toBe("electron-main");
164 expect(electron?.currentRssBytes).toBe(1_024);
165 expect(history.buckets.reduce((total, bucket) => total + bucket.ioWriteBytes, 0)).toBe(4_000);
166 });
167
168 it("uses observed RSS for the history-window peak instead of the lifetime process peak", () => {
169 const first = snapshot(1, STARTED_AT_MS, 100, 1_000);
170 const second = snapshot(2, STARTED_AT_MS + 1_000, 200, 2_000);
171 const history = buildResourceTelemetryHistory({
172 readAt: DateTime.makeUnsafe(STARTED_AT_MS + 2_000),
173 windowMs: 10_000,
174 bucketMs: 10_000,
175 sampleIntervalMs: 1_000,
176 serverPid: SERVER_PID,
177 sidecarPid: Option.none(),
178 desktopSnapshot: Option.none(),
179 snapshots: [
180 {
181 ...first,
182 processes: first.processes.map((process) =>
183 process.pid === CHILD_PID
184 ? { ...process, residentBytes: 2_000, peakResidentBytes: 50_000 }
185 : process,
186 ),
187 },
188 {
189 ...second,
190 processes: second.processes.map((process) =>
191 process.pid === CHILD_PID
192 ? { ...process, residentBytes: 3_000, peakResidentBytes: 60_000 }
193 : process,
194 ),
195 },
196 ],
197 health,
198 });
199
200 expect(
201 history.topProcesses.find((process) => process.identity.pid === CHILD_PID)?.peakRssBytes,
202 ).toBe(3_000);
203 });
204
205 it("retains cumulative baselines while a process is absent from an intermediate sample", () => {
206 const first = snapshot(1, STARTED_AT_MS, 100, 1_000);
207 const absent = snapshot(2, STARTED_AT_MS + 1_000, 0, 0);
208 const returned = snapshot(3, STARTED_AT_MS + 2_000, 350, 5_000);
209 const history = buildResourceTelemetryHistory({
210 readAt: DateTime.makeUnsafe(STARTED_AT_MS + 3_000),
211 windowMs: 10_000,
212 bucketMs: 10_000,
213 sampleIntervalMs: 1_000,
214 serverPid: SERVER_PID,
215 sidecarPid: Option.none(),
216 desktopSnapshot: Option.none(),
217 snapshots: [
218 first,
219 {
220 ...absent,
221 processes: absent.processes.filter((process) => process.pid !== CHILD_PID),
222 },
223 returned,
224 ],
225 health,
226 });
227
228 const child = history.topProcesses.find((process) => process.identity.pid === CHILD_PID);
229 expect(child?.cpuTimeMs).toBe(250);
230 expect(child?.ioWriteBytes).toBe(4_000);
231 });
232
233 it("uses an exact current Electron identity for slightly older native samples", () => {
234 const history = buildResourceTelemetryHistory({
235 readAt: DateTime.makeUnsafe(STARTED_AT_MS + 2_000),
236 windowMs: 10_000,
237 bucketMs: 10_000,
238 sampleIntervalMs: 1_000,
239 serverPid: SERVER_PID,
240 sidecarPid: Option.none(),
241 desktopSnapshot: Option.some(desktopSnapshot()),
242 snapshots: [snapshot(1, STARTED_AT_MS, 100, 1_000)],
243 health,
244 });
245
246 expect(
247 history.topProcesses.find((process) => process.identity.pid === ELECTRON_PID)?.category,
248 ).toBe("electron-main");
249 });
250
251 it("uses the preceding sample as a baseline without attributing pre-window deltas", () => {
252 const readAtMs = STARTED_AT_MS + 10_000;
253 const history = buildResourceTelemetryHistory({
254 readAt: DateTime.makeUnsafe(readAtMs),
255 windowMs: 5_000,
256 bucketMs: 5_000,
257 sampleIntervalMs: 1_000,
258 serverPid: SERVER_PID,
259 sidecarPid: Option.none(),
260 desktopSnapshot: Option.none(),
261 snapshots: [
262 snapshot(1, STARTED_AT_MS, 100, 1_000),
263 snapshot(2, STARTED_AT_MS + 5_000, 600, 6_000),
264 snapshot(3, readAtMs + 1_000, 10_000, 20_000),
265 ],
266 health,
267 });
268
269 const child = history.topProcesses.find((process) => process.identity.pid === CHILD_PID);
270 expect(child?.sampleCount).toBe(1);
271 expect(child?.cpuTimeMs).toBe(0);
272 expect(child?.ioWriteBytes).toBe(0);
273 expect(history.buckets.reduce((total, bucket) => total + bucket.ioWriteBytes, 0)).toBe(0);
274 expect(
275 history.buckets.every((bucket) => DateTime.toEpochMillis(bucket.startedAt) <= readAtMs),
276 ).toBe(true);
277 });
278
279 it("prorates a cumulative delta that crosses the history window boundary", () => {
280 const readAtMs = STARTED_AT_MS + 10_000;
281 const history = buildResourceTelemetryHistory({
282 readAt: DateTime.makeUnsafe(readAtMs),
283 windowMs: 5_000,
284 bucketMs: 5_000,
285 sampleIntervalMs: 1_000,
286 serverPid: SERVER_PID,
287 sidecarPid: Option.none(),
288 desktopSnapshot: Option.none(),
289 snapshots: [
290 snapshot(1, STARTED_AT_MS, 100, 1_000),
291 snapshot(2, STARTED_AT_MS + 7_500, 850, 8_500),
292 ],
293 health,
294 });
295
296 const child = history.topProcesses.find((process) => process.identity.pid === CHILD_PID);
297 expect(child?.cpuTimeMs).toBe(250);
298 expect(child?.ioWriteBytes).toBe(2_500);
299 expect(history.buckets.reduce((total, bucket) => total + bucket.ioWriteBytes, 0)).toBe(2_500);
300 });
301
302 it("replays the Electron root identity recorded with each native sample", () => {
303 const oldElectron = snapshot(1, STARTED_AT_MS, 100, 1_000);
304 const restartedElectron = snapshot(2, STARTED_AT_MS + 1_000, 200, 2_000);
305 const history = buildResourceTelemetryHistory({
306 readAt: DateTime.makeUnsafe(STARTED_AT_MS + 2_000),
307 windowMs: 10_000,
308 bucketMs: 10_000,
309 sampleIntervalMs: 1_000,
310 serverPid: SERVER_PID,
311 sidecarPid: Option.none(),
312 desktopSnapshot: Option.none(),
313 snapshots: [
314 {
315 ...oldElectron,
316 externalProcesses: [{ pid: ELECTRON_PID, startTimeMs: 20 }],
317 },
318 {
319 ...restartedElectron,
320 externalProcesses: [{ pid: 201, startTimeMs: 40 }],
321 processes: [
322 ...restartedElectron.processes.filter((process) => process.pid !== ELECTRON_PID),
323 processSample({
324 pid: ELECTRON_PID,
325 ppid: SERVER_PID,
326 startTimeMs: 999,
327 name: "reused",
328 command: "unrelated process",
329 }),
330 processSample({
331 pid: 201,
332 ppid: 1,
333 startTimeMs: 40,
334 name: "electron",
335 command: "electron",
336 }),
337 ],
338 },
339 ],
340 health,
341 });
342
343 expect(
344 history.topProcesses.find(
345 (process) => process.identity.pid === ELECTRON_PID && process.identity.startTimeMs === 20,
346 )?.category,
347 ).toBe("electron-main");
348 expect(
349 history.topProcesses.find(
350 (process) => process.identity.pid === ELECTRON_PID && process.identity.startTimeMs === 999,
351 )?.category,
352 ).toBe("server-child");
353 expect(history.topProcesses.find((process) => process.identity.pid === 201)?.category).toBe(
354 "electron-main",
355 );
356 });
357});