Factory MBOM

Schema Reference

The scalarcut.factory_bom.v1.1 document, field by field: header, pieces, cut types, recipes, pack rounding, consumables, totals, and stable IDs.

The Factory MBOM document is versioned by a top-level schema string. The current version is scalarcut.factory_bom.v1.1. Treat the schema field as the contract: if a constant or field meaning changes, the version bumps.

Dual units, one truth

The planner's internal lattice is in metres, but the exported document is millimetres:

  • Cut sizes and export fields are integer millimetres (round(m × 1000)).
  • The document states unit_system: "metric" and lattice_unit: "mm".
  • Canonical piece sizes are always w_mm / h_mm.
  • Inch/foot display in the planner converts from the millimetre lattice and is never written back into the cut keys. This export emits no inch columns.

Document header

Field Meaning
schema scalarcut.factory_bom.v1.1
scene_id Planner scene id, or null if unsaved
project_id Same as scene_id this round (one tiling scene = one ERP key)
title Scene display label
unit_system / lattice_unit / unit_policy metric / mm / policy string
rates Frozen consumable constants (below)
totals Room rollup across surfaces
surfaces / pieces / recipes Per-surface BOM, cut list, and CRE recipes

Pieces

A piece describes a cut group — a size repeated qty times. Key fields:

Field Meaning
surface_id wall-a … wall-d, or floor
letter Legend letter matching the PDF cut list (A, B, …)
group_id Stable group id derived from location + size
sku Catalog SKU, or empty on the first-party planner
w_mm / h_mm Canonical millimetre size
cut_type The cut class for this piece
qty Number of identical pieces
fragile True when the cut is below the 50 mm fragility floor
cre_recycled True when the piece is recycled by the Cut Recycling Engine
cre_parent Parent blank size key (tileW×tileH mm) when recycled, else empty
is_l_cut True for L-shaped cuts

Cut types

cut_type classifies how the piece is produced. An integrator can key cutting-table behaviour off it. Fragile pieces are flagged separately so they can be routed for special handling rather than dropped onto a machine that will shatter them.

L-cuts

L-shaped pieces are flagged with is_l_cut and carry their arm dimensions in the piece geometry. CRE nesting still treats each piece as its w_mm × h_mm bounding rectangle.

Optional leftover polygon (geometry)

A piece may include an additive geometry object:

"geometry": {
  "frame": "tile_local_mm",
  "vertices_mm": [[0, 0], [180, 0], [180, 600], [0, 600]]
}
  • The frame is wall-aligned millimetres translated so the nominal unclipped tile AABB minimum is (0, 0).
  • Present when the leftover is a single convex/simple ring (a 45° diagonal or herringbone fragment, or an axis-aligned rectangular leftover).
  • Omitted for L-cuts, multi-fragment leftovers, and qty groups whose members do not share the same ring.
  • It is not a CNC toolpath and does not introduce arbitrary blade angles — CRE still nests w_mm × h_mm rectangles.
  • Unknown fields are additive: an ERP that ignores geometry keeps w_mm / h_mm / cut_type / is_l_cut.

Box and pack rounding

When the total piece count (totalPieces) is known:

  1. orderPieces = ceil(totalPieces × (1 + wastage) − 1e-12)
  2. With a pack quantity (pack_qty, tiles per box) of 1 or more:
    • fullBoxes = floor(orderPieces / pack_qty)
    • looseTiles = orderPieces % pack_qty
    • boxes_to_order = fullBoxes — leftover tiles are not rounded into an extra box.
    • pack_mode = "full_boxes_plus_loose"
  3. With no pack quantity: pack_mode = "pack_unset", boxes_to_order = null; the tile line is still orderPieces.

When totalPieces is unknown: pack_mode = "area_ceil_boxes", boxes_to_order = ceil(grossTileAreaSqm / sqmPerBox − 1e-12).

Surface packing fields: pack_qty, pack_mode, order_pieces, full_boxes, loose_tiles, boxes_to_order, and the deprecated boxes alias (equal to boxes_to_order).

Consumables (frozen rates)

Consumables are emitted as a rates formula version and as kg/L per surface and in totals. These constants are frozen with the schema; if they change between builds, the contract has changed and the schema bumps.

Constant Value Use
adhesive_kg_per_sqm 4.5 adhesiveKg = grossTileAreaSqm × 4.5
adhesive_bag_kg 25 adhesiveBags = ceil(adhesiveKg / 25 − 1e-12)
primer_l_per_sqm 0.2 primerL = grossTileAreaSqm × 0.2
grout_density_kg_m3 1200 CAD grout mass
grout_compaction_factor 1.05 CAD grout mass

Grout mass is computed from pattern geometry with density × compaction. Display rounding (0.1 steps) is for the human sheets only; the factory JSON stores the engine value before display rounding.

Totals rollup

totals sums the surface BOM fields, plus:

  • cut_qty — sum of piece qty (must match the blueprint cut-list header when audited).
  • boxes_to_order (and deprecated boxes) — sum of surface carton counts where set.

Stable IDs

  • Surfaces: wall-a, wall-b, wall-c, wall-d, floor.
  • Cut groups: group_id from location key + size (w×h mm or L-arm key).
  • Legend letters: A, B, … from group array order, identical to the PDF cut list.

The same lattice always yields the same group_id and letters on re-export.

SKU

  • An empty sku is allowed on the first-party planner (demo, no catalog).
  • A catalog / widget embed must populate sku for a live factory feed.
  • An empty SKU does not block the export.

CSV piece list

The CSV is the piece list only (same columns as v1). Packing, ids, rates, totals, and the optional geometry live in JSON.

Columns: surface_id, letter, group_id, sku, w_mm, h_mm, cut_type, qty, fragile, cre_recycled, cre_parent, is_l_cut.