From ebc7fea1f2a6beb0b6314519de77c216e1d9dfcf Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Sun, 9 Aug 2026 08:12:14 +0000 Subject: [PATCH 1/2] fix(running-in-ci): don't let a failed status probe read as no incident MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upstream-incident recipe piped a possibly-non-JSON body into jq, so a challenge page or any non-200 produced empty stdout — indistinguishable from a clean result, and read by the surrounding guidance as licence to file the workaround PR. Fetch first, parse second, and name a failed probe as unknown. --- .../tend-ci-runner/skills/running-in-ci/SKILL.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md b/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md index 68beb9a8..624945ed 100644 --- a/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md +++ b/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md @@ -588,10 +588,22 @@ If you can't find source evidence for a specific detail, say so ("I'm not sure o Intermittent or inconsistent behavior — the same query returning different results within seconds, an API silently returning empty when records demonstrably exist, a CLI flag working sometimes — points more strongly at an active upstream incident than at a CLI or skill bug. Reproducing the flake confirms the symptom but not the cause; the cause is often a current incident on the upstream service, in which case the right disposition is to wait for resolution rather than commit a code workaround that outlives the incident. Before designing a workaround, check upstream status. For GitHub-side symptoms: ```bash -curl -s 'https://www.githubstatus.com/api/v2/incidents/unresolved.json' \ - | jq '.incidents[] | {created_at, name, impact, components: [.components[].name]}' +# Fetch first, parse second. The endpoint sits behind an edge that sometimes +# answers a CI runner with an HTML challenge page instead of JSON; piping that +# straight into jq gives a parse error on stderr and an empty stdout, which +# reads exactly like "no open incidents". `-f` turns the non-200 into a +# non-zero exit, and capturing it means the pipeline's status is curl's, not +# jq's (a bare `curl … | jq … || …` exits 0 on the challenge page). +if ! INCIDENTS=$(curl -fsS 'https://www.githubstatus.com/api/v2/incidents/unresolved.json'); then + echo 'STATUS PROBE FAILED — upstream state unknown, not clear' +else + echo "$INCIDENTS" \ + | jq '.incidents[] | {created_at, name, impact, components: [.components[].name]}' +fi ``` +**A failed probe is `unknown`, never `clear`.** Empty output from a successful query means no open incident; a probe that errored means you didn't check. Both resolve the same way — record the symptom in the evidence log and skip the workaround PR — so an unreachable status endpoint is not a reason to file one. + If the response is non-empty and the components/timing match the symptom (e.g. Issues / Pull Requests / Actions during a search-degradation incident), record the symptom in the run's evidence log and exit without a PR. Sibling matrix legs that hit different surface symptoms of the same incident otherwise each open their own near-duplicate workaround PR — title and file dedup don't catch them because each leg picks a different command to mitigate. From e35d61b5e2d0cafe406d17934e229d271c174229 Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Sun, 9 Aug 2026 08:18:46 +0000 Subject: [PATCH 2/2] fix(running-in-ci): validate the status probe's body, not just its HTTP status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An edge challenge served with 200 passed `curl -f`, parse-errored in jq, and left stdout empty — the same reading as a clean probe. Add a `jq -e` validity check on the captured body so the guard closes the class rather than the one observed non-2xx instance. --- plugins/tend-ci-runner/skills/running-in-ci/SKILL.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md b/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md index 624945ed..65945ec0 100644 --- a/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md +++ b/plugins/tend-ci-runner/skills/running-in-ci/SKILL.md @@ -591,10 +591,12 @@ Intermittent or inconsistent behavior — the same query returning different res # Fetch first, parse second. The endpoint sits behind an edge that sometimes # answers a CI runner with an HTML challenge page instead of JSON; piping that # straight into jq gives a parse error on stderr and an empty stdout, which -# reads exactly like "no open incidents". `-f` turns the non-200 into a -# non-zero exit, and capturing it means the pipeline's status is curl's, not -# jq's (a bare `curl … | jq … || …` exits 0 on the challenge page). -if ! INCIDENTS=$(curl -fsS 'https://www.githubstatus.com/api/v2/incidents/unresolved.json'); then +# reads exactly like "no open incidents". `-f` catches a challenge served as a +# non-200 and the `jq -e` probe catches one served as 200; capturing the body +# means the status is curl's or jq's, not a pipeline's (a bare +# `curl … | jq … || …` exits 0 on the challenge page). +if ! INCIDENTS=$(curl -fsS 'https://www.githubstatus.com/api/v2/incidents/unresolved.json') \ + || ! echo "$INCIDENTS" | jq -e . >/dev/null 2>&1; then echo 'STATUS PROBE FAILED — upstream state unknown, not clear' else echo "$INCIDENTS" \