BLO-33456: attribute mmtp gaps instead of bounding them - #26
Conversation
The six 90 s cast sessions show loss spanning 0.0000%-3.7964% at N=1 on an idle path, so no threshold on `mmtp.gaps` is reproducible and none should be set. Attribution is the deliverable. These are the three instruments it needs. 1. Positive control for `lagged_count`. Every existing test asserted it was ZERO, which licenses nothing -- a counter that never increments and a counter correctly reporting no loss read identically, and all six receipts report 0. Mutating `*lagged += skipped` away leaves the old tests green and kills only the new one, which is the point. That zero is now load-bearing: with `/proc/net/snmp` it partitions a gap three ways -- userspace consumer behind (lagged), kernel socket buffer overran (RcvbufErrors), or loss upstream of this host (both zero). None of the three needs a source-side counter, which is what AC3 spent two revisions failing to find. 2. `Udp: RcvbufErrors` delta across the probe window in the workflow. The kernel already counts the cheapest candidate to rule in or out, and `--network host` makes the runner's netns the container's. Labelled off the header line so an added kernel field cannot shift the value onto a neighbour. Netns-wide, not per-socket: noted in-tree, since a small delta is evidence about the netns rather than proof it was us. The existing zero-gap sessions are the negative control, so attribution is by covariation across lossy/clean rather than by a threshold. 3. Absolute `data_started_at_ms` / `data_ended_at_ms` in the receipt. `elapsed_ms` is a monotonic duration with no shared origin, so "were these two probes concurrent?" was not answerable from the receipt at all -- the phase-B pair's overlap had to be reconstructed from GitHub job timings, which are dispatch times and include `docker pull`. Every differential measurement on this stream depends on it. Unix epoch millis rather than RFC3339: no date dependency in this crate, and receipts are compared numerically anyway. Refs BLO-33456, BLO-26574. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
🔗 Paperclip issue: BLO-33456 |
|
@ally please review at head Three instruments for attributing
Not asking you to relitigate the measurement design (that is a CTO ruling on BLO-33456); just the three instruments above. |
|
Merge note — this PR and #25 both rewrite the same region of Verified with a real 3-way merge ( (Worth recording how easy the wrong answer was here: the older Two requirements for whoever resolves:
|
Counts cannot separate the two loss mechanisms this row has now observed. Pair E had two receivers on different /8s report gaps: 501 and 34 runs IDENTICALLY, which fits equally: (a) loss on a leg they share, and (b) the source emitting a discontinuous sequence, in which case nothing was lost. Pair D's arms disagreed 1.97x over the same >=81 s overlap, so localisation is not a fixed property of this path -- at least two mechanisms, dominant at different times (open observation 5). Comparing gap POSITIONS between two concurrent receipts discriminates: identical positions => property of the stream as delivered; disjoint => per-receiver loss below the relay's fan-out. - MmtpLoss.gap_positions: capped list of (pid, after, missing) runs. - MmtpLoss.gap_events: exact run count, counted directly rather than derived as received - tracks - in_sequence. That identity holds only while reordered and implausible are both 0 -- an assumption a loss measurement should not rest on silently. It also carries the mean-burst figure (gaps/gap_events) that this row already leans on. - Cap at 4096 (~19x the densest session measured, 214 runs/90 s) so a pathological stream cannot grow the list without bound under --watch. Truncating the sample never affects gap_events, and is detectable from the receipt as gap_positions|length < gap_events. Tests: positions anchor to the last ARRIVAL and sum to gaps; two arms of a shared discontinuity produce byte-identical entries while private loss stays disjoint; the cap truncates the sample and not the count. The zero-loss test now also asserts an EMPTY position list -- without that negative control "positions match" is trivially true for two empty lists. Workflow: records the comparison jq, since the receipt is already uploaded and the field rides along with no probe change. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
@ally please review at head New commit
Prior commits on this PR ( |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: dbddde8
Critical Issues (0)
Important Issues (1)
- [gstack/review]
.github/workflows/amt-public-vantage-probe.yml:153-160— theawkdelta parser does not validate that the/proc/net/snmpheader, before row, and after row have matching field counts.split()leaves missing fields unset, and arithmetic on an unset value coerces it to zero, so a shortened or malformed after row can silently printRcvbufErrors=0and create a false receiver-loss attribution. The current header is also read independently from the snapshots, so a row-shape mismatch is not detected.- Fail closed when the three row widths differ, or parse and validate the named
RcvbufErrorsfield explicitly before printing the delta. Emit a non-zero status so the probe cannot treat an invalid counter sample as a clean zero.
- Fail closed when the three row widths differ, or parse and validate the named
Suggestions (0)
Strengths
GapEvent { pid, after, missing }anchors runs to sequence space rather than arrival order, and the corrected shared/private fixture exercises that invariant.gap_eventsremains exact independently of the bounded diagnostic sample, with truncation observable from the receipt.- The absolute data-phase timestamps make concurrency checkable from the receipts instead of inferred from dispatch timing.
Recommended Action
- Fix the Important issue before relying on the workflow's receiver-side attribution output.
- The Rust sequence accounting and tests otherwise look ready for this review.
…fake zero An empty or short `Udp:` line made every field print `=0`: `split()`'s return was discarded, so `A[i]-B[i]` on unset fields yielded a complete, well-formed, entirely fake `udp_delta ... RcvbufErrors=0` line. That zero is indistinguishable from a real one to any consumer thresholding on it -- and RcvbufErrors=0 is the reading that excluded branch (i) on BLO-33456 AC3. Require hdr/before/after field counts to agree; on mismatch emit `udp_delta_invalid hdr=N before=N after=N` and NO `udp_delta` line, so a grep for `RcvbufErrors=` finds absence rather than a fabricated value. Exits 0 deliberately: `set -e` is in force and a failed step discards report.json, which is the AC1 defect this issue exists to fix. Fail closed on the counter, not on the run. Capture validity only -- it does nothing for field responsiveness. RcvbufErrors has still never been driven non-zero on this runner. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
@ally please re-review at head Your finding is right and I've taken it. I've implemented a different remedy than the one you asked for, and I want to say why rather than quietly diverge. The mechanism is worse than "prints 0"A short after row prints a large negative ( On the remedy — not
|
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 37ef2bb
Prior Findings Dispositioned (1)
- prior:dbddde8 important 1 — fixed —
.github/workflows/amt-public-vantage-probe.yml:173— the delta parser now splits the header, before, and after rows, requiresnh >= 2and exact width equality before emitting anyudp_deltaline, and otherwise emits onlyudp_delta_invalidwith exit 0. That preservesreport.jsonwhile preventing a fabricatedRcvbufErrors=0from reaching consumers.
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- The
/proc/net/snmpguard fails closed on counter validity without failing the whole probe, which matches the receipt-preservation requirement this workflow is built around. - The new
lagged_countpositive control makes the zero value meaningful instead of assuming the counter can move. gap_positionsand absolute data-phase timestamps give future receipts enough information to compare concurrent receivers without relying on dispatch timing or aggregate gap counts alone.
Recommended Action
- No Ally blockers remain for this head.
- Keep the stated
RcvbufErrorspositive-control gap as a separate follow-up if field responsiveness needs formal proof.
|
Re: the Your diagnosis was right and the mechanism is slightly worse than the report stated. A shortened after row prints a large negative ( Fixed at Non-zero exit is the one thing I can't do here. So it fails closed on the counter, not on the run: validate One caveat I want on the record rather than glossed: this is about capture validity only. It does nothing for field responsiveness. |
Follow-through on the CTO ruling of 2026-09-13T02:25Z on BLO-33456: receiver-intrinsic loss on the cast tuple is to be attributed, not bounded. Six 90 s sessions at N=1 on an idle path span 0.0000%–3.7964%, so no threshold on
mmtp.gapsreproduces and none should be set.Three instruments, no new dependencies.
1. Positive control for
lagged_count(src/bin/amt-verify.rs)Every existing test asserted
lagged == 0. That licenses nothing — a counter that never increments and a counter correctly reporting no loss read identically, and all six receipts reportlagged_count: 0. Mutating*lagged += skippedaway leaves the pre-existing tests green and kills only the new one; that asymmetry is the reason to add it.The zero is now load-bearing, and it buys a three-way partition of any gap:
lagged_count > 0RcvbufErrors > 00,gaps > 0None of the three needs a source-side counter — the thing AC3 spent two revisions failing to find.
2.
Udp: RcvbufErrorsdelta across the probe window (workflow)The kernel already counts the cheapest candidate to rule in or out, and
--network hostmakes the runner's netns the container's. Labelled off the header line so a kernel that adds a field cannot silently shiftRcvbufErrorsonto a neighbour's value.Stated in-tree rather than glossed: the counter is netns-wide, not per-socket, so a small delta is evidence about the netns, not proof it was our socket. The existing zero-gap sessions are a built-in negative control, so attribution is by covariation across lossy/clean sessions rather than by any threshold.
3. Absolute timestamps in the receipt (
data_started_at_ms/data_ended_at_ms)elapsed_msis a monotonic duration with no shared origin, so "did these two probes observe the same wall clock?" was not answerable from the receipt at all — the phase-B pair's overlap had to be reconstructed from GitHub job timings, which are dispatch times and includedocker pull. Every differential measurement on this stream depends on this. Unix epoch millis rather than RFC3339: no date dependency in this crate, and receipts are compared numerically anyway.Verification
cargo test --features native --bin amt-verify— 13/13 pass, including the newoverflowing_the_broadcast_channel_is_counted_as_lagged.laggedwiring fails only the new test (12 passed / 1 failed).cargo fmt --checkclean,cargo clippy --all-targetsclean./proc/net/snmpand labelsRcvbufErrorsby name.Note the timestamp fields only reach a dispatch receipt once
ghcr.io/blockcast/amt-verify:mainis republished; the snmp delta is workflow-side and takes effect on merge.