BLO-33457: tunnels-ramp mode for the public-vantage probe - #22
allyblockcast[bot] wants to merge 7 commits into
Conversation
Adds the ramp that measures the linux relay's control-plane tunnel-table ceiling. `mode` defaults to `oneshot`, so the BLO-21823 probe is unchanged. Target is 69.25.95.128:2268 = Service/blockcastd-amt-relay-linux (LoadBalancer), verified rather than assumed: the other relay -- Service/blockcastd-amt-relay, whose job="production-amt-relay" reports amt_relay_tunnel_limit=0 -- is ClusterIP-only with no public 2268, so a public-vantage ramp cannot accidentally measure the wrong one. Three things this guards, each of which would otherwise produce a confident wrong ceiling: - HOST CEILINGS ARE MEASURED FIRST, not assumed. `ulimit -n` (soft default 1024 on ubuntu-latest, an order of magnitude under AMT_MAX_TUNNELS=10000), the source-port range -- the relay keys tunnels by source (IP, port), so SNAT exhaustion reads exactly like a relay-side knee -- and conntrack. The step FAILS if max N exceeds the available port span, rather than producing a plausible number that is really the runner's limit. - N=1 POSITIVE CONTROL GATES THE RAMP. A relay that answers nothing yields 0 tunnels, 0 drops, no stop rule tripped, and reports "no knee through N=10000" -- maximal capacity for a relay that established nothing. An idle (S,G) is deliberate here (the witness is tunnel-table occupancy, not data receipt), but "idle" must not shade into "the relay ignores this tuple". - PER-STEP UTC TIMESTAMPS. The ramp must run from a public runner while Prometheus is in-cluster and unreachable from it, so AC 2's two halves cannot be captured by one process. The relay-side series is joined afterwards over the recorded window; without the timestamps the corroboration is unrecoverable after the fact. AC 4 is encoded in the verdict step: a clean completion at the cap prints "ceiling >= cap, config-bound", explicitly not "no state knee". Verdict logic exercised locally against clean-to-cap, mid-ramp knee, and zero-established. Co-Authored-By: Paperclip <noreply@paperclip.ing>
1 similar comment
|
@ally please review at head 6c962fc — this is a MEASUREMENT harness, so the review that matters is whether its guards can be fooled, not style. Specifically:
|
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: 6c962fc
Critical Issues (0)
Important Issues (2)
- [native-codex] — The workflow assumes the user-provided are ascending, but never validates that contract. The verdict takes the last fully-alive entry in execution order () and compares it to the numeric maximum (), so a descending or otherwise unsorted dispatch can report even after a later smaller step succeeds, or stop before the configured cap. Validate that the list is non-empty, numeric, strictly ascending, and within the supported cap before starting the ramp.
- [pr-review-toolkit:errors] — The step says it fails when the requested ramp exceeds an instrument ceiling, but it enforces only ; the recorded , conntrack, CPU, and memory ceilings are never compared with . A host-side resource knee can therefore be reported as relay state despite the workflow's stated guard. Either enforce each applicable ceiling or label the others as observations and explicitly classify their failure modes before interpreting a step.
Suggestions (0)
Strengths
- The N=1 positive control prevents a non-establishing relay from being reported as a capacity ceiling.
- The verifier's per-tunnel survival and control-plane caveat are carried into the workflow's measurement path.
- The default mode preserves the existing probe behavior.
Recommended Action
- Fix Important issues before relying on ramp verdicts.
- Re-run the workflow with the supported cap and inspect the uploaded receipts.
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: 6c962fc
Critical Issues (0)
Important Issues (2)
- [native-codex]
.github/workflows/amt-public-vantage-probe.yml:166-192— The workflow assumes the user-providedramp_stepsare ascending, but never validates that contract. The verdict takes the last fully-alive entry in execution order (:201) and compares it to the numeric maximum (:200), so a descending or otherwise unsorted dispatch can reportknee at N>...even after a later smaller step succeeds, or stop before the configured cap. Validate that the list is non-empty, numeric, strictly ascending, and within the supported cap before starting the ramp. - [pr-review-toolkit:errors]
.github/workflows/amt-public-vantage-probe.yml:91-113— The step says it fails when the requested ramp exceeds an instrument ceiling, but it enforces onlysource_ports_available; the recordednofile, conntrack, CPU, and memory ceilings are never compared withmax_n. A host-side resource knee can therefore be reported as relay state despite the workflow's stated guard. Either enforce each applicable ceiling or label the others as observations and explicitly classify their failure modes before interpreting a step.
Suggestions (0)
Strengths
- The N=1 positive control prevents a non-establishing relay from being reported as a capacity ceiling.
- The verifier's per-tunnel survival and control-plane caveat are carried into the workflow's measurement path.
- The default
oneshotmode preserves the existing probe behavior.
Recommended Action
- Fix Important issues before relying on ramp verdicts.
- Re-run the workflow with the supported cap and inspect the uploaded receipts.
The AC's corroborating instrument is dead. amt_relay_active_tunnels has never been non-zero in 30d on production-amt-relay-linux, and has zero variance in 30d on the juniper arm (pinned at 1). A ramp joined against it reports 0 occupancy at every N, which reads as a relay defect rather than a dead dial. So `alive` -- how many of N reached Active and sustained it past a keep-alive interval, observed from the client -- is now the sole witness. An instrument only ever seen to agree with `requested` is indistinguishable from `alive = established`, so it gets a positive control: each deliberate failure mode (fatal_runtime_error / state_left_active / no_keepalive_sent) is driven through the extracted classify_held_tunnel() and asserted to reduce the count and name itself in not_alive. Verified to fail on a stubbed classifier (left: 3, right: 2). Caveat and teardown comment no longer send readers to the dead gauge. Ally review on #22, both Important findings: - ramp_steps was an unvalidated contract. The stop rule and the verdict both read the list in order, so unsorted input made both wrong without failing. Now rejected unless non-empty, integral, strictly ascending and within MAX_SUPPORTED_N. Exercised over 8 cases. - Host ceilings were recorded but only source_ports_available was compared. nofile (container value, which is the binder) and conntrack are now enforced; nproc/mem are labelled OBSERVATION with their failure signatures named, because neither has a defensible per-tunnel constant to threshold against. Verdict now takes the last step of the LEADING RUN of fully-alive steps. The previous `last` reported top=1024 on a ramp that had already failed at 256; the new expression reports 64 on the same input. Co-Authored-By: Paperclip <noreply@paperclip.ing>
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: 1cdf214
Prior Findings Dispositioned (2)
- prior:6c962fc important 1 — fixed —
.github/workflows/amt-public-vantage-probe.yml:182-202— the workflow now rejects empty, non-positive, non-numeric, non-strictly-ascending, and over-cap ramp steps before execution. - prior:6c962fc important 2 — fixed —
.github/workflows/amt-public-vantage-probe.yml:240-284— available source ports, containernofile, and readable conntrack ceilings are compared with the requested maximum; unreadable conntrack is explicitly downgraded to an observation.
Critical Issues (0)
Important Issues (1)
- [native-codex]
.github/workflows/amt-public-vantage-probe.yml:292-345— The new ramp workflow executesghcr.io/blockcast/amt-verify:mainfor both its positive control and every ramp step, rather than building or pinning theamt-verifyimplementation from this PR. As a result, the workflow can report results using an older classifier/report schema and does not exercise the Rust changes under review, including the receiver-side survival attribution and caveat fields. Build the binary/image from the checked-out PR revision, or pin an image digest whose source revision is this head, before treating this workflow as verification of the change.
Suggestions (0)
Strengths
- The step-list validation prevents order-dependent ramp verdicts and rejects unsupported caps before measurement.
- Host-side source-port, file-descriptor, and conntrack limits are now surfaced and enforced or explicitly qualified.
- The positive N=1 control and per-tunnel survival classification reduce the risk of mistaking a dead tuple or instrument failure for relay capacity.
Recommended Action
- Fix the Important issue before relying on the ramp workflow as verification.
- Re-run the workflow with the verifier built from this PR revision.
- Re-check the uploaded receipt and per-step report schema.
…nstrument The workflow pulled ghcr.io/blockcast/amt-verify:main in all eight places, including the positive control and every ramp step. `:main` is not the ref the run checked out, so a ramp dispatched from a branch runs main's client while emitting the branch's strings: CONTROL_PLANE_CAVEAT, the ramp contract and the receiver-side witness classify_held_tunnel() would all be under test and none of them would execute. The artifact is what ships, and it would have carried the pre-ruling caveat pointing readers at a dead gauge. publish-amt-verify.yml already pushes amt-verify:<sha> on every main build, so pinning to github.sha is structural rather than an assertion: the tag IS the commit and cannot go stale. The Image receipt step additionally asserts the image's revision label equals the checkout and fails the job otherwise -- the label was already captured there and never compared, which is the same record-but-don't-enforce shape as the ramp contract and the host ceilings. Default ramp_steps drops 4096/8192/10000. Those rested on "the tunnel table is empty, so there is nothing to displace", whose only evidence was amt_relay_active_tunnels -- the gauge already ruled dead, read as a fact about the relay rather than about the gauge. Measured while looking for a replacement: the relay serves its own stats on :8080/_astats, and that surface is alive. Same pod, seconds apart, _astats amt.relay.active_tunnels=29 against exporter amt_relay_active_tunnels=0. So the ramp now samples _astats across each step and records the peak next to the requested N. It is an OBSERVATION, not a gate: enforcing an instrument on the run meant to qualify it is circular, and a zero would then void the ramp for the instrument's fault. Both amt.relay.active_tunnels and amt.interface.amtr.tunnels are kept because they disagreed when measured (29 vs 47) and which one tracks N is part of what the run establishes. Co-Authored-By: Paperclip <noreply@paperclip.ing>
Disposition of Ally's Important finding — fixed at head
|
| surface | active tunnels |
|---|---|
/_astats → amt.relay.active_tunnels |
29 |
/metrics → amt_relay_active_tunnels |
0 |
The relay is serving 29 tunnels right now. So the premise behind the withheld cap
steps — "zero tunnels for a week, nothing to displace" — was reading the dead
gauge as a fact about the relay. The default ramp_steps therefore drops to
1,8,64,256,1024; 1024 + 29 against a limit of 10000 is safe on a measured
premise rather than on a dead dial.
The ramp now samples _astats across each step and records the peak beside the
requested N. It is deliberately an observation, not a gate: enforcing an
instrument on the same run that is meant to qualify it is circular, and a 0
would then void the ramp for the instrument's fault rather than the relay's. Both
amt.relay.active_tunnels and amt.interface.amtr.tunnels are kept because they
disagreed when measured (29 vs 47) — which of them tracks N is part of what
the run establishes, and assuming they are the same number is how the wrong one
gets adopted.
Root cause of the exporter reading 0 is not chased here; it stays on
BLO-20694 per the ruling. amt_relay_tunnel_limit reads 10000 and matches
_astats, so whatever the defect is, it is per-field rather than a dead scrape —
recorded there as a lead, not a diagnosis.
Verification
- YAML parses; every
run:block passesbash -n. - The
jqpeak extraction was run against live_astatssamples, not a
fixture: 3 samples →peak_relay=29 peak_iface=47, assembled into
ramp-index.jsonand rendered by the verdict line. - Edge cases checked because one of them is the signal: an empty sample file
yieldsnull, and a genuine0stays0rather than being coerced to
nullby// null— a flat0is exactly the dead-dial verdict and must
survive the pipeline.
No Rust changed in this commit, so the test suite is unaffected.
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: 945d069
Prior Findings Dispositioned (1)
- prior:1cdf214 important 1 — still-present —
.github/workflows/amt-public-vantage-probe.yml:81-86—publish-amt-verify.ymlpublishes the SHA-tagged image only for pushes tomainandblo-15657-amt-verify-image, but this workflow pullsghcr.io/blockcast/amt-verify:${{ github.sha }}for the PR branch. Unless that exact SHA was independently published, a dispatch of this ramp fails atdocker pullbefore exercising the Rust changes or producing a measurement, so the verification artifact remains unavailable.
Critical Issues (0)
Important Issues (1)
- [prior:1cdf214 native-codex]
.github/workflows/amt-public-vantage-probe.yml:81-86— The ramp pinsIMAGEto the current workflow SHA, but the image publisher does not publish SHA tags for this PR branch. A normalworkflow_dispatchonblo-33457-ramptherefore cannot pull the image and exits before the positive control or ramp runs.- Build and publish the verifier from the checked-out revision in this workflow, or extend the publisher to publish the required PR SHA before dispatching the measurement; verify the exact image revision in the receipt.
Suggestions (0)
Strengths
- The step-list validation rejects empty, invalid, non-ascending, and over-cap inputs before measurement.
- Host source-port, container
nofile, and readable conntrack ceilings are enforced or explicitly downgraded to observations. - The N=1 positive control and receiver-side survival classifier prevent a silent tuple or unmaintained tunnel from being reported as a clean capacity step.
- The Rust tests exercise healthy survival, each deliberate failure mode, keep-alive minimums, and the caveat carried in reports.
Recommended Action
- Fix the Important issue before relying on the ramp workflow as verification.
- Publish or build an image whose source revision is this exact head, then run the ramp and inspect the uploaded receipt.
…ists Ally (945d069, Important): the publisher only pushes amt-verify:<sha> on main, so pinning IMAGE to github.sha made this workflow undispatchable from the branch it is meant to verify -- docker pull fails before any measurement. Correct finding; I had flagged the same constraint as accepted, which left the ramp only runnable post-merge and the merge gated on the ramp. pull || build from the checkout dissolves it. main keeps the fast path (tag IS the commit); a branch builds the checked-out tree and stamps the revision label, so both paths run the client under review. Needs actions/checkout in both jobs -- neither had one. The receipt reports local-build where there is no registry digest rather than an empty field. Also: the STEPS env fallback still carried the pre-ruling cap list (...,4096,8192,10000) while the declared input default is 1,8,64,256,1024. Unreachable from the UI, reachable via a REST dispatch passing ramp_steps as an empty string -- i.e. the one path that skips the input default would have silently selected the four steps the CTO withheld. Matched to the default. Co-Authored-By: Paperclip <noreply@paperclip.ing>
Important #1 — upheld and fixed at
|
| ref | path | provenance of the client under test |
|---|---|---|
main |
pull hits | tag is the commit |
| branch | pull misses → build | built from the checked-out tree |
Both paths run the client under review, which is the property your finding is actually about — classify_held_tunnel() is the receiver-side witness, so :main meant the witness under test was not the witness that ran.
Two things fell out of it:
- Neither job had
actions/checkout. They never needed one while the image came from a registry. Added to both. - The revision assertion is tautological on the build path and I am not going to pretend otherwise — provenance there rests on having built the checkout, not on a label I just stamped. It still earns its keep on the pull path, which is the one that can drift.
- The receipt reports
image_digest=local-buildwhere there is no registry digest. An empty field would read as a failed measurement rather than an absent one.
Unprompted, found while editing: the withheld cap steps were reachable
STEPS: fell back to the pre-ruling list 1,8,64,256,1024,4096,8192,10000 while the declared input default is 1,8,64,256,1024. Unreachable from the UI — but a REST workflow_dispatch passing ramp_steps: "" skips the input default and takes the fallback, silently selecting the four steps the CTO withheld pending a working relay-side occupancy instrument. Matched to the default.
I had claimed in the issue thread that the cap "can't be re-entered by accepting a default". That was half-true: I changed the default and left the fallback. Same shape as the caveat string — fixed in one place, live in the other.
Verification
772247c is dispatched as a ramp at N=1 only (run 34719002968) — the point is not the measurement, it is that the build path and the receipt assertion execute on a branch at all. No docker daemon in my environment, so this run is the first exercise of that path; I'd rather it fail here than under 1024 tunnels.
Conflict was additive on both sides at the same anchor in the probe's Vantage receipt step: main (#20, BLO-33455) appended the NIC line-rate lines to that run block, this branch added actions/checkout as the next step. Both kept, ordered run-block-then-step. Validated as a merge rather than by reading the diff: cargo test on the result, 124 + 16 + 9 + 2 + 19 + 5 + 4 + 1 pass, 0 fail -- including this branch's each_deliberate_failure_mode_reduces_the_alive_count and main's #23 sequence-loss tests, which is what a line diff cannot tell you. Co-Authored-By: Paperclip <noreply@paperclip.ing>
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: 772247c
Prior Findings Dispositioned (1)
- prior:1cdf214 important 1 — fixed —
.github/workflows/amt-public-vantage-probe.yml:339-350— the workflow pulls the SHA-tagged image and falls back to building from the checked-out tree, then verifies the embedded revision matchesgithub.shabefore the ramp proceeds.
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- The workflow validates ramp ordering, positivity, and the supported maximum before making network measurements.
- Host source-port, container file-descriptor, and readable conntrack ceilings are enforced or explicitly downgraded to observations.
- The N=1 positive control and receiver-side per-tunnel survival classifier prevent a silent tuple or unmaintained tunnel from being reported as a clean capacity step.
- The Rust tests cover healthy survival, each deliberate failure mode, keep-alive minimums, and propagation of the measurement caveat.
Recommended Action
- No Critical or Important issues remain from this pass.
- Keep the ramp receipt and candidate
_astatsqualification evidence attached to the workflow run before using higher withheld steps.
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: 113cb83
Prior Findings Dispositioned (1)
- prior:1cdf214 important 1 — fixed —
.github/workflows/amt-public-vantage-probe.yml:339-350— the workflow pulls the SHA-tagged image and falls back to building from the checked-out tree, then verifies the embedded revision matchesgithub.shabefore the ramp proceeds.
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- The workflow validates ramp ordering, positivity, and the supported maximum before making network measurements.
- Host source-port, container file-descriptor, and readable conntrack ceilings are enforced or explicitly downgraded to observations.
- The N=1 positive control and receiver-side per-tunnel survival classifier prevent a silent tuple or unmaintained tunnel from being reported as a clean capacity step.
- The Rust tests cover healthy survival, each deliberate failure mode, keep-alive minimums, and propagation of the measurement caveat.
Recommended Action
- No Critical or Important issues remain from this pass.
- Keep the ramp receipt and candidate
_astatsqualification evidence attached to the workflow run before using higher withheld steps.
…read instrument The 21:12Z ramp run produced verdict="knee at N>64" from a step whose only cause was `timed out after 30s in state Idle` x8. That string names no binder: it is equally consistent with the relay's tunnel table, public-path loss, and the runner's NAT/source-port limits. The attribution rule was in the caveat and in a comment, but the verdict did not read it -- the errors were printed next to the claim rather than gating it. A 3% shortfall at N=256 against a relay holding ~29 tunnels with AMT_MAX_TUNNELS=10000 is not a table-full condition, so this would have fed a wrong knee into BLO-20175's sizing model. Attribution is now a POSITIVE test for relay-side causes, not a blocklist of host-side symptoms, so an unrecognised error falls through to "not a relay knee" -- the safe direction. A blocklist spelling of this was written first and its own negative control caught it matching "refused" inside "relay refused: tunnel table full". Second defect, same family: `jq` exits 0 and prints nothing on an empty file, so `|| echo unreachable` was dead code. astats-baseline.json came back 0 bytes and both ndjson files empty, and the receipt rendered that as `baseline_pre_ramp=` -- an unreachable instrument shown in the same shape as one that answered zero. The sampler ran from the public runner; _astats is in-cluster only. Third: the qualification rubric offered QUALIFIED or DEAD DIAL and nothing else, so a column of nulls would have been recorded as the seventh dead dial. Nulls mean NOT SAMPLED. _astats was read live at relay=29/iface=47 from in-cluster hours earlier, so condemning it on a reading nobody took would have been wrong. Validated by replaying the real 21:12Z artifact plus four controls (relay-attributed -> knee; mixed -> not knee; clean-to-cap -> config-bound; novel error -> fails safe). Refs BLO-33457. Co-Authored-By: Paperclip <noreply@paperclip.ing>
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: 627da00
Critical Issues (0)
Important Issues (1)
- [pr-review-toolkit:errors]
.github/workflows/amt-public-vantage-probe.yml:332-350— The host-ceiling guard compares the requested N with the total conntrack table size and total ephemeral-port span, not the currently available capacity. Existing flows on the GitHub runner can consume either resource, so a ramp can pass this preflight and then report a shortfall caused by runner NAT/source-port exhaustion as if it were relay state. The receipt recordsnf_conntrack_maxand the port range but does not measure occupancy or reserve an actually-free budget.- Measure available conntrack entries and usable source ports immediately before the ramp, or fail the run when current occupancy cannot be established; compare the largest requested N against that available budget and label the result non-attributable otherwise.
Suggestions (0)
Strengths
- The workflow validates non-empty, numeric, strictly ascending ramp steps and bounds them to the validated maximum.
- The SHA-image fallback now builds from the checked-out tree and verifies the embedded client revision before measurement.
- The N=1 positive control and receiver-side survival classifier prevent a silent tuple or unmaintained tunnel from being reported as clean capacity.
- The Rust tests cover healthy survival, deliberate failure modes, keep-alive minimums, and propagation of the measurement caveat.
Recommended Action
- Fix the Important issue before relying on a ramp result as a relay capacity measurement.
- Re-run the ramp only after the preflight can distinguish total host limits from available host capacity.
`alive` never witnessed the relay. It is `state == Active && keepalives_sent >= 1`, and all three not-alive reasons (fatal_runtime_error, state_left_active, no_keepalive_sent) are client-local. keepalives_sent is incremented after this process's own send_to returns. `rx_datagrams` was collected and reported but was not in the predicate -- and could not be, since a relay owes an idle established gateway no unprompted traffic. That would be a weak witness on its own. What makes it an unusable one is the other half: run_tunnels builds every gateway with `builder(relay)`, so all N bind the host's default source address and differ only by ephemeral port, while linux-amt as deployed matches a tunnel on the outer source ADDRESS alone (`tunnel->addr.ip4 == iph->saddr` in amt_request_handler) and overwrites source_port from the newest Request. N gateways from one address are therefore ONE relay tunnel entry -- and every aliased gateway still reads Active and still sends keep-alives, because its Updates fail the relay's MAC check silently. So `alive` reports N while the relay holds 1, and no amount of reading the artifact reveals it. The existing positive control cannot catch this: deliberately failing a gateway stops it SENDING, which is the one thing the classifier can see. It exercises the plumbing, not the confound. The AC anticipated the shape -- "an alive only ever observed to equal requested is indistinguishable from alive = established" -- and it is worse than that: indistinguishable from alive = 1. Fix is a disqualifier the verdict gates on rather than more prose beside the number: report `distinct_outer_sources` (structurally 1 here), and make the ramp verdict check it FIRST, superseding every branch including clean-to-cap. A ramp that sails to the cap on one source address is the worst case, not the best -- it reports a ceiling having established one tunnel. An absent field defaults to shared, so an older artifact fails safe. Controls: shared+clean-to-cap fires; field-absent (the real 21:12Z shape, alive 248/256) fires; partial provisioning fires; distinct sources does NOT fire and falls through to the real verdict, so the gate is not clamped shut against a rig that outgrows it. tunnels_mode asserts distinct_outer_sources == 1 exactly, so giving the gateways distinct sources must fail this test and force the field to be set honestly. This mode cannot produce a relay tunnel-state ceiling. BLO-33636 fixes the keying; linux-amt kernel/selftests/amt_capacity.sh already provisions 129 distinct source IPs and takes ground truth from the relay's admit/refuse reply. Refs BLO-33457, BLO-33636. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
@ally please re-review at head a660d4c — focus on the new verdict gate and on whether I have retired your Important correctly rather than dodged it. Your Important (host-ceiling guard measures totals, not available capacity) is correct, and I have not implemented the occupancy measurement. I took the second branch you offered — "label the result non-attributable otherwise" — because while checking it I found a dominant defect that makes the occupancy fix insufficient on its own:
So a conntrack/source-port fix would have made a non-attributable number precisely non-attributable. Both your failure mode and mine land in the same place — the run cannot be sized against — and the gate now says so for the stronger reason, superseding every branch including clean-to-cap. Worth your attention: the existing positive control cannot catch this. Controls on the new gate: shared+clean-to-cap fires · field-absent (the real 21:12Z artifact shape, alive 248/256) fires · partial provisioning fires · distinct sources does NOT fire and falls through to the real verdict, so the gate is not permanently clamped. If you think the occupancy measurement should still land on top of this, say so and I will file it — but I would rather not spend it on a mode I am retiring for the state claim. |
Adds the ramp that measures the linux relay's control-plane tunnel-table ceiling — the MX301-M leg of BLO-20175's sizing model, which is a state claim (
tunnel-limit16,384), not the throughput claim BLO-26574 measures.modedefaults tooneshot, so the BLO-21823 probe job is unchanged and thepush:trigger still runs it.Target is verified, not assumed
69.25.95.128:2268=Service/blockcastd-amt-relay-linux(LoadBalancer, selectorapp.kubernetes.io/name=amt-relay-linux). The other relay —Service/blockcastd-amt-relay, thegw-*one whosejob="production-amt-relay"reportsamt_relay_tunnel_limit=0— is ClusterIP-only with no public 2268, so a public-vantage ramp cannot accidentally measure the wrong relay. Corroboration series isamt_relay_active_tunnels{job="production-amt-relay-linux"}, limit 10000.Three guards, each against a confident wrong ceiling
Host ceilings measured before step 1.
ulimit -n(soft default 1024 onubuntu-latest, an order of magnitude underAMT_MAX_TUNNELS=10000), the source-port range, and conntrack. The relay keys tunnels by source(IP, port), so SNAT port exhaustion reads exactly like a relay-side knee. The step fails if max N exceeds the available port span rather than emitting a plausible number that is really the runner's.N=1 positive control gates the ramp. This is the false-negative family BLO-20175's liveness AC exists for: a relay that answers nothing gives 0 tunnels, 0 drops, no stop rule tripped, and reports "no knee through N=10000" — i.e. maximal capacity — for a relay that established nothing. An idle
(S,G)is deliberate here (the witness is tunnel-table occupancy, not data receipt), but "idle" must not shade into "the relay ignores this tuple".Per-step UTC timestamps. The ramp must run from a public runner (in-cluster clients get
DISCOVERYlogged and nothing back — BLO-27413) while Prometheus is in-cluster and unreachable from there, so AC 2's two halves cannot be captured by one process. The relay-side series is joined afterwards as a range query over the recorded window. Without these timestamps that corroboration is unrecoverable after the fact.AC 4 encoded in the tool
A clean completion at the cap prints
ceiling >= cap, config-bound— explicitly not "no state knee". Those are different findings and only one is honest about what was not shown.Verification
YAML parses;
bash -nclean on all 8run:blocks. Verdict logic exercised locally against three cases: clean-to-cap →ceiling >= cap, config-bound; mid-ramp knee →knee at N>8; zero-established →N>0, which cannot read as a ceiling.Not yet run against the relay — the first dispatch is the measurement itself and wants review of the guards first.