Move the authenticated drift check into the repository as
tools/compat_auth.py, run daily by .github/workflows/compat-auth.yml on the
maintainer's forge only. Credentials come from FH_EMAIL and FH_PASSWORD, the
output is pass/fail labels only because the run log is public, and a failed
run pushes the report to ntfy. Exit 5 means all hold, 10 drift, anything
else that it could not run.
Point compat.yml, tools/compat.py and the docs at it, add a README section,
and cut 0.5.1.
The compat badge was red on bookkeeping, not on compatibility: the check passed
16/16 and the run then failed trying to commit the refreshed matrix and open a
PR. That step should never have existed here — GitHub is a read-only mirror of
Gitea, so anything a bot pushes is clobbered by the next sync. It now publishes
the matrix to the run summary and the workflow only needs contents:read, so the
badge means what it says.
The README had grown into an implementation document. Endpoints, markup traps,
the login handshake and the drift-detection design move to docs/internals.md;
what is left is installation, entities, events, the dashboard, requirements and
troubleshooting.
actions.py covers skip, donate, cart add/remove, subscriptions and vacation
holds. Every mutating endpoint on the site is guarded by rotating per-render
tokens, so each action re-derives them from a live page rather than storing
anything; skip additionally compares the date the server states in its
confirmation against the date it was asked to skip, and refuses on a mismatch.
All actions default to dry_run.
tools/compat.py records what the integration assumes about a site that offers
no API and no stability contract, and CI asserts it daily. Only the
unauthenticated surface is covered: checking the rest would mean putting a
personal account password in public repo secrets.