From 24b65c3c6436a00f1c6e2b841e8d6796ed9d12da Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Sat, 8 Aug 2026 17:53:01 -0500 Subject: [PATCH 1/3] fix(agents): make the optimizer recursion guard actually correlate runs The guard counts prior optimizer runs for an issue by matching the issue number against `displayTitle`. workflow_dispatch runs display the bare workflow name ("Agents Issue Optimizer"), so the filter matched nothing. Observed on Fine-Art-Archive#464, which the optimizer re-ran roughly once a minute for ~20 hours while its own guard logged: Optimizer runs for issue #464 in last hour: 0 Set `run-name` so both trigger types carry `#`, raise the `gh run list` window past its 20-run default (a tight loop exhausts that inside the hour), and match with `endswith` rather than `contains` so the new suffix form cannot count #4640 against #464. Co-Authored-By: Claude Opus 5 --- .github/workflows/agents-issue-optimizer.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index dd625514c..77b507db9 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -1,5 +1,13 @@ name: Agents Issue Optimizer +# The recursion guard below correlates prior runs by issue number via `displayTitle`. +# workflow_dispatch runs otherwise display the bare workflow name, so the guard matched +# nothing and reported 0 for an issue it was re-running every minute. Pin the issue +# number into the run name so both trigger types are correlatable. +run-name: >- + Agents Issue Optimizer #${{ + github.event.issue.number || inputs.issue_number }} + on: issues: types: [labeled] @@ -140,14 +148,17 @@ jobs: '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \ || date -u -v-1H '+%Y-%m-%dT%H:%M:%SZ') + # `gh run list` defaults to 20 runs, which a tight loop exhausts inside the + # window; ask for enough history to actually see the recursion. # shellcheck disable=SC2016 count=$(gh run list \ --workflow=agents-issue-optimizer.yml \ + --limit 100 \ --json conclusion,createdAt,displayTitle \ | jq --arg cutoff "$one_hour_ago" \ --arg issue "#$ISSUE_NUMBER" \ '[.[] | select(.createdAt > $cutoff - and (.displayTitle | contains($issue))) + and (.displayTitle | endswith($issue))) ] | length') echo "Optimizer runs for issue #$ISSUE_NUMBER in last hour: $count" From 9c27aa63347f48a40a07ddac72df2da22f5273c2 Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Sat, 8 Aug 2026 18:26:22 -0500 Subject: [PATCH 2/3] fix(agents): apply the recursion-guard correlation fix to the consumer template Check Template Drift flagged agents-issue-optimizer.yml as unallowlisted: the root copy carried the fix and the consumer template did not. The template is the copy the fleet's 13 consumer repos actually run, so it needs the same run-name, endswith match, and --limit 100. Co-Authored-By: Claude Opus 5 --- .../.github/workflows/agents-issue-optimizer.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index c75bb5243..b84c664e9 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -1,5 +1,13 @@ name: Agents Issue Optimizer +# The recursion guard below correlates prior runs by issue number via `displayTitle`. +# workflow_dispatch runs otherwise display the bare workflow name, so the guard matched +# nothing and reported 0 for an issue it was re-running every minute. Pin the issue +# number into the run name so both trigger types are correlatable. +run-name: >- + Agents Issue Optimizer #${{ + github.event.issue.number || inputs.issue_number }} + on: issues: types: [labeled] @@ -171,14 +179,17 @@ jobs: '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \ || date -u -v-1H '+%Y-%m-%dT%H:%M:%SZ') + # `gh run list` defaults to 20 runs, which a tight loop exhausts inside the + # window; ask for enough history to actually see the recursion. # shellcheck disable=SC2016 count=$(gh run list \ --workflow=agents-issue-optimizer.yml \ + --limit 100 \ --json conclusion,createdAt,displayTitle \ | jq --arg cutoff "$one_hour_ago" \ --arg issue "#$ISSUE_NUMBER" \ '[.[] | select(.createdAt > $cutoff - and (.displayTitle | contains($issue))) + and (.displayTitle | endswith($issue))) ] | length') echo "Optimizer runs for issue #$ISSUE_NUMBER in last hour: $count" From c49feee25efbe082f6bfe8067ba4fdc8d93f1e52 Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Sat, 8 Aug 2026 18:27:51 -0500 Subject: [PATCH 3/3] chore(drift): re-baseline the issue-optimizer template fingerprint pair Both surfaces changed in this branch, so the stored pair.11 fingerprints no longer match and the drift check reported unallowlisted content. Refresh both hashes and record this round's shared contract in the reason, per the file's existing re-baseline convention. Co-Authored-By: Claude Opus 5 --- config/template-drift-allowlist.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index 328f94aac..4835ee874 100644 --- a/config/template-drift-allowlist.txt +++ b/config/template-drift-allowlist.txt @@ -113,9 +113,9 @@ reason = Intentional divergence re-baselined 2026-06-30: root and consumer guard [pair.11] main = .github/workflows/agents-issue-optimizer.yml template = templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml -main_sha256 = d14dacb2a76447d35295a5d8a4da1e9a56a545323f87413fd76cf0654e8cf116 -template_sha256 = 05ad7bff15067f0827e136559145e3c13e0372b538889ac78281ce47658cefce -reason = Intentional divergence re-baselined 2026-08-08c: root remains in-tree (scripts/langchain + .github/scripts/issue_format.py); consumer vendors those via Workflows sparse-checkout under workflows-scripts/. Shared behavioral contract this round: concurrency includes inputs.issue_number for workflow_dispatch dedupe, cancel-safe (failure()||cancelled()) agents:format lease release, issue_dedup wrapped in set +e/set -e so advisory failures cannot abort under bash -e, and visible non-zero exit warnings. Do not align wholesale — that would strip consumer action pins/token setup. +main_sha256 = ae9a2d80a47ad995f4ce1a0681a7c8b236518b2c1337370d11578e4059ae7489 +template_sha256 = d5469b188c5e757d2f8a289e40c066961047d8a9625ae32413c2959c7a824c21 +reason = Intentional divergence re-baselined 2026-08-08c: root remains in-tree (scripts/langchain + .github/scripts/issue_format.py); consumer vendors those via Workflows sparse-checkout under workflows-scripts/. Shared behavioral contract this round: concurrency includes inputs.issue_number for workflow_dispatch dedupe, cancel-safe (failure()||cancelled()) agents:format lease release, issue_dedup wrapped in set +e/set -e so advisory failures cannot abort under bash -e, and visible non-zero exit warnings. Re-baselined 2026-08-08d: both surfaces now set a `run-name` carrying `#` so the recursion guard can correlate workflow_dispatch runs, match prior runs with `endswith` instead of `contains`, and pass `--limit 100` to `gh run list` (see #2991). Do not align wholesale — that would strip consumer action pins/token setup. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml