aee1395c
docs: record what the decisions rest on
a73x 2026-08-06 09:12
Commit message
docs/README.md
| Old | New | ||
|---|---|---|---|
| @@ -31,3 +31,5 @@ By what you're trying to do: | |||
| 31 | 31 | ||
| 32 | - [decisions.md](decisions.md)—the settled decisions, the alternatives they | 32 | - [decisions.md](decisions.md)—the settled decisions, the alternatives they |
| 33 | beat, and the reasons | 33 | beat, and the reasons |
| 34 | - [assumptions.md](assumptions.md)—what those decisions rest on, and which | ||
| 35 | claims are proven versus still taken on trust | ||
docs/assumptions.md
| Old | New | ||
|---|---|---|---|
| @@ -0,0 +1,71 @@ | |||
| 1 | # Assumptions | ||
| 2 | |||
| 3 | What the decisions rest on. Every entry is a claim that could be false, the | ||
| 4 | decision that would be wrong if it were, and how we know—or that we don't. | ||
| 5 | Three lines each. For the choices themselves, see [decisions.md](decisions.md). | ||
| 6 | |||
| 7 | Write one down whenever a decision is made. An assumption nobody recorded is | ||
| 8 | one nobody can re-check when the ground moves. | ||
| 9 | |||
| 10 | ### A guest's address is host-local | ||
| 11 | |||
| 12 | Nothing outside a host ever dials a guest: the gate resolves a name to | ||
| 13 | (host, VM) and tunnels over the sync connection, and the agent on that host | ||
| 14 | does the dial. Underpins putting network attachment inside the provisioner. | ||
| 15 | **Proven**: traced in code, and live—gate SSH reaches guests on two hosts. | ||
| 16 | |||
| 17 | ### The reservation table is the used-address set | ||
| 18 | |||
| 19 | The agent's DHCP responder builds its allocation exclusion list from the same | ||
| 20 | map it stores reservations in, under one lock. This is why replaying | ||
| 21 | reservations at startup makes address collisions impossible, and why the | ||
| 22 | address hint was redundant enough to delete. | ||
| 23 | **Proven**: verified in code; a new VM has never taken a live guest's address. | ||
| 24 | |||
| 25 | ### An agent upgrade preserves running guests and their addresses | ||
| 26 | |||
| 27 | Replacing the binary under running VMs leaves them alive and re-adopts them | ||
| 28 | with the same addresses. Underpins rolling agents to a live fleet at all. | ||
| 29 | **Proven** 2026-08-01 on bare metal: a guest created by the old agent survived | ||
| 30 | the swap, kept its address, and stayed reachable through the gate. | ||
| 31 | |||
| 32 | ### Old agents tolerate raw images | ||
| 33 | |||
| 34 | `qemu-img convert -O raw` auto-detects its input, so a raw image is copied | ||
| 35 | rather than rejected. This is what makes the rollout order safe—publish raw | ||
| 36 | and repoint the default *before* shipping the agent that drops conversion. | ||
| 37 | **Proven** 2026-08-01: converting a raw input with `-O raw` yields a | ||
| 38 | byte-identical copy at exit 0, with the input detected as raw. The claim is | ||
| 39 | about the tool, not a particular host—which is why it outlived the fleet's | ||
| 40 | last old-agent machine. | ||
| 41 | |||
| 42 | ### macOS hands out guest addresses; we can only read them | ||
| 43 | |||
| 44 | vmnet's DHCP assigns after the guest boots, and the lease is readable without | ||
| 45 | privileges. Underpins discovering the address rather than assigning it, and | ||
| 46 | rejecting both bootpd reservations and a userspace network stack. | ||
| 47 | **Partly proven**: lease read-back spiked on real hardware; no provisioner | ||
| 48 | consumes it yet. | ||
| 49 | |||
| 50 | ### Nobody depends on bring-your-own qcow2 | ||
| 51 | |||
| 52 | Dropping conversion entirely—rather than keeping a fallback—assumes no user | ||
| 53 | supplies their own qcow2 image today. | ||
| 54 | **Unverified**: we have no telemetry on custom `image_url` use. The blast | ||
| 55 | radius is a permanent, legible failure at create, not silent breakage. | ||
| 56 | |||
| 57 | ### A laptop is a viable fleet host | ||
| 58 | |||
| 59 | A Mac that sleeps and wakes rejoins without intervention. Underpins enrolling | ||
| 60 | one at all. | ||
| 61 | **Partly proven**: the agent survived sleep and reconnected on its own—with | ||
| 62 | zero guests. What sleep does to a host *running* VMs is untested, and neither | ||
| 63 | reconcile nor lost-VM detection was designed for it. | ||
| 64 | |||
| 65 | ### Fleet hosts can reach the image server locally | ||
| 66 | |||
| 67 | Serving guest images from the box that serves eitri.sh assumes every host | ||
| 68 | reaches it over the LAN rather than hairpinning out through the uplink, and | ||
| 69 | that hosts stay on that LAN. | ||
| 70 | **Unverified**: one fleet host is a laptop that leaves the network, and a | ||
| 71 | public hostname resolving to a public address would route the long way round. | ||
docs/decisions.md
| Old | New | ||
|---|---|---|---|
| @@ -2,7 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | Settled ground: the irreversible or contested choices, what they beat, and why. | 3 | Settled ground: the irreversible or contested choices, what they beat, and why. |
| 4 | Three lines each—when a rationale needs more, it lives in the relevant doc. | 4 | Three lines each—when a rationale needs more, it lives in the relevant doc. |
| 5 | For *how* we decide, see [ethos.md](ethos.md). | 5 | For *how* we decide, see [ethos.md](ethos.md); for what these rest on, see |
| 6 | [assumptions.md](assumptions.md). | ||
| 6 | 7 | ||
| 7 | ### Desired-state loop, not RPC | 8 | ### Desired-state loop, not RPC |
| 8 | 9 | ||