filtering: hiding is an explicit per-device flag (docs/FILTERING.md)

Agreed with the owner: whether a device is on the plan is a CHECKBOX
('Hide device from plan', every kind incl. virtual), not a runtime
algorithm. The old filter survives only as the SEEDER of those flags.

- marker.hidden is the flag; hidden devices are BUILT (room LQI counts
  them — owner's decision) but rendered only in the device editor with
  'Show hidden' on, ghosted. They cast no glow and no light fill: an
  invisible device casts no visible light (owner's decision).
- seedHiddenBindings(): non-physical devices (excluded domains, Group,
  scene, bridge, myheat children, grouped lamps) in bound areas WITHOUT a
  marker. The editing client materialises them into hidden:true stub
  markers, sets settings.filter_seeded, retires settings.show_all, and
  strips fresh-hidden ids from the red-dot list. Unticking the checkbox
  keeps a hidden:false marker — the seeder never revisits a marked device,
  so the user's decision is final. New non-physical devices hide silently;
  physical ones keep the red-dot flow.
- legacy configs (no filter_seeded) keep the OLD behaviour verbatim —
  runtime filter, shared show_all, hidden-means-gone — until an editing
  client materialises them, so a read-only tablet never sees a half-state.
- 'Show all' is renamed 'Show hidden' and is LOCAL to the tab; the shared
  settings.show_all retires with the runtime filter.
- 'Remove from plan' disappears for auto/entity devices (the checkbox is
  the way); a virtual device's Delete remains a real deletion.
- docs/FILTERING.md is the source of truth for the mechanism.

Tests: seeder/seeded/legacy/lights units (146), smoke_hidden_flag with 12
assertions (68 smokes). Inventory: 146 / 51 / 43 / 68.
This commit is contained in:
Matysh
2026-07-29 11:35:35 +03:00
parent 996a7442ec
commit 694e1e9a3b
13 changed files with 457 additions and 101 deletions
+61
View File
@@ -0,0 +1,61 @@
# Filtering: the explicit "hide from plan" flag
Agreed with the owner 2026-07-29. This document is the source of truth for the
mechanism; the code follows it.
## Principle
Whether a device is on the plan is an EXPLICIT, per-device fact: the
"Hide from plan" checkbox, stored as `marker.hidden`. The old on-the-fly
filtering algorithm survives only as the SEEDER of those flags — it decides
the initial value once, and the user owns the flag from then on.
## Data model
- `marker.hidden: true` — hidden from the plan. For an auto device without a
marker, hiding creates a stub marker (this mechanism predates this spec).
- `marker.hidden: false` (marker present) — explicitly VISIBLE: the seeder
never touches a device that has any marker, so unhiding must KEEP the stub
marker. That is the re-seed protection.
- No marker — never evaluated by the seeder yet, or a plain physical device.
- `settings.filter_seeded: true` — this config has been materialised.
- `settings.show_all` — removed (deleted during materialisation). The old
toggle was shared config state; the new one is a local editor tool.
## Seeding
"Non-physical" = the old filter rules: excluded integration domains, model
"Group", scene-like models, bridges, myheat children, and individual lamp
devices in an area covered by a light group (when group folding is on).
The seeder runs on the editing client (write permission required) whenever
devices rebuild, and creates `hidden: true` stub markers for non-physical
devices in BOUND areas that have NO marker. It is idempotent: marked devices
are never revisited. It fires on:
1. first load of a config without `filter_seeded` (materialises the current
behaviour; nothing changes visually, the flags become real and editable);
2. an area newly bound to the plan;
3. a new device appearing in a bound area — non-physical ones are hidden
silently (no red dot); physical ones keep the red-dot flow.
Until a config is seeded (`filter_seeded` absent), `buildDevices` applies the
LEGACY runtime filter, so a read-only client on an old config sees exactly
the old behaviour until an editing client materialises it.
## Behaviour
- Hidden devices ARE built (flagged `hidden`), but not rendered in any mode,
except the device editor with "Show hidden devices" on — there they render
ghosted (translucent, dashed) and clicking opens the dialog to untick.
- "Show hidden devices" (rename of "Show all") is LOCAL, ephemeral state of
the current tab.
- Room LQI counts hidden devices (owner's decision).
- Light fill and glow do NOT count hidden devices — an invisible device casts
no visible light (owner's decision). Room climate is registry-wide and
unaffected, as before.
- The checkbox appears in the dialog of EVERY device kind, virtual included.
- "Remove from plan" disappears for auto/entity devices (the checkbox is the
one way to hide); a virtual device's "Delete" remains a real deletion.
- Duplicate names are still numbered, light groups still fold — those are
aggregation, not hiding.