import { describe, expect, it } from "vitest"; import { EMPTY_PROCESS_CAPTURE_EXAMPLE } from "./processCapture.fixture.js"; import { processCaptureSchema, type UnverifiedProcessCapture, } from "./processCapture.js"; import { createProcessObservation, projectProcessObservation, } from "./processObservation.js"; const emptyCapture = processCaptureSchema.parse(EMPTY_PROCESS_CAPTURE_EXAMPLE); const capture: UnverifiedProcessCapture = { ...emptyCapture, frames: [{ sequence: 0, at_ms: 1, data: "Ready" }], rendered_frames: [ { sequence: 0, at_ms: 2, columns: 80, rows: 24, cursor_x: 0, cursor_y: 0, active_buffer: "normal", lines: ["Ready"], serialized_state: "Ready", }, ], interaction_events: [ { sequence: 0, scheduled_at_ms: 2, dispatched_at_ms: 3, type: "signal", data: "SIGINT", outcome: "dispatched", }, ], process_samples: [ { at_ms: 4, pid: 2, parent_pid: 1, command: "worker", process_group_id: 1, session_id: 1, }, ], }; describe("process observation vocabulary", () => { it("projects capture collections without timestamp sorting", () => { const locations = [ { collection: "frames", index: 0, capture_order: 4 }, { collection: "rendered_frames", index: 0, capture_order: 3 }, { collection: "interaction_events", index: 0, capture_order: 2 }, { collection: "lifecycle", index: 0, capture_order: 8 }, { collection: "lifecycle", index: 1, capture_order: 9 }, { collection: "process_samples", index: 0, capture_order: 1 }, { collection: "filesystem_checkpoints", index: 0, capture_order: 0 }, ] as const; const observations = locations.map((location) => projectProcessObservation(capture, location), ); expect(observations.map((value) => value?.source)).toEqual([ "terminal_raw", "terminal_rendered", "interaction", "lifecycle", "lifecycle", "process", "filesystem", ]); expect(observations.map((value) => value?.capture_order)).toEqual( locations.map(({ capture_order }) => capture_order), ); expect(observations[5]).toMatchObject({ event_id: "obs.process_samples.0", source_sequence: 0, captured_at_ms: 4, subject_id: "process:2", }); expect(observations[3]?.captured_at_ms).toBeNull(); expect(observations[4]?.captured_at_ms).toBeNull(); }); it("uses the same constructor for live and post-hoc observations", () => { const location = { collection: "frames" as const, index: 0, capture_order: 4, }; const projected = projectProcessObservation(capture, location); const live = createProcessObservation({ source: "terminal_raw", source_sequence: 0, captured_at_ms: 1, subject_id: null, location, payload: capture.frames[0], }); expect(live).toEqual(projected); }); it("returns no observation for a missing raw record", () => { expect( projectProcessObservation(capture, { collection: "frames", index: 1, capture_order: 10, }), ).toBeNull(); }); });