CluPilotCloud/app
nexxo 0543a5a542 Let a failed measurement beat a green badge, and say which zone was missing
Three findings from the live readiness page, and the worst of them is the one
that looks like nothing.

Green "Erfüllt" sat directly above red "nicht in Ordnung", in the same row,
twice — for the DNS token and for the VM template. The badge came from
`satisfied` alone, the passive check that only establishes something IS
configured, and the measurement was rendered beside it without being allowed to
overrule it. Somebody scanning that list reads the badge, not the small print,
and walks away with "all green" while a measurement said it does not work. R19
names this exact shape — a call that reads as an assurance and is not one — as
worse than no check at all. The measurement wins now, for the badge, the icon
and the reason line.

zone_not_found was a dead end. It reads like "the token is wrong", so the
operator replaces the token — but a wrong token never gets that far: it comes
back as `rejected` from the 401 above. The token had just successfully listed
the zones. What is missing is the ZONE. The check now returns the zones it did
see, and the page puts them next to the one it wanted: looked for
clupilot.cloud, this account holds clupilot.com. The question answers itself.
An empty list says something else again, and gets its own sentence: the token
belongs to a different Hetzner project.

And two traffic tests were failing on main, unrelated to any of this, which is
why they were checked against a clean checkout before being touched. They build
"last month" as now()->subMonth()->format('Y-m'), and Carbon resolves that
calendrically: on 31 July it lands on 1 July, so the row meant to be last
period lands in the current one. Red on the 29th, 30th and 31st of every long
month, and today is the 31st. The production code does not have the trap —
currentPeriod() is now()->format('Y-m') with no arithmetic, and the two places
that do compute months already guard it — so this is the tests, and only the
tests.

2045 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 15:26:27 +02:00
..
Actions Stop charging VAT to the customers who owe us none 2026-07-30 02:15:41 +02:00
Console Fill the hostname page from the installation, not from a blank form 2026-07-31 00:53:12 +02:00
Exceptions Refuse the sale instead of reaching Stripe without a key 2026-07-30 11:58:01 +02:00
Http Rebuild Add host as a page with one job, and let downloads through the gate 2026-07-30 21:51:30 +02:00
Jobs Let the export have as many destinations as somebody wants 2026-07-29 02:43:15 +02:00
Listeners Keep a register of what was sent, and answer the customer from here 2026-07-29 21:02:36 +02:00
Livewire Fill the hostname page from the installation, not from a blank form 2026-07-31 00:53:12 +02:00
Mail Merge main into the operating-mode branch 2026-07-30 17:53:20 +02:00
Models Fill the hostname page from the installation, not from a blank form 2026-07-31 00:53:12 +02:00
Notifications Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Observers Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
Policies Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
Providers Subtract only what was counted, not everything a singleton adopted 2026-07-30 18:20:27 +02:00
Provisioning Keep the platform on .com and the customers on .cloud 2026-07-30 21:04:08 +02:00
Services Let a failed measurement beat a green badge, and say which zone was missing 2026-07-31 15:26:27 +02:00
Support Keep IP addresses out of a certificate overview 2026-07-31 01:01:47 +02:00