Files
continuum-proxy/schemas/bambulab/v1/README.md
T
octoturge 42eb0b62d5 Add JSON Schema documentation for bambulab/v1, with real inheritance
Mirrors src/printer/bambu_commands/ as language-agnostic schema docs (not
used for codegen — the Rust structs stay hand-written). envelope.schema.json
is the base; get_version/pushall request+response schemas extend it via
allOf + $ref, which is genuinely closer to real inheritance than anything
else in this project's schema stack: proto and Rust only ever gave us
composition (embed a field holding the base struct), never a mechanism
that reuses a *referenced* schema's constraints automatically.

Verified with the jsonschema Python library, not just written by hand:
all three real examples from the conversation validate correctly, and —
importantly — negative tests confirm the base schema's required fields
and the command consts are actually enforced through the allOf chain, not
just documented. README covers the one real gotcha (additionalProperties:
false on a base schema silently breaks allOf composition, since allOf
validates each sub-schema against the whole instance independently rather
than merging them).
2026-08-28 22:53:59 +00:00

68 lines
2.8 KiB
Markdown

# bambulab/v1 JSON Schemas
Documentation/validation schemas mirroring `src/printer/bambu_commands/`
not used for codegen (the Rust structs are hand-written, see that module's
doc comment for why), but useful on their own: as language-agnostic
documentation of the wire format, or for validating a captured MQTT
payload without writing Rust to do it.
## The "inheritance" pattern
`envelope.schema.json` is the base — `sequence_id` + `command`, the two
fields every command/response shares. Every other schema here *extends*
it with `allOf` + `$ref`:
```json
{
"allOf": [
{ "$ref": "envelope.schema.json" },
{ "type": "object", "properties": { "command": { "const": "get_version" } } }
]
}
```
This is genuinely closer to real inheritance than anything else in this
project's schema stack (proto, Rust): the instance must satisfy the base
schema *and* the extension schema simultaneously, and — verified, not just
asserted — the base's `required: ["sequence_id", "command"]` is actually
enforced on every schema that extends it, not just copy-pasted as
documentation. Proto and Rust only ever gave us composition (embed a field
holding the base), never something that reuses a *named, referenced*
schema's constraints automatically like this.
**One gotcha if you add a new base-style schema**: don't set
`"additionalProperties": false` on something meant to be `allOf`-extended.
`allOf` validates every sub-schema against the *whole* instance
independently — it doesn't merge object schemas — so a closed base schema
would reject every field the extending schema adds. Leave
`additionalProperties` unset (defaults to allowed) on anything used as a
base; enforce closedness only on the top-level schemas
(`request.schema.json`/`report.schema.json` do this correctly — check
their `additionalProperties: false`).
## Files
- `envelope.schema.json` — the base
- `module_info.schema.json` — nested object used inside `get_version`'s response
- `get_version.request.schema.json` / `get_version.response.schema.json`
- `pushall.request.schema.json` / `pushall.response.schema.json`
- `request.schema.json` / `report.schema.json` — the top-level `{"info": ...}` / `{"pushing": ...}` dispatch, matching `BambuRequest`/`BambuReport`
## Validating something
```python
from referencing import Registry, Resource
from jsonschema import Draft202012Validator
import json, glob, os
resources = []
for path in glob.glob("*.schema.json"):
contents = json.load(open(path))
resources.append((contents["$id"], Resource.from_contents(contents)))
resources.append((os.path.basename(path), Resource.from_contents(contents)))
registry = Registry().with_resources(resources)
schema = json.load(open("request.schema.json"))
Draft202012Validator(schema, registry=registry).validate({"info": {"sequence_id": "0", "command": "get_version"}})
```