mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 21:26:44 +00:00
Both init gates made every replica other than slot 1 block until the installed version equalled its own image's. Only a task that gets past the gate runs the upgrade, so the gate waited on a state it was itself preventing. In CI run 38818071194 the floating tag nextcloud:34-fpm-alpine moved from 34.0.4 to 34.0.5 between the job's two deploys, swarm handed the new image to slot 2 first, and the service sat at 2/3 with UpdateStatus updating until the converge wait exhausted 600 attempts. php-fpm never started, the healthcheck failed, and swarm killed and recreated an identical task in a loop. Delete the version comparison. The lock probe and the installed, maintenance and needsDbUpgrade conditions all stay, so the gate still cannot release a replica onto a tree under modification. The version decision belongs to the upstream entrypoint, which makes it under a blocking flock on the same *-init-sync.lock the gate probes, re-reads the installed version after acquiring it, and exits non-zero on a downgrade. That contract is measured, not assumed. The pulled image's /entrypoint.sh is byte identical to upstream's, and its own version expression - the one the deleted line compared against - prints 34.0.5.1 against the 34.0.4.1 the live stack reported. A harness drives that entrypoint against a faked tree: equal versions skip the upgrade and exec, an installed version higher than the image refuses and never execs, and a peer holding the lock makes it block, re-read and skip. The re-read also closes the gate's own TOCTOU window, because a peer that takes the lock in the gap cannot be overtaken. Old and new gate were run side by side over 17 states for both roles: 13 behave identically and the 4 that differ are all states where the old gate waited forever. Deleting a condition can only change behaviour where it was false, and where it was false the old outcome was never a working one. The deleted line was also a substring match, so an image at 34.0.4.1 matched a tree reporting 34.0.4.10. Friendica carried the same shape and is fixed with it. Its pinned image maps to an entrypoint that takes the lock blocking, reads both versions after acquiring, refuses a downgrade and upgrades under the lock, verified the same way. The lint fails if an image-version equality returns to any init gate, and also requires every gate to keep probing its lock, because that probe is what makes the deletion safe. Putting the deleted line back makes it fail naming the file and line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>