Agent-flows Phase 0: fail-loud metrics, real SRE trigger, AlitaBot docs, orphan cleanup#274
Merged
Conversation
…cs, orphan cleanup
Four mechanical fixes from .github/AGENT-FLOWS-REDESIGN.md's Phase 0:
- scripts/gather-metrics.sh: remove the `|| echo '{"data":{"result":[]}}'`
failure-swallowing fallback (same class of bug fixed in #264's
gather-product-data.sh). Every source (Prometheus/Loki/ArgoCD) is now
probed up front with retry-then-exit-1, and the report leads with a
machine-readable `{"sources":{...}}` manifest line.
- Rewire the SRE agent so it actually runs: sre.yml's `issues: [labeled]`
trigger never fired (GITHUB_TOKEN anti-recursion — 6/6 runs skipped,
7 real deploy-failure issues closed with zero SRE comments). Replaced
with a reusable _sre-agent.yml called directly from _bot-deploy.yml on
deploy/verify failure, bot identity passed as workflow inputs instead of
read from an issue body. Added sre-manual.yml for hand-triggered
investigations. sre.md: bot identity now comes from the prompt, not an
issue read; 5xx-based health checks replaced with Loki level="Error"
rate (the webhook always returns 200, so 5xx was structurally dead);
added an if: always() ArgoCD auto-sync re-enable step so a killed run
can't leave it disabled. Also threaded AZURE_OPENAI_API_KEY/BASE_URL
through _bot-deploy.yml and its three callers, required for
`secrets: inherit` to actually reach the nested reusable workflow.
- AGENTS.md: documented AlitaBot (repo structure, DB, workflows,
command/feature summary) and corrected the "two-bot repo" opening line.
- Deleted the orphaned .github/prompts/review.md (invoked by no workflow,
references MCP tools codex-action doesn't provide) and its one
reference in project.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU
Szer
added a commit
that referenced
this pull request
Jul 26, 2026
…275) PR #274 wired _sre-agent.yml (which requests `contents: write` for the SRE one-liner-mitigation PR path) into _bot-deploy.yml. All three *-deploy.yml callers grant `contents: read`. A called reusable workflow cannot escalate permissions beyond its caller, so GitHub rejected the whole run at load time: `Alita: Deploy` run 30226209727 returned startup_failure with zero jobs. Only Alita surfaced it because alita-deploy.yml is the sole caller whose path filter includes its own file. Vahter and Coupon were equally broken and would have failed on their next deploy. sre-manual.yml had no permissions block at all, so it inherited the repo default and would have failed the same way; given an explicit one. Claude-Session: https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
6 tasks
Szer
added a commit
that referenced
this pull request
Jul 27, 2026
* CI: add actionlint gate for .github/workflows/** Runs actionlint (pinned v1.7.12, commit 914e7df21a07ef503a81201c76d2b11c789d3fca) on PRs touching .github/** plus workflow_dispatch, failing the PR on any actionlint error. Verified against a minimal repro of tonight's PR #274 bug (caller declaring `permissions: contents: read` calling a reusable workflow that declares `permissions: contents: write`): actionlint v1.7.12 reports 0 errors, so it would NOT have caught that specific class — GitHub's permission-escalation check happens at run-load time, not in actionlint's static analysis. Adding the gate regardless since it catches many other real workflow bug classes (shellcheck issues in run: blocks, unknown inputs/outputs, bad expressions). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU * verify-deploy: classify failures as infra vs app, thread through to SRE agent verify-deploy.sh now emits failure-class=infra|app|unknown to $GITHUB_OUTPUT (guarded for local runs) at every existing exit-1 path, without changing any pass/fail semantics — a failure still fails the deploy exactly as today, only the classification is new: - infra: could not reach ArgoCD (fail_connectivity) — the 2026-07-23 argo.internal VPN-drop class (issue #251) - app: control plane reachable, app genuinely unhealthy (readiness, Loki errors, 5xx) - unknown: reachable but inconclusive (sync never converged in time) _bot-deploy.yml passes the class through: verify-deploy job output -> deploy- failure issue body ("**Failure class:**" line, "infra" label added when applicable) -> _sre-agent.yml call input. _sre-agent.yml gains a matching optional `failure-class` input, surfaced in the agent's prompt. sre.md tells the agent that `infra` strongly suggests P3/transient: confirm ArgoCD actually converged and the app is healthy before opening any escalation, and prefer closing as transient with a short note — this is exactly the class of alert that would have fired for the SRE agent's very first real run tonight (issue #251, VPN drop, deploy had actually succeeded). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU * CI: suppress pre-existing shellcheck findings surfaced by the new actionlint gate The new lint-workflows.yml gate (previous commit) surfaced 4 pre-existing shellcheck findings that were invisible before actionlint was added: - _bot-build.yml SC2086 x3: printf ' %s\n' $CHANGED/$NON_DOC/$RELEVANT rely on intentional word splitting (each var holds a whitespace-separated file list; the unquoted splat is what makes printf emit one filename per line). Quoting would collapse each list onto a single summary line and silently degrade the build-skip decision logging — the linter's suggested fix is wrong here, so this is a targeted `disable=SC2086` with a why-comment, not a code change. - vahter-upstream-sync.yml SC2012: `ls vahter-ban-bot.sln* | head -1` is a minor, genuine fragility, but switching to `find` touches the upstream mirror sync path and is out of scope for a CI-hardening PR — suppressed with a comment noting the glob is a fixed, known-safe, non-alphanumeric-free pattern, and flagging `find` as a possible follow-up. Re-ran actionlint v1.7.12 with shellcheck v0.11.0 on PATH (matching the CI runner) over all of .github/workflows/**: 0 errors in 16 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Summary
Phase 0 of the approved agent-flows redesign (
.github/AGENT-FLOWS-REDESIGN.md, §4 "Phase 0 — stop the lying"). Four mechanical fixes:scripts/gather-metrics.shfails loud. Removed the|| echo '{"data":{"result":[]}}'fallback that made an unreachable Prometheus/Loki/ArgoCD render as "zero restarts, zero errors, zero 5xx" — the same class of bug that blinded the product agent for 21 runs (Fix: product agent's DB queries silently time out over split-tunnel VPN #264). Every source is now probed up front with retry-then-exit 1(matchinggather-product-data.sh's style), and the report leads with a machine-readable{"sources":{"prometheus":"ok","loki":"ok","argocd":"ok"}}manifest line for a later automated gate to key off.sre.yml'sissues: [labeled]trigger has fired 0/6 times in practice — thedeploy-failureissue is created withsecrets.GITHUB_TOKEN, and GitHub Actions never triggers workflows from default-token-authored events (anti-recursion). Replaced with_sre-agent.yml, a reusable workflow called directly from_bot-deploy.ymlwhen the deploy or its verification fails, with bot identity (bot,argocd-app-name,container-name,docker-image,commit,run-url, optionalissue-number) passed as workflow inputs instead of read from an issue body. Addedsre-manual.yml(workflow_dispatch) as a hand-triggered entry point, sinceworkflow_callworkflows can't also declareworkflow_dispatch.sre.md: bot identity now comes from the prompt; the 5xx-based health checks are replaced with Lokilevel="Error"rate (the/botwebhook always returns HTTP 200 to Telegram regardless of internal exceptions, so 5xx was structurally dead logic); added anif: always()step that re-enables ArgoCD auto-sync so a killed run can't leave it permanently off.AZURE_OPENAI_API_KEY/AZURE_OPENAI_BASE_URLthrough_bot-deploy.yml's ownsecrets:contract and its three callers (vahter-deploy.yml,coupon-deploy.yml,alita-deploy.yml) — required sosecrets: inheriton the newsre:job actually has those secrets to inherit, since a reusable workflow only receives what its own caller explicitly passed it.AGENTS.md. Repository structure, DB, its three workflows, command/feature summary, and corrected the opening line that described this as a two-bot repo..github/prompts/review.md(invoked by no workflow; references MCP tools the codex-action runtime doesn't provide) and its one reference inproject.md.Full rationale:
.github/AGENT-FLOWS-REDESIGN.md(§1, §3.5, §4 Phase 0, §9).Scope note —
if: failure()interpretation in_bot-deploy.ymlThe new
srejob usesneeds: [deploy, verify-deploy, notify-failure],if: ${{ failure() && inputs.sre-enabled }}— same shape as the existingnotify-failurejob, so the SRE agent is guaranteed to run wheneverdeployorverify-deployfails (GitHub'sfailure()covers the whole transitiveneedschain, so it stays true even thoughnotify-failureitself typically succeeds).notify-failureis also aneedso the new job can consume itsoutputs.issue-number(captured fromgh issue create's output URL) and pass it through to_sre-agent.yml; ifnotify-failuredidn't run or its output is empty,issue-numberis simply blank and the prompt tells the agent to skip issue comment/close steps.Deviations
shellchecknoractionlintare installed in this environment — validated withbash -n(all touched scripts) andpython3 -c "import yaml..."(all touched/created workflow YAML) instead, per the brief's documented fallback.*.internalendpoints will not resolve without VPN)" assumption didn't hold in this sandbox — it turns out to have live routes to the real*.internalinfra (confirmed:prometheus.internal/argo.internalboth actually resolve and respond here). Used a genuinely-nonexistent hostname (prometheus.bogus-host-that-does-not-exist.internal, confirmed viagetent hosts→ exit 2) to faithfully reproduce "unreachable" and prove the fail-loud path; also exercised a real-but-wrong-credential ArgoCD 401 as a second failure mode. Both produce curl's real diagnostic text and a non-zero exit with no report printed — see the PR description checks below / test-plan.src/CouponHubBot/docs/PROJECT-AGENT.mdstill documents the oldsre.yml/issues: labeledmechanism — left untouched per "do not modify anything undersrc/"; flagging as a known follow-up for whoever picks up Phase 1.BotNotAvailable/ErrorLogsDetectedGrafana alert rules (Phase 0 item 3 in the redesign doc) — that's Grafana provisioning config, not something editable in this repo, and wasn't one of the four listed changes.Test plan
bash -nonscripts/gather-metrics.sh— cleanpython3 -c "import yaml..."on every created/edited workflow YAML — cleangather-metrics.shagainst a genuinely-unreachable Prometheus host: exits 1, prints the realcurl: (6) Could not resolve host: ...error, prints no reportgather-metrics.shagainst a real ArgoCD endpoint with a bad token: exits 1, printscurl: (22) The requested URL returned error: 401, prints no report_sre-agent.yml/sre-manual.yml— this PR is not merged, per instructions🤖 Generated with Claude Code
https://claude.ai/code/session_01P41roCWN5Fec7m69sSaunU