Merge order for the 2026-09-04 cohort: four PRs that merge clean in sequence, and why several contain each other
The ask
Merge #1806. It is one commit, server-side only, purely additive, and has no dependencies. That single merge is what unblocks the rest of this cohort.
If you want to go further in one sitting, this sequence merges clean and compiles at the end — I verified it rather than assuming it:
#1806 → #1805 → #1828 → #1823
Nothing else in this issue needs anything from you. Everything after #1823 is mine to rebase, and I will.
What the cohort is for
These are not six unrelated features that happened to be opened on the same day. They are one arc, and it is already written down in your tree: ADR-345, merged in #1862.
ADR-345 measured why device-free position estimation kept failing here, from two directions. Phase is unusable — common-mode phase is re-randomized every packet by packet-detection timing quantization, about 120 full wraps, and measured across ~40,000 frames it is statistically indistinguishable from uniform random. Amplitude works but had no parallax: the three AP → node links sit inside a 36.5° fan. Its answer is to model CSI per link (receiver, transmitter) rather than per node, because node-to-node links cross at 108.7° — roughly 3× the parallax — "with both endpoints known, fixed, and under our control."
Each PR in this cohort is one clause of that sentence:
| PR | what it makes possible |
|---|---|
| #1806 / #1805 | A measurement gets a link identity. ADR-345 measured that on node 2 the AP was only 34% of frames; the other 66% were peer frames the sink could not attribute, because the v1 wire carries no transmitter address. |
| #1828 | CSI is modelled per link instead of per node. MEASURED 2026-09-01: links 31 → 137, transmitters 10 → 32, illuminators heard by two or more receivers 1 → 24. No firmware or network change — those frames were always arriving. |
| #1823 | "known" — ADR-345 computes its bearings from room_config.json, so that file is load-bearing. This turns it from a CLI flag over an assumed rectangle into a real building: storeys, walls, and the actual footprint. |
| #1833 | "fixed" — of everything the fleet now hears, which transmitters can be trusted to stand still? A neighbour's router is fixed; a phone in a pocket is not, and an emitter that moves teaches an association that is only true while it stands still. |
| #1834 | Seeing it. A geometry error is invisible in JSON and obvious in a picture of the building with the fleet and the illuminators in it. |
What this cohort does not claim. ADR-345's own status line is "measurement layer implemented and validated on hardware; localization not built", and nothing here changes that. None of these PRs makes position work. They build the representation that any attempt at position would need, and they are honest about the two negative results — phase and scalar energy weighting — that closed the earlier attempts.
That is also the argument for starting at #1806: it is the first clause, and nothing downstream of it means anything until a measurement can say which link it belongs to.
Why several of these PRs contain each other
Thirty-two of my open PRs were opened on 2026-09-04 as one batch, and a reviewer opening any one of them finds commits that also appear in three others. That is worth explaining, because it looks like five independent attempts at the same work and it is not.
GitHub will not let a pull request from a fork use another fork branch as its
base. Every PR I open has to be based on ruvnet/RuView@main. When change B
depends on change A and A has not merged yet, B's branch has to carry A's
commits or it does not compile — so the duplication is forced by the fork
workflow, not a packaging choice. Stacked PRs would solve it and are not
available to me.
The practical consequence is the useful part: once a prerequisite merges,
the duplicate commits cost nothing. git rebase drops them by patch-id
automatically, so the dependent PR shrinks to its unique commits without
anyone resolving anything.
What contains what
Shared commits, identified by git patch-id --stable so this is content
identity and not a matching subject line:
| patch-id | commit | appears in |
|---|---|---|
b85eb629df8e |
feat(server): parse CSI wire v2 and v3 headers | #1806, #1828, #1833, #1834 |
898a7d25f301 |
feat(server): per-link CSI metrics keyed by (receiver, transmitter) | #1828, #1833, #1834 |
b04ca8aa26d4 |
feat(ui): add Room Builder tab | #1823, #1833, #1834 |
59e460beac67 |
test(sensing-server): cover room-builder config validation | #1823, #1833, #1834 |
dd02ff7492a4 |
feat(room): storeys, walls and AP placement | #1823, #1833, #1834 |
b04e9921809e |
feat(room): draw the building's footprint | #1823, #1833, #1834 |
5ef151f4461e |
feat(emitters): four-state triage | #1833, #1834 |
Bold marks the PR that owns the commit — the smallest one it appears in, and the one worth reviewing it in.
Reading that as set containment:
- #1806 — wire v2/v3 parser. Owns nothing else. One commit.
- #1805 — the firmware half of the same wire change. Independent of the
server tree (touches
firmware/only), but it should land after #1806: #1806's own commit message says the server must parse v2/v3 before any node starts emitting it, so there is never a moment where a node sends something the server rejects. - #1828 — per-link CSI metrics. Carries #1806.
- #1823 — Room Builder, storeys, footprint. Independent of all of the above; overlaps nothing in #1806 or #1828.
- #1833 — emitter triage. Carries #1806 + #1828 + #1823's four commits.
- #1834 — 3D view. Carries all of #1833 plus one new file,
ui/world3d.html.git diffbetween the two PR heads is exactly that one file;main.rsis the same blob on both.
The sequence, verified
Merged in this order against origin/main at dd02efe2:
| step | result |
|---|---|
main + #1806 |
clean — 1 file, +152 |
| + #1805 | clean |
| + #1828 | clean — 2 files, +1554 |
| + #1823 | clean — 7 files, +3093 |
and the result compiles: cargo check -p wifi-densepose-sensing-server --no-default-features exits 0 in 2m10s, with no new warnings.
That last line is the one I would not have claimed a week ago. I told you on #1823 that a branch "merges cleanly but does not compile against current main", so a clean merge is not evidence of anything on its own. This one was built.
Reproducer:
git fetch origin refs/pull/1806/head:prs/1806 refs/pull/1805/head:prs/1805 \
refs/pull/1828/head:prs/1828 refs/pull/1823/head:prs/1823
git checkout -B chain origin/main
for pr in 1806 1805 1828 1823; do git merge --no-edit prs/$pr || break; done
cd v2 && cargo check -p wifi-densepose-sensing-server --no-default-features
Why this cohort's CI is trustworthy
Most of these PRs show a recent updated date because I re-triggered CI
across twenty-five of my branches on 2026-09-15. main had moved well past
the commit each of them was last tested against, and a green tick earned
against an older main is not a signal either of us should merge on. The
re-run was the only way to find out which greens were real: twenty-three
held, and two turned out to be genuine breaks against current main that
the stale tick had been hiding.
main has moved twelve commits since that sweep (45fc41ac → dd02efe2),
so those results are one base-move old again. That is why the sequence above
is verified by merging and compiling against dd02efe2 directly rather than
by pointing at a CI tick — the claim is about today's main, not about a
run from last week.
If re-triggering that way is disruptive to how you track the queue, say so and I will keep these fresh some other way.
After that
#1833 merges clean into main today, and stays clean after #1806. It
conflicts once #1828 or #1823 land — 3 and 13 conflict markers
respectively, all of them in main.rs. That is expected and it is my problem,
not yours: when #1828 and #1823 are in, I rebase #1833 and #1834 onto the new
main and force-push my own branches. Both shrink to their unique commits —
#1834 to a single file — and I will not ask you to resolve anything.
What I am not asking for
I am not asking you to review thirty-two PRs, and I am not asking for any of these to be merged unreviewed. #1806 is the one decision this issue is really about; the rest is a map so that whenever you do get to the others, none of the time goes into working out why the same commit is in four places.
Generated by Claude Code
Source: ruvnet/RuView