From 344c4f9030b9b422926f47b346a13fbe5abde82c Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sat, 17 Oct 2026 12:49:37 +0200 Subject: [PATCH] CI workflow: a manual proof that the failure mail can be sent (R-1129) workflow_dispatch with input force_alarm (default false). A dispatch-only step prints the RESEND_API_KEY length (never the key) and, when forced, fails so the alarm step sends its real mail, subject marked FORCED TEST. Push runs are unchanged. No agent release. Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- .gitea/workflows/gates.yml | 33 +++++++++++++++++++++++++++++++-- CHANGELOG.md | 11 +++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/gates.yml b/.gitea/workflows/gates.yml index 622acdd..daeb7f0 100644 --- a/.gitea/workflows/gates.yml +++ b/.gitea/workflows/gates.yml @@ -16,7 +16,16 @@ # A failing run must reach a person — a detector nobody hears is the defect R-29 filed, rebuilt one # layer up. That is the last step, and it runs ONLY on failure. name: gates -on: [push] +# R-1129: `workflow_dispatch` is the manual PROOF that the failure mail can be sent. A push run is +# unchanged by it: the proof step below is skipped on a push, and `force_alarm` is then empty. +on: + push: + workflow_dispatch: + inputs: + force_alarm: + description: "Fail this run on purpose so the alarm step sends its real mail (a proof, not a gate result)" + type: boolean + default: false jobs: gates: @@ -57,6 +66,22 @@ jobs: GITEA_BASE: http://gitea.gitea-system.svc.cluster.local:3000 run: cd ws/felhom-agent && python3 scripts/agent_gates.py + - name: Manual proof - alarm key present, optional forced failure (dispatch only, R-1129) + # Runs ONLY on a manual dispatch, never on a push. It prints the key's LENGTH, never the key, + # so "CI can see the secret" is an observable rather than an assumption. With + # force_alarm=true it then fails on purpose so the alarm step below sends its real mail; + # the commit itself stays green, because its push run skips this step. + if: github.event_name == 'workflow_dispatch' + env: + RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} + FORCE_ALARM: ${{ github.event.inputs.force_alarm }} + run: | + python3 -c 'import os;print("RESEND_API_KEY length: %d" % len(os.environ.get("RESEND_API_KEY","")))' + if [ "$FORCE_ALARM" = "true" ]; then + echo "force_alarm=true - failing on purpose so the alarm step runs (R-1129 proof)" + exit 1 + fi + - name: Alarm on failure # THE POINT OF THE WHOLE THING. Probe P5 measured that a failed run produces NO mail, NO # notification row and NO log line from Gitea itself — a red tick in a web UI nobody watches @@ -70,6 +95,8 @@ jobs: if: failure() env: RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} + # Empty on a push, so a push run's mail is exactly what it was before R-1129. + FORCE_ALARM: ${{ github.event.inputs.force_alarm }} run: | python3 - <<'PY' import json, os, sys, urllib.request, urllib.error @@ -87,7 +114,9 @@ jobs: body = json.dumps({ "from": "Felhom CI ", "to": ["admin@felhom.eu"], - "subject": "[felhom CI] gates FAILED in %s" % repo, + "subject": ("[felhom CI] FORCED TEST, not a real failure - gates FAILED in %s" + if os.environ.get("FORCE_ALARM") == "true" + else "[felhom CI] gates FAILED in %s") % repo, "text": ( "The gate entry point exited non-zero.\n\n" "Repository : %s\n" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fd6600..af9f536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## CI only — a manual proof that the failure mail can be sent (R-1129, 2026-10-17) + +No agent release; no binary changes. + +`.gitea/workflows/gates.yml` gains a manual `workflow_dispatch` trigger with one input, `force_alarm` (default false), and +one step that runs ONLY on a dispatch: it prints the length of `RESEND_API_KEY` (never the key) and, with +`force_alarm=true`, fails on purpose so the existing alarm step sends its real mail; the mail's subject then starts +„FORCED TEST, not a real failure". A push run is unchanged: the new step is skipped and the subject is the old one. Same +change in all four repos' workflows. Purpose: prove the failure mail now goes out after the operator set the key +(every failed run until today ended „ALARM FAILED: RESEND_API_KEY is empty"). + ## scripts only — the decoy suite is a gate of the full run (R-1116, 2026-10-17) No agent release; no binary changes. `scripts/test_gate_decoys.py` is now the `gate-decoys` row of `agent_gates.py`: