The dailyprog puzzle safety net The dailyprog puzzle site now runs a nightly CI job that auto-generates a puzzle if tomorrow's is missing, using DeepSeek V4 Flash and validation gates, ensuring the site never goes dark. The workflow checks for an existing puzzle, generates one if absent, runs test suites, commits, and deploys, all with a two-hour lead time for human review. dailyprog https://dailyprog.club needs a new puzzle every day. I wrote the first few drafts by hand, then built a generator /posts/generating-coding-puzzles-with-llms/ that writes them with an LLM and validates the output against real sandbox execution. The generator works, but it still needs someone to run it. Pick a pattern, kick off the script, review the result, commit. Fifteen minutes on a good day. More if the model gets stuck in a repair loop and I need to nudge it. Some days I don’t have fifteen minutes. Some days I forget. Before last week, either of those meant the site went dark at midnight UTC and stayed dark until I woke up and fixed it. Now it doesn’t. At 22:00 UTC every night, two hours before the puzzle day rolls over, a CI job runs on the Forgejo runner. It checks whether tomorrow’s puzzle exists in the catalogue. If it does, nothing happens. If it doesn’t, the job generates one, validates it, commits it, and deploys it. The site never goes dark. The job is a single workflow file. The check step is four lines of bash: TOMORROW=$ date -u -d '+1 day' +%Y-%m-%d if -f "workspaces/app/content/puzzles/$TOMORROW.json" ; then echo "puzzle for $TOMORROW is already authored — nothing to do" fi If the file is missing, the rest of the job runs: install toolchain, install dependencies, call the same gen:puzzle script I run manually. The model defaults to DeepSeek v4 Flash. Medium difficulty, no pattern hint. The diversity constraint scan the last 7 puzzles’ technique tags, block repeats keeps the model from producing three binary search puzzles in a row. It usually closes in 2 attempts. The generation is the easy part. The interesting thing is what comes after. The generator script only writes files to disk when it passes every gate: schema validation, reference solution against all test cases, brute-force collapse proof, technique diversity. That’s the first safety net. But the CI job runs a second one anyway. After the generator finishes, it fires the full catalogue test suite: pnpm run check:ci pnpm --filter @dailyprog/app exec vitest run lib/puzzles.test.ts lib/puzzle-quality.test.ts puzzles.test.ts loads every .solution.ts file in the catalogue and runs the reference solution against every visible and hidden test case. If the generator produced a solution that doesn’t pass its own tests, this catches it. puzzle-quality.test.ts runs the guardrails: no duplicate technique in the recent window, no back-to-back hard days, every language produces output within the runtime budget. These are the same tests that run on every push to main. The generated puzzle goes through them twice. If the tests pass, the job commits as puzzle-bot and pushes straight to main: feat: add puzzle 47 - staggered delivery Auto-generated by the nightly safety-net workflow. Co-Authored-By: DeepSeek V4 Flash