Conversation
New tab (index.html nav + section, wired in app.js following the same
container-lookup + component pattern as the other tabs) backed by
GET/POST /api/v1/config/room. A 2D top-down canvas: set room width/
depth, add/remove sensor nodes, drag them into place or type exact
X/Y/Z, save. Save applies immediately (live, no restart) and persists
to room_config.json, which future launches load automatically -
replacing the --node-positions CLI-only workflow.
Metric/imperial unit toggle (display-only - this.config and everything
sent to the API always stay in meters, remembered per-browser via
localStorage). Compass badge + explanatory text establishing (0,0,0)
as the room's Northwest corner, +X = East, +Y = South, so placements
can be oriented to the real room.
Rows are matched to their node by array index rather than by id -
id is itself one of the editable fields, and using it as the lookup
key meant renaming a node into an id already in use broke the row<->
node link (two rows silently reading/writing the same node object,
which looked like one node jumping onto or stacking with another).
Duplicate ids are now also caught client-side (warned while editing,
hard-blocked on save) ahead of the server's own validation, and a
server-side validation rejection (200 OK with an {"error": ...} body,
not a failure status) is now checked for explicitly rather than
silently treated as a successful save.
Co-Authored-By: claude-flow <ruv@ruv.net>
(cherry picked from commit 4cc202a)
Extracted POST /api/v1/config/room's validation into a pure validate_room_config(&RoomConfig) -> Result<(), String> function so it's unit-testable without a full SharedState/axum harness; behavior unchanged, the handler just delegates to it now. 9 new tests: load-missing/malformed-file defaults, save+load round trip, and validation for non-positive/non-finite dimensions, non-finite node coordinates, duplicate node ids, and an empty node list. Also adds a "Reload from Saved" button to the Room Builder UI (discards unsaved local edits, re-fetches the live server config). Co-Authored-By: claude-flow <ruv@ruv.net> (cherry picked from commit a3b9907)
Extends the Room Builder from a single flat rectangle to a building: multiple storeys, walls drawn per storey, and a placed access point. Storeys share one origin. The origin (0, 0, 0) is the north-west corner of the first floor at floor level, and every storey is measured from it rather than being re-zeroed, so a node's X/Y means the same thing on every floor and distances between nodes on different storeys are plain Euclidean. Nodes and walls on other storeys are drawn faintly rather than hidden, which is what lets an upper-floor node be lined up against the wall below it. Storey elevation is derived from ceiling height plus subfloor thickness rather than typed in directly, because those are the two numbers someone can actually measure. Heights are entered in inches. A node carries `floor` alongside `z`. That is redundant for geometry and deliberately so: it is what the builder groups by and what walls are associated with, and deriving it from `z` would guess wrong for a node mounted high in a stairwell. `floor` is optional, so a config written before storeys existed keeps working unchanged. Every persisted field is served back by GET /api/v1/config/room. That response body is hand-maintained and will not complain when it falls behind the struct, so it carries a comment saying so at the point where the next field will be added -- a field that is saved but not served looks exactly like "the setting will not stick". Wall entry takes a start and an end and refuses a zero-length wall, which is otherwise easy to stage by double-tapping a corner. Co-Authored-By: claude-flow <ruv@ruv.net>
…ngle The Room Builder modelled a storey as width x depth. Most buildings are not rectangles, and the ones that are not tend to be exactly where the interesting propagation happens: a wing off the main block, an L around a stairwell, a garage bay that swallows a link. Adds a footprint editor. A storey is a polygon of points placed on the canvas rather than two numbers, so a node in a wing has coordinates that mean something relative to the building it is actually in, instead of being placed in empty space outside an assumed rectangle. Width and depth are kept as the polygon's bounding box, so existing configs and anything reading those two fields keep working unchanged. Co-Authored-By: claude-flow <ruv@ruv.net>
…al Vec ruvnet#1791 landed node_positions_config as a positional Vec<[f32;3]> keyed by active-node rank, not the HashMap<u8,[f32;3]> this branch was written against, so the Room Builder handlers stopped compiling. Read path enumerates and derives the id from the index, matching the convention the fusion path uses. Write path builds the vector indexed BY node id before assigning, so a sparse id set still lands each node in the right slot instead of shifting everything after a gap. Co-Authored-By: claude-flow <ruv@ruv.net>
2345a98 to
b5a5db1
Compare
…wrote ruvnet#1823 is a strict superset of ruvnet#1822 and ruvnet#1824 in every line of code, which is why the other two are being closed in its favour. It is not a superset of their *comments*: two rationale blocks from ruvnet#1822 were dropped while the code they explain stayed the same. `config_set_room` builds `positions` as a Vec sized to `max_id + 1` and assigns `positions[n.id]`, rather than pushing in iteration order. That is a deliberate choice -- a sparse or non-contiguous set of node ids still lands each node at the right slot, and a gap stays at the origin instead of shifting every later node one place. Nothing in the code says so, so the next reader sees an oversized allocation and an indexed write and has no reason not to "simplify" it into a push. `config_get_room` lost the second half of the ruvnet#1791 note, which is the part that says what goes wrong: the Room Builder must describe the same binding the fusion path uses, *or the UI shows positions the server is not applying*. A convention without its failure mode is not a reason. Comment-only. `cargo check -p wifi-densepose-sensing-server --no-default-features` passes. Co-Authored-By: claude-flow <ruv@ruv.net>
|
Consolidating the Room Builder work here. #1822 and #1824 are now closed in The three were one body of work opened as three nested variants — Worth recording because it nearly produced the wrong answer: the tip commit The one place this branch was genuinely not a superset was comments, not This PR is now the Room Builder base. Reviewing it unblocks the per-storey |
|
Correction to my note above, from the CI run that comment triggered: this The tip commit here, "follow node_positions_config becoming a positional The last CI run here was 2026-09-04T20:28Z — minutes after the breaking This does not change the consolidation — #1822 and #1824 carry the identical I have not pushed the fix, because the right shape is a decision about the Happy to push that rework here if you would like it in this PR rather than a |
The Room Builder modelled a storey as width x depth. Most buildings are not
rectangles, and the ones that are not tend to be exactly where the interesting
propagation happens: a wing off the main block, an L around a stairwell, a
garage bay that swallows a link.
Adds a footprint editor. A storey is a polygon of points placed on the canvas
rather than two numbers, so a node in a wing has coordinates that mean
something relative to the building it is actually in, instead of being placed
in empty space outside an assumed rectangle.
Width and depth are kept as the polygon's bounding box, so existing configs and
anything reading those two fields keep working unchanged.
Rebased onto current
mainbefore opening: staged before today's seven merges, so it needed replaying to avoid reading as a revert of them. Clean rebase, no files deleted.