Skip to main content

cloud/reconciler/
ingress_verify.rs

1//! Is the backend reachable at the port its service record advertises? — the
2//! half [`collate_workspace_ingress`](crate::validate::collate_workspace_ingress)
3//! deliberately cannot answer (R844-F16).
4//!
5//! **Read [§What this does not prove](#what-this-does-not-prove) before
6//! treating a green result as a deploy gate.** That question is narrower than
7//! "does the front door work", and on 2026-09-03 the difference took yah.dev
8//! down for four minutes.
9//!
10//! `yah cloud ingress collate` is pure: no network, no credentials. That purity
11//! is load-bearing — it is what lets `xtask/tests/mirror_ingress.rs` plan this
12//! camp's real `.yah/services/` tree as a unit test — but it means the
13//! `100.64.0.3:8080` it prints is an **echo of declarations**: the mirror's
14//! `upstream_host` pin, or since R844-F12 the placement machine's declared
15//! `[registration].mesh_ipv4`. Collate attests that the mirrors *cohere*. It
16//! has never attested that anything answers.
17//!
18//! That distinction is not academic in this repo. The apex's `upstream_host`
19//! was once left at `127.0.0.1` after a second front door existed, and collate
20//! rendered it exactly as confidently as it renders a correct one — for the
21//! nineteen days the site was frozen.
22//!
23//! ## Four claims, and this module measures only the third
24//!
25//! | claim | evidence | who says it |
26//! |---|---|---|
27//! | "the mirrors agree on what fronts what" | the declaration tree | `collate` |
28//! | "a ready record exists for it" | `GET /service-records?ready=true` | [`ServiceRecordFanout`] |
29//! | "that record's address answers" | a TCP connect | **this module** |
30//! | "the front door is configured to dial it" | an HTTPS GET of the hostname, compared against the backend | **this module**, [`apply_public_path`] (R844-F18) |
31//!
32//! The second is *yubaba's opinion*, and R844-B11 is the proof it can be wrong
33//! while looking right: us-west-001 advertised `100.64.0.3:4325` as `Ready`
34//! while the workload answered on `100.64.0.1:4325`. The record was healthy,
35//! the record's own address refused connections, and every layer above it
36//! reported success. A connect is the only step that can catch that, because it
37//! is the only step that asks the world instead of asking a declaration.
38//!
39//! ## What this does not prove
40//!
41//! **Updated by R844-F18 — the gap this section describes is now closed by
42//! [`apply_public_path`], and the history below is why that check exists and
43//! what it is still not.** [`verify_collation`] alone proves **the backend is
44//! reachable at the port the record advertises**; on its own it never proves
45//! **the front door is configured to dial that port**. Those two coincide only
46//! while a pin forces them to — so that pass is *weakest in exactly the
47//! portless configuration it was built to certify*.
48//!
49//! That is not a theoretical gap. R844-T10 deleted the apex's `port` pin on the
50//! strength of a green run from this verb, on 2026-09-03:
51//!
52//! * kamaji allocated a **new** port for the redeployed workload — 34759;
53//! * the service record correctly advertised 34759;
54//! * this verb dialed 34759, found it open, and printed
55//!   *"2 rule(s) … 2 proven to serve, 0 not"*;
56//! * the public got **HTTP 503** for four minutes, because the running passway
57//!   was still configured for 8080 and **nothing reconfigures it**.
58//!
59//! So the verb reported success during the live outage it was built to prevent.
60//! The prior measurement that authorised the edit was green for a reason that
61//! did not survive a real deploy: it stripped the pins from a *copy* of the
62//! config while the old workload was still bound to 8080, which is the one
63//! arrangement in which the record and the front door cannot disagree.
64//!
65//! This is [`collate`]'s own limitation one level up — collate attests
66//! coherence and not reachability; a dial attests reachability of a *record*,
67//! and not that the front door agrees with that record.
68//!
69//! [`apply_public_path`] closes it by traversing the **public path** and
70//! comparing: it fetches the publish beacon
71//! ([`publish_beacon`](crate::reconciler::publish_beacon)) from
72//! `https://<hostname>/` and from each discovered backend, and fails the rule
73//! when the two serve different publishes. A bare `GET /` would not have done —
74//! a door pointed at the wrong backend answers 200 with a plausible page, which
75//! is how the apex stayed frozen for nineteen days. The beacon is the only
76//! object on either side that says *which publish this is*.
77//!
78//! **Two things that check is still not.** It is a **detector of the current
79//! state**, not a simulation of a pending edit — run it before and after an
80//! apply and require both green. And the public fetch goes wherever **DNS**
81//! sends it, so a hostname on two front doors is measured at one of them; the
82//! verdict says so in a note rather than implying it covered both.
83//!
84//! **So: a green [`verify_collation`] alone is necessary, not sufficient. Do
85//! not use it without the public-path pass as the gate on removing a pin.**
86//!
87//! [`collate`]: crate::validate::collate_workspace_ingress
88//!
89//! ## Why this is a separate verb and not a flag on `collate`
90//!
91//! Because the purity above is the feature. A `--live` flag would put a network
92//! read inside the function eleven offline tests call, and the pressure to make
93//! those tests pass would then push the network read towards being optional in
94//! a way that silently degrades. A sibling verb costs nothing that flag would
95//! not cost more.
96//!
97//! ## Pure, like everything else on this seam
98//!
99//! Nothing here opens a socket. The caller does the fanout read and the dial,
100//! and hands both in as data — the fifth instance of the shape
101//! [`resolve_ingress_placements`](crate::reconciler::resolve_ingress_placements),
102//! [`IngressPlan::resolve_upstreams`], [`IngressPlan::resolve_ports`] and
103//! [`IngressPlan::resolve_upstreams_from_config`] already use. So the verdict
104//! logic — which is where the interesting mistakes live — is unit-testable
105//! against a fake fleet with no network at all.
106//!
107//! ## A subset renders like a success, so a subset is a failure
108//!
109//! The failure class this whole relay exists to remove is a partial answer that
110//! looks complete. A rule placed on two nodes that resolves one address is
111//! *half a front door*: it renders, it dials, it serves — and half the fleet's
112//! traffic capacity is silently absent. [`RuleVerdict`] therefore fails a rule
113//! whose resolved backends do not cover its whole declared placement, and names
114//! the node that went missing along with why.
115//!
116//! @yah:ticket(R844-F18, "Verify the PUBLIC path — an HTTPS GET of the hostname through the real front door, compared against what the record claims")
117//! @yah:status(review)
118//! @yah:assignee(agent:bundle-anthropic-ashguard)
119//! @yah:at(2026-09-04T01:55:44Z)
120//! @yah:parent(R844)
121//! @yah:next("KEEP `collate` PURE (R772, R844-F5, R844-F12, R844-F16 each fought for this) and prefer a third verb or a flag on `verify` over touching it. `cargo test -p xtask --test main mirror_ingress` planning the camp's REAL .yah/services tree with no network is the property being protected; it is currently 11 green.")
122//! @yah:verify("And it must still be green on the healthy fleet: https://yah.dev/ through both declared front doors, agreeing with what `yah cloud ingress verify` resolves.")
123//! @yah:gotcha("A LIVE-OUTAGE-DETECTOR IS NOT AUTOMATICALLY A PRE-FLIGHT GATE, and this ticket should be honest about which it is building. An HTTPS GET proves the CURRENT front door serves; it cannot tell you what a config change is ABOUT to do, because the front door has not been reconfigured yet. That may still be enough — run it before and after an apply and require both green — but say so explicitly rather than letting a future reader assume it gates the edit. The failure that started this was precisely someone (twice) treating a green from the wrong vantage point as authorisation.")
124//! @yah:next("A SHAPE FOR THIS, from @Ashguard:griffin (session:75f87e36, the session that caused the outage behind it) — offered as a starting point, not a settled design. The open question on this ticket is whether an HTTPS GET is a pre-flight GATE or only an outage DETECTOR. I think it is only ever a detector, and that the ticket is really TWO checks answering two different questions:\n\n  1. PRE-FLIGHT, and it is not a probe at all — it is a COMPARISON. Read what the front door is actually configured to dial, FROM THE DOOR, and compare it against what the service record says the backend is. That is the check that would have caught tonight's outage BEFORE it happened, because the two disagreed (passway held 8080, the record advertised 34759) at a moment when every probe of either side in isolation was green. Note what makes it different from R844-F16's verify: verify reads the record and dials the port the record names, so both of its inputs come from the same side of the disagreement. The door's own configured value is the input nobody currently reads, and it is the only one that makes the comparison possible.\n\n  2. POST-CONDITION, which is where the HTTPS GET belongs — an unauthenticated GET of the public hostname through the real front door, asserted AFTER an apply, once R844-B19 guarantees the door has actually been repointed. Today that assertion cannot be trusted to mean anything, because B19's ordering bug means the door may never have been updated at all; the GET would just be re-measuring the old configuration and calling it a pass.\n\nWHY THIS PAIRS F18 WITH B19 RATHER THAN DUPLICATING IT: B19 makes the front-door update reliably HAPPEN; (2) is the assertion that it DID; (1) is the only one of the three that can speak before a change is applied. Sequencing follows from that — do not land (2) before B19, or it encodes today's broken ordering as the expected one.\n\nTHE CAVEAT I CANNOT RESOLVE AND WHOEVER TAKES THIS SHOULD NOT ASSUME AWAY: even (1) compares two CURRENT states. It does not simulate what a config change is about to do, which is what we actually wanted to know tonight. It catches an existing divergence, and it would catch this specific class because the divergence appears the moment the workload is redeployed — but it is not a general \"is this edit safe\" oracle, and nothing in this design is. If someone needs that, it is a different and much larger ticket, and it should be filed as one rather than smuggled in here.")
125//! @yah:handoff("LANDED. `yah cloud ingress verify` now takes the fourth step, on by default. For every hostname in the collation it fetches `https://&lt;hostname&gt;/.well-known/yah-publish.json`, for every discovered backend it fetches the same object over the mesh, and it FAILS the rule when the two name different publishes. Verdict logic is `apply_public_path` in oss/yubaba/crates/cloud/src/reconciler/ingress_verify.rs, pure like the rest of that seam — the CLI does both fetches and hands them in as `PublicReadings`, so the interesting mistakes are unit-testable against a fake fleet. New surface: `BeaconFetch`, `PublicReadings`, `apply_public_path`, three `VerifyFinding` arms, `fetch_beacon` and `--skip-public` in app/yah/cli/src/cloud.rs.")
126//! @yah:handoff("THE COMPARISON IS THE CONTENT, NOT THE GET — this is the design decision, and the ticket title's \\\"HTTPS GET\\\" understates it. A bare `GET /` proves only that something answered: a door pointed at the wrong backend returns 200 with a plausible page, which is exactly how the apex stayed frozen for nineteen days with every signal green. The publish beacon (`publish_beacon.rs`, `BEACON_KEY = .well-known/yah-publish.json`, R703-B4) is the one object on either side of the door that says WHICH PUBLISH THIS IS, so fetching it from both and comparing digests is what turns \\\"something answered\\\" into \\\"the front door is serving the backend the records name\\\". Reused rather than invented — the object already exists, `mesofact serve` already answers it out of the bundle, and R2 static publishes already write it.")
127//! @yah:handoff("THE TICKET'S OWN OPEN QUESTION — GATE OR DETECTOR — ANSWERED, AND ANSWERED THE WAY ITS FILER EXPECTED: **detector**, and the code says so in its own output rather than leaving a reader to infer it. `apply_public_path`'s doc, the CLI `--help`, the summary line printed on every run, W267 and the service-toml guide all now carry the same sentence: it compares two CURRENT states, cannot simulate an edit you have not applied, and the protocol is run-before-and-after-and-require-both-green. That is enough for the failure it was built for — the divergence appears the moment the workload is redeployed onto a new port — and it is deliberately NOT sold as an \\\"is this edit safe\\\" oracle. @Ashguard:griffin's caveat on this ticket was right and is preserved as the design, not assumed away.")
128//! @yah:handoff("GRIFFIN'S PART (1), THE PRE-FLIGHT \\\"READ THE DOOR'S OWN CONFIG AND COMPARE\\\", IS NOT WHAT SHIPPED — say so plainly rather than letting the ticket read as fully covered. Their shape proposed reading what passway is CONFIGURED to dial, from the door, and comparing that against the record. This ships the equivalent comparison one layer out: what the door ACTUALLY SERVES versus what the backend serves. Why that substitution rather than the config read: the running passway holds its upstreams in container env (`PASSWAY_UPSTREAMS`, `PASSWAY_UPSTREAM_SOURCE=static` — oss/passway/crates/passway/src/main.rs), so reading it means an SSH or a docker inspect per door, i.e. credentials and a shell on a production box inside a read-only verb. The served comparison needs neither, catches the same divergence class (it is true exactly when the door is dialing something else), and additionally catches a stale edge cache, which a config read cannot see. What the config read would still buy is naming WHY they diverge; that is a genuinely separable ticket and is not smuggled in here.")
129//! @yah:handoff("A FAILURE IS ONLY A FAILURE WHEN SOMETHING WAS ACTUALLY COMPARED — the design care, and the thing a careless version of this gets wrong in the direction that matters. Three arms produce a NOTE and leave the rule clean rather than a finding: a hostname that answers 200 with no beacon (it fronts something that is not a mesofact publish — a limit on the check, not a fault of the host, and failing it would red every non-bundle hostname in the fleet); a public 200 with no comparable backend (the note says verbatim that this proves the hostname is up and NOT that it is fronting the discovered backend); and a hostname nobody measured. Two arms fail: a transport failure, and a non-2xx. One arm is the point: `PublicBackendDivergence`, which names both digests and the backend address it compared against. And a backend that answers without a beacon adds nothing — `verify_collation` already dialed it and said what it found, so a second opinion phrased as an error would double-count one fact.")
130//! @yah:gotcha("THE LIMIT I COULD NOT DESIGN AWAY, AND DID NOT HIDE: the public fetch goes wherever DNS sends it, so a hostname published through two front doors is measured at ONE of them and this pass cannot say which. A divergence affecting only the other door reads as clean. Every verdict for such a hostname carries a note saying so — but only once a comparison actually happened, since on a rule where nothing could be compared that note is noise stacked on the finding. Closing it needs a fetch pinned to each door's public address with a `Host` override, which needs a public IP per door that nothing in the `Collation` carries today. Pinned by `a_hostname_on_two_front_doors_is_noted_as_measured_at_only_one`.")
131//! @yah:verify("UNIT: `cargo test --manifest-path oss/yubaba/Cargo.toml -p yah-cloud --lib ingress_verify` = 19 passed / 0 failed (11 before, +8 new). THE ONE THAT MATTERS IS `a_503_at_the_apex_fails_a_rule_whose_mesh_side_is_entirely_green` — it reproduces the 2026-09-03 outage as a unit test, asserting FIRST that `verify_collation` alone reports the rule clean (that assertion is the precondition, because a green mesh side is what reported success during the outage) and THEN that the public leg fails it. The other seven cover the stale-serve shape (200 serving a different digest than the backend), a transport failure, a hostname with no beacon, a public 200 with nothing to compare, an unmeasured hostname, a hostname on two doors, and the fully-clean case where the two digests match and NOTHING is caveated. Wider: `-p yah-cloud --lib ingress` = 94 passed / 0 failed; `-p yah-cloud --lib` = 1019 passed / 0 failed / 4 ignored (1011 before, so +8 and nothing lost).")
132//! @yah:verify("THE PURITY CANARY, which this ticket's own `next` named as the property to protect: `cargo test -p xtask --test main mirror_ingress` = 11 passed / 0 failed. `collate` was not touched — the public leg is a fourth step on `verify`, per the same reasoning R844-F16 used to make `verify` a sibling verb rather than a flag. `cargo check --workspace --all-targets` cargo-exit=0, zero `^error` lines. Installed and re-installed with `cargo xtask install` (sha256 b751f470e329253765075e5c050256f4e848ae1e9265f55fd6965f024bafbf24, `PATH resolves here`), per this relay's standing gotcha that `cargo build` does not update the binary an operator runs.")
133//! @yah:verify("THIS TICKET'S STATED ACCEPTANCE TEST — \\\"green on the healthy fleet, https://yah.dev/ through both declared front doors, agreeing with what verify resolves\\\" — WAS **NOT** MET, AND NOT BECAUSE OF THIS CHANGE. The fleet is not healthy right now: the mesh coordination server is down (`cloud.mesh.yah.dev` -&gt; 15.204.89.240 REFUSES :443 and :80 while :22 answers, and `tailscale status` reports this machine logged out with \\\"fetch control key ... connection refused\\\"), so NO 100.64.0.0/10 address is reachable from here and the mesh half of the check cannot run at all. Filed as R858 with the full measurement chain. I am recording this as unmet rather than reporting a partial green.")
134//! @yah:verify("WHAT THE LIVE RUN DID PROVE, and it is more than nothing: `yah cloud ingress verify --path .` from the freshly installed binary fetched `https://yah.dev/.well-known/yah-publish.json` over the real public internet, parsed it, and — because no backend beacon could be read across the dead mesh — printed exactly the right sentence instead of a pass: \\\"https://yah.dev answers with a publish beacon, but no discovered backend served one to compare it against, so this proves the hostname is up and NOT that it is fronting the discovered backend\\\". Independently confirmed by hand: `curl https://yah.dev/` = HTTP 200 in 0.81s and the beacon is `{\\\"prefix\\\":\\\"bundle/yah-marketing\\\",\\\"digest\\\":\\\"bfb47cd42468b080c474193fa6091ec273b6c99ab5a8a3b91d9c847cd7278551\\\",\\\"files\\\":39}`. So the public leg ran end to end against production and, on a real unplanned failure it was never designed for, refused to overclaim — which is the behaviour this ticket exists to install. `--skip-public` also exercised live: every verdict then reads \\\"the public path was not checked for yah.dev — this verdict speaks only for the mesh side, which is necessary and not sufficient\\\", and the summary names the dropped claim.")
135//! @yah:next("RE-RUN THE ACCEPTANCE TEST ONCE R858 CLEARS — it is one command and it is the only thing outstanding on this ticket: `yah cloud ingress verify --path .` must exit 0 with both front doors' rules reporting the mesh dial open AND the public beacon matching the backend's. Until the mesh is reachable that run measures nothing about the fourth claim.")
136//! @yah:notify_on(R858, "The mesh is reachable again — run this ticket's outstanding acceptance test: `yah cloud ingress verify --path .` must exit 0 with BOTH front doors reporting the mesh dial open AND the public beacon digest matching the backend's. It could not be run at landing time because no 100.64.0.0/10 address answered. If it passes, that closes the last open item here; if it fails, read which of the two legs failed before touching the code — the mesh leg is R844-F16's and predates this change.")
137
138use std::collections::{BTreeMap, BTreeSet};
139use std::fmt;
140
141use anyhow::Result;
142
143use crate::config::{IngressProvider, MachineConfig};
144use crate::reconciler::domain::{public_origins, PasswayOrigin};
145use crate::reconciler::ingress::{Collation, IngressPlan, IngressRule};
146use crate::reconciler::service_discovery::ServiceRecordFanout;
147
148/// What a TCP connect to one resolved `host:port` actually did.
149///
150/// Two arms, no `Unknown`: unlike a discovery read — which can fail to *ask* a
151/// node, and whose whole vocabulary
152/// ([`RecordVisibility`](crate::reconciler::RecordVisibility)) exists to keep
153/// that apart from an empty answer — a dial either completed or it did not.
154/// The attempt is the evidence.
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum DialOutcome {
157    /// The connect completed. This is the only positive evidence in the whole
158    /// ingress stack that anything is listening.
159    Open {
160        /// How long the connect took, for an operator eyeballing a slow path.
161        millis: u128,
162    },
163    /// The connect did not complete, in the transport's own words — refused,
164    /// timed out, no route.
165    Closed(String),
166}
167
168impl DialOutcome {
169    /// One short label for a summary line.
170    pub fn as_str(&self) -> &'static str {
171        match self {
172            Self::Open { .. } => "open",
173            Self::Closed(_) => "CLOSED",
174        }
175    }
176
177    /// Did anything answer?
178    pub fn is_open(&self) -> bool {
179        matches!(self, Self::Open { .. })
180    }
181}
182
183impl fmt::Display for DialOutcome {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        match self {
186            Self::Open { millis } => write!(f, "open ({millis}ms)"),
187            Self::Closed(why) => write!(f, "CLOSED — {why}"),
188        }
189    }
190}
191
192/// One dialed address and what came back.
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct EndpointCheck {
195    /// The `host:port` dialed — exactly what the front door would dial.
196    pub address: String,
197    pub outcome: DialOutcome,
198}
199
200/// How one rule's placement resolved against a live discovery read.
201///
202/// Recorded *during* resolution rather than reconstructed after it, because two
203/// of these three facts are unrecoverable from the resolved plan: whether the
204/// address came from a pin or from the fleet, and which placement node supplied
205/// it. Both are exactly what an operator needs to act on a failure.
206#[derive(Debug, Clone, PartialEq, Eq)]
207pub struct RuleResolution {
208    pub hostname: String,
209    pub slot: String,
210    /// The rule already carried an address before the read — the slot pins
211    /// `upstream_host`, and the pin wins everywhere (R844-F5/F12).
212    ///
213    /// Reported because it changes what the dial *means*: a pinned rule's
214    /// connect measures whether a **declaration** answers, and the fleet has no
215    /// say in what was dialed. That is the 127.0.0.1 case above.
216    pub pinned: bool,
217    /// Placement nodes that answered with a ready record on this rule's port.
218    pub covered: Vec<String>,
219    /// Placement nodes that did not, each with the reason — an `Unknown` node's
220    /// own words, or "answered, and has no such record".
221    pub missing: Vec<(String, String)>,
222}
223
224impl RuleResolution {
225    /// Key under which a resolution is looked up once collation has grouped the
226    /// rules by node.
227    ///
228    /// `(hostname, slot)` rather than hostname alone: one hostname is fronted
229    /// through exactly one provider (`collate_front_doors` rejects otherwise),
230    /// but the slot is what an operator opens to fix a finding, so carrying it
231    /// costs nothing and a message without it points at no file.
232    pub fn key(&self) -> (String, String) {
233        (self.hostname.clone(), self.slot.clone())
234    }
235}
236
237/// Everything the resolution pass learned, keyed for the verify pass.
238pub type RuleResolutions = BTreeMap<(String, String), RuleResolution>;
239
240/// Why one rule is not proven to serve.
241#[derive(Debug, Clone, PartialEq, Eq)]
242pub enum VerifyFinding {
243    /// No port resolved — the slot declares `fronted = true`, pins no number,
244    /// and no ready record supplied one.
245    PortUnresolved,
246    /// No address resolved. The detail carries whether the read was complete,
247    /// because "the workload is not up" and "the node that has it could not be
248    /// seen" are different facts (R844-F4).
249    NoBackend { detail: String },
250    /// Fewer backends than the rule's declared placement. Fatal on purpose —
251    /// see the module doc.
252    PartialPlacement {
253        covered: Vec<String>,
254        missing: Vec<(String, String)>,
255    },
256    /// A resolved address did not answer. The one finding no offline pass could
257    /// ever produce.
258    Unreachable {
259        address: String,
260        why: String,
261        /// The address came from the slot's `upstream_host` rather than from a
262        /// service record. Carried because it changes *which* claim just got
263        /// falsified — a discovered address that refuses means the record and
264        /// the world disagree, a pinned one means the TOML is wrong — and a
265        /// message that names the wrong one sends the operator to the wrong
266        /// file. Caught by running this verb against a mirror with a bogus pin.
267        from_pin: bool,
268    },
269    /// No resolution was recorded for this rule at all — a bug in the caller's
270    /// wiring rather than a fact about the fleet, reported instead of silently
271    /// rendering the rule as fine.
272    Unresolved,
273    /// The public hostname did not answer at all — DNS, TLS, connect, timeout
274    /// (R844-F18). The one finding that speaks for the public rather than for
275    /// the mesh.
276    PublicPathFailed { hostname: String, why: String },
277    /// The public hostname answered with a status the public would read as
278    /// broken. `503` here is the 2026-09-03 outage exactly: every mesh dial
279    /// open, every record correct, and this the only signal that disagreed.
280    PublicPathStatus { hostname: String, status: u16 },
281    /// The public path and the backend the service record names are serving
282    /// **different publishes** (R844-F18). The finding this ticket exists for:
283    /// it is true precisely when the front door is dialing something other than
284    /// the backend the rest of this report just proved reachable.
285    PublicBackendDivergence {
286        hostname: String,
287        public_digest: String,
288        address: String,
289        backend_digest: String,
290    },
291}
292
293impl VerifyFinding {
294    /// Human-readable finding, in the imperative where there is something to do.
295    pub fn message(&self) -> String {
296        match self {
297            Self::PortUnresolved => "no port resolved — the slot declares `fronted = true` \
298                 without `port`, and no in-scope node reported a ready record naming one. \
299                 Either the workload is not up, or its yubaba predates named ports and the \
300                 record is ambiguous; pin `port = <n>` on the slot to publish it anyway."
301                .to_string(),
302            Self::NoBackend { detail } => {
303                format!("no backend resolved — {detail}")
304            }
305            Self::PartialPlacement { covered, missing } => format!(
306                "resolves {} of {} declared placement node(s) — a SUBSET that renders like a \
307                 whole front door. Serving: {}. Missing: {}.",
308                covered.len(),
309                covered.len() + missing.len(),
310                covered.join(", "),
311                missing
312                    .iter()
313                    .map(|(m, why)| format!("{m} ({why})"))
314                    .collect::<Vec<_>>()
315                    .join("; ")
316            ),
317            Self::Unreachable {
318                address,
319                why,
320                from_pin,
321            } => {
322                let origin = if *from_pin {
323                    "The slot PINS this address in `upstream_host`, so nothing discovered it and \
324                     nothing but this connect could have contradicted it — fix the pin, or drop \
325                     it and let the fleet answer."
326                } else {
327                    "A ready service record is yubaba's OPINION; this connect is the measurement, \
328                     and they disagree (R844-B11)."
329                };
330                format!("{address} did not answer — {why}. {origin}")
331            }
332            Self::Unresolved => "no discovery resolution was recorded for this rule — the \
333                 verify pass planned it but never resolved it, which is a wiring bug in the \
334                 caller, not a fact about the fleet."
335                .to_string(),
336            Self::PublicPathFailed { hostname, why } => format!(
337                "https://{hostname}/ did not answer — {why}. Every line above measures the \
338                 MESH side; this is the only one that measures what the public gets, so a \
339                 report that is otherwise clean means the front door is not reaching the \
340                 backend the records name."
341            ),
342            Self::PublicPathStatus { hostname, status } => format!(
343                "https://{hostname}/ answered HTTP {status}. The backend above is reachable at \
344                 the port its service record advertises, so the front door is configured to \
345                 dial something else — that pair of facts is exactly the 2026-09-03 outage \
346                 (R844-T10), where a redeploy moved the port and nothing reconfigured the door."
347            ),
348            Self::PublicBackendDivergence {
349                hostname,
350                public_digest,
351                address,
352                backend_digest,
353            } => format!(
354                "https://{hostname}/ and the backend its service record names are serving \
355                 DIFFERENT publishes: the public path returns digest {public_digest}, {address} \
356                 returns {backend_digest}. The hostname answers, so nothing else in this report \
357                 can see it — the front door is dialing a backend other than the discovered one, \
358                 or an edge cache is still holding the previous publish."
359            ),
360        }
361    }
362}
363
364/// One rule's verdict on one front door.
365#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct RuleVerdict {
367    /// Node whose front door publishes this rule.
368    pub machine: String,
369    /// Front-door provider, as `IngressProvider::as_str`.
370    pub provider: String,
371    pub hostname: String,
372    pub slot: String,
373    pub port: Option<u16>,
374    /// The address came from the slot's `upstream_host` pin, so the dial below
375    /// measured a declaration rather than a discovered fact.
376    pub pinned: bool,
377    /// Every resolved backend, dialed.
378    pub endpoints: Vec<EndpointCheck>,
379    /// Empty means proven: every declared placement node resolved and every
380    /// resolved address answered.
381    pub findings: Vec<VerifyFinding>,
382    /// Non-fatal context — today, the placement gaps of a *pinned* rule, where
383    /// the pin overrides placement so a gap is worth saying and not worth
384    /// failing.
385    pub notes: Vec<String>,
386}
387
388impl RuleVerdict {
389    /// Proven to serve.
390    pub fn is_ok(&self) -> bool {
391        self.findings.is_empty()
392    }
393
394    /// Every address this verdict dialed, in resolution order.
395    pub fn addresses(&self) -> Vec<String> {
396        self.endpoints
397            .iter()
398            .map(|e| e.address.clone())
399            .collect()
400    }
401
402    /// This rule's port for a message, or `<unresolved>` — the same spelling
403    /// [`IngressRule::port_label`] uses, so a verify line and a collate line
404    /// describing one unresolved rule read identically.
405    pub fn port_label(&self) -> String {
406        self.port
407            .map(|p| p.to_string())
408            .unwrap_or_else(|| "<unresolved>".to_string())
409    }
410}
411
412/// Every rule on every collated front door, verified.
413#[derive(Debug, Clone, Default, PartialEq, Eq)]
414pub struct VerifyReport {
415    pub verdicts: Vec<RuleVerdict>,
416}
417
418impl VerifyReport {
419    /// Rules that are not proven to serve.
420    pub fn failures(&self) -> impl Iterator<Item = &RuleVerdict> {
421        self.verdicts.iter().filter(|v| !v.is_ok())
422    }
423
424    /// Nothing to fix.
425    pub fn is_clean(&self) -> bool {
426        self.failures().next().is_none()
427    }
428}
429
430// ── The public path (R844-F18) ───────────────────────────────────────────────
431
432/// What one HTTP GET of a publish beacon returned — the caller's measurement,
433/// handed in as data like every other input on this seam.
434///
435/// The URL is always
436/// `<base>/.well-known/yah-publish.json` ([`publish_beacon::BEACON_KEY`]),
437/// because that object is the only thing on either side of the comparison that
438/// *identifies which publish is being served*. A bare `GET /` cannot do this
439/// job: a front door pointed at the wrong backend still answers 200 with a
440/// plausible page, which is how `yah.dev` stayed frozen for nineteen days with
441/// every signal green.
442///
443/// [`publish_beacon::BEACON_KEY`]: crate::reconciler::publish_beacon::BEACON_KEY
444#[derive(Debug, Clone, PartialEq, Eq)]
445pub enum BeaconFetch {
446    /// The request completed.
447    Answered {
448        status: u16,
449        /// The `digest` field of the beacon, when the body parsed as one.
450        /// `None` when it did not — a 404, or a hostname fronting something
451        /// that is not a mesofact publish. That is a limit on the comparison,
452        /// not a failure of the host, and is reported as a note.
453        digest: Option<String>,
454    },
455    /// The request did not complete — DNS, TLS, connect, timeout.
456    Failed(String),
457}
458
459/// Everything the caller measured on the public path, keyed for the pure pass.
460///
461/// Two maps rather than one because the two sides are addressed differently and
462/// deduplicated differently: a hostname is fetched once however many front doors
463/// publish it, and a backend address is fetched once however many hostnames
464/// resolve to it.
465#[derive(Debug, Clone, Default, PartialEq, Eq)]
466pub struct PublicReadings {
467    /// `hostname` → what `https://<hostname>/.well-known/yah-publish.json`
468    /// returned. A hostname absent from this map was not measured, and
469    /// [`apply_public_path`] says so rather than passing it.
470    pub public: BTreeMap<String, BeaconFetch>,
471    /// `host:port` → what `http://<host:port>/.well-known/yah-publish.json`
472    /// returned, read over the mesh. This is "what the record claims", made
473    /// comparable.
474    pub backends: BTreeMap<String, BeaconFetch>,
475}
476
477/// Add the public-path verdict to a report that so far only knows the mesh
478/// side (R844-F18).
479///
480/// ## The claim this closes
481///
482/// [`verify_collation`] answers *"is the backend reachable at the port its
483/// record advertises"*. This answers *"and does the front door actually reach
484/// it"* — the fourth row of the table in the module docs, which read `nothing
485/// yet` until this landed. It closes it by comparing two publish beacons: the
486/// one the **public** gets through the real front door, and the one the
487/// **backend the record names** serves. They agree only if the door is dialing
488/// that backend.
489///
490/// ## Detector, not oracle — read this before using it as a gate
491///
492/// It compares two *current* states. It cannot tell you what a config change is
493/// about to do, because the front door has not been reconfigured yet: run it
494/// before and after an apply and require both green. That is enough for the
495/// failure it was built for — the divergence appears the moment the workload is
496/// redeployed onto a new port — and it is not a general "is this edit safe"
497/// oracle. Nothing in this module is.
498///
499/// ## The limit that cannot be designed away here
500///
501/// The public fetch goes wherever **DNS** sends it. A hostname published
502/// through two front doors is measured at one of them, and this pass cannot say
503/// which — so a divergence that affects only the other door reads as clean. The
504/// verdicts for such a hostname carry a note saying so; closing it needs a fetch
505/// pinned to each door's public address with a `Host` override, which needs a
506/// public IP per door that nothing in the collation carries today.
507pub fn apply_public_path(report: &mut VerifyReport, readings: &PublicReadings) {
508    let doors_per_hostname = report.verdicts.iter().fold(
509        BTreeMap::<String, usize>::new(),
510        |mut acc, v| {
511            *acc.entry(v.hostname.clone()).or_default() += 1;
512            acc
513        },
514    );
515
516    for verdict in &mut report.verdicts {
517        let Some(fetched) = readings.public.get(&verdict.hostname) else {
518            verdict.notes.push(format!(
519                "the public path was not checked for {} — this verdict speaks only for the mesh \
520                 side, which is necessary and not sufficient",
521                verdict.hostname
522            ));
523            continue;
524        };
525
526        let public_digest = match fetched {
527            BeaconFetch::Failed(why) => {
528                verdict.findings.push(VerifyFinding::PublicPathFailed {
529                    hostname: verdict.hostname.clone(),
530                    why: why.clone(),
531                });
532                continue;
533            }
534            BeaconFetch::Answered { status, .. } if !(200..300).contains(status) => {
535                verdict.findings.push(VerifyFinding::PublicPathStatus {
536                    hostname: verdict.hostname.clone(),
537                    status: *status,
538                });
539                continue;
540            }
541            BeaconFetch::Answered { digest, .. } => digest,
542        };
543
544        let Some(public_digest) = public_digest else {
545            verdict.notes.push(format!(
546                "https://{} answers, but serves no publish beacon, so the public path could not \
547                 be COMPARED against the backend — only that something is there",
548                verdict.hostname
549            ));
550            continue;
551        };
552
553        let mut compared = false;
554        for endpoint in &verdict.endpoints {
555            match readings.backends.get(&endpoint.address) {
556                Some(BeaconFetch::Answered {
557                    digest: Some(backend_digest),
558                    ..
559                }) => {
560                    compared = true;
561                    if backend_digest != public_digest {
562                        verdict.findings.push(VerifyFinding::PublicBackendDivergence {
563                            hostname: verdict.hostname.clone(),
564                            public_digest: public_digest.clone(),
565                            address: endpoint.address.clone(),
566                            backend_digest: backend_digest.clone(),
567                        });
568                    }
569                }
570                // A backend that answers without a beacon, or does not answer
571                // at all, leaves nothing to compare against. Not a finding of
572                // its own: `verify_collation` already dialed it and said what
573                // it found, and a second opinion phrased as an error would
574                // double-count one fact.
575                _ => {}
576            }
577        }
578
579        if !compared {
580            verdict.notes.push(format!(
581                "https://{} answers with a publish beacon, but no discovered backend served one \
582                 to compare it against, so this proves the hostname is up and NOT that it is \
583                 fronting the discovered backend",
584                verdict.hostname
585            ));
586        } else if doors_per_hostname
587            .get(&verdict.hostname)
588            .copied()
589            .unwrap_or(0)
590            > 1
591        {
592            // Only worth saying once a comparison actually happened: on a rule
593            // where nothing could be compared, the note above is the finding
594            // and this one is noise stacked on top of it.
595            verdict.notes.push(format!(
596                "{} is published through more than one front door and the public fetch went \
597                 wherever DNS sent it, so this compares ONE of them",
598                verdict.hostname
599            ));
600        }
601    }
602}
603
604/// Fill one plan's rules from a live fanout **without stopping at the first
605/// rule that cannot be dialed**, recording how each one resolved.
606///
607/// Deliberately not [`IngressPlan::resolve_upstreams_from`], though it applies
608/// the same precedence (a rule that already has an address keeps it — the pin
609/// always wins) and reads the same `upstreams_for`. That method `bail!`s on the
610/// first undialable rule, which is right for an *apply*: publishing a front door
611/// that is 80% correct is worse than publishing none. It is wrong for a
612/// *verifier*, whose entire job is the complete picture — an operator who fixes
613/// one rule and re-runs only to be told about the next one has been handed a
614/// linked list instead of a report.
615///
616/// Ports must already be resolved ([`IngressPlan::resolve_ports_from`]):
617/// discovery matches records by port, so a portless rule resolves no address
618/// either and is reported as both.
619pub fn resolve_upstreams_reporting(
620    plan: &mut IngressPlan,
621    fanout: &ServiceRecordFanout,
622) -> Vec<RuleResolution> {
623    let mut out = Vec::new();
624    for rule in &mut plan.rules {
625        let pinned = !rule.upstream_hosts.is_empty();
626        if !pinned {
627            rule.upstream_hosts = fanout.upstreams_for(rule);
628        }
629        let (covered, missing) = placement_coverage(rule, fanout);
630        out.push(RuleResolution {
631            hostname: rule.hostname.clone(),
632            slot: rule.slot.clone(),
633            pinned,
634            covered,
635            missing,
636        });
637    }
638    out
639}
640
641/// Which of a rule's declared placement nodes actually supplied a backend, and
642/// why each of the others did not.
643///
644/// Mirrors [`ServiceRecordFanout::upstreams_for`]'s matching (by port, scoped to
645/// the rule's placement) so the two cannot disagree about what "covered" means —
646/// it answers *which nodes* produced that method's addresses, one level of
647/// detail below what it returns.
648fn placement_coverage(
649    rule: &IngressRule,
650    fanout: &ServiceRecordFanout,
651) -> (Vec<String>, Vec<(String, String)>) {
652    let mut covered = Vec::new();
653    let mut missing = Vec::new();
654    for machine in &rule.machines {
655        match fanout.nodes.get(machine.as_str()) {
656            None => missing.push((
657                machine.clone(),
658                "was never asked — it is not in the set this read fanned out over".to_string(),
659            )),
660            Some(visibility) => match visibility.unknown_reason() {
661                Some(reason) => missing.push((machine.clone(), reason.to_string())),
662                None => {
663                    let serving = rule.port.is_some_and(|port| {
664                        visibility
665                            .records()
666                            .iter()
667                            .any(|r| r.ports.contains(&port))
668                    });
669                    if serving {
670                        covered.push(machine.clone());
671                    } else {
672                        missing.push((
673                            machine.clone(),
674                            match rule.port {
675                                Some(port) => format!(
676                                    "answered, and reports no ready record on port {port}"
677                                ),
678                                None => "the rule has no resolved port to match a record on"
679                                    .to_string(),
680                            },
681                        ));
682                    }
683                }
684            },
685        }
686    }
687    (covered, missing)
688}
689
690/// Verify every rule on every collated front door: check the resolution, then
691/// dial what it produced.
692///
693/// `dial` is the caller's TCP connect. Each distinct address is dialed **once**
694/// — a rule published through two front doors is the same backend twice, and
695/// two connects would be two chances to disagree about one fact.
696///
697/// `read_note` is [`ServiceRecordFanout::unknown_note`]: when the fanout could
698/// not see part of the fleet, an empty resolution is `UNKNOWN`, not `absent`,
699/// and every [`VerifyFinding::NoBackend`] says so rather than asserting the
700/// workload is down.
701///
702/// Verdicts come back in front-door order, then rule order — the same walk the
703/// collation itself renders in, so a caller may stream the two side by side
704/// rather than looking each verdict up.
705pub fn verify_collation<D>(
706    collation: &Collation,
707    resolutions: &RuleResolutions,
708    read_note: Option<&str>,
709    mut dial: D,
710) -> VerifyReport
711where
712    D: FnMut(&str) -> DialOutcome,
713{
714    let mut dialed: BTreeMap<String, DialOutcome> = BTreeMap::new();
715    let mut verdicts = Vec::new();
716
717    for door in &collation.front_doors {
718        for rule in &door.rules {
719            let mut findings = Vec::new();
720            let mut notes = Vec::new();
721            let key = (rule.hostname.clone(), rule.slot.clone());
722            let resolution = resolutions.get(&key);
723
724            let pinned = resolution.is_some_and(|r| r.pinned);
725            if resolution.is_none() {
726                findings.push(VerifyFinding::Unresolved);
727            }
728
729            if rule.port.is_none() {
730                findings.push(VerifyFinding::PortUnresolved);
731            }
732
733            if rule.upstream_hosts.is_empty() {
734                findings.push(VerifyFinding::NoBackend {
735                    detail: match read_note {
736                        Some(note) => format!(
737                            "and the discovery read was PARTIAL, so this is UNKNOWN rather than \
738                             empty: {note}"
739                        ),
740                        None => "every node in scope answered and none reports a ready record \
741                                 for it, so the workload is not serving"
742                            .to_string(),
743                    },
744                });
745            } else if let Some(res) = resolution {
746                if !res.missing.is_empty() {
747                    if pinned {
748                        // The pin overrides placement, so a gap is not a
749                        // shortfall in what gets published — but it IS the
750                        // shape that hid the 127.0.0.1 drift, so it is said
751                        // out loud rather than dropped.
752                        notes.push(format!(
753                            "slot pins `upstream_host`, so this dialed a DECLARATION, not a \
754                             discovered address; {} placement node(s) report no ready record \
755                             for it: {}",
756                            res.missing.len(),
757                            res.missing
758                                .iter()
759                                .map(|(m, why)| format!("{m} ({why})"))
760                                .collect::<Vec<_>>()
761                                .join("; ")
762                        ));
763                    } else {
764                        findings.push(VerifyFinding::PartialPlacement {
765                            covered: res.covered.clone(),
766                            missing: res.missing.clone(),
767                        });
768                    }
769                }
770            }
771
772            let mut endpoints = Vec::new();
773            if let Ok(addrs) = rule.upstreams() {
774                for address in addrs {
775                    let outcome = match dialed.get(&address) {
776                        Some(prior) => prior.clone(),
777                        None => {
778                            let outcome = dial(&address);
779                            dialed.insert(address.clone(), outcome.clone());
780                            outcome
781                        }
782                    };
783                    if let DialOutcome::Closed(why) = &outcome {
784                        findings.push(VerifyFinding::Unreachable {
785                            address: address.clone(),
786                            why: why.clone(),
787                            from_pin: pinned,
788                        });
789                    }
790                    endpoints.push(EndpointCheck { address, outcome });
791                }
792            }
793
794            verdicts.push(RuleVerdict {
795                machine: door.machine.clone(),
796                provider: door.provider.as_str().to_string(),
797                hostname: rule.hostname.clone(),
798                slot: rule.slot.clone(),
799                port: rule.port,
800                pinned,
801                endpoints,
802                findings,
803                notes,
804            });
805        }
806    }
807
808    VerifyReport { verdicts }
809}
810
811// ── Undeclared front doors (R858-B27) ────────────────────────────────────────
812
813/// A public origin that is **not** a declared passway front door for
814/// `hostname`, and so should not be able to serve it.
815#[derive(Debug, Clone, PartialEq, Eq)]
816pub struct UndeclaredDoorProbe {
817    pub hostname: String,
818    pub origin: PasswayOrigin,
819}
820
821impl UndeclaredDoorProbe {
822    /// The failure line for a probe whose origin answered with HTTP `status`
823    /// over a TLS handshake that verified a certificate for the hostname.
824    pub fn message(&self, status: u16) -> String {
825        format!(
826            "{} ({}) serves {} with a valid certificate (HTTP {status}) but no mirror declares \
827             it a front door for that hostname — DNS, rendered from the declared doors, will \
828             never send it traffic, and no other yah surface can see it. Declare it in the \
829             mirror's `ingress_machines`, or withdraw the enrollment on the box.",
830            self.origin.machine, self.origin.address, self.hostname
831        )
832    }
833}
834
835/// Every `(hostname, public origin)` pair where the origin is **not** a declared
836/// passway front door for the hostname — the pairs that must fail to serve.
837///
838/// ## Why this exists
839///
840/// On 2026-09-12 us-west-001 answered `yah.dev`, `noisetable.com` and
841/// `api.noisetable.com` with valid certificates while every declaration left it
842/// out: R870 had enrolled it as a third origin by hand, the mirror still had it
843/// commented out, and DNS — rendered from the mirror since R859-F1 — agreed with
844/// the mirror. Every probe in the camp dials the public hostname, so it can only
845/// ever sample the origins DNS hands it, and an undeclared door is invisible by
846/// construction: a spare nobody knows they have and an enrollment that outlived
847/// its reason read identically. The demux's route table is also its TLS
848/// allowlist (W267 Decision 2), which makes *who serves what* a security fact,
849/// not a capacity one.
850///
851/// So the caller dials each pair pinned to the origin's public address, and any
852/// pair that completes a verified TLS handshake is an undeclared door.
853///
854/// ## Scope
855///
856/// Only hostnames **this workspace's mirrors** collate, and only passway edges —
857/// a Cloudflare-tunnel hostname is not served off a node's public address, so
858/// probing one would measure nothing. Tenant hostnames enrolled from another
859/// camp (noisetable, scrabcake) are that camp's collation to check.
860///
861/// Candidates are every machine carrying the `public-ip` taint, resolved through
862/// [`public_origins`], so a tainted machine with no public address is the same
863/// hard error it is on the apex render.
864pub fn undeclared_door_probes(
865    collation: &Collation,
866    machines: &[MachineConfig],
867) -> Result<Vec<UndeclaredDoorProbe>> {
868    let names: Vec<String> = machines.iter().map(|m| m.name.clone()).collect();
869    let mut origins = public_origins(&names, machines, &[])?.origins;
870    origins.sort_by(|a, b| a.machine.cmp(&b.machine));
871
872    let mut declared: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
873    for door in &collation.front_doors {
874        if door.provider != IngressProvider::Passway {
875            continue;
876        }
877        for rule in &door.rules {
878            declared
879                .entry(rule.hostname.as_str())
880                .or_default()
881                .insert(door.machine.as_str());
882        }
883    }
884
885    let mut probes = Vec::new();
886    for (hostname, doors) in &declared {
887        for origin in &origins {
888            if !doors.contains(origin.machine.as_str()) {
889                probes.push(UndeclaredDoorProbe {
890                    hostname: hostname.to_string(),
891                    origin: origin.clone(),
892                });
893            }
894        }
895    }
896    Ok(probes)
897}
898
899#[cfg(test)]
900mod tests {
901    use super::*;
902    use crate::config::ConnectSpec;
903    use crate::reconciler::ingress::{collate_front_doors, PlannedEdge};
904    use crate::reconciler::service_discovery::{DiscoveredRecord, UnknownReason};
905
906    fn machine(name: &str, address: &str, taints: &[&str]) -> MachineConfig {
907        MachineConfig {
908            name: name.into(),
909            provider: "ovh".into(),
910            location: None,
911            server_type: None,
912            hosts_mirrors: vec![],
913            mesh_tags: vec![],
914            region: None,
915            zone: None,
916            arch: None,
917            bucket: None,
918            vendor: None,
919            nickname: None,
920            legacy_hostkey_fingerprint: None,
921            registration: Default::default(),
922            ssh_keys: vec![],
923            cloudflared: None,
924            hosts_operator_bridge: false,
925            connect: Some(ConnectSpec {
926                address: address.into(),
927                ssh: format!("root@{address}"),
928                identity_file: "~/.ssh/yah".into(),
929                yubaba_port: None,
930                yubaba: None,
931            }),
932            allocatable: None,
933            taints: taints.iter().map(|t| t.to_string()).collect(),
934            sovereign_group: None,
935            sovereign_role: None,
936            ingress_floating_ip: None,
937        }
938    }
939
940    /// The live fleet on 2026-09-14: three public doors and a mesh-only box.
941    fn fleet() -> Vec<MachineConfig> {
942        vec![
943            machine("us-east-001", "51.81.85.145", &["public-ip"]),
944            machine("us-south-001", "45.32.194.254", &["public-ip"]),
945            machine("us-west-001", "15.204.89.240", &["public-ip"]),
946            machine("us-west-011", "100.64.0.11", &[]),
947        ]
948    }
949
950    fn apex(front_doors: &[&str], provider: IngressProvider) -> Collation {
951        let mut p = plan(
952            vec![rule("yah.dev", Some(8080), &["us-east-001"])],
953            front_doors,
954        );
955        p.provider = provider;
956        collate_front_doors(&[PlannedEdge {
957            service: "yah-marketing".into(),
958            env: "prod".into(),
959            plan: p,
960        }])
961        .unwrap()
962    }
963
964    #[test]
965    fn a_public_origin_left_out_of_the_declared_doors_is_probed() {
966        let probes = undeclared_door_probes(
967            &apex(&["us-east-001", "us-south-001"], IngressProvider::Passway),
968            &fleet(),
969        )
970        .unwrap();
971
972        let got: Vec<_> = probes
973            .iter()
974            .map(|p| (p.hostname.as_str(), p.origin.machine.as_str()))
975            .collect();
976        assert_eq!(got, vec![("yah.dev", "us-west-001")]);
977        assert!(probes[0].message(200).contains("15.204.89.240"));
978    }
979
980    #[test]
981    fn declaring_the_door_leaves_nothing_to_probe() {
982        let probes = undeclared_door_probes(
983            &apex(
984                &["us-east-001", "us-south-001", "us-west-001"],
985                IngressProvider::Passway,
986            ),
987            &fleet(),
988        )
989        .unwrap();
990        assert!(probes.is_empty(), "{probes:#?}");
991    }
992
993    #[test]
994    fn a_tunnel_hostname_is_never_probed_against_public_origins() {
995        let probes = undeclared_door_probes(
996            &apex(&["us-east-001"], IngressProvider::CloudflareTunnel),
997            &fleet(),
998        )
999        .unwrap();
1000        assert!(probes.is_empty(), "{probes:#?}");
1001    }
1002
1003    fn rule(hostname: &str, port: Option<u16>, machines: &[&str]) -> IngressRule {
1004        IngressRule {
1005            hostname: hostname.to_string(),
1006            port,
1007            slot: "bundle".to_string(),
1008            provider_id: None,
1009            machines: machines.iter().map(|m| m.to_string()).collect(),
1010            upstream_hosts: vec![],
1011        }
1012    }
1013
1014    fn plan(rules: Vec<IngressRule>, front_doors: &[&str]) -> IngressPlan {
1015        IngressPlan {
1016            provider: IngressProvider::Passway,
1017            rules,
1018            front_doors: front_doors.iter().map(|m| m.to_string()).collect(),
1019            tunnel_id: None,
1020            edge_provider_id: None,
1021            image: None,
1022            auth: None,
1023            via: None,
1024            behind_tunnel: false,
1025            tunnel_door: None,
1026        }
1027    }
1028
1029    fn record(ident: &str, mesh_ip: &str, ports: &[u16]) -> DiscoveredRecord {
1030        DiscoveredRecord {
1031            ident: ident.to_string(),
1032            mesh_ip: mesh_ip.to_string(),
1033            ports: ports.to_vec(),
1034            named_ports: Default::default(),
1035        }
1036    }
1037
1038    /// Plan → resolve → collate → verify, the whole pipeline the CLI runs.
1039    fn run(
1040        mut plans: Vec<(&str, &str, IngressPlan)>,
1041        fanout: &ServiceRecordFanout,
1042        dial: impl FnMut(&str) -> DialOutcome,
1043    ) -> VerifyReport {
1044        let mut resolutions = RuleResolutions::new();
1045        let mut planned = Vec::new();
1046        for (service, env, plan) in &mut plans {
1047            for res in resolve_upstreams_reporting(plan, fanout) {
1048                resolutions.insert(res.key(), res);
1049            }
1050            planned.push(PlannedEdge {
1051                service: service.to_string(),
1052                env: env.to_string(),
1053                plan: plan.clone(),
1054            });
1055        }
1056        let collation = collate_front_doors(&planned).unwrap();
1057        let note = fanout.unknown_note();
1058        verify_collation(&collation, &resolutions, note.as_deref(), dial)
1059    }
1060
1061    fn always_open(_: &str) -> DialOutcome {
1062        DialOutcome::Open { millis: 1 }
1063    }
1064
1065    #[test]
1066    fn a_resolved_rule_whose_endpoint_answers_is_clean() {
1067        let mut fanout = ServiceRecordFanout::default();
1068        fanout.push_answer(
1069            "us-east-001",
1070            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1071        );
1072
1073        let report = run(
1074            vec![(
1075                "yah-marketing",
1076                "prod",
1077                plan(
1078                    vec![rule("yah.dev", Some(8080), &["us-east-001"])],
1079                    &["us-east-001"],
1080                ),
1081            )],
1082            &fanout,
1083            always_open,
1084        );
1085
1086        assert!(report.is_clean(), "{:#?}", report.verdicts);
1087        assert_eq!(report.verdicts.len(), 1);
1088        assert_eq!(report.verdicts[0].addresses(), vec!["100.64.0.3:8080"]);
1089        assert!(!report.verdicts[0].pinned);
1090    }
1091
1092    #[test]
1093    fn a_ready_record_whose_address_refuses_is_a_failure() {
1094        // R844-B11 in miniature: the record is Ready and every offline check
1095        // passes; only the connect knows.
1096        let mut fanout = ServiceRecordFanout::default();
1097        fanout.push_answer(
1098            "us-west-001",
1099            vec![record("yah-marketing", "100.64.0.3", &[4325])],
1100        );
1101
1102        let report = run(
1103            vec![(
1104                "yah-marketing",
1105                "prod",
1106                plan(
1107                    vec![rule("yah.dev", Some(4325), &["us-west-001"])],
1108                    &["us-west-001"],
1109                ),
1110            )],
1111            &fanout,
1112            |_| DialOutcome::Closed("connection refused".to_string()),
1113        );
1114
1115        assert!(!report.is_clean());
1116        let msg = report.verdicts[0].findings[0].message();
1117        assert!(msg.contains("100.64.0.3:4325"), "{msg}");
1118        assert!(msg.contains("connection refused"), "{msg}");
1119        assert!(
1120            msg.contains("OPINION"),
1121            "a DISCOVERED address that refuses means the record and the world \
1122             disagree, and the message has to say which: {msg}"
1123        );
1124    }
1125
1126    #[test]
1127    fn an_unreachable_pin_blames_the_toml_not_a_service_record() {
1128        // Found by running the verb against a mirror pinning a dead address:
1129        // the message told the operator a service record disagreed with the
1130        // world, when nothing had discovered anything — the address came
1131        // straight off the slot, and that is the file to open.
1132        let mut fanout = ServiceRecordFanout::default();
1133        fanout.push_answer(
1134            "us-east-001",
1135            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1136        );
1137
1138        let mut pinned_rule = rule("yah.dev", Some(8080), &["us-east-001"]);
1139        pinned_rule.upstream_hosts = vec!["100.64.0.99".to_string()];
1140
1141        let report = run(
1142            vec![(
1143                "yah-marketing",
1144                "prod",
1145                plan(vec![pinned_rule], &["us-east-001"]),
1146            )],
1147            &fanout,
1148            |_| DialOutcome::Closed("connection timed out".to_string()),
1149        );
1150
1151        let msg = report.verdicts[0].findings[0].message();
1152        assert!(msg.contains("upstream_host"), "{msg}");
1153        assert!(
1154            !msg.contains("OPINION"),
1155            "no record was consulted, so none can be blamed: {msg}"
1156        );
1157    }
1158
1159    #[test]
1160    fn resolving_a_subset_of_the_declared_placement_fails() {
1161        // The failure class this verb exists to remove: one of two nodes
1162        // answers, the rule renders and dials fine, and half the front door is
1163        // silently absent.
1164        let mut fanout = ServiceRecordFanout::default();
1165        fanout.push_answer(
1166            "us-east-001",
1167            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1168        );
1169        fanout.push_answer("us-west-001", vec![]);
1170
1171        let report = run(
1172            vec![(
1173                "yah-marketing",
1174                "prod",
1175                plan(
1176                    vec![rule("yah.dev", Some(8080), &["us-east-001", "us-west-001"])],
1177                    &["us-east-001"],
1178                ),
1179            )],
1180            &fanout,
1181            always_open,
1182        );
1183
1184        assert!(!report.is_clean(), "a subset must not pass");
1185        let msg = report.verdicts[0].findings[0].message();
1186        assert!(msg.contains("1 of 2"), "{msg}");
1187        assert!(msg.contains("us-west-001"), "{msg}");
1188        // The address it DID resolve is still reported — a failure that hides
1189        // the working half is a worse report, not a stricter one.
1190        assert_eq!(report.verdicts[0].addresses(), vec!["100.64.0.3:8080"]);
1191    }
1192
1193    #[test]
1194    fn an_unseen_placement_node_fails_as_unknown_not_as_down() {
1195        let mut fanout = ServiceRecordFanout::default();
1196        fanout.push_answer(
1197            "us-east-001",
1198            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1199        );
1200        fanout.push_unknown(
1201            "us-west-001",
1202            UnknownReason::Unreachable("no route to host".to_string()),
1203        );
1204
1205        let report = run(
1206            vec![(
1207                "yah-marketing",
1208                "prod",
1209                plan(
1210                    vec![rule("yah.dev", Some(8080), &["us-east-001", "us-west-001"])],
1211                    &["us-east-001"],
1212                ),
1213            )],
1214            &fanout,
1215            always_open,
1216        );
1217
1218        assert!(!report.is_clean());
1219        let msg = report.verdicts[0].findings[0].message();
1220        assert!(msg.contains("us-west-001"), "{msg}");
1221        assert!(msg.contains("no route to host"), "{msg}");
1222    }
1223
1224    #[test]
1225    fn a_rule_with_no_record_anywhere_reports_no_backend_on_a_complete_read() {
1226        let mut fanout = ServiceRecordFanout::default();
1227        fanout.push_answer("us-east-001", vec![]);
1228
1229        let report = run(
1230            vec![(
1231                "yah-marketing",
1232                "prod",
1233                plan(
1234                    vec![rule("yah.dev", Some(8080), &["us-east-001"])],
1235                    &["us-east-001"],
1236                ),
1237            )],
1238            &fanout,
1239            always_open,
1240        );
1241
1242        assert!(!report.is_clean());
1243        let msg = report.verdicts[0].findings[0].message();
1244        assert!(msg.contains("not serving"), "{msg}");
1245        assert!(
1246            !msg.contains("PARTIAL"),
1247            "a complete read must not hedge: {msg}"
1248        );
1249    }
1250
1251    #[test]
1252    fn a_rule_with_no_record_on_a_partial_read_says_unknown_rather_than_down() {
1253        let mut fanout = ServiceRecordFanout::default();
1254        fanout.push_unknown(
1255            "us-east-001",
1256            UnknownReason::EndpointAbsent("GET … returned 404".to_string()),
1257        );
1258
1259        let report = run(
1260            vec![(
1261                "yah-marketing",
1262                "prod",
1263                plan(
1264                    vec![rule("yah.dev", Some(8080), &["us-east-001"])],
1265                    &["us-east-001"],
1266                ),
1267            )],
1268            &fanout,
1269            always_open,
1270        );
1271
1272        assert!(!report.is_clean());
1273        let msg = report.verdicts[0].findings[0].message();
1274        assert!(msg.contains("UNKNOWN"), "{msg}");
1275        assert!(msg.contains("404"), "{msg}");
1276    }
1277
1278    #[test]
1279    fn a_portless_rule_reports_both_halves_rather_than_only_the_address() {
1280        // The `fronted = true` shape with nothing to match on: it must not read
1281        // as "the address is missing" alone.
1282        let mut fanout = ServiceRecordFanout::default();
1283        fanout.push_answer("us-east-001", vec![]);
1284
1285        let report = run(
1286            vec![(
1287                "yah-marketing",
1288                "prod",
1289                plan(vec![rule("yah.dev", None, &["us-east-001"])], &["us-east-001"]),
1290            )],
1291            &fanout,
1292            always_open,
1293        );
1294
1295        let findings = &report.verdicts[0].findings;
1296        assert!(
1297            findings
1298                .iter()
1299                .any(|f| matches!(f, VerifyFinding::PortUnresolved)),
1300            "{findings:#?}"
1301        );
1302        assert!(
1303            findings
1304                .iter()
1305                .any(|f| matches!(f, VerifyFinding::NoBackend { .. })),
1306            "{findings:#?}"
1307        );
1308    }
1309
1310    #[test]
1311    fn a_pinned_upstream_is_dialed_and_flagged_as_a_declaration() {
1312        // The 127.0.0.1 case. The pin wins, so the dial is still performed —
1313        // but the verdict has to say the address came from a TOML, and the
1314        // placement gap it papers over has to be visible.
1315        let mut fanout = ServiceRecordFanout::default();
1316        fanout.push_answer("us-east-001", vec![]);
1317
1318        let mut pinned_rule = rule("yah.dev", Some(8080), &["us-east-001"]);
1319        pinned_rule.upstream_hosts = vec!["127.0.0.1".to_string()];
1320
1321        let mut dialed: Vec<String> = Vec::new();
1322        let report = run(
1323            vec![(
1324                "yah-marketing",
1325                "prod",
1326                plan(vec![pinned_rule], &["us-east-001"]),
1327            )],
1328            &fanout,
1329            |addr| {
1330                dialed.push(addr.to_string());
1331                DialOutcome::Open { millis: 1 }
1332            },
1333        );
1334
1335        assert_eq!(dialed, vec!["127.0.0.1:8080"]);
1336        let v = &report.verdicts[0];
1337        assert!(v.pinned);
1338        assert!(v.is_ok(), "a pin that answers is not a failure: {v:#?}");
1339        assert_eq!(v.notes.len(), 1, "{:#?}", v.notes);
1340        assert!(v.notes[0].contains("DECLARATION"), "{}", v.notes[0]);
1341        assert!(v.notes[0].contains("us-east-001"), "{}", v.notes[0]);
1342    }
1343
1344    #[test]
1345    fn one_backend_published_through_two_front_doors_is_dialed_once() {
1346        let mut fanout = ServiceRecordFanout::default();
1347        fanout.push_answer(
1348            "us-east-001",
1349            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1350        );
1351
1352        let mut dialed: Vec<String> = Vec::new();
1353        let report = run(
1354            vec![(
1355                "yah-marketing",
1356                "prod",
1357                plan(
1358                    vec![rule("yah.dev", Some(8080), &["us-east-001"])],
1359                    &["us-east-001", "us-west-001"],
1360                ),
1361            )],
1362            &fanout,
1363            |addr| {
1364                dialed.push(addr.to_string());
1365                DialOutcome::Open { millis: 1 }
1366            },
1367        );
1368
1369        assert_eq!(
1370            report.verdicts.len(),
1371            2,
1372            "both front doors publish the rule, so both are verified"
1373        );
1374        assert_eq!(dialed, vec!["100.64.0.3:8080"], "dialed twice");
1375        assert!(report.is_clean());
1376    }
1377
1378    #[test]
1379    fn every_rule_is_reported_even_after_one_of_them_fails() {
1380        // The reason this does not call `resolve_upstreams_from`: an operator
1381        // fixing one rule at a time is being handed a linked list.
1382        let mut fanout = ServiceRecordFanout::default();
1383        fanout.push_answer(
1384            "us-east-001",
1385            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1386        );
1387
1388        let report = run(
1389            vec![(
1390                "yah-marketing",
1391                "prod",
1392                plan(
1393                    vec![
1394                        rule("a.yah.dev", Some(9999), &["us-east-001"]),
1395                        rule("b.yah.dev", Some(8080), &["us-east-001"]),
1396                    ],
1397                    &["us-east-001"],
1398                ),
1399            )],
1400            &fanout,
1401            always_open,
1402        );
1403
1404        assert_eq!(report.verdicts.len(), 2);
1405        let a = report
1406            .verdicts
1407            .iter()
1408            .find(|v| v.hostname == "a.yah.dev")
1409            .unwrap();
1410        let b = report
1411            .verdicts
1412            .iter()
1413            .find(|v| v.hostname == "b.yah.dev")
1414            .unwrap();
1415        assert!(!a.is_ok(), "the unresolvable rule fails");
1416        assert!(
1417            b.is_ok(),
1418            "and the rule after it is still resolved and dialed: {b:#?}"
1419        );
1420    }
1421
1422    // ── the public path (R844-F18) ───────────────────────────────────────────
1423
1424    /// The healthy apex: one hostname, one door, one backend, both sides
1425    /// serving the same publish.
1426    fn healthy_report() -> VerifyReport {
1427        let mut fanout = ServiceRecordFanout::default();
1428        fanout.push_answer(
1429            "us-east-001",
1430            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1431        );
1432        run(
1433            vec![(
1434                "yah-marketing",
1435                "prod",
1436                plan(
1437                    vec![rule("yah.dev", Some(8080), &["us-east-001"])],
1438                    &["us-east-001"],
1439                ),
1440            )],
1441            &fanout,
1442            always_open,
1443        )
1444    }
1445
1446    fn served(digest: &str) -> BeaconFetch {
1447        BeaconFetch::Answered {
1448            status: 200,
1449            digest: Some(digest.to_string()),
1450        }
1451    }
1452
1453    #[test]
1454    fn matching_beacons_on_both_sides_leave_the_verdict_clean() {
1455        let mut report = healthy_report();
1456        let readings = PublicReadings {
1457            public: [("yah.dev".to_string(), served("abc123"))]
1458                .into_iter()
1459                .collect(),
1460            backends: [("100.64.0.3:8080".to_string(), served("abc123"))]
1461                .into_iter()
1462                .collect(),
1463        };
1464        apply_public_path(&mut report, &readings);
1465        assert!(report.is_clean(), "{:#?}", report.verdicts);
1466        assert!(
1467            report.verdicts[0].notes.is_empty(),
1468            "a fully compared rule has nothing to caveat: {:?}",
1469            report.verdicts[0].notes
1470        );
1471    }
1472
1473    /// THE 2026-09-03 OUTAGE, reproduced as a unit test. Every mesh signal is
1474    /// green — the record is correct, the address answers, `verify_collation`
1475    /// alone reports the rule clean — and the public gets a 503 because the
1476    /// running front door is still dialing the port the workload left.
1477    #[test]
1478    fn a_503_at_the_apex_fails_a_rule_whose_mesh_side_is_entirely_green() {
1479        let mut report = healthy_report();
1480        assert!(
1481            report.is_clean(),
1482            "precondition: the mesh side is what reported success during the outage"
1483        );
1484
1485        let readings = PublicReadings {
1486            public: [(
1487                "yah.dev".to_string(),
1488                BeaconFetch::Answered {
1489                    status: 503,
1490                    digest: None,
1491                },
1492            )]
1493            .into_iter()
1494            .collect(),
1495            backends: [("100.64.0.3:8080".to_string(), served("abc123"))]
1496                .into_iter()
1497                .collect(),
1498        };
1499        apply_public_path(&mut report, &readings);
1500
1501        assert!(!report.is_clean());
1502        let msg = report.verdicts[0].findings[0].message();
1503        assert!(msg.contains("503"), "{msg}");
1504        assert!(
1505            msg.contains("yah.dev"),
1506            "the finding names the hostname the public dials: {msg}"
1507        );
1508    }
1509
1510    /// The stale-serve shape: the hostname answers 200 with a real page, so
1511    /// nothing short of comparing publishes can see it. This is the failure
1512    /// that froze the apex for nineteen days.
1513    #[test]
1514    fn a_200_serving_a_different_publish_than_the_backend_is_a_failure() {
1515        let mut report = healthy_report();
1516        let readings = PublicReadings {
1517            public: [("yah.dev".to_string(), served("old-digest"))]
1518                .into_iter()
1519                .collect(),
1520            backends: [("100.64.0.3:8080".to_string(), served("new-digest"))]
1521                .into_iter()
1522                .collect(),
1523        };
1524        apply_public_path(&mut report, &readings);
1525
1526        assert!(!report.is_clean());
1527        let msg = report.verdicts[0].findings[0].message();
1528        assert!(msg.contains("old-digest"), "{msg}");
1529        assert!(msg.contains("new-digest"), "{msg}");
1530        assert!(
1531            msg.contains("100.64.0.3:8080"),
1532            "and it names the backend it compared against: {msg}"
1533        );
1534    }
1535
1536    #[test]
1537    fn a_public_path_that_does_not_answer_at_all_is_a_failure() {
1538        let mut report = healthy_report();
1539        let readings = PublicReadings {
1540            public: [(
1541                "yah.dev".to_string(),
1542                BeaconFetch::Failed("dns error: no record".to_string()),
1543            )]
1544            .into_iter()
1545            .collect(),
1546            backends: [("100.64.0.3:8080".to_string(), served("abc123"))]
1547                .into_iter()
1548                .collect(),
1549        };
1550        apply_public_path(&mut report, &readings);
1551
1552        assert!(!report.is_clean());
1553        assert!(report.verdicts[0].findings[0]
1554            .message()
1555            .contains("dns error"));
1556    }
1557
1558    /// A hostname fronting something that is not a mesofact publish has no
1559    /// beacon to compare. That is a limit on the CHECK, not a fault of the
1560    /// host — so it is a note, and the rule stays clean rather than failing
1561    /// every non-bundle hostname in the fleet.
1562    #[test]
1563    fn a_hostname_with_no_beacon_is_noted_and_not_failed() {
1564        let mut report = healthy_report();
1565        let readings = PublicReadings {
1566            public: [(
1567                "yah.dev".to_string(),
1568                BeaconFetch::Answered {
1569                    status: 200,
1570                    digest: None,
1571                },
1572            )]
1573            .into_iter()
1574            .collect(),
1575            backends: [("100.64.0.3:8080".to_string(), served("abc123"))]
1576                .into_iter()
1577                .collect(),
1578        };
1579        apply_public_path(&mut report, &readings);
1580
1581        assert!(report.is_clean(), "{:#?}", report.verdicts);
1582        assert!(
1583            report.verdicts[0]
1584                .notes
1585                .iter()
1586                .any(|n| n.contains("no publish beacon")),
1587            "{:?}",
1588            report.verdicts[0].notes
1589        );
1590    }
1591
1592    /// The distinction this whole relay is about: "answers" is not "answers
1593    /// with the backend we just proved". A public 200 with no comparable
1594    /// backend must not read as a full pass.
1595    #[test]
1596    fn a_public_200_with_nothing_to_compare_says_so_rather_than_implying_a_match() {
1597        let mut report = healthy_report();
1598        let readings = PublicReadings {
1599            public: [("yah.dev".to_string(), served("abc123"))]
1600                .into_iter()
1601                .collect(),
1602            backends: BTreeMap::new(),
1603        };
1604        apply_public_path(&mut report, &readings);
1605
1606        assert!(report.is_clean());
1607        assert!(
1608            report.verdicts[0]
1609                .notes
1610                .iter()
1611                .any(|n| n.contains("NOT that it is fronting the discovered backend")),
1612            "{:?}",
1613            report.verdicts[0].notes
1614        );
1615    }
1616
1617    #[test]
1618    fn an_unmeasured_hostname_is_marked_as_unmeasured_not_as_passing() {
1619        let mut report = healthy_report();
1620        apply_public_path(&mut report, &PublicReadings::default());
1621
1622        assert!(report.is_clean(), "not checking is not failing");
1623        assert!(
1624            report.verdicts[0]
1625                .notes
1626                .iter()
1627                .any(|n| n.contains("was not checked")),
1628            "{:?}",
1629            report.verdicts[0].notes
1630        );
1631    }
1632
1633    /// DNS picks one door, so the comparison covers one door. Saying that is
1634    /// the difference between a caveat and a false claim of coverage.
1635    #[test]
1636    fn a_hostname_on_two_front_doors_is_noted_as_measured_at_only_one() {
1637        let mut fanout = ServiceRecordFanout::default();
1638        fanout.push_answer(
1639            "us-east-001",
1640            vec![record("yah-marketing", "100.64.0.3", &[8080])],
1641        );
1642        fanout.push_answer(
1643            "us-south-001",
1644            vec![record("yah-marketing", "100.64.0.2", &[8080])],
1645        );
1646        let mut report = run(
1647            vec![(
1648                "yah-marketing",
1649                "prod",
1650                plan(
1651                    vec![rule(
1652                        "yah.dev",
1653                        Some(8080),
1654                        &["us-east-001", "us-south-001"],
1655                    )],
1656                    &["us-east-001", "us-south-001"],
1657                ),
1658            )],
1659            &fanout,
1660            always_open,
1661        );
1662        assert_eq!(report.verdicts.len(), 2, "one verdict per front door");
1663
1664        let readings = PublicReadings {
1665            public: [("yah.dev".to_string(), served("abc123"))]
1666                .into_iter()
1667                .collect(),
1668            backends: [
1669                ("100.64.0.3:8080".to_string(), served("abc123")),
1670                ("100.64.0.2:8080".to_string(), served("abc123")),
1671            ]
1672            .into_iter()
1673            .collect(),
1674        };
1675        apply_public_path(&mut report, &readings);
1676
1677        assert!(report.is_clean(), "{:#?}", report.verdicts);
1678        assert!(
1679            report
1680                .verdicts
1681                .iter()
1682                .all(|v| v.notes.iter().any(|n| n.contains("wherever DNS sent it"))),
1683            "{:#?}",
1684            report.verdicts
1685        );
1686    }
1687}