Repository navigation
Conversation
This was referenced Oct 29, 2026
The nightly build was red for nine nights with nobody told, and release 0.1.76 left a tag with no image after a Docker Hub 429. This adds a watchdog that files an issue per finding and closes it once the finding clears, and makes a release unable to cancel another or to stop half way without a retry. hack/ci_alarm keeps one issue per alarm key (label ci-alarm, assigned to the owner with an @mention); a changed body comments, an unchanged one comments again only after 24 h. When the repository has issues disabled it prints a ::error annotation and the step summary and exits 3. hack/watchdog (.github/workflows/watchdog.yml: hourly at :47 and after CI, Docs and every release workflow completes on main) raises stale:<file> and red:<file> for scheduled workflows (failed jobs, the failed log up to its last error, a signature hint, one re-dispatch per failed run), disabled:<file>, ci-missing and ci-main for main (dispatching ci.yml once when HEAD has no run), release:<ver> when the newest tag older than 45 min lacks its Docker Hub or GHCR image, its .deb, .rpm and SHA256SUMS, or its AUR update (one release re-dispatch when the Hub image is missing), bot-pr-stuck for autobump PRs over 72 h without green CI, and simulate on demand. Its own errors become watchdog-error. The tests replay the October red nights and the 0.1.76 tag from the real run list, jobs and failed log. build-and-push.yml queues each release version on its own, builds each variant in up to three attempts, and pushes only the versioned tags; the floating tags move afterwards, from hack/release-tags, only for the highest aur-v* tag, and aur-deploy.yml never moves AUR back. hack/release-paths is the one list of shipped paths (now including console/, images.lock and the shipped bench and oracle files): auto-release.yml repeats it as its push paths and release_cas.sh reads it, and a mode=changed dispatch releases only when one of them changed. Every job has a timeout, every workflow a permissions block, and no cron fires at minute 0 or 30.
The watchdog re-dispatched a red scheduled workflow, or a release with no Docker Hub image, and only then wrote the record that stops the next re-dispatch into the alarm. With Issues disabled (this repository today) the record can never be written and every watchdog run exits 1, so each run re-dispatched build-and-push.yml, the missing release and watchdog.yml itself, and each dispatched watchdog run did the same, without end. A failed alarm write or a failed alarm listing lost the record the same way. The record now goes into the alarm before the dispatch. A run that cannot read or file the alarm dispatches nothing: with Issues disabled the alarm is only annotated, after a failed listing the alarm is left as it is so its record survives, and a failed write stops the dispatch. A failed dispatch rewrites the alarm without the record, so the next run tries again. workflow_run's branches filter matches the triggering run's head branch name, which a fork's pull request can also call main, so watchdog.yml now also requires the run to come from this repository. bot-pr-stuck skips cross-repository PRs, so a fork's autobump/* branch cannot hold it open. The AUR guard in aur-deploy.yml failed the deploy when the AUR RPC could not be read (pipefail made the command substitution fail the step), the opposite of its comment; an unreadable RPC now lets the deploy go ahead.
88plug
force-pushed
the
claude/fresh-alarm-release
branch
from
October 30, 2026 00:51
b07a143 to
2eb4fd1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The nightly "Auto-update, Build & Release" failed nine scheduled runs in a row (2026-10-20 to 10-28) and nobody was told: GitHub mailed only the last editor of the cron line. Release 0.1.76 left tag aur-v0.1.76 with no image after a Docker Hub 429. A single concurrency group meant one pending release could replace another, and a console-only merge cut no release. This PR is part P1 (alarm-release) of the freshness spec.
Owner action needed before this is useful
The repository has Issues turned off (
has_issues: false;gh issue listanswers "the '88plug/k3d-gpu' repository has disabled issues"). Every alarm is an issue, so turn Issues on in Settings > General > Features. I did not change it because repository settings are off limits for this work.Until Issues are on, the watchdog cannot file anything, and it re-dispatches nothing (a re-dispatch is recorded in its alarm first). Instead,
hack/ci_alarmprints a::errorannotation and the alarm body to the step summary and exits 3, andhack/watchdogexits 1. Every watchdog run is red, so the gap stays loud.What changes
hack/ci_alarm open|close|list[ci-alarm] <key>: <title>and labelledci-alarm(the label is created with--force).$ALARM_OWNER(default 88plug) and puts an @mention in the body.hack/watchdogand.github/workflows/watchdog.ymlworkflow_runfor CI, Docs and the four release workflows, on main only. It always checks out main, never the code of the triggering run.stale:<file>(no green scheduled run within cron period + 6 h)red:<file>(run URL, failed jobs, the last 60 log lines up to the last##[error], and the first hint fromhack/ci_alarm_signatures.tsv; one re-dispatch per failed run id)disabled:<file>ci-missing(ci.ymlis dispatched once when HEAD is 30 min old and has no CI run; the alarm opens at 2 h)ci-mainrelease:<ver>: the newest tag older than 45 min must have its Docker Hub and GHCR images, its.deb,.rpmandSHA256SUMS, and its AUR update. A missing Docker Hub image triggers onebuild-and-push.yml -f release=<ver>dispatch. Older broken tags from the last 14 days are listed for information, and superseded release alarms close.bot-pr-stucksimulateworkflow_runstarts it only for runs from this repository's main (a fork's PR branch can also be called main), andbot-pr-stuckignores forks'autobump/*branches.watchdog-error; the other checks still run.Release hardening (
build-and-push.yml)build-and-push-${{ inputs.release && format('release-{0}', inputs.release) || 'nightly' }}.hack/release-tags(checked out from main) copies the floating tags (latest,ubuntu26.04,ubuntu24.04,<k3s>-ubuntu*) withdocker buildx imagetools create. It does so only when the version is the highestaur-v*tag on origin at that moment.aur-deploy.ymlskips a version older than the one AUR already has. It also getspermissions: contents: read.Release paths
hack/release-pathsis the single list of shipped paths. It now addsconsole/**,images.lockand every bench and oracle file that nfpm or the formula ships.auto-release.ymlrepeats the list as literal push paths, and a test keeps the two equal.release_cas.shreads the file.mode:force(default): today's behaviour.changed: runs as a push, so it releases only when a shipped path changed. Each mode queues separately.Workflow hygiene
timeout-minutesof about twice its observed maximum (10 min floor; console 40, detect and tune 30, capacity 25, release 60).0 6to17 6.ci.ymlgainsworkflow_dispatch, which the watchdog needs, and anops-testsjob at the end.Tests (written first, each seen failing for the missing piece)
tests/ci_alarm_test.shtests/watchdog_test.shtests/ops/fixtures/); see belowtests/release_tags_test.shtests/auto_release_cas_test.shtests/ci_wiring_test.shtests/ops/workflow_checks.py(PyYAML): timeouts, permissions, cron minutes, watchdog discovery andworkflow_runnames, per-version group, retry structure, floating-tag step order, release-path equality and nfpm/Formula coverage, mode mapping, AUR guard (run against a fake AUR RPC: newer skips, same/older/unreadable deploy), fork guard onworkflow_runtests/image_test.shtests/gate_merge_test.shtests/packaging_test.shtests/image_pins_test.shtests/claims_check.shtests/claims_check_test.shtests/ledger_drift_check.pytests/ledger_drift_check_test.pyACTIONLINT_IMAGE)The
tests/watchdog_test.shcases:red:build-and-push.ymlwith run 39412124435, jobrepin-images, the "refusing to allow a GitHub App" line and its hint, plus exactly one re-dispatch. The next hour adds no dispatch and no comment. Night 2 re-dispatches once more and opensstale. The green 10-29 run closes both.release=0.1.76dispatch, then the alarm. A complete 0.1.77 closes it as superseded.autobump/*PR is not a stuck bot PR.ci-missing(10 min: nothing; 40 min: one dispatch; 2 h 10 min: alarm),ci-main, GHCR-only gap, a running release defers the check, a 73 h bot PR, thesimulate_redround trip, a gh error becomingwatchdog-error, issues disabled.Mutation checks: re-dispatching on every run, dropping the 6 h margin, and dispatching CI before 30 min each turn the watchdog suite red.
A read-only run of
hack/watchdogagainst the live repository was also made, with gh writes blocked. It read every real API shape. It confirmed 0.1.79 and 0.1.77 complete and 0.1.76 missing on Docker Hub, on GHCR and as a GitHub release. It stopped at the disabled Issues as described above.Open after merge (eyes-on)
gh workflow run watchdog.yml -f simulate_red=true. It should open[ci-alarm] simulate, assigned to 88plug, and the next scheduled watchdog run should close it.workflow_runfires for runs that aGITHUB_TOKENdispatch started. This is unverified; the hourly cron is the backstop.pull-requests: read, forgh pr list.dependabot-auto-merge.ymlonly gained a timeout, because P2 removes it.