carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1# Zero-downtime deploys: rev 19 amendment (generation socket names)
2
3Status: rev 19, 2026-10-13. Paul approved the fix on 2026-10-13 after Gate F
4failed. This amends §7.1 of
5`2026-10-07-zero-downtime-deploys-design.md` (rev 17, as amended by rev 18).
6
7## What happened
8
9Gate F armed the flagship's IE box at 22:08Z on 2026-10-13. For about
103.5 minutes every generation wake of three instances of one app crash-looped,
11until the flag was removed (amadan #272).
12
13The app's framework works out its origin from the file name of its `--socket`
14argument:
15
16- A bare `app.sock` names no host, so the framework falls back to its
17 configured origin. This is how every nested instance starts with the flag
18 off.
19- The nested generation socket `app.3.sock` parsed as the host `app.3`. That
20 disagreed with the configured origin, so the app refused to start.
21
22`CARLOS_HOST` was set on those launches, and the docs say to read it rather
23than the socket name, but deployed builds do not. A platform release must not
24break a build that starts today. The dev probe passed because `zddprobe`
25ignores its socket name.
26
27## The rule (replaces §7.1's generation paths)
28
291. **A generation's socket file name is the flag-off one.**
30 - Nested: `app.sock`.
31 - Flat: `<host>.sock`.
32
33 Each generation gets its own directory instead:
34 - Nested: `<instance run dir>/g<n>/app.sock`, for example
35 `/run/carlos/instances/<id>/g3/app.sock`.
36 - Flat: `/run/carlos/g/<n>/<host>.sock`.
37
38 The control socket stays `<socket>.control`, beside it. Rev 15's canonical
39 link at `rt.Socket` keeps pointing at the current generation's socket by
40 absolute path. §7.1's "the hostname never appears in it" no longer holds
41 for flat generation paths. See rule 4 for the length bound that replaced
42 it.
432. **A generation launch matches a flag-off launch.** Its argv and its
44 agent-owned environment are the same as a flag-off launch of the same
45 build, except for the directory part of `--socket`. This already holds for
46 the environment (`agentOwnedVars`). A test pins it for both layouts.
473. **The directory's lifecycle.**
48 - Before generation n's stale-file removal and start, the agent makes its
49 directory, mode 0750 with setgid, inheriting the carlos-sockets group as
50 the run dirs do.
51 - The stale-file rule is unchanged: before the app binds, only the file at
52 this generation's own path is removed.
53 - Once the generation's termination proof holds and its socket is gone,
54 the agent removes the directory if it is empty. A sibling's directory is
55 never touched.
56 - A leftover directory from an earlier agent process is harmless, and the
57 stale-file rule clears its socket the next time n is used.
584. **The length bound.** A unix socket path is at most 107 bytes. A flat host
59 whose generation path would exceed that has no generation path: it is
60 handled exactly as a foreign row is today, keeping its canonical socket.
61 This adds no new member-facing state and no new copy. The window is small,
62 because the flag-off path `/run/carlos/<host>.sock` is already near the
63 bound for the same host. Nested paths are bounded by the 40-byte instance
64 identifier and stay well under it.
65
66 The bound is measured on the host alone: the control socket
67 `/run/carlos/g/<n>/<host>.sock.control` at the largest generation number
68 (20 digits). So flat hosts of up to 59 bytes get generation paths,
69 against 82 bytes for the flag-off control socket. Measuring at the
70 current number would let a row change treatment as the counter grows,
71 even in the middle of a swap: an attempt admitted as an overlap could
72 meet a generation that cannot bind.
735. **The probe checks it.** `cmd/zddprobe` exits 1, with a clear line on
74 stderr, before it listens if either of these is wrong:
75 - the base name of `--socket` is neither `app.sock` nor
76 `$CARLOS_HOST.sock`;
77 - `CARLOS_HOST` is empty.
78
79 A dev or flagship probe then fails its health check the way the tenant
80 did, instead of passing.
81
82## Not changed
83
84- Generation numbering, the generations file, the termination proof, the
85 scheduler, the canary, and the failure book.
86- Flag-off paths. With `CARLOS_SWAP` unset, nothing in this amendment runs.
87
88## Before Gate F runs again
89
90- Release the fix, and roll it to dev and then the flagship.
91- Re-run the dev swap under load with the new probe.
92- Clear annie's stale failure record. It holds bdn/ips build `2d577ebda` on
93 canada, which is the live build. Clearing it needs Paul's approval.
94