Skip to content

fix(align): stream JSONL + support sensing_update format (unblocks ADR-079 P8)#641

Merged
ruvnet merged 1 commit into
mainfrom
fix/align-ground-truth-streaming-and-sensing-update
May 19, 2026
Merged

fix(align): stream JSONL + support sensing_update format (unblocks ADR-079 P8)#641
ruvnet merged 1 commit into
mainfrom
fix/align-ground-truth-streaming-and-sensing-update

Conversation

@ruvnet

@ruvnet ruvnet commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

Two real blockers found while running ADR-079 P7→P8 end-to-end for the first time against a 30-min paired session:

  1. Node V8 string limit (~512 MB) on the 750 MB CSI recording. fs.readFileSync(_, 'utf8').split('\n') errored with `Cannot create a string longer than 0x1fffffe8 characters`. Replaced `loadJsonl` with a 1 MiB byte-buffer streaming reader that decodes line-by-line.
  2. Schema mismatch with the current sensing-server. The aligner filtered on legacy `raw_csi` / `feature` types; the live server emits a single `sensing_update` record per tick (with `nodes[].amplitude` and top-level `features`). Result: 0 frames matched every time. Added a `sensing_update` branch that projects each tick into rawCsi/features entries the existing windowing logic can consume, and updated `extractCsiMatrix` to use already-extracted amplitudes when `iqHex` is absent. `timestamp` is now accepted as either ISO string or numeric float-seconds.

End-to-end verified: 1,077 paired samples produced at `--min-confidence 0.3 --window-frames 20`; downstream `train-wiflow-supervised.js` runs to completion.

The PCK gap that came out of this run (0% on every joint, more data + GPU needed) is tracked separately in #640 — those are training concerns, not aligner concerns.

Test plan

  • Aligner produces 1,077 paired samples (`[56, 20]` shape) from the 30-min P7 session
  • Memory stays bounded — no V8 string limit error
  • Training script consumes the paired output successfully end-to-end
  • Reviewer: spot-check that no schema fields were dropped

🤖 Generated with claude-flow

Two blockers discovered while running ADR-079 P7→P8 end-to-end against
a 30-minute paired session (39,088 GT frames + 45,625 CSI frames):

1. `readFileSync(_, 'utf8').split('\n')` hit Node's `String.MaxLength`
   (~512 MB) on the 750 MB CSI recording. Result:
       Error: Cannot create a string longer than 0x1fffffe8 characters
   Replaced loadJsonl with a 1 MiB byte-buffer streaming reader that
   decodes line-by-line, so memory use stays bounded by the largest
   single record.

2. The sensing-server has long since switched from the legacy `raw_csi`
   / `feature` typed records to a single `sensing_update` record per
   tick (with nodes[].amplitude and top-level features). The aligner
   filtered on the old types and produced 0 frames every time. Added a
   `sensing_update` branch that projects each tick into rawCsi/features
   entries the existing windowing code can consume, and updated
   extractCsiMatrix to use already-extracted amplitudes when iqHex is
   absent. timestamp is now accepted as either ISO string (legacy) or
   numeric float-seconds (current).

End-to-end verified: produces 1,077 paired samples at
`--min-confidence 0.3 --window-frames 20` from the full 30-min
recording; downstream `train-wiflow-supervised.js` runs to completion.
See follow-up #640 for the PCK gap (data + GPU needed) — those are
training concerns, not aligner concerns.
@ruvnet ruvnet merged commit ef20a72 into main May 19, 2026
13 checks passed
@ruvnet ruvnet deleted the fix/align-ground-truth-streaming-and-sensing-update branch May 19, 2026 18:51
ruvnet added a commit that referenced this pull request May 21, 2026
Motivated by #499 (multi-node double-skeletons) which PR #491 stopped
the bleeding on but didn't take to the WiFi-CSI literature's state of
the art. Designs a learned counter that replaces today's slot
heuristic + dedup_factor knob, reusing the primitives we've already
shipped this week:

  * Candle / RTX 5080 training pipeline (proven yesterday, 2.1 s for
    400 epochs on pose_v1.safetensors)
  * HF presence encoder as initialization (architectures compatible,
    unlike the pose head case)
  * ruvector-mincut (Stoer-Wagner) for multi-node fusion upper-bound
  * Cog packaging spec (ADR-100) + edge module registry (ADR-102)
  * Paired-data pipeline (PR #641 streaming-safe align-ground-truth.js)
    — `n_persons` labels come for free; no new data collection
    campaign required to bootstrap.

Architecture:
  per-node CSI [56×20] -> frozen HF encoder -> 128-dim embedding
                                          \
                                           > count head (softmax {0..7})
                                           > confidence head (sigmoid)
  N nodes' distributions -> confidence-weighted log-sum
                         -> Stoer-Wagner min-cut upper-bound clip
                         -> { count, confidence,
                              count_p95_low, count_p95_high,
                              per_node_breakdown }

Compares the proposal explicitly against WiCount / DeepCount /
CrossCount / HeadCount published numbers and is honest about the
hardware gap (their 3x3 MIMO research NICs vs our 1x1 SISO ESP32-S3).

v0.1.0 acceptance gates target >=80% within-+/-1 same-room and
>=60% cross-room — modest on purpose; bounded by the same paired-
data scarcity #645 documents for pose. The framework is the
deliverable; the accuracy follows the data.

Includes:
  * Architecture diagram in ascii
  * Comparison table vs published WiFi-CSI counting SOTA
  * Per-failure-mode mapping from #499 symptoms to how the
    learned counter addresses each
  * v0.1.0 + v0.2.0 acceptance gates with measurable thresholds
  * Repo layout for the new `v2/crates/cog-person-count/` crate
  * Five-step migration plan from this ADR -> first GCS release

Status: Proposed. Implementation follows in the same incremental
pattern ADR-101 used: scaffold-cog PR -> train+publish PR ->
server-wiring PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant