Products
Catalog, under Components: Products (/products, with product:read, covered by every viewer’s *:read floor)
is the directory of products: the concrete SKUs the fleet is built from, on the same
flat-registry pattern as Location Types and Tags. A product is
a specific model (a Kestrel VRoom, a Boreal Edge 55), not an organization and not an installed
unit. It is where the two leaf catalogs converge: the vendor that makes
it and the driver that speaks to it, classified by a kind and a
component type. Each row shows the
name (for example kestrel-vroom), the label, its
vendor, driver, kind, and its origin (official or custom). A
product also carries an id, a uuid minted by the database, the internal address the handle resolves
to (ADR-0062); the handle is what you type and read.
A product is also what a component points at: component.product_id names the product a component
is, required, so every component always resolves a shape (its vendor, driver, and classification)
and, through its product, a device-class component type. The
component-level component_type retired in the fields fold; the registry returned differently shaped,
above the product rather than beside the component, so a component’s genus is read through the product
it is, never stored on the component itself. The system side has the same arrangement one level up: a
system conforms to a standard, which is the blueprint’s counterpart of a
product. See core entities for where both registries sit in the fleet
model.
-
Kind classifies what the product is: a device (a physical unit), an app (software), or a service (something hosted). There is no default: kind is required at create, so a mislabeled cloud service never reads as correct through a silent fallback. It is a closed set; a value outside it is refused (422), and the retired vm value folds into app (nothing forked on a virtual machine that did not fork the same way on any other app).
-
Type classifies the product under a component type (required): the device-class genus (
display,dsp,mic, …) that carries the naming stem a generated component name uses, the console glyph, and the hostname abbreviation. Three generic types (generic-device,generic-app,generic-service) exist for anything not yet modeled more specifically. It is also what a role assignment checks: a component fills a slot only when its product’s type falls within a type the role accepts (self or a descendant), and, if the role pins specific products, only when its product is one of them. That guard runs once, at assignment; afterward the occupant keeps its slot unless its own health verdict goes to outage (a lesser alarm degrades it but does not cost it the slot); see Work with an entity. -
Icon is an optional override on the type’s icon: unset, a product’s glyph is whatever its type resolves to (walking up the type’s own tree if the type itself leaves its icon blank); set, the override wins. A per-SKU glyph is the exception, not the rule.
-
Vendor, driver, and parent are each optional pointers: the vendor that makes the product, the driver that talks to it, and a parent product it is a variant of (see below). Each must resolve against the vendor / driver / product catalogs; an unknown reference is refused (422). These three are nulled if their target is deleted, not blocked: removing a vendor clears the product’s vendor pointer rather than blocking the vendor delete.
-
Variants use parent product: a specific SKU that inherits from a base product points at it with
parent_product_id(a trim or regional variant of the same model). A product with no parent is a base product. -
New product (with
product:create, an admin permission) opens a create drawer: give it a name (unique tenant-wide, e.g.kestrel-vroom) and a label, pick its kind (defaults to device) and its component type, and, optionally, its vendor, driver, and parent product. -
Pick a row to open its detail blade. The footer Edit pencil (with
product:update) edits the label, vendor, driver, kind, type, and parent; the name is fixed, since a catalog row carries no rename. Delete (withproduct:delete) removes the row, behind a confirm. A verb you lack greys just that button, its hover reason naming the permission (Requires product:update,Requires product:delete); the pair never disappears. -
An official row is always read-only: the blade keeps the Edit and Delete pair in place, greyed, with the reason on hover: “Official: ships with Omniglass and updates with it.” Omniglass ships a starter set of official products, upserted idempotently at boot so the shared set cannot drift install to install; add a custom product for anything else. Like the vendors they come from, the SKUs are fictional, each shaped like the real device class it stands for. The shipped set, rendered from the seed itself (its declared-property contract included):
Product Vendor Driver Kind Declared properties boreal-edge-55(Boreal Edge 55)borealsnmp-genericdevice serial-numberfirmware-versionmodel-number= "Edge 55"boreal-edge-65(Boreal Edge 65)borealsnmp-genericdevice serial-numberfirmware-versionmodel-number= "Edge 65"boreal-edge-75(Boreal Edge 75)borealsnmp-genericdevice serial-numberfirmware-versionmodel-number= "Edge 75"boreal-edge-86(Boreal Edge 86)borealsnmp-genericdevice serial-numberfirmware-versionmodel-number= "Edge 86"boreal-edge-98(Boreal Edge 98)borealsnmp-genericdevice serial-numberfirmware-versionmodel-number= "Edge 98"boreal-beam-340(Boreal Beam 340)borealsnmp-genericdevice boreal-cast-m1(Boreal Cast M1)borealhttp-jsondevice kestrel-vroom(Kestrel VRoom)kestrelkestrel-apidevice serial-numberfirmware-versionmodel-number= "VRoom"kestrel-relay-c1(Kestrel Relay C1)kestrelkestrel-apidevice kestrel-gaze-p2(Kestrel Gaze P2)kestrelkestrel-apidevice lyra-arc-a2(Lyra Arc A2)lyrasnmp-genericdevice lyra-hx-1(Lyra HX-1)lyrasnmp-genericdevice lyra-gn-12(Lyra GN-12)lyradevice meridian-mx-84(Meridian MX 84)meridiansnmp-genericdevice meridian-xl-1(Meridian XL-1)meridiansnmp-genericdevice newtron-panel-7(Newtron Panel 7)newtronnewtron-nvpdevice newtron-slate-5(Newtron Slate 5)newtronnewtron-nvpdevice newtron-core-3(Newtron Core CP-3)newtronnewtron-nvpdevice polaris-dsp-16(Polaris DSP 16)polarissnmp-genericdevice polaris-amp-4100(Polaris Amp 4-100)polarissnmp-genericdevice polaris-sky-c6(Polaris Sky C6)polarisdevice tessellate-census-c1(Tessellate Census C1)tessellatehttp-jsondevice generic-device(Generic Device)device generic-app(Generic App)app generic-service(Generic Service)service -
Delete enforces the referential guard the leaf catalogs deferred: a product still referenced by a component (
component.product_id) cannot be deleted (409), the same delete-refused-while-referenced rule the Location Types registry enforces. Remove or repoint the component first. An official row is still refused (422) regardless.
Minting a product is admin-gated, and the product form is where the vendor and driver
catalogs are finally consumed, as the pickers that choose a product’s vendor and driver. The same
operations are omniglass product list/get/create/update/delete from the CLI
(see the CLI reference).
Declared properties: the product’s contract
Section titled “Declared properties: the product’s contract”A product’s blade also carries a Declared properties panel, the product’s contract: which properties every instance of the product exposes, and what each one defaults to. It is half of “the product is the source of a component’s shape”: the type says what the product is, the contract says what it carries.
- Declare a property (with
product:update) picks a name from the property catalog, optionally types a default, and optionally marks it required. The property must already exist in the catalog, since the contract only names it: mint it under Catalog, under Telemetry: Properties first. Declaring is idempotent, so declaring a property already on the contract revises that line in place rather than adding a second. - The default is typed by the catalog, not here. The panel labels the input with the property’s
data type, coerces what you type to it, and refuses a value that will not parse. Type and validation
live on the property, so a product cannot redefine what
serial-numbermeans, only what a fresh instance of that product starts with. - Required means an instance must resolve the property to a value. A component of the product cannot save with a required property empty (see set a property on an instance).
- Withdraw (with
product:delete, from the blade’s edit mode, so the pencil’sproduct:updateis also in the path; behind a confirm) removes a line from the contract. Components keep any value they set for it; the value simply reads as off contract from then on, since nothing declares it any more. - An official product’s contract is read-only, like the rest of the row: each shipped product’s declarations are the ones the table above lists, and they come with the release.
From the CLI the contract is omniglass product property list boreal-edge-55,
omniglass product property update boreal-edge-55 <property>, and
omniglass product property delete boreal-edge-55 <property>.