FlatBuffers Policy Schema
The binary files under a study’s policy/ directory are
FlatBuffers buffers. Cobre’s runtime writes
and reads them through a hand-rolled, allocation-free path in Rust, but
external consumers (Python, C++, TypeScript, Java, Go, …) can use the
canonical schema file shipped with the source tree to generate a typed
reader in any language flatc supports.
| File path | Root table |
|---|---|
policy/cuts/stage_NNN.bin | StageCuts |
policy/basis/stage_NNN.bin | StageBasis |
policy/states/stage_NNN.bin | StageStates (only when exports.states = true) |
The schema lives at
crates/cobre-io/schemas/policy.fbs
under namespace Cobre.IO.Policy. It has no file_identifier and no
root_type — pass --root-type to flatc to select the entry point
for each file.
Quick start: dumping a .bin to JSON
Section titled “Quick start: dumping a .bin to JSON”flatc ships a converter that turns any FlatBuffers buffer into JSON
when given the schema. This is the closest thing to a human-readable
view of a policy checkpoint:
flatc -t --strict-json --raw-binary \ --root-type StageCuts \ crates/cobre-io/schemas/policy.fbs \ -- output/policy/cuts/stage_000.bin# writes stage_000.json next to the .binFor the basis or states files, swap the --root-type argument for
StageBasis or StageStates.
Generating a typed reader
Section titled “Generating a typed reader”flatc emits idiomatic source code for any of its supported target
languages. Pick the one matching your toolchain.
Python
Section titled “Python”flatc --python crates/cobre-io/schemas/policy.fbs# emits Cobre/IO/Policy/{Cut,StageCuts,StageBasis,StageStates}.pyfrom Cobre.IO.Policy.StageCuts import StageCuts
with open("output/policy/cuts/stage_000.bin", "rb") as f: buf = bytearray(f.read())
cuts = StageCuts.GetRootAs(buf, 0)print("stage_id =", cuts.StageId())for i in range(cuts.CutsLength()): cut = cuts.Cuts(i) print(cut.CutId(), cut.Intercept(), [cut.Coefficients(j) for j in range(cut.CoefficientsLength())])flatc --cpp crates/cobre-io/schemas/policy.fbs# emits policy_generated.hTypeScript / JavaScript
Section titled “TypeScript / JavaScript”flatc --ts crates/cobre-io/schemas/policy.fbs# emits TypeScript modules under cobre/io/policy/For other targets see flatc --help.
Field-by-field reference
Section titled “Field-by-field reference”The authoritative description of every field lives in
policy.fbs
itself — every field carries an inline doc comment. The
Output Format page has a tabular summary suitable
for reading on the web.
Reserved slot: Cut.domination_count
Section titled “Reserved slot: Cut.domination_count”Field id 4 of the Cut table (domination_count) is marked
deprecated and is preserved in the schema only so that:
- The vtable slot number is permanently burned and cannot be reused by a future field.
- Legacy policy files that still contain it continue to deserialise via FlatBuffers’ graceful-absence rule — the slot is read, ignored, and discarded.
Generated readers emit no accessor for it; generated writers cannot emit it. The Cobre runtime’s own writer never sets it in policy files written by the current release.
How drift is prevented
Section titled “How drift is prevented”The schema is not consumed by Cobre’s own build. Two independent implementations describe the same wire format:
- The schema file
crates/cobre-io/schemas/policy.fbs, with explicit(id: N)attributes on every field. - The hand-rolled writer/reader in
crates/cobre-io/src/output/policy/codec.rs, which encodes vtable slots via the*_FIELD_*: u16constants. The slot offset is(field_id + 2) * 2.
A conformance test, tests/flatbuffers_schema_conformance.rs in
cobre-io, round-trips representative buffers in both directions:
- Hand-rolled writer →
flatc -t→ JSON: catches the writer emitting a slot the schema does not declare, or at the wrong offset. - JSON →
flatc -b→ hand-rolled reader: catches the schema declaring a slot the reader expects at a different offset.
The test is gated behind the flatc-conformance cargo feature so that
the everyday cargo test does not depend on flatc. To run it:
cargo test -p cobre-io \ --features flatc-conformance \ --test flatbuffers_schema_conformanceIf you change either the schema or the slot constants, run the
conformance test before merging. The CI workflow that has flatc
available runs it on every pull request that touches policy/codec.rs or
the schema file.
Versioning policy
Section titled “Versioning policy”FlatBuffers’ graceful-absence rule lets us add new fields to any table
without breaking older readers, as long as new fields are appended
at the end with the next available id. This is the only schema
change that does not require an output-format version bump:
- Adding a field at the next free id → backward compatible. Old readers see the field as absent and use the FlatBuffers default (zero / empty vector). New readers see the value when the writer was new enough to emit it.
- Removing a field → mark it
deprecated, never reuse the id. SeeCut.domination_countfor a worked example. - Changing a field’s type → breaking. Bumps the major output format version.
- Renaming a field → breaking for
flatc-generated code (the accessor name changes). Avoid; if necessary, treat as a major bump. - Reordering fields → harmless if
(id: N)attributes stay put. The wire layout is determined by the ids, not by source order.