test(forgejo-runner): drive the liveness note's state boundary
codex and kimi are right: the four checks proved the LINES EXIST and nothing proved they fire only when the unit is active. kimi deleted the state guard and the suite stayed 790/790 green, so the boundary #133 cares about most — no misleading liveness note on an absent or inactive unit — was unprotected. #133's own test plan says driven, not grepped where behaviour can be executed, and this was the line it crossed. The note is now a function, which is what makes the boundary executable, and the suite drives it on active (note present, remedy named), inactive (empty) and unset (empty). Removing the guard now fails two checks instead of none. The no-warn and no-network guards stay greps: those properties are source-level by nature, as kimi noted. Two things I got wrong on the way, both caught by running it rather than reading it: the function was defined below its call site (shellcheck SC2218), and the block reused $WORK, which is rm -rf'd at :3206 long before it — so it now takes its own scratch dir like the file's other fixtures. Refs #133 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1daf7004d7
commit
848e3f42ef
2 changed files with 48 additions and 17 deletions
|
|
@ -11,6 +11,31 @@ log() { printf 'rig-forgejo-runner: %s\n' "$*"; }
|
|||
warn() { printf 'rig-forgejo-runner: WARNING: %s\n' "$*" >&2; }
|
||||
die() { printf 'rig-forgejo-runner: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
||||
|
||||
# forgejo_runner_liveness_note <systemctl-state> — what `active` does not cover.
|
||||
#
|
||||
# `active` is the strongest health signal this command has, and it proves only
|
||||
# that a process exists — not that the runner is still asking Forgejo for work.
|
||||
# A poller can go quiet while the daemon stays up: measured 2026-07-30 (#129,
|
||||
# #133), a daemon logged "[poller] launched" and never fetched a job dispatched
|
||||
# four minutes later, while a daemon started fresh claimed that same queued task
|
||||
# in one second. Both times it read as a label-mapping bug on the forge, which
|
||||
# is the wrong place to look.
|
||||
#
|
||||
# A FUNCTION rather than an inline `if`, because the state boundary is the part
|
||||
# worth pinning: an absent or inactive unit must say nothing, and a grep over
|
||||
# the source cannot tell the difference (codex/kimi, !134).
|
||||
#
|
||||
# log, not warn: nothing has been DETECTED here. An idle runner with no queued
|
||||
# jobs is silent in exactly the same way a stalled one is, so there is no signal
|
||||
# separating them — a warning on every status run would be crying wolf, and warn
|
||||
# in this file means a drift actually measured (the .runner mode below).
|
||||
forgejo_runner_liveness_note() {
|
||||
[ "${1:-}" = active ] || return 0
|
||||
log " note: 'active' is not proof the runner is fetching jobs — only that the process is up."
|
||||
log " If a job stays queued and its run page says it never started, run"
|
||||
log " 'systemctl restart forgejo-runner' and re-read before suspecting the labels."
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
usage: rig forgejo-runner status [--user <name>]
|
||||
|
|
@ -80,23 +105,8 @@ log "name: ${RUNNER_NAME:-unknown}"
|
|||
log "labels: ${LABELS}"
|
||||
log "dir: ${RUNNER_DIR}"
|
||||
log "service: ${SERVICE}"
|
||||
# `active` is the strongest health signal this command has, and it proves only
|
||||
# that a process exists — not that the runner is still asking Forgejo for work.
|
||||
# A poller can go quiet while the daemon stays up: measured 2026-07-30 (#129,
|
||||
# #133), a daemon logged "[poller] launched" and never fetched a job dispatched
|
||||
# four minutes later, while a daemon started fresh claimed that same queued
|
||||
# task in one second. Both times it read as a label-mapping bug on the forge.
|
||||
#
|
||||
# log, not warn: nothing has been DETECTED here. An idle runner with no queued
|
||||
# jobs is silent in exactly the same way a stalled one is, so there is no
|
||||
# signal separating them — a warning on every status run would be crying wolf,
|
||||
# and warn in this file means a drift actually measured (the .runner mode
|
||||
# below). Saying what the signal does not cover is the honest middle.
|
||||
if [ "${STATE:-}" = active ]; then
|
||||
log " note: 'active' is not proof the runner is fetching jobs — only that the process is up."
|
||||
log " If a job stays queued and its run page says it never started, run"
|
||||
log " 'systemctl restart forgejo-runner' and re-read before suspecting the labels."
|
||||
fi
|
||||
forgejo_runner_liveness_note "${STATE:-}"
|
||||
|
||||
|
||||
# status is the only command an operator runs when nothing is obviously wrong,
|
||||
# which makes it the right place to notice a mode that drifted. It reports and
|
||||
|
|
|
|||
21
test/cli.sh
21
test/cli.sh
|
|
@ -3424,6 +3424,27 @@ check "forgejo-runner: …and names the remedy, so the line is actionable" 0 "re
|
|||
# file reserves warn for drift it has actually measured (the .runner mode).
|
||||
check "forgejo-runner: the liveness note is informational, never a WARNING" 1 "" \
|
||||
grep -nE 'warn ".*not proof' "$FJS"
|
||||
|
||||
# codex/kimi on !134: the three greps above prove the LINES EXIST; nothing
|
||||
# proved they fire only when the unit is active. Deleting the state guard left
|
||||
# the suite 790/790 green, so the acceptance boundary #133 cares about most —
|
||||
# no misleading liveness note on an absent or inactive unit — was unprotected.
|
||||
# Drive the decision instead, extracted the way test/drill.sh extracts its own.
|
||||
# Its own scratch dir: $WORK is rm -rf'd at :3206, well before this block.
|
||||
FJS_DIR="$(mktemp -d)"
|
||||
FJSW="$FJS_DIR/fjs-note.sh"
|
||||
{ printf '%s\n' 'log() { printf "rig-forgejo-runner: %s\\n" "$*"; }'
|
||||
awk '/^forgejo_runner_liveness_note\(\) \{/,/^\}/' "$FJS"
|
||||
} > "$FJSW"
|
||||
check "forgejo-runner: liveness note extracted (guards the awk)" 0 "forgejo_runner_liveness_note() {" \
|
||||
cat "$FJSW"
|
||||
note_for() { bash -c '. "$1"; forgejo_runner_liveness_note "$2"' _ "$FJSW" "$1"; }
|
||||
check "liveness note: an ACTIVE unit is told what active does not prove" 0 "not proof" note_for active
|
||||
check "liveness note: …and is given the remedy" 0 "systemctl restart forgejo-runner" note_for active
|
||||
note_is_empty() { [ -z "$(note_for "$1")" ]; }
|
||||
check "liveness note: an INACTIVE unit gets nothing" 0 "" note_is_empty inactive
|
||||
check "liveness note: an ABSENT unit (empty state) gets nothing" 0 "" note_is_empty ""
|
||||
rm -rf "$FJS_DIR"
|
||||
# The header contract at :25 — no token, no network call — survives this.
|
||||
check "forgejo-runner: status still makes no network call" 1 "" \
|
||||
grep -nE '^[^#]*(curl|wget) ' "$FJS"
|
||||
|
|
|
|||
Loading…
Reference in a new issue