diff --git a/.github/scripts/github-api-with-retry.js b/.github/scripts/github-api-with-retry.js index 99231c2e1..90b72cbe4 100755 --- a/.github/scripts/github-api-with-retry.js +++ b/.github/scripts/github-api-with-retry.js @@ -170,7 +170,7 @@ function logWithCore(core, level, message) { core[level](message); return; } - const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.error; + const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.log; logFn(message); } diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index 3acb8f601..e5fbae6fd 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -202,8 +202,34 @@ jobs: # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. + # Capture the attempt clock before dispatch: gh workflow run can exit non-zero + # after GitHub has already accepted the request. + dispatch_attempted_at=$(date -u +%Y-%m-%dT%H:%M:%SZ) if ! gh workflow run agents-issue-optimizer.yml --repo "$GITHUB_REPOSITORY" \ -f issue_number="$NUMBER" -f phase=format; then + accepted=false + for _try in 1 2 3 4 5; do + sleep 2 + # shellcheck disable=SC2016 + match_count=$(gh run list --repo "$GITHUB_REPOSITORY" \ + --workflow=agents-issue-optimizer.yml \ + --event workflow_dispatch \ + --limit 20 \ + --json createdAt,displayTitle \ + | jq --arg since "$dispatch_attempted_at" --arg issue "#$NUMBER" \ + '[.[] | select(.createdAt >= $since and (.displayTitle | contains($issue)))] | length') + if [[ "${match_count:-0}" -gt 0 ]]; then + accepted=true + break + fi + done + if [[ "$accepted" == true ]]; then + echo "::warning::optimizer dispatch CLI failed but a matching run was accepted; preserving agents:format lease" + echo "::error::optimizer dispatch status ambiguous; no completion marker written" + exit 1 + fi + gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --remove-label "agents:format" \ + || echo "::warning::could not release failed agents:format lease" echo "::error::optimizer dispatch failed; no completion marker written so later runs can retry" exit 1 fi diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index 501bccb86..d8b266c08 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -349,6 +349,7 @@ jobs: }); NODE + set +e python - <<'PY' import json from scripts.langchain import issue_dedup @@ -385,6 +386,7 @@ jobs: out.write(comment) PY dedup_rc=$? + set -e if [[ $dedup_rc -ne 0 ]]; then echo "::warning::issue dedup python exited with $dedup_rc; continuing without similar-issues comment" fi diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index a669a5967..e639fa0a9 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 = ccf1cd3ccdba84c54743d2950367308df15c5928b95c1e7400a5d2858b7c1fa5 -template_sha256 = a4d50beb165724ff9266a18390d738105538fe0c13a5eb3a620fb8c9297fe80f -reason = Intentional divergence re-baselined 2026-08-08b: 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, and fixed issue_dedup Python indentation with visible non-zero exit warnings. Do not align wholesale — that would strip consumer action pins/token setup. +main_sha256 = 128b60e2af8e3957209849c7f20502a1b9a971e0c8c347e25a0d501a868bc484 +template_sha256 = f7987a566c15971ae9039bb3d1a53f0bb654378e6c1dc3103f5692f5abca022d +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. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml diff --git a/langsmith-fleet-worker-attempt.json b/langsmith-fleet-worker-attempt.json index 336c7a2e8..5c8ce841b 100644 --- a/langsmith-fleet-worker-attempt.json +++ b/langsmith-fleet-worker-attempt.json @@ -1,13 +1,13 @@ { "agent": "codex", "cli_version": "0.144.1", - "emitted_at": "2026-08-08T11:32:33.483036Z", + "emitted_at": "2026-08-08T15:51:23.873676Z", "execution_profile": "codex-default", "fallback_models": [ "gpt-5.5" ], "operation_role": "worker", - "pr_number": "2981", + "pr_number": "2985", "requested_model": "gpt-5.6-terra", "runner": "reusable-codex-run", "schema": "langsmith-fleet/v1", diff --git a/templates/consumer-repo/.github/scripts/github-api-with-retry.js b/templates/consumer-repo/.github/scripts/github-api-with-retry.js index 99231c2e1..90b72cbe4 100755 --- a/templates/consumer-repo/.github/scripts/github-api-with-retry.js +++ b/templates/consumer-repo/.github/scripts/github-api-with-retry.js @@ -170,7 +170,7 @@ function logWithCore(core, level, message) { core[level](message); return; } - const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.error; + const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.log; logFn(message); } diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index 3acb8f601..e5fbae6fd 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -202,8 +202,34 @@ jobs: # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. + # Capture the attempt clock before dispatch: gh workflow run can exit non-zero + # after GitHub has already accepted the request. + dispatch_attempted_at=$(date -u +%Y-%m-%dT%H:%M:%SZ) if ! gh workflow run agents-issue-optimizer.yml --repo "$GITHUB_REPOSITORY" \ -f issue_number="$NUMBER" -f phase=format; then + accepted=false + for _try in 1 2 3 4 5; do + sleep 2 + # shellcheck disable=SC2016 + match_count=$(gh run list --repo "$GITHUB_REPOSITORY" \ + --workflow=agents-issue-optimizer.yml \ + --event workflow_dispatch \ + --limit 20 \ + --json createdAt,displayTitle \ + | jq --arg since "$dispatch_attempted_at" --arg issue "#$NUMBER" \ + '[.[] | select(.createdAt >= $since and (.displayTitle | contains($issue)))] | length') + if [[ "${match_count:-0}" -gt 0 ]]; then + accepted=true + break + fi + done + if [[ "$accepted" == true ]]; then + echo "::warning::optimizer dispatch CLI failed but a matching run was accepted; preserving agents:format lease" + echo "::error::optimizer dispatch status ambiguous; no completion marker written" + exit 1 + fi + gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --remove-label "agents:format" \ + || echo "::warning::could not release failed agents:format lease" echo "::error::optimizer dispatch failed; no completion marker written so later runs can retry" exit 1 fi diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index ab2f44db1..45dc41a03 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -348,6 +348,7 @@ jobs: }); NODE + set +e python - <<'PY' import json import sys @@ -386,6 +387,7 @@ jobs: out.write(comment) PY dedup_rc=$? + set -e if [[ $dedup_rc -ne 0 ]]; then echo "::warning::issue dedup python exited with $dedup_rc; continuing without similar-issues comment" fi diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index 021aa25fc..203836296 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -81,6 +81,16 @@ def test_format_lease_is_required_and_released_after_failure() -> None: assert "exit 1" in text[lease_idx:dispatch_idx] # Dispatch must stay inside the success path after lease acquisition. assert '--add-label "agents:format"' in text[:dispatch_idx] + # Clock capture precedes the dispatch so an accepted-but-errored CLI can be + # reconciled; lease release stays inside the failure block only after that probe. + failure_start = text.index("if ! gh workflow run agents-issue-optimizer.yml") + assert "dispatch_attempted_at=" in text[dispatch_idx - 200 : failure_start] + failure_end = text.index("\n fi", failure_start) + failure_block = text[failure_start:failure_end] + assert "preserving agents:format lease" in failure_block + assert '--remove-label "agents:format"' in failure_block + assert '|| echo "::warning::could not release failed agents:format lease"' in failure_block + assert "no completion marker written so later runs can retry" in failure_block for text in ( WORKFLOW_PATH.read_text(encoding="utf-8"),