19 of 25 live booths returned 500 with `UndefinedError: 'item_marks' is
undefined`. Neither the old code nor the new code was broken — the service was
running both at once.
`booth.service` sets WorkingDirectory to this repo, so the repo IS the
deployment root: no build step, no staging copy, the live service imports these
files. Python is read once when the process starts. Jinja's FileSystemLoader
re-reads a template on EVERY render. So the two halves of the service had
different staleness rules, and editing booth.html deployed it instantly against
Python from 22:03 that had never heard of the context the new markup wanted.
The failure mode is worth naming precisely, because it is invisible to the
suite by construction: the skew exists between a running process and the disk
underneath it, so every test can pass against a tree that is simultaneously
serving 500s. No amount of green catches this. The operator found it.
Fixed at the source rather than with a reminder to restart. The template
Environment is built here with auto_reload=False, so templates are cached at
startup exactly like the Python, and there is ONE rule: nothing takes effect
until you restart. The price is that template work needs a restart to see —
that price is the entire point, and it is cheaper than a page of 500s while
someone is reviewing.
Building the Environment by hand means autoescape no longer comes from the
Jinja2Templates constructor, so it is explicit and load-bearing: booth names,
item names and mark text are all agent- or operator-authored strings that land
in HTML. Verified escaped, not merely configured.
Two tests hold the line — one on the snapshot property, one on the `dur` filter
that is no longer incidental to the constructor. The environment is reachable at
app.state.templates because a promise about the deployed service needs an
assertion, and an assertion needs the env the app actually renders with.
Also records the foot-gun in CLAUDE.md and persistent-memory: anyone editing
this repo while the operator may be using the service is editing production.
244 tests. No version bump — the release tier for U2 is still the operator's
call, and this rides with it.