`stream:camera_frames` and `channel:print_alerts` are the only interface between `continuum-backend` and `continuum-ai-worker`, and there was nothing specifying either. They had drifted completely: the backend wrote `farmId`, `printerId`, `r2ObjectKey` and `capturedAt`; the worker read a single field called `printer_id` and ignored the rest. Every task was delivered, acknowledged, and attributed to a printer called "unknown" - and nothing errored, because a stream entry is a flat string map and asking it for a field that is not there is not a failure. Same shape as the /ws/edge/v1 drift, found the same way. `schemas/continuum/v1/ai/` is now canonical, with a TypeBox mirror in ts-types and a Rust mirror in the worker. Two things the schemas have to say that JSON Schema does not naturally express, both of which caused real bugs: - A Valkey stream entry is a flat field/value map of *strings*. No nesting, no numbers, no null. So FrameTask has no numeric or nested properties, and a field with no value is omitted from the XADD rather than written as `""` - an empty string is a value, and the producer was writing one for `print_job_id`, which a consumer would carry into a lookup or a uuid column. - PrintAlert, by contrast, *is* a JSON document, because PUBLISH carries one opaque string. It is also fire-and-forget with no persistence, so it can only ever be a live-console feed and never the record of a detection. The README's layout section was stale (it still listed four DTOs that were removed in 2026-09) and did not mention `edge/` or `ai/` at all. It now names both, says why the inter-service protocols live here, and notes that their Rust mirrors sit in the single repo that consumes each rather than in `packages/rust-types`.
48 lines
2.4 KiB
JSON
48 lines
2.4 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/continuum/v1/ai/print_alert.schema.json",
|
|
"title": "PrintAlert",
|
|
"description": "A print-failure detection, published by continuum-ai-worker for live operator consoles.\n\nUnlike FrameTask this one IS a JSON document: it travels as the payload of a Valkey PUBLISH, which carries a single opaque string, so the structure has to be inside it.\n\nPUBLISH is fire-and-forget with no persistence and no delivery guarantee: an alert published while nothing is subscribed is gone. That is acceptable for the live-console path it feeds and is NOT acceptable as the record of a detection, which belongs in Postgres. As of 2026-10-11 nothing subscribes to this channel and nothing persists it - see the README section on the AI path.",
|
|
"x-channel": "channel:print_alerts",
|
|
"type": "object",
|
|
"properties": {
|
|
"printer_id": {
|
|
"type": "string",
|
|
"format": "uuid",
|
|
"description": "`printers.id`, taken from the frame task that produced the detection."
|
|
},
|
|
"print_job_id": {
|
|
"type": "string",
|
|
"format": "uuid",
|
|
"description": "Omitted when the frame was not attributed to a tracked job."
|
|
},
|
|
"label": {
|
|
"type": "string",
|
|
"description": "What the model thinks it saw, e.g. \"spaghetti\", \"layer_shift\", \"detachment\". A free string rather than an enum on purpose: the label set is a property of the model file, which changes without this schema changing."
|
|
},
|
|
"confidence": {
|
|
"type": "number",
|
|
"minimum": 0,
|
|
"maximum": 1,
|
|
"description": "The model's own score. Whether it is high enough to act on is the consumer's policy decision, not the worker's - the worker publishes what it found and does not threshold on behalf of an operator who may want to see near-misses."
|
|
},
|
|
"captured_at": {
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "From the frame, not from the detection. An operator needs to know when the printer looked like this, not when a GPU got round to looking."
|
|
},
|
|
"r2_object_key": {
|
|
"type": "string",
|
|
"description": "The frame the detection came from, so a console can show the operator the picture rather than only a label."
|
|
}
|
|
},
|
|
"required": [
|
|
"printer_id",
|
|
"label",
|
|
"confidence",
|
|
"captured_at",
|
|
"r2_object_key"
|
|
],
|
|
"additionalProperties": false
|
|
}
|