Skip to content

Location types

Catalog, under Locations: Types (/location-types, with location_type:read, covered by every viewer’s *:read floor) is the registry of place classifiers: the location_type a location is classified by. It is one registry with one page on purpose; its former home, a tabbed Types page, shared a fetch with the secret type registry, and a viewer without secret:read lost both. The two now stand alone (secret shapes live on Secret Types), and two other kinds left even earlier, because a bare label registry was never what they were: a component’s shape comes from the product it points at, and a system’s from the standard it conforms to.

The page is that registry’s directory: a table of its rows, sorted alphabetically by display name, each showing the name (for example wing), label, an icon glyph key, and its origin (official, custom, or overridden). A type 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.

  • name matches a name or label, and official narrows the list to shipped, yours, or overridden rows.

  • New location type (with location_type:create, an admin permission) opens a create drawer: give it a name (unique within the registry, e.g. wing), a label, an icon glyph key (defaults to map-pin), and its allowed parents: a checkbox list of the other location types plus a Root option, the set of parent types (or the top of the tree) a location of this type may be placed under. Leave every box unchecked for unconstrained (any parent, or root), the default; root is a reserved name no real type may take.

  • Pick a row to open its detail blade. The footer Edit pencil (with location_type:update) edits the label, the icon, the allowed parents, and the naming rule; the name is fixed, since a catalog row carries no rename (:rename is a component, system, location, and principal group affordance). Delete (with location_type:delete) removes the row, behind a confirm. A verb you lack greys just that button, its hover reason naming the permission (Requires location_type:update, Requires location_type:delete); the pair never disappears.

  • The shipped location types are yours to change, and the platform still owns the rows. Relabel them, give them a different icon, or re-parent them: your version is stored over the shipped row rather than replacing it, the row’s origin reads overridden, and Restore default in the blade puts it back. A restart never reverts your edits, and because the platform owns the row underneath, a release can also correct a shipped type or withdraw something it used to ship. Deleting one is refused; restoring is the removal a shipped row admits. See the seed model. The shipped set, rendered from the seed itself:

    TypeAllowed parentsNames
    campus (Campus)rootyou name it
    building (Building)root, campusyou name it
    floor (Floor)building, campusyou name it
    room (Room)floor, building, campusyou name it
  • A type can name its own locations. A location type carries an optional name rule, and having one is the opt-in: without it, every location of that type is named by whoever creates it, which is where all four shipped types stay. None of them carries a rule, because a campus, a building, a floor and a room each have a real-world name you hold and the platform does not, and 17c is a fact rather than a default. So in a fresh install nothing is auto-named on this page until you set a rule yourself.

    A floor is named by you, and the reason is worth a sentence. floor did ship with a positional rule for two releases, so a nameless floor was called 1, then 2. That was withdrawn (ADR-0103): a floor’s designation is not a number in the first place. Buildings sign B2, LG, G, M, 1, 12A, P3, and an allocated ordinal spells none of them, so a floor named 1 in a building whose signage says Level 2 is not a small inaccuracy, it is the wrong kind of value. Name your floors what the signs say (b1, lg, level-2, 12a), and the shipped label rule reads that name back as “B1”, “Lg”, “Level 2”, “12a” without your typing a label at all.

    Where a rule does earn its place is a type whose number is an arbitrary disambiguator rather than a designation anybody reads off a wall: a parking deck, a rack row, a berth, a pad. There the platform picking the next free number saves you inventing one and nothing is claimed about the world. That is the test to apply before setting a rule: if your team reads the number off a sign, type it.

    A rule is a stem plus whether the first of that stem under one parent carries a number. Leave the stem empty and the type is positional: creating a location of it with no name gives 1, then 2, counted among that parent’s own children, so every building has its own deck 1. Give it a stem, wing, and you get wing-1, wing-2, or wing then wing-2 if you suppress the first number. A rule that could produce an illegal name is refused here, when you save the rule (422), never later as a create you cannot explain.

    Set one from the blade. In the detail blade’s Edit mode, the Naming field carries the whole rule: tick The platform names locations of this type, type the name stem (leave it empty for a positional type), and tick No number on the first one under a parent if the only one there should read wing rather than wing-1. Save, and the field reads back the names the rule actually produces, in the platform’s own words: “Named wing, then wing-2, within their parent.” Those two names come from the server rather than from the browser, so what you are shown is what a create will stamp. A stem with a capital or a space is refused at the field, before the save; anything else the platform will not accept comes back on the save with the reason at the top of the blade, and the blade stays open so you can fix it.

    The same rule, from the CLI:

    Terminal window
    omniglass location-type create --name deck --label "Deck" --name-rule '{"stem":""}'

    Editing a rule renames nothing. Every location that already exists keeps its name; the new rule decides how the next one is named. To bring an existing location onto the rule, use its own regenerate name verb, one row at a time and behind location:rename, because a rename breaks the bookmarks and runbooks you keep outside Omniglass. There is no bulk rename, deliberately, and that is the one place this differs from a type’s label rule, which does have a preview-then-apply recompute: a label is display, and a name is an address.

    Reclassifying a platform-named location needs its name claimed first. A name the platform owns is minted from its type’s rule, so changing the type re-mints it, and moving to a type with no rule leaves nothing to mint from: the platform would be left owning a name it can no longer produce. That save is refused (422) rather than quietly handing you the pen. Every shipped type is a type with no rule, so this is the ordinary case rather than a corner: reclassifying a generated deck as a room, a floor, a building or a campus is refused until you claim the name. The way through is two steps, and the refusal names it.

    Terminal window
    omniglass location rename boi.17c.1 --name lobby # the name is now yours
    omniglass location update boi.17c.lobby --location-type room

    Only a platform-named location is affected. One you named yourself was never the platform’s to re-mint, so it reclassifies to anything, and its name comes through untouched. Reclassifying between two types that both carry a rule is fine too: the name is simply re-minted from the new one.

    One thing to weigh before you set one: regenerate name on, say, a building would then mint building-1 over the 17c you typed, so set a rule only on a type whose names you want the platform to own.

    Turning it back off is the same tick box. Clear The platform names locations of this type and save: the rule goes and naming comes back to you, with names already minted left exactly as they are. On the wire it is the field named in update_mask with no rule in the body, which is how every nullable object field clears (an omitted key and an explicit null are the same value once a request is decoded, so the mask is what carries the intent):

    Terminal window
    omniglass location-type update floor --update-mask '["name_rule"]'

    A release can withdraw a shipped rule too, and it reaches your fleet on the next boot: the boot seed writes the shipped types authoritatively, so a value dropped from the shipped set leaves every install rather than only the new ones. If you had overridden the type, your version stands until you restore it.

  • An official row is editable and undeletable: Edit is live (the edit stores your version over the shipped one), and Delete stays greyed with the reason on hover, “Official: ships with Omniglass and updates with it.” Once you have changed one, that slot becomes Restore default, which discards your version and takes whatever the current release ships. The same treatment the component type registry uses, and the reason both registries have it is that a release must be able to correct the vocabulary it ships.

  • Delete is refused (409) while a location still uses that type: reclassify or remove the referencing rows first.

  • A location type is flat: it has no parent, so it inherits nothing and every fact on it is its own. The nested registries beside it, component type and system type, do inherit, and their blades say so: an empty Stem, Abbrev or Icon box shows the value the type would take in grey, and the hint under it names the ancestor that value comes from, which may be further up than the immediate parent. Clearing a box therefore tells you what you just fell back to instead of going blank.

  • A non-empty allowed parents set is enforced when a location is created or moved: an out-of-order placement (for example a floor under a room) is refused with a message naming both types. An empty set never blocks a placement. Existing locations are grandfathered: adding or tightening a set does not touch a placement already made, only a later move.

Minting a type is admin-gated; using one, classifying a location by picking it on the location’s own create or edit form, is the ordinary entity write, gated by location:update. The same operations are omniglass location-type list/create/update/delete from the CLI (see the CLI reference).

Declared properties: the location type’s contract

Section titled “Declared properties: the location type’s contract”

A location type’s blade carries a Declared properties panel, its contract: which properties every location of that type exposes, and what each one defaults to. It is the same editor as a product’s or a standard’s, and it keeps this page’s permission story: the read rides location_type:read, declaring a line needs location_type:update, and withdrawing one needs location_type:delete. Every contract control lives in the blade’s edit mode, so the pencil’s location_type:update is in the path either way.

  • Declare a property picks a name from the property catalog, optionally types a default, and optionally marks it required. The property must already exist in the catalog; mint it under Catalog, under Telemetry: Properties first. Declaring is idempotent.
  • Type and validation are the catalog’s, not the contract’s, so a location type cannot redefine what a property means, only what a fresh location of that type starts with.
  • Locations inherit live. Change a default and every location of the type that has not overridden that property picks up the new value. Withdraw removes the line; locations keep any value they set, now off contract.

From the CLI the contract is omniglass location-type property list <id>, omniglass location-type property update <id> <property>, and omniglass location-type property delete <id> <property>. The registry and its contract are one noun, mirroring the routes (/location-types for the registry, /location-types/{id}/properties for its contract): a hyphen joins a two-word noun, a space means the thing beneath it.