f95e8b8ecb
Closes #1. Generator (scripts/flow2json.py): - Emit all nodes at top level with z field (no wrapped tabs) - Set icon: "" on ui-button to avoid Dashboard 2.0 prependIcon TypeError - Set z field on ui-* widgets so they render in Dashboard 2.0 SPA - Use ui-text label from spec, not name Policy (policy/flow.rego) — 9 new deny rules: - deny_wrapped_tab: tab with internal nodes[] (nodered 5.0 bug) - deny_missing_wires: missing or non-array wires (Flow.js rewireNode crash) - deny_no_autoconnect: mqtt-broker must reconnect - deny_invalid_protocol: protocolVersion must be 3/4/5 - deny_unused_broker: broker declared but never referenced - Plus deny_broker_port / deny_group_ref / deny_page_ref / deny_wire_ref refinements Flow (zigbee-monitor.*): - 22-node flat flow: button-in → btn-filter → 4 parallel plug-outs - 4 ui-text widgets + ui-button for permit-join (60s) - Renamed plug: "Laser & Fog" → "DJ Booth" (matches z2m friendly_name) Repo hygiene: - justfile: fix host IP 192.168.9.147 → 192.168.81.147, /ui → /dashboard - README.md: document 8 generation invariants and rule table Verified end-to-end: publishing {"action":"single"} on zigbee2mqtt/Door Button triggers {"state":"TOGGLE"} on all four .../set topics including the renamed DJ Booth. 462/462 conftest tests pass.