v0.7.7 — two releases shipped to a browser that never received them

buildStamp()'s no-git fallback was the literal "nogit", and the .s9pk
Dockerfile copies the tree in without .git — so git rev-parse fails on
every packaged build. That string is also the cache-bust key every
module URL carries, so v0.7.4, v0.7.5 and v0.7.6 all published
./web/main.js?v=nogit, byte-identical, and returning browsers refetched
nothing. v0.7.5's setup screen and v0.7.6's door fix were both correct
and neither arrived.

The fallback is now the package version plus the build timestamp, always
distinct. And serveStatic sent no Cache-Control at all, which is the
other half — a cached play.html pins a player to the whole build it
names. A request carrying ?v= is now immutable for a year; everything
else is no-cache. ?v= rather than "not HTML" because build-web.ts tags
the modules and nothing else.

Neither half is sufficient alone.

864 tests pass, two new.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
This commit is contained in:
Jesse.Markowitz
2026-08-29 22:23:09 -04:00
co-authored by Claude Sonnet 5
parent b4f09f05cb
commit af68aac78d
6 changed files with 129 additions and 10 deletions
+13 -4
View File
@@ -323,10 +323,19 @@ Queued 2026-08-29, from building Gitea#11 and #16 (both shipped in v0.7.3, main
before ever looking at solitaire's own state, and a bare `./play.html` load could not tell "I
clicked Play solitaire" apart from "I reloaded mid multiplayer game" — the same class of problem
`?lobby` already solved for the door on the other side (D11), just never applied to this one. The
door now marks its intent (`?solitaire`), checked ahead of the remembered-session lookup. Still
not verified past that: nobody has clicked all the way through the setup screen's own fields and
confirmed the dealt game matches what was chosen. Worth being an early item in the next play
session, alongside #39's four unplayed v0.7.4 features.
door now marks its intent (`?solitaire`), checked ahead of the remembered-session lookup.
**And it happened AGAIN on v0.7.6, which is what found the real cause — fixed in v0.7.7.** Every
packaged build published the same cache-bust key (`?v=nogit`, because the `.s9pk` build has no
`.git` for `git rev-parse`), and the server sent no `Cache-Control` at all, so neither release
ever reached the browser that asked for it. Both earlier fixes were correct and both were
verified by reading what the SERVER served — which was true and was never the thing in doubt.
**The lesson worth keeping: when a fix appears to have had no effect, check that it arrived
before re-diagnosing it.** A hard-reload would have answered it on the first report.
Still not verified past that: nobody has clicked all the way through the setup screen's own
fields and confirmed the dealt game matches what was chosen. Worth being an early item in the
next play session, alongside #39's four unplayed v0.7.4 features.
---