From b5382ab47ca208002215a529bf6fe70ce28fa577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iwo=20Strzebo=C5=84ski?= Date: Thu, 15 Oct 2026 21:37:20 +0000 Subject: [PATCH] Accept a telemetry stage, and prove the field is really there `stage` comes from the shared schema, so this is contract tests only. The test that matters asserts a *wrongly typed* stage is rejected rather than only that a valid one is accepted. `PrinterTelemetrySchema` permits unknown properties - verified empirically, `{ totally_bogus: 1 }` validates - so `{ stage: 54 }` passes whether or not the field is declared, and a test built only on the positive case would keep passing if someone deleted it. Worth knowing separately: that open `additionalProperties` means a gateway sending a misspelled field name is accepted and the value silently dropped, which is the same drift this suite exists to catch. Not changed here, because tightening it needs a check against what real gateways send. --- tests/edge_protocol.test.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/edge_protocol.test.ts b/tests/edge_protocol.test.ts index e1050db..197ee1f 100644 --- a/tests/edge_protocol.test.ts +++ b/tests/edge_protocol.test.ts @@ -54,6 +54,41 @@ describe("gateway -> backend frames", () => { expect(printers.every((p) => typeof p.printer_id === "string" && p.printer_id.length > 0)).toBe(true); }); + it("accepts a stage, including stage 0", () => { + // `stage` is Bambu's `stg_cur`: what the printer is doing when it is not + // laying down plastic. 0 means printing, and a schema or serialiser that + // treats 0 as absent loses the distinction that makes the field worth + // having - a printer at 14% and layer 0 is mid-bed-levelling at stage 54 + // and genuinely stuck at stage 0. + for (const stage of [0, 13, 54]) { + check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", percent: 14, layer: 0, stage }], + }); + } + + // The assertion that makes the loop above mean anything. This schema + // permits unknown properties, so `{ stage: 54 }` validates whether or + // not `stage` is declared - verified, it does. Rejecting a *wrongly + // typed* stage is what proves the field is really in the schema, so this + // is what fails if someone removes it. + expect( + Value.Check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", stage: "54" }], + }), + ).toBe(false); + }); + + it("still accepts telemetry with no stage at all", () => { + // The field is additive: the committed live capture predates it, and a + // gateway that has not been updated yet simply omits it. + check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", percent: 0 }], + }); + }); + it("rejects a telemetry batch whose printer has no id", () => { // printer_id and name are the only required fields; everything else is // genuinely unknowable for a printer that has only just connected.