Loading the last stored run…
The scheduled sweep is OFF. This page's button is the primary path.
Set INVARIANT_CHECK_SECONDS to a number of seconds (3600 is sensible) to let
it run on its own, after you have read a run by hand at least once.
Alerts fire on change, not on condition. The first time a critical
invariant breaks, and again when it is fixed — never on every sweep in between, because a
sentence repeated hourly is a sentence nobody reads. Set
SLACK_INVARIANTS_WEBHOOK to get those in Slack (unset = nothing is posted
anywhere), and INVARIANT_DAILY_SUMMARY=1 for one message a day listing what is
still open — the antidote to the change rule's blind spot, which is a failure announced
six weeks ago and never fixed.
Adding an invariant is five lines in routers/invariants.py: an id, the
sentence, a severity, and either a SQL query or a function. Ownership of the underlying
facts is written down in FACTS.md.