Commit Graph
3 Commits
Author SHA1 Message Date
Melvin StroblandClaude Opus 5.5 4701e3a5fb Device security and robustness (openpanel C0): check code, pnc, lenient report
- POST /devices/pair answers a 2-character `check`, listed by /devices/pending
  and shown beside each waiting entry; five codes a minute per address, and at
  50 waiting the oldest gives way instead of a 429
- portal-minted device tokens are asked for with the device's nonce (`pnc`) and
  held against it, so unpair and delete revoke them; one without `pnc` stands
  only while the nonce is 0
- a device credential acts as the device (`device_principal`), not as the
  approving superuser, so deleting that account unpairs nothing
- the report is validated port by port: unknown enum values read as `unknown`,
  unreadable ports and sections are left out and logged, `config` may name an
  entry of `config_schemas`; 422 only for no schema 1 or no object
- devices.json is parsed once per change (cached by stat), delete drops the
  report and keeps the nonce, a busy recheck runs in the background
- scope and io only from enabled flows (start/stop tells the devices), a port
  bound twice gives one io row
- the Devices tab's saves cancel and hold back device refetches until settled

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138N7k5PT4dcR1iEqXaaQ9k
2026-10-16 19:26:05 +02:00
Melvin StroblandClaude Opus 5.5 f8011d2a8a Device node: a device's ports are wired in flows
- flow/nodes/device.py: `device` node with params `device` and `config`;
  provides the device's `in` ports, requires its `out` ports without
  waking anything, never run (Node.passive), down "Offline" from presence
- DeviceDef.io and DevicePort go; GET /devices/{id} computes `io` and
  `bindings` from the device nodes of published flows, in a fixed order,
  cached by FlowStore.revision; the credential's scope comes from them
- issues `unknown_device` and `device_port` (wired twice; against a report
  the wrong direction or dtype, or unlisted as advisory), rechecked when a
  device is created or deleted; ValidationIssue.advisory is a field
- a device publishing on a bound port is credited to its node by the
  server; the panel endpoint kind is gone from `_endpoints` and the canvas
- a rebuild that moves a device's bindings sends `dashboard_changed` with
  an empty name, which the firmware refetches on
- startup moves each device's `io` rows into device nodes in the flows
  declaring their messages, draft and published, one commit; rows no
  flow declares are logged and left out
- frontend: Device node settings (device, Publishes, Follows, a port
  picker from a report), palette shortcuts per reported port, DeviceDetail
  lists bindings with "Use in flow" in place of the I/O editor
- docs: devices, flow editor, node types, issues, API

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 16:40:31 +02:00
Melvin StroblandClaude Opus 5.5 ed06bdec6b Panels become devices: per-device documents in the flow repo, a Devices tab
- flow/devices.py: DeviceDef in FLOWS_DIR/_devices/<id>.json, committed under
  the flow store's write lock, 409 on a stale version; nonces in DEVICES_FILE
  outside git; in-memory presence announced as device_status
- api/routes/devices.py: CRUD, pairing with an optional {name, board,
  firmware}, a pending list adopted without a code from the LAN only, unpair;
  /panels/pair, /panels/pair/{code} and GET /panels/{id} kept as aliases,
  PUT /panels/ gone
- _device_may replaces _panel_may, JWT claims unchanged
- panels.json moves into devices once at startup, then .migrated
- MCP list_devices, get_device; search category device
- Devices tab (list, detail with presence, pairing, ordered dashboards,
  touch, I/O), PanelsDialog removed, serialised optimistic saves

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:48:36 +02:00