import { describe, expect, test } from "bun:test"; import { Value } from "@sinclair/typebox/value"; import { FrameTaskSchema, PrintAlertSchema, type FrameTask } from "@continuum/ts-types"; import { checkFrameTask, frameTaskToStreamFields } from "../src/queue/frame_task"; /** * The mirror of `continuum-ai-worker/src/task.rs`'s test module. Both sides * assert the same field names against the same canonical schema * (`schemas/continuum/v1/ai/frame_task.schema.json`), because the bug this * replaced was invisible from either side alone: the producer wrote * `printerId` and `r2ObjectKey`, the consumer read `printer_id` and nothing * else, every task was delivered and acknowledged, and every frame was * attributed to a printer called "unknown". * * A stream entry is a flat string map, so there is nothing to parse and * nothing to fail - which is exactly why the field names need a test rather * than a type. */ const FARM = "11111111-1111-1111-1111-111111111111"; const PRINTER = "22222222-2222-2222-2222-222222222222"; const JOB = "33333333-3333-3333-3333-333333333333"; const task: FrameTask = { farm_id: FARM, printer_id: PRINTER, r2_object_key: "farms/x/frames/1.jpg", captured_at: "2026-10-11T12:00:00Z", }; /** The flat list XADD takes, as the `{field: value}` map a consumer sees. */ function asMap(fields: string[]): Record { const map: Record = {}; for (let i = 0; i < fields.length; i += 2) map[fields[i]!] = fields[i + 1]!; return map; } describe("the stream:camera_frames wire form", () => { test("is snake_case, and exactly the keys the schema names", () => { // Written out rather than derived from the schema: a test that reads the // field names from the same place the implementation does cannot catch // them both being wrong. expect(Object.keys(asMap(frameTaskToStreamFields(task))).sort()).toEqual([ "captured_at", "farm_id", "printer_id", "r2_object_key", ]); }); test("carries the values through unchanged", () => { expect(asMap(frameTaskToStreamFields(task))).toEqual({ farm_id: FARM, printer_id: PRINTER, r2_object_key: "farms/x/frames/1.jpg", captured_at: "2026-10-11T12:00:00Z", }); }); test("includes print_job_id when there is one", () => { const fields = asMap(frameTaskToStreamFields({ ...task, print_job_id: JOB })); expect(fields.print_job_id).toBe(JOB); }); /** * The counterpart of the Rust `an_empty_job_id_is_no_job_id` test. The old * producer wrote `""`; a stream entry has no null, so the only way to say * "no job" is to leave the field out. */ test("omits print_job_id entirely rather than writing an empty string", () => { const fields = frameTaskToStreamFields(task); expect(fields).not.toContain("print_job_id"); expect(fields).not.toContain(""); expect("print_job_id" in asMap(fields)).toBe(false); }); test("emits an even number of field/value entries", () => { // XADD takes pairs; an odd count is a wrong-arity error at the server // rather than at the type level. expect(frameTaskToStreamFields(task).length % 2).toBe(0); expect(frameTaskToStreamFields({ ...task, print_job_id: JOB }).length % 2).toBe(0); }); test("never emits a camelCase key", () => { // The actual regression. Both field name sets, side by side, so the // failure message names the one that came back. const keys = Object.keys(asMap(frameTaskToStreamFields({ ...task, print_job_id: JOB }))); for (const camel of ["farmId", "printerId", "printJobId", "r2ObjectKey", "capturedAt"]) { expect(keys).not.toContain(camel); } }); }); describe("the producer's schema check", () => { test("accepts a well-formed task", () => { expect(checkFrameTask.Check(task)).toBe(true); }); test("rejects a task with a camelCase field instead of the real one", () => { const { printer_id, ...rest } = task; expect(checkFrameTask.Check({ ...rest, printerId: printer_id })).toBe(false); }); test("rejects a task missing any required field", () => { for (const key of Object.keys(task) as Array) { const partial = { ...task }; delete partial[key]; expect(checkFrameTask.Check(partial)).toBe(false); } }); test("rejects an empty object key", () => { // `minLength: 1`: an empty key would send the worker looking for the // object named "". expect(checkFrameTask.Check({ ...task, r2_object_key: "" })).toBe(false); }); /** * Guards `src/validation/formats.ts`. TypeBox treats an unregistered * format as a failure, not as "skip", so this check started life rejecting * every task with `Unknown format 'uuid'`. These two assertions fail if * the registration is lost (everything rejected) *or* if it became a no-op * that accepts anything (nothing rejected). */ test("the uuid format is actually enforced, not merely declared", () => { expect(checkFrameTask.Check(task)).toBe(true); expect(checkFrameTask.Check({ ...task, printer_id: "unknown" })).toBe(false); expect(checkFrameTask.Check({ ...task, farm_id: "11111111-1111-1111-1111-11111111111" })).toBe( false, ); }); test("the date-time format is actually enforced", () => { expect(checkFrameTask.Check({ ...task, captured_at: "yesterday" })).toBe(false); }); test("rejects a print_job_id that is an empty string", () => { // Belt and braces with the omit-don't-empty rule: if a caller does pass // `""`, the producer refuses rather than writing it. expect(checkFrameTask.Check({ ...task, print_job_id: "" })).toBe(false); }); }); describe("the channel:print_alerts payload", () => { // Asserted here as well as in the worker because the backend is the side // that will have to parse these once the fan-out route exists, and this is // where that expectation should be recorded. const alert = { printer_id: PRINTER, label: "spaghetti", confidence: 0.91, captured_at: "2026-10-11T12:00:00Z", r2_object_key: "farms/x/frames/1.jpg", }; test("the shape the worker publishes validates", () => { expect(Value.Check(PrintAlertSchema, alert)).toBe(true); }); test("print_job_id is optional, and null is not the same as absent", () => { expect(Value.Check(PrintAlertSchema, { ...alert, print_job_id: JOB })).toBe(true); expect(Value.Check(PrintAlertSchema, { ...alert, print_job_id: null })).toBe(false); }); test("confidence outside 0..1 is refused", () => { expect(Value.Check(PrintAlertSchema, { ...alert, confidence: 1.5 })).toBe(false); expect(Value.Check(PrintAlertSchema, { ...alert, confidence: -0.1 })).toBe(false); }); test("an alert carries the frame it came from, not just a label", () => { // Without `r2_object_key` an operator gets "printer X is failing" and no // way to look at the evidence. const { r2_object_key, ...withoutFrame } = alert; expect(Value.Check(PrintAlertSchema, withoutFrame)).toBe(false); }); });