Journey event  ·  10 Sep 2026

Add and remove devices per space, with the driven/switched/known tier

plan-spatial-layout-2026-09-10.md S3, shipped in commit 4e21bab. space_device already allowed N devices per space, so what this adds is the part that keeps the list honest. §2's ru

  state copied from the tracker, never improved

  event date 2026-09-10

Event date 2026-09-10
Version found
Version fixed
Expected kit firmware
Release file
SHA-256
Served count
Source https://app.notion.com/3d62b4cda3708168be4dce14afc078c3

plan-spatial-layout-2026-09-10.md S3, shipped in commit 4e21bab. space_device already allowed N devices per space, so what this adds is the part that keeps the list honest. §2’s rule: a device the brain can PLACE is not necessarily one it can DRIVE. The hub has a fixed number of PWM channels and relays; past those a fan is on a smart plug, or simply present. Three tiers: driven (sets level, reads back), switched (on/off via plug), known (not controlled at all). All three cost power and move air; only one has a control. kind/role/tier/binding live in extra beside catalog_id — the pattern the SF1000 set — so no migration. The pair that cannot be fudged is validated IN THE STORE, not just the form: a driven/switched device is defined by having something to drive, a known one by having nothing; either violation is refused. device_controllable treats an UNSET tier as NOT controllable, so a row that has not said what it is gets no control rather than one that silently does nothing. Also shipped: DELETE route, GET /spaces/device-tiers (so the desk cannot invent a tier), and a ‘Devices in each space’ settings card with add / remove / retier / inline binding edit. BACKFILL: ensure_kit_spaces only INSERTed when a device was absent, so the new tier defaults never reached an existing install (the Pi included) and the card would have shown two ‘tier not set’ rows for kit we know the answer for. It now fills in only the ABSENT keys — an operator’s watts and an operator’s tier both win over the defaults. TWO BUGS FOUND BY DRIVING THE UI, NOT THE TESTS: 1. upsert_space_device is reached as a PATCH (the desk sends one field) but defaulted every absent field, so promoting a 35 W fan from known to switched SILENTLY ZEROED ITS WATTAGE. Absent keys now keep what the row holds; an explicit 0 is still reachable. 2. The tier chips could never succeed on a device added as known — the error correctly said ‘needs a binding’ with nowhere to type one. The binding is now an editable field on the row. Also: the remove dialog said ‘a driven device keeps running’ for a switched one (deviceControllable covers both). It names the device’s own tier now. Brain suite 675 pass; add / retier / remove driven end to end in the browser; clean console on a fresh load. NEEDS VERIFICATION: not deployed to the Pi.

All events  ·  DSC  ·  CannaLib  ·  Site  ·  Firmware releases

Empty rows are honest

A blank cell means the tracker has no value for it. Nothing on this page is filled in to look complete.