5592edcfa7
lint / lint (push) Successful in 41s
test / stage-firecracker-inputs (pull_request) Successful in 2s
tracker-policy-pr / check-pr (pull_request) Successful in 10s
test / unit (pull_request) Failing after 29s
test / integration-docker (pull_request) Successful in 32s
test / build-infra (pull_request) Successful in 3m26s
test / integration-firecracker (pull_request) Successful in 1m27s
test / coverage (pull_request) Failing after 57s
test / publish-infra (pull_request) Has been skipped
An unattributed bottle, an unreachable orchestrator, and an unparseable policy all become a deny-all Config, and a deny-all is indistinguishable from "policy loaded, host not allowed" at the decision point — both are just "no matching route". So every one of them reported `host X is not in the bottle's egress.routes allowlist`, which reads as a config problem and sends the operator hunting for a route that was never missing. Diagnosing a bricked registration cost hours for exactly this reason. Carry the structural reason on Config and prefer it in decide(). A genuine allowlist miss — a policy that loaded and simply lacks the host — keeps the original wording, so the message now tells the two cases apart. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>