DEVOURER_TX_REPORT=N: sampled CCX reports — deterministic coverage under the fw emission ceiling (#363 step 2) - #369
Conversation
…erage under the fw emission ceiling The CCX emission path saturates at ~1.3-1.4k reports/s, so per-frame SPE_RPT above ~1.25k fps collapses coverage load-dependently (53-56% at 2.4k fps). The report knob is now the sampling divisor N: request a report on every Nth frame (0 = off, 1 = every frame — the previous semantics unchanged), while the halmac SW_DEFINE tag still stamps EVERY frame, so received-tag deltas are exact multiples of N and any other delta is a dropped report. On the 8812 report format (no tag echo) sampling only relieves the rate; a new per-device counter drives the cadence there. Measured (2.4k fps, on air): N=1 control collapses to 56.4% (achieved 1,329 rpt/s — the ceiling again); N=2 delivers 100.0% of the sampled reports (191,298/191,323, zero lost, zero off-modulo anomalies, achieved 1,107 rpt/s) and the sampled ok-rate reads 99.71% against a 99.99% ledger truth — pessimistic by the ACK-loss asymmetry, the safe direction. N=1 at 1k fps is byte-for-byte the old behaviour: 99.9% coverage, no tag gaps, and the arq_e2e verdict stays acked_undelivered=0. txrpt_coverage_attrib.py gains --sample-n (expected-delta accounting: k*N = k-1 sampled reports lost, non-multiples flagged as anomalies); arq_e2e_delivery.sh gains the DRONE_REPORT_N passthrough; docs/scheduled-mac.md documents the knob next to the measured envelope. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoDEVOURER_TX_REPORT as sampling divisor for deterministic CCX report coverage
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
Code Review by Qodo
1.
|
…ation, aggregation.md caught up - The 16-bit tag counter's wrap at 65,536 jumps the sampling phase for any N that doesn't divide it — off-modulo tag deltas masquerading as dropped reports at every seam; J1's 32-bit request counter hits the same seam in ~20 days at field rates. Both are 64-bit now (seam unreachable); the tag byte and checksummed-span handling are unchanged. - The sampled expectation ceils (the request fires on k%N==0, frame 0 first) — odd totals no longer undercount by one. - docs/aggregation.md's tx.report paragraph carries the divisor semantics and the ceiling instead of "every descriptor". Validated: 48/48 ctest; on-air N=2 smoke under the widened counters — sampled-coverage 100.0% (82,465/82,490 with the ceil expectation), zero lost, zero off-modulo anomalies. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…he rx.seq ledger (#363 step 3) (#370) Closes #363. ## The tier this completes The ARQ campaign established the two lower tiers' limits: the hardware ACK's horizon is chip-FIFO admission (it can never confirm host delivery — #359), and per-frame CCX reports collapse against the fw's ~1.3 k reports/s emission ceiling (#368, sampled in #369). This PR adds the tier neither can reach: **the receiving application counts what it consumed and mails it back.** - `src/cell/RxReceipt.h` — `ReceiptWindow` (receiver: sliding ring bitmap over the last W frame indices) + `ReceiptLedger` (transmitter: idempotent merge of overlapping, versioned receipt TLVs; strict-prefix parse; absorbs only receipts naming its own TA). Same caller-side contract as `UeRxAttribution`: demos feed frames, RX loops untouched, no payload convention assumed. - duplex: notes on the existing `rx.seq` path, injects a receipt frame every `DEVOURER_RX_RECEIPT_MS` on the feedback path (802.11 data at 6M; concurrent `send_packet` callers serialize on a demo mutex). `DEVOURER_RX_RECEIPT_WINDOW` sizes coverage (default 8192). - txdemo: `DEVOURER_TX_RECEIPTS` absorbs and emits **every** receipt as `tx.receipt` with the raw TLV hex. - `tests/receipt_verify.py`: replays the TLV merge and demands **set-equality** with the receiver's own `rx.seq` ledger — the issue's acceptance bar, literally. - `receipt_roundtrip` ctest selftest; `RECEIPT_MS` knob in the arq harness; docs (logging.md rows, scheduled-mac.md tier paragraph). ## Measured (on air) | regime | frames verified | receipts | verdict | |---|---|---|---| | clean, 5 cycles | 126,594 | 1,671 | **FRAME-EXACT** | | 150 ms consumer stalls @ 2.4 k fps, spsc-fat parking ring | 349,455 | 1,330 | **FRAME-EXACT** | ## Two bench-taught lessons, in the code 1. **Received bodies carry the trailing FCS** — the first live run absorbed zero receipts because the TLV parse demanded exact length; an ACK frame logging `len:14` (10 + FCS) was the tell. The parse is strict-prefix now, with the TA-match keeping arbitrary payloads out. 2. **The window must exceed the worst backlog drain in frames** — with a 2,048-bit window, a stalled spsc-fat pool draining ~3 k frames inside one receipt interval evicted 2,846 delivered frames before any receipt covered them (`MISSING` in the verifier, `late=0` — eviction, not reordering). The sizing rule is at the class comment: `window_bits > pool_bytes / min_frame_bytes + one encode interval of arrivals`; the 8192 default clears this bench's worst case ~2.7×. ## Validation `ctest` 49/49 (new selftest included); four on-air runs (first-light smoke, full-scale clean, failed 2048-window stress — kept as the sizing lesson — and the passing 8192-window stress). The verifier's `NO-RECEIPTS` and `MISMATCH` paths were both exercised for real during bring-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Step 2 of #363 (step 3, windowed RX receipts, remains).
What it does
The report knob becomes the sampling divisor N: SPE_RPT is requested on every Nth frame (0 = off, 1 = every frame — previous semantics unchanged), while the halmac SW_DEFINE tag still stamps every frame. Received-tag deltas are therefore exact multiples of N; any other delta is a dropped report (k·N = k−1 sampled reports lost, non-multiples are anomalies). On the 8812 report format (no tag echo) sampling only relieves the rate, via a new per-device counter.
Spec derived in #368: the CCX emission path saturates at ~1.3–1.4 k reports/s, so pick N ≥ fps/1300 and coverage of the sampled frames is deterministic instead of load-collapsed.
Measured (on air, 2.4 k fps)
Statistical-accounting check: the N=2 sampled ok-rate read 99.71% against a 99.99% ledger ground truth — pessimistic by the known ACK-loss asymmetry (
ok=0-but-delivered), the safe direction for a delivery-accounting consumer.Changes
DeviceConfig::Tx::reportbool → int (doc-tagged with the ceiling + the N ≥ fps/1300 rule); env parse clamps 0..255 (tag-unwrap ambiguity bound)._tx_ccx_ctrdrives the cadence.tests/txrpt_coverage_attrib.py --sample-n— expected-delta accounting for sampled ledgers.tests/arq_e2e_delivery.sh—DRONE_REPORT_Npassthrough.docs/scheduled-mac.md— the knob documented next to the measured envelope, favourable and adversarial numbers together.Validation
Three fresh on-air runs (money/control/regression above);
ctest48/48; existing matrix scripts unaffected (they pinDEVOURER_TX_REPORT=1, whose semantics are unchanged).🤖 Generated with Claude Code