feat: add Triage Self-Hosted CI Failure template - #5
Merged
Conversation
Classifies a failed GitHub Actions run on self-hosted Kubernetes runners as a code failure or a runner-infrastructure failure, and offers a gated re-run only when the failure was transient infrastructure. Runs on a webhook rather than on demand because the decisive evidence is perishable: runner pods are deleted when their job ends and kubectl events age out in about an hour, so `describe pod` and the event stream cannot be recovered by the time a human notices CI is red. The AI chooses from a closed remediation vocabulary (rerun_failed | none) and never emits a command — the workflow runs a pre-written one for the chosen action, so approving means approving a known operation rather than rubber-stamping model-authored shell. First template to use a webhook trigger; requires a workflow_webhook integration named github_ci_webhook, documented inline above the trigger.
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
blue4209211
approved these changes
Jul 27, 2026
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.
What this adds
triage_self_hosted_ci_failure— when a GitHub Actions run fails on self-hosted Kubernetesrunners, decide whether it was the code or the runner infrastructure, and offer a gated
re-run only when the failure was transient infra.
Why it is webhook-triggered and not manual
Every existing template is
type: manual. This one cannot be, and that is the whole point.The decisive evidence is perishable. Runner pods are deleted the moment their job ends, and
kubectl events age out in roughly an hour. By the time a human notices CI is red and opens an
assistant,
describe podreturns NotFound and the event stream is gone — the investigation isreduced to metric archaeology. Firing on the webhook captures that state while it still exists.
Trade-off: the trigger is inert until the tenant creates a
workflow_webhookintegration namedgithub_ci_webhookand points a repository webhook at it with theworkflow_runevent. There isno error to signal this — it simply never fires. Setup steps are in a comment above the trigger.
webhookis already inTRIGGER_TYPESinscripts/validate.py, so CI accepts it.The AI picks an action, never writes one
rcareturnsremediation.actionfrom a closed list —rerun_failedornone— and the workflowruns a pre-written command for the chosen branch. The model never emits shell.
This matters because the approval would otherwise be theatre:
scm.github.cliexecutes arbitrarybash with an org GitHub token, so a human approving a command they did not read is privilege
escalation with extra steps.
rerun_failedalso requires infra and transient, so a code failuregets no button — re-running one wastes a runner and hides the defect.
Bugs carried forward from live testing
Each of these was found by running the workflow against real failures, and each is commented in the
template so the next author does not rediscover it:
| from_jsonon every payload reference. The webhook body reaches tasks as a JSON string,not an object, so
Inputs.webhook_payload.repository.full_nameerrors withCan't use Getitem on None. The filter sees parsed JSON; tasks do not.| inton the run id. JSON numbers decode as floats, so the id renders30280501006.0andgh run viewfails.;not&&in the snapshot command. A missing runner pod is the NORMAL case, so chainingwith
&&letdescribe podabort the two event queries behind it — losing precisely theperishable evidence the task exists to capture.
status in ['approve','approved'].core.approvalemits the chosenapproval_optionsvalue(
approve), notapproved. Comparing againstapprovedskips the retry silently: the approvalsucceeds, the workflow completes, and the human who clicked Approve gets nothing.
Validation
Also exercised end-to-end on a dev cluster against a real GKE spot preemption: the runner node was
preempted mid-job, the workflow classified it
infra/node/transientwith confirmed evidencefrom pod events, and proposed
rerun_failed.Notes for review
against the workflow budget. I raised the ceiling rather than shrink the approval — a retry prompt
that expires in 30 minutes is useless overnight.
message_thread_idoncore.approvalneeds nudgebee-enterprise#35003, which added thepassthrough. Older runbook-server ignores the param; the prompt just posts top-level.
testing. Narrowing it with
--field-selectorwould cut tokens at the cost of neighbouring-podcontext the agent sometimes uses. Left broad deliberately; worth revisiting.
labelsare limited to the schema enum, so this is taggeddiagnostic+deploy; there isno
ciorapprovallabel available.