octoturgeandClaude Opus 5 9b348902a7 Add msg to v1 push_status, and say why v2 has no vt_tray
Two things the live captures showed that the schemas did not say.

`msg` was missing from the v1 push_status schema, which is the one version
where it is load-bearing. v1 pushes only the fields that changed, except for
a pushall-triggered push which is the whole object, and `msg` is how a v1
message self-describes which it is (0 forced/full, 1 automatic/partial). A
consumer that replaces its cached object with a partial push silently unsets
every field that push did not mention, and there is no other way to tell:
push_status does not echo `sequence_id`, so there is no correlation back to
the pushall that asked for it. continuum-proxy has read this field since the
cache was written; the schema just never declared it.

v2 had it with no description. It is informational there - v2 sends the whole
object every time - so it now points at the v1 note rather than repeating it.

The other half is an absence, which a schema cannot express by staying
silent: v2 has no `vt_tray` because a real v2 printer omits the key entirely
rather than sending an empty object. That is recorded as a comment so nobody
adds it for symmetry with v1, because the distinction is the thing: absence
means "not reported", not "no external spool", and it is exactly why
`EXTERNAL_SPOOLS` in continuum-proxy is a constant instead of being counted
from a report.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-15 21:45:38 +00:00
2026-10-15 21:37:20 +00:00

continuum-schemas

Single source of truth for the Continuum data model. Everything here is JSON Schema, compiled into two consumer packages:

  • packages/ts-types - hand-written TypeBox schemas under src/schemas/ used for runtime validation in continuum-backend's ElysiaJS routes.
  • packages/rust-types - a Rust crate (continuum-rust-types) with hand-written, serde-derived structs for continuum-proxy and continuum-ai-worker.

Layout

schemas/continuum/v1/     Continuum's own model
  ai/                     continuum-backend <-> continuum-ai-worker: the
                          stream:camera_frames work queue and the
                          channel:print_alerts notification channel
  edge/                   continuum-backend <-> continuum-proxy: the
                          /ws/edge/v1 gateway uplink protocol
  material/  printer/     domain objects
  vendor.schema.json
schemas/bambulab/         Bambu Lab MQTT wire schemas (v1/v2, report + request)
packages/ts-types/        TypeBox schemas (hand-written, mirrors schemas/)
packages/rust-types/      serde structs (hand-written, mirrors schemas/)

The two inter-service protocols - edge/ and ai/ - are here for a specific reason: each has two independent implementations, one per repo, and when there was nothing written down between them they drifted completely while every test passed. /ws/edge/v1 had an auth handshake the gateway never sent; stream:camera_frames had a producer writing printerId and a consumer reading printer_id, so every frame was attributed to a printer called "unknown". Neither failure was visible from either side alone, which is what a canonical schema plus a contract test on each end is for.

schemas/continuum/v1/*.schema.json is the canonical shape for each domain object; packages/ts-types/src/schemas/ and packages/rust-types/src/lib.rs both mirror it by hand. A mirror is added per schema only once something actually consumes it, so not every file here has one, and the two inter-service protocols keep their Rust mirror in the single repo that consumes it rather than in packages/rust-types: edge/ in continuum-proxy/src/uplink/protocol.rs, ai/ in continuum-ai-worker/src/task.rs. The set is small and changes slowly, which is why keeping hand-synced copies in sync is less overhead than a codegen pipeline (protoc/ts-proto/prost-build) nothing actually consumed - see git history for the protobuf version this replaced, and why it was dropped: every service in this system talks JSON (JSON Schema for the wire, TypeBox/serde for runtime validation), so protobuf's actual value - a single schema compiled into a compact binary wire format for both languages - never applied.

Whenever a domain schema changes, update all three by hand: the JSON Schema file, the TypeBox schema, and the Rust struct.

Build / verify

Requires npm install at the repo root, and a Rust toolchain, first.

npm install
npm run build:rust   # cargo build, confirms the Rust structs compile
npm run typecheck     # tsc -b, confirms the TypeBox schemas compile

There's no build:ts step - the TS side is hand-written, not generated.

S
Description
Continuum platform: continuum-schemas
Readme
319 KiB
Languages
TypeScript 100%