M6 was not a planned milestone — it was an audit of the retired monitor’s
20-post build log against the rebuild, logged in docs/GAPS.md. This is the
first of eleven gaps closed, each with the same discipline: the gap, the
decision that mattered, the proof.
Gap: the old monitor said which certificate failure it saw; the rebuild
flattened everything to connect — the least useful alert text there is.
What changed: TLS errors now classify into cert_expired,
cert_not_yet_valid, cert_name_mismatch, cert_untrusted, or generic tls
as committed check detail. The deeper fix was the trust config itself: reqwest
on macOS delegates verification to Security.framework, which returns opaque OS
status codes — the rich CertificateError variants are destroyed before the
classifier sees them. So the monitor builds its own rustls ClientConfig on
webpki-roots: deterministic on every OS, and honest in a specific way — the
monitor reports what public clients see, and a corporate root can’t quietly
mask a real failure. For operators with internal CAs,
ProbePolicy::extra_roots trusts what they explicitly add, nothing else.
Proof: rcgen fixtures over a real rustls server cover all four classes plus
a trusted chain; live drill — expired.badssl.com committed cert_expired, a
wrong-host endpoint committed cert_name_mismatch.
Lesson: the verifier is part of the contract. Switching off the platform verifier wasn’t just about better error strings — it makes classification deterministic across OSes and stops a local root store from silently rewriting what “trusted” means.