Skip to content

Drift to issue

Drift to issue #6

name: Drift to issue
# When a Harness drift sensor fails on main (or on the nightly schedule),
# open or update a single tracking GitHub issue per sensor. This stops
# drift signals from rotting in CI logs — they become actionable work
# items instead. Closes the steering-loop arrow: sensor fires → issue
# exists → human decides whether to fix or accept the drift.
#
# Only fires on main / scheduled runs, not on PRs (the in-PR annotation
# from harness.yml is enough there — we don't want every PR to open
# issues).
on:
workflow_run:
workflows: ['Harness']
types: [completed]
branches: [main]
permissions:
contents: read
issues: write
jobs:
open-or-update-issue:
# No workflow-level conclusion check: Harness jobs use
# `continue-on-error: true`, which means the workflow itself concludes
# `success` even when individual sensors fail. We inspect job-level
# conclusions inside the Python loop below — jobs that pass are a no-op.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Find failed jobs and (re)open issues
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }}
RUN_URL: ${{ github.event.workflow_run.html_url }}
run: |
set -euo pipefail
jobs_json=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs" --paginate)
# For each failed job, ensure a single open tracking issue
# exists. Title format `[harness-drift] <job name>` makes
# updates idempotent.
echo "$jobs_json" | python3 - <<'PY'
import json, os, subprocess, sys
jobs = json.loads(sys.stdin.read())["jobs"]
run_url = os.environ["RUN_URL"]
for job in jobs:
if job["conclusion"] != "failure":
continue
name = job["name"]
title = f"[harness-drift] {name}"
body = (
f"The harness drift sensor `{name}` failed on `main`.\n\n"
f"Run: {run_url}\n\n"
"This issue is automatically opened by `.github/workflows/drift-to-issue.yml`.\n"
"It's a *tracking* issue — the sensor will keep firing until either:\n"
" - the underlying drift is resolved (close this issue), or\n"
" - the sensor is intentionally disabled (remove the job from `harness.yml`).\n\n"
"Repeat failures update this same issue rather than opening duplicates."
)
search = subprocess.run(
["gh", "issue", "list", "--state", "open", "--label", "harness-drift",
"--search", f'in:title "{title}"', "--json", "number,title"],
capture_output=True, text=True, check=True,
)
existing = [i for i in json.loads(search.stdout) if i["title"] == title]
if existing:
num = existing[0]["number"]
subprocess.run(
["gh", "issue", "comment", str(num), "--body",
f"Sensor fired again. Run: {run_url}"],
check=True,
)
print(f"updated #{num}: {title}")
else:
subprocess.run(
["gh", "issue", "create", "--title", title, "--body", body,
"--label", "harness-drift"],
check=True,
)
print(f"opened: {title}")
PY