R-265 CI timeout + golden 0.210.0 baked; R-221/R-259/R-258 closed, R-266 minted, G-3 unblocked
gates / gates (push) Successful in 32s
gates / gates (push) Successful in 32s
Four defects of one family, all shipped today: something the box already knows, thrown away or drawn
as its opposite. Agent v0.128.0, controller v0.210.0. NO HUB CODE, no hub bump, no ArgoCD sync.
R-265 (this repo). timeout-minutes: 5 on the gates job — every honest run in the observed session
finished in 18-34s, so this is ~9x the slowest and far under whatever reaped run 264 at 834s with no
log. The alarm mail now carries Elapsed (start stamp via $GITHUB_ENV; an absent stamp prints
"unknown (no start stamp)", never a bogus 1.7-billion-second figure) and its "names itself in the run
log" sentence is qualified so it cannot mislead when there is no log.
⚠ THE UNKNOWN IS NOT CLOSED. Whether the if: failure() alarm fires for a REAPED job is still
unverified. The timeout makes the reap unreachable in practice; it does not answer what happens in
one. Demonstrating it means deliberately hanging a run on main, which would leave the branch red for
a parallel session. Said in the workflow comment, the changelog, R-265 and the report — none of them
claiming it is answered.
GOLDEN 0.210.0 baked, published, round-trip verified, NOT VOUCHED. The currency gate went red the
moment the controller was bumped — correct — and is closed by the bake, never --no-verify. No
--no-verify anywhere this session.
⚠ THE AGENT WAS NOT PUBLISHED UNTIL THIS SESSION CHECKED, AND IT MATTERED. R-221's fix is in the
AGENT, and a fresh install takes its agent from the Day-0 manifest. The binary had been hand-deployed
to felhom-pve and never published, so agent_version 0.128.0 was not selectable and a fresh install
would have received 0.127.0 — the golden would have carried the controller fixes and NOT the one the
headline defect needed. Caught by checking each Day-0 value was FETCHABLE rather than assuming.
Published from the live-deployed bytes, sha-verified across the hop first.
Registers. R-221, R-259, R-258, R-265 CLOSED. R-266 MINTED (READY): the failed root statfs still
travels to the hub as a 0-of-0 disk; ranked LOW because it is the quiet direction — it can only miss
a true alarm, never raise a false one — and it is now a two-repo wire change governed by G-1's gate.
Highest ID moved R-265 -> R-266.
CONTEXT S-39 rules the convention this project was missing: "we do not know" is never drawn as
"fine", and the codebase has ONE way of saying it — an explicit ...Known bool companion checked in
the template. ROADMAP G-3 was explicitly blocked on that decision and is unblocked; what remains
there is a survey-and-convert of existing sites, not the gate.
Capability map row 93 CHECKED and it was NOT claiming something untrue — it is about the operator
notification path. But its narrative ("the page you open to ask whether ONE app is backed up")
invites the wrong reading, and the adjacent thing WAS false until v0.210.0, so the row now records
that the two halves disagreed and only the operator half was true.
Six red-proofs across the two code repos, each with the mutation asserted applied. The one that
matters: Part 1 Scenario A FAILED against today's tree, with the intended message.
Part 1's operator-present live validation is OWED and is the session's STOP.
repo_gates --fast: all 8 OK.
This commit is contained in:
@@ -21,9 +21,28 @@ on: [push]
|
||||
jobs:
|
||||
gates:
|
||||
runs-on: felhom-gates
|
||||
# R-265: A RUN THAT HANGS MUST FAIL ITSELF, LOUDLY AND WITH A LOG.
|
||||
#
|
||||
# Run 264 (2026-08-08) took 834 s and was reaped by the platform, leaving NO log at all — the
|
||||
# log fetch returns HTTP 500 "264.log.zst: file does not exist". Every honest run in that same
|
||||
# session finished in 18–34 s, and every real gate failure finished in under 35 s WITH a log. So
|
||||
# the alarm mail below arrived pointing at a run log that does not exist, telling the operator
|
||||
# "the failing gate names itself in the run log" when nothing could.
|
||||
#
|
||||
# 5 minutes is ~9x the slowest honest run and far under whatever reaped 264, so a hang now ends
|
||||
# as a JOB failure — which produces a log and a step record — rather than as a platform reap,
|
||||
# which produces neither.
|
||||
#
|
||||
# ⚠ WHAT THIS DOES NOT ANSWER, and must not be read as answering: whether the `if: failure()`
|
||||
# alarm step runs at all for a REAPED job is still UNKNOWN. This makes the reap unreachable in
|
||||
# practice; it does not tell us what happens in it. Recorded as still open in R-265.
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Fetch the pushed commit
|
||||
run: |
|
||||
# R-265: the start stamp the alarm reports, so a mail can never again describe a run
|
||||
# without saying how long it took.
|
||||
echo "GATES_STARTED_AT=$(date +%s)" >> "$GITHUB_ENV"
|
||||
# Shallow, and pinned to the exact SHA that was pushed — not to the branch tip, which can
|
||||
# move under us if two pushes race. Probe P3 proved the two are equal when done this way.
|
||||
git init -q .
|
||||
@@ -94,7 +113,7 @@ jobs:
|
||||
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json, os, sys, urllib.request, urllib.error
|
||||
import json, os, sys, time, urllib.request, urllib.error
|
||||
|
||||
key = os.environ.get("RESEND_API_KEY", "")
|
||||
if not key:
|
||||
@@ -106,6 +125,18 @@ jobs:
|
||||
run = os.environ.get("GITHUB_RUN_NUMBER", "?")
|
||||
srv = os.environ.get("GITHUB_SERVER_URL", "https://gitea.dooplex.hu")
|
||||
|
||||
# R-265: how long the run took, so a reap is self-identifying. An honest gate failure
|
||||
# lands in well under a minute; a multi-minute figure means the job hit its own timeout
|
||||
# and the interesting question is the runner, not the gates.
|
||||
started = os.environ.get("GATES_STARTED_AT", "")
|
||||
try:
|
||||
# An ABSENT stamp is "unknown", never a number. Defaulting to 0 would print an elapsed
|
||||
# of ~1.7 billion seconds, which is a confident wrong answer — the exact failure mode
|
||||
# this whole session is about.
|
||||
elapsed = "%d s" % (int(time.time()) - int(started)) if started else "unknown (no start stamp)"
|
||||
except (TypeError, ValueError):
|
||||
elapsed = "unknown (unparseable start stamp %r)" % started
|
||||
|
||||
body = json.dumps({
|
||||
"from": "Felhom CI <monitoring@felhom.eu>",
|
||||
"to": ["admin@felhom.eu"],
|
||||
@@ -114,12 +145,18 @@ jobs:
|
||||
"The gate entry point exited non-zero.\n\n"
|
||||
"Repository : %s\n"
|
||||
"Commit : %s\n"
|
||||
"Run : %s/%s/actions/runs/%s\n\n"
|
||||
"The failing gate names itself in the run log.\n\n"
|
||||
"Run : %s/%s/actions/runs/%s\n"
|
||||
"Elapsed : %s\n\n"
|
||||
"The failing gate names itself in the run log - WHEN THERE IS ONE. A run that\n"
|
||||
"hung and was reaped by the platform leaves no log at all (R-265, run 264: 834 s,\n"
|
||||
"log fetch 500). The job now times out at 5 minutes so that case should fail as a\n"
|
||||
"job and keep its log; if Elapsed above is minutes rather than seconds, suspect\n"
|
||||
"the runner before the gates, and if the log is missing say so rather than\n"
|
||||
"guessing which gate it was.\n\n"
|
||||
"If the local pre-push hook was GREEN for this commit, then CI and the hook\n"
|
||||
"disagree - that is a finding about the gates themselves, not about CI, and it\n"
|
||||
"outranks whatever the push was for.\n"
|
||||
) % (repo, sha, srv, repo, run),
|
||||
) % (repo, sha, srv, repo, run, elapsed),
|
||||
}).encode()
|
||||
|
||||
req = urllib.request.Request(
|
||||
|
||||
Reference in New Issue
Block a user