hosting-capability-wire
Follow-up to 78d5664, acting on a Fable review and a Codex review that independently reached the same verdict: right instinct, false story, three real defects. This fixes all four. Discussion #110.
1. Hosting is answered per box, never inferred across boxes
78d5664 keyed hosting on data_bucket alone. An absent data_bucket is exactly what an old writer and a bucket-less new box both produce, so it had to decide when silence meant "no" — and it decided by asking whether any other box had spoken. The first box in a fleet to adopt a bucket-publishing build therefore withdrew every region that had not yet rolled, all of them healthy: minutes for an uninterrupted fleet roll, hours at one box an hour, unbounded if a roll stalled.
Codex put it best: one writer's upgrade cannot establish another writer's capabilities.
Each box now states its own answer. hibernation_configured is on every edges file, always published, never omitempty — that is the whole point, because only an explicit false can carry the third state:
| wire | meaning | |---|---| | absent | a writer predating the field — unknown | | true | the activator is configured | | false | it is not |
Unknown is not no. A box predating the field keeps the eligibility it had before the field existed. Deliberately generous, and it is what makes a box roll safe in either direction: a create into a genuinely unconfigured old box can still strand, but that is the bug we already had, where refusing creates into regions that host perfectly well would be a new one caused by the fix.
It reports configuration, not verified hosting. A box naming a bucket its IAM role cannot reach publishes true and still fails every wake.
2. Three doors stop sharing one bar
They were asking three different questions through one predicate, which is how a static site came to be refused for want of an activator it never needed.
- Reachable (an EIP) — required by every kind.
- Hosting — required only by a socket-backed instance, the only kind an activator spawns. A static route is served from bucket bytes by every armed edge; an addr-backed service proxies to a process the platform never starts. The create gate ran before the record's kind was read, so it applied to all three alike. It now asks
provision.Record.DerivesPaths, so it cannot drift from what reconcile will mint. - Staging (published bucket coordinates) — the move door's bar, and unconditional, no dormant path.
internal/host'smoveTargetsdrops any target with nodata_bucketandrunMoveRoundthen answers "publishes no data bucket yet — waiting" forever. The door accepted such a move on reachability alone and wedged a live instance's residence inpreparingwith no way out but a manual cancel — the door and the worker disagreeing about one fact, which is the failure this family of gates exists to prevent. Unknown is acceptable for a create, which stakes one new instance; not for a move, which stakes a running one.
3. The prose is corrected
78d5664 asserted in six places that tito's five region boxes had no CARLOS_HIBERNATE_BUCKET and that this caused #110's 502. That is false — every tito region box publishes a data_bucket, so their activators are armed. Every sentence resting on that story is gone.
The 502 remains unexplained. Current lead: per-instance DNS for a region-placed host is "Recorded, not built", so *.go.tito.io resolves to the home box (54.228.234.85) and never to the region box, and the request has to cross the backhaul — whose dial and TLS failures are also bare 502s.
The log line no longer claims every request 502s (it cannot see whether something outside the platform is bound to that socket) and no longer gives env advice that helps only one of the two roles that reach it.
4. The documented gap, closed at the source
The gap 78d5664 should have cited is real: region-host/README.md's minimum host.env listed four variables and said "nothing more", so a box built strictly by the docs is an edge that cannot host. It now carries the hibernation block and says what leaving it out costs.
Tests
TestPlacementsAnswersHostingPerBox— the three states apart, and specifically that one box publishing a bucket does not make another box's silence mean no.TestPlacementsFoldsAcrossBoxesInARegion,TestPlacementsDormantWithoutAnyPlacementCode.TestCreateDoorLetsStaticIntoANonHostingRegion,TestCreateDoorLetsAddrBackedServiceIntoANonHostingRegion,TestCreateDoorRefusesEveryKindIntoAnUnreachableRegion.TestMoveDoorRequiresAStagingBucket.
Each was verified to fail against the unfixed code: the static/service pair returns 400 when the kind exemption is removed, and the move door accepts (202 preparing) when its bar is weakened from Staging to Hosting — the wedge, reproduced.
Wire-body tests in internal/host/edgesfile_test.go are updated for the new key; they exist to make exactly this kind of change deliberate.
Wire change
Additive: hibernation_configured is a new key on control/edges/<box>.json. Every reader that predates it ignores it, and every file written before it still parses. Console-first rollout is the intended order (an unrolled console simply never reads the key), but either order is safe because unknown preserves legacy eligibility.
Discussions
- No discussions on this branch yet.
Tasks
- No tasks yet.
Activity
- No activity yet.