One script, ending in a pull request.
The data update used to run from a private repository. scripts/nightly.sh in the public repository now does the same work: scrape the Centre's site, rebuild data/, run the checks, export, and open a pull request that changes only data/. A maintainer merges it, then the workflows publish the site, the Hugging Face dataset and the images. --dry-run does all of it locally without pushing. The script refuses to run inside GitHub Actions.
Models read amendments and citations.
After the build checks pass, the script asks a model to judge proposed amendments and to read article citations: Gemini through the agy command first, Claude when agy is out of quota. Only unanswered inputs are asked. The answers go in db/model/ inside the same data pull request, so a person sees them before they reach the site. A failed model step keeps what was read and never blocks the export.
Two dry runs, two catches.
The first dry run pointed the scraper at a partial copy of its store, and the export removed 93,487 laws from the local archive, keeping only the 9,710 that copy held. The build check failed on the missing laws, and nothing was exported. The second run reset the last-changed date of 164,305 of 165,855 unchanged pages to that day. Shipped, every sitemap date would have moved and every page would have rendered again. The script now loads page dates from the published data/ before it builds, and LEBLEG_SCRAPE=0 builds from the published archive when another job already scrapes.
New text gets vectors under a daily cap.
Search by meaning needs a vector for every passage. The vectors workflow now finds passages without one and embeds them with gemini-embedding-001, at most $1 and 20,000 passages a day. A run that reaches the cap resumes the next day without paying twice, and nothing is published while any current passage lacks a vector.