zdd rev 19 amendment: generation sockets keep the flag-off file name
Gate F (2026-10-13) crash-looped an app whose framework takes its origin from the --socket file name: app.3.sock read as host app.3. Each generation now gets its own directory and keeps the flag-off base name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+85
−0
docs/superpowers/specs/2026-10-13-zero-downtime-deploys-rev19-amendment.md+85 −0
CI failed — run details
CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok amadan.net/carlos/platform.git/launchctx 0.011s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok github.com/carlosframework/platform 331.167s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 3.209s
ok github.com/carlosframework/platform/cmd/moveprobe 93.245s
ok github.com/carlosframework/platform/cmd/zddprobe 0.382s
ok github.com/carlosframework/platform/internal/activator 227.226s
ok github.com/carlosframework/platform/internal/agentsock 0.026s
ok github.com/carlosframework/platform/internal/alerting 0.003s
ok github.com/carlosframework/platform/internal/analytics 0.019s
ok github.com/carlosframework/platform/internal/appconfig 2.330s
ok github.com/carlosframework/platform/internal/apperr 0.076s
ok github.com/carlosframework/platform/internal/applog 0.144s
ok github.com/carlosframework/platform/internal/awsinv 0.005s
ok github.com/carlosframework/platform/internal/boxchoice 0.004s
ok github.com/carlosframework/platform/internal/boxid 0.624s
? github.com/carlosframework/platform/internal/boxid/boxidtest [no test files]
? github.com/carlosframework/platform/internal/boxid/internal/signtest [no test files]
ok github.com/carlosframework/platform/internal/boxvolumes 0.009s
ok github.com/carlosframework/platform/internal/caps 0.015s
ok github.com/carlosframework/platform/internal/certwarm 0.002s
ok github.com/carlosframework/platform/internal/cgroup 0.707s
ok github.com/carlosframework/platform/internal/changelog 0.293s
ok github.com/carlosframework/platform/internal/clamd 0.055s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 362.170s
? github.com/carlosframework/platform/internal/controlname [no test files]
? github.com/carlosframework/platform/internal/controlsock [no test files]
ok github.com/carlosframework/platform/internal/dbdoor 5.644s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.010s
ok github.com/carlosframework/platform/internal/dbverify 0.007s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.005s
ok github.com/carlosframework/platform/internal/domains 2.076s
ok github.com/carlosframework/platform/internal/doorkey 0.006s
ok github.com/carlosframework/platform/internal/economics 0.004s
ok github.com/carlosframework/platform/internal/edge 26.325s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.008s
ok github.com/carlosframework/platform/internal/fleetapi 0.121s
ok github.com/carlosframework/platform/internal/gate 1.656s
ok github.com/carlosframework/platform/internal/genselect 0.016s
ok github.com/carlosframework/platform/internal/geo 0.017s
ok github.com/carlosframework/platform/internal/geoip 0.032s
ok github.com/carlosframework/platform/internal/host 94.461s
ok github.com/carlosframework/platform/internal/hostactors 0.500s
ok github.com/carlosframework/platform/internal/hostbox 2.079s
ok github.com/carlosframework/platform/internal/hostclaim 0.494s
ok github.com/carlosframework/platform/internal/hostevidence 0.006s
--- FAIL: TestRenewalRequestStartAndIndependentExpiry (4.00s)
controller_test.go:211: blocked PUT blocked watchdog
panic.go:694: context deadline exceeded
FAIL
FAIL github.com/carlosframework/platform/internal/hostexec 8.768s
ok github.com/carlosframework/platform/internal/hostfence 0.038s
ok github.com/carlosframework/platform/internal/hostfiles 10.595s
ok github.com/carlosframework/platform/internal/hostfloor 0.012s
ok github.com/carlosframework/platform/internal/hostguard 1.003s
ok github.com/carlosframework/platform/internal/hostops 1.432s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.002s
ok github.com/carlosframework/platform/internal/hostquarantine 0.005s
ok github.com/carlosframework/platform/internal/hostrelocate 0.471s
ok github.com/carlosframework/platform/internal/hostresolve 0.128s
ok github.com/carlosframework/platform/internal/hostwrite 0.001s
ok github.com/carlosframework/platform/internal/infraview 0.002s
ok github.com/carlosframework/platform/internal/instancectl 1.820s
ok github.com/carlosframework/platform/internal/instanceexec 2.712s
ok github.com/carlosframework/platform/internal/instancefs 0.016s
ok github.com/carlosframework/platform/internal/instancekey 0.013s
ok github.com/carlosframework/platform/internal/instanceupdates 0.020s
ok github.com/carlosframework/platform/internal/layout 1.383s
ok github.com/carlosframework/platform/internal/lease 9.434s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.016s
ok github.com/carlosframework/platform/internal/ledger 0.024s
ok github.com/carlosframework/platform/internal/mail 0.157s
ok github.com/carlosframework/platform/internal/maintenance 0.080s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.594s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.077s
ok github.com/carlosframework/platform/internal/metrics 0.004s
ok github.com/carlosframework/platform/internal/moves 20.942s
ok github.com/carlosframework/platform/internal/moves/archive 0.749s
ok github.com/carlosframework/platform/internal/objstore 0.152s
ok github.com/carlosframework/platform/internal/ops 0.164s
ok github.com/carlosframework/platform/internal/park 0.206s
ok github.com/carlosframework/platform/internal/privatefile 0.004s
ok github.com/carlosframework/platform/internal/provision 12.977s
ok github.com/carlosframework/platform/internal/publicrelease 0.007s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 4.039s
ok github.com/carlosframework/platform/internal/relay 7.234s
ok github.com/carlosframework/platform/internal/release 20.156s
ok github.com/carlosframework/platform/internal/rollout 3.687s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.007s
ok github.com/carlosframework/platform/internal/rootparticipation 0.006s
ok github.com/carlosframework/platform/internal/rootstate 0.024s
ok github.com/carlosframework/platform/internal/s3compat 0.005s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.311s
ok github.com/carlosframework/platform/internal/sim/hostlife 9.495s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 3.792s
ok github.com/carlosframework/platform/internal/status 0.036s
ok github.com/carlosframework/platform/internal/steering 0.005s
ok github.com/carlosframework/platform/internal/stopevidence 0.212s
ok github.com/carlosframework/platform/internal/svcrole 0.002s
ok github.com/carlosframework/platform/internal/telemetry 0.004s
ok github.com/carlosframework/platform/internal/termfence 0.004s
ok github.com/carlosframework/platform/internal/tunnelclient 0.004s
ok github.com/carlosframework/platform/internal/unixdial 0.002s
ok github.com/carlosframework/platform/internal/updatewords 0.004s
ok github.com/carlosframework/platform/internal/usage 0.004s
ok github.com/carlosframework/platform/internal/version 0.001s
ok github.com/carlosframework/platform/internal/vet 1.547s
FAIL
make: *** [Makefile:18: test] Error 1
amadan: step gate failed: exit status 2
amadan: job failed at step gate — its output is above, not at the tail of this log
diff --git a/docs/superpowers/specs/2026-10-13-zero-downtime-deploys-rev19-amendment.md b/docs/superpowers/specs/2026-10-13-zero-downtime-deploys-rev19-amendment.md| new file mode 100644 |
| index 000000000..672cad915 |
| --- /dev/null |
| +++ b/docs/superpowers/specs/2026-10-13-zero-downtime-deploys-rev19-amendment.md |
| @@ -0,0 +1,85 @@ |
| +# Zero-downtime deploys: rev 19 amendment (generation socket names) |
| + |
| +Status: rev 19, 2026-10-13. Paul approved the fix on 2026-10-13 after Gate F |
| +failed. This amends §7.1 of |
| +`2026-10-07-zero-downtime-deploys-design.md` (rev 17, as amended by rev 18). |
| + |
| +## What happened |
| + |
| +Gate F armed the flagship's IE box at 22:08Z on 2026-10-13. For about |
| +3.5 minutes every generation wake of three instances of one app crash-looped, |
| +until the flag was removed (amadan #272). |
| + |
| +The app's framework works out its origin from the file name of its `--socket` |
| +argument: |
| + |
| +- A bare `app.sock` names no host, so the framework falls back to its |
| + configured origin. This is how every nested instance starts with the flag |
| + off. |
| +- The nested generation socket `app.3.sock` parsed as the host `app.3`. That |
| + disagreed with the configured origin, so the app refused to start. |
| + |
| +`CARLOS_HOST` was set on those launches, and the docs say to read it rather |
| +than the socket name, but deployed builds do not. A platform release must not |
| +break a build that starts today. The dev probe passed because `zddprobe` |
| +ignores its socket name. |
| + |
| +## The rule (replaces §7.1's generation paths) |
| + |
| +1. **A generation's socket file name is the flag-off one.** |
| + - Nested: `app.sock`. |
| + - Flat: `<host>.sock`. |
| + |
| + Each generation gets its own directory instead: |
| + - Nested: `<instance run dir>/g<n>/app.sock`, for example |
| + `/run/carlos/instances/<id>/g3/app.sock`. |
| + - Flat: `/run/carlos/g/<n>/<host>.sock`. |
| + |
| + The control socket stays `<socket>.control`, beside it. Rev 15's canonical |
| + link at `rt.Socket` keeps pointing at the current generation's socket by |
| + absolute path. §7.1's "the hostname never appears in it" no longer holds |
| + for flat generation paths. See rule 4 for the length bound that replaced |
| + it. |
| +2. **A generation launch matches a flag-off launch.** Its argv and its |
| + agent-owned environment are the same as a flag-off launch of the same |
| + build, except for the directory part of `--socket`. This already holds for |
| + the environment (`agentOwnedVars`). A test pins it for both layouts. |
| +3. **The directory's lifecycle.** |
| + - Before generation n's stale-file removal and start, the agent makes its |
| + directory, mode 0750 with setgid, inheriting the carlos-sockets group as |
| + the run dirs do. |
| + - The stale-file rule is unchanged: before the app binds, only the file at |
| + this generation's own path is removed. |
| + - Once the generation's termination proof holds and its socket is gone, |
| + the agent removes the directory if it is empty. A sibling's directory is |
| + never touched. |
| + - A leftover directory from an earlier agent process is harmless, and the |
| + stale-file rule clears its socket the next time n is used. |
| +4. **The length bound.** A unix socket path is at most 107 bytes. A flat host |
| + whose generation path would exceed that has no generation path: it is |
| + handled exactly as a foreign row is today, keeping its canonical socket. |
| + This adds no new member-facing state and no new copy. The window is small, |
| + because the flag-off path `/run/carlos/<host>.sock` is already near the |
| + bound for the same host. Nested paths are bounded by the 40-byte instance |
| + identifier and stay well under it. |
| +5. **The probe checks it.** `cmd/zddprobe` exits 1, with a clear line on |
| + stderr, before it listens if either of these is wrong: |
| + - the base name of `--socket` is neither `app.sock` nor |
| + `$CARLOS_HOST.sock`; |
| + - `CARLOS_HOST` is empty. |
| + |
| + A dev or flagship probe then fails its health check the way the tenant |
| + did, instead of passing. |
| + |
| +## Not changed |
| + |
| +- Generation numbering, the generations file, the termination proof, the |
| + scheduler, the canary, and the failure book. |
| +- Flag-off paths. With `CARLOS_SWAP` unset, nothing in this amendment runs. |
| + |
| +## Before Gate F runs again |
| + |
| +- Release the fix, and roll it to dev and then the flagship. |
| +- Re-run the dev swap under load with the new probe. |
| +- Clear annie's stale failure record. It holds bdn/ips build `2d577ebda` on |
| + canada, which is the live build. Clearing it needs Paul's approval. |