Skip to content

fix(scheduler): isolate central Actions inventory quota - #1231

Draft
seonghobae wants to merge 23 commits into
mainfrom
fix/scheduler-actions-read-token
Draft

fix(scheduler): isolate central Actions inventory quota#1231
seonghobae wants to merge 23 commits into
mainfrom
fix/scheduler-actions-read-token

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Current status — Proposed / decomposition required

This historical branch remains open so no valid delta is lost. It is intentionally Draft because exact head 99a1a481871f26ee1793338fe401d6373d85281e is 23 commits ahead and 38 commits behind protected main@78a4937c684a54ca8e415822c913742f41c6efc4, is conflicted, and combines 17 files from several independent responsibilities. Earlier test counts, approvals, and required-workflow receipts belong to predecessor heads and are not current admission evidence.

Verified successor carryover

The following bounded responsibilities now have current-base RED→GREEN successors:

  • #2002 — host-scoped Actions inventory/cancellation credentials; RED 8cc62ce…, GREEN 7bf3451a…
  • #2003 — prove selected mutation token differs from workflow github.token and preserve recorded guidance; RED ebcc6715…, GREEN e2204eeb…
  • #2004 — restore Python Security and Runtime Quality coverage for stacked PRs; RED 890bac2f…, GREEN 14f7c85c…
  • #2005 — skip non-authoritative target Actions inventory for centralized review; RED 08a16caa…, GREEN a42ab003…
  • #2006 — reject Draft PRs at direct-merge and auto-merge mutation boundaries; RED 2d140a84…, GREEN 5abc0a02…
  • #2007 — case-insensitive owned-head and compare-ref identity; RED 4fb514db…, GREEN 75e9d67c…
  • #2030 — trusted actionlint/shfmt provisioning and fail-closed queue: max cancellation proof; RED 98768d6…, implementation 822222ed…, exact-head whitespace repair 6d104003…
  • #2031 — deterministic Rust GPGPU software-adapter pathname selection without ls | head; RED 4d976e8…, implementation fd2a497…, exact-head fixture/pin repair 4bea311e…
  • #2033 — deterministic completion-order regression for the already-concurrent agent-mention sweep; RED 570da463…, GREEN de96b8b4…

All successors are Draft/Proposed and preserve normal non-force lineage. Runtime Quality is now exact-head GREEN on #2002 and #2004#2007, while CodeQL and other required receipts remain mixed queued/terminal; no stack node inherits another node's evidence. #2030, #2031, and #2033 generated fresh hosted workflows on their own exact heads; terminal evidence remains required. #1231 is not retired or closed.

Remaining delta ledger

The following historical responsibilities still require current-main comparison and, where still valid, independent RED→GREEN successors or a non-destructive semantic restack:

  • configured repository-dispatch run-name deduplication is verified complete on protected main: #1983 merged as 74224b2091701a754b2fd1a539833c7a6d50b79e; current main@78a4937c684a54ca8e415822c913742f41c6efc4 is 5 commits ahead / 0 behind that commit, and the production matcher plus OpenCode/Strix rendered-run-name regressions are present. No duplicate successor is required.
  • actionlint/shfmt policy, queue: max compatibility, workflow provisioning, and license-boundary changes are preserved in Proposed successor fix(autofix): fail closed on ambiguous workflow validation #2030; they remain incomplete until its exact-head checks are terminal and the delta is integrated
  • Rust GPU adapter selection is preserved in Proposed successor fix(opencode): make GPU adapter selection deterministic #2031 and remains incomplete until exact-head checks terminate and the delta is integrated
  • NVIDIA/cross-provider fallback is verified complete on protected main: #1331 commit 33dc57d7984b937e4f5ab915d5eae69a0f42e3a5 and #1353 commit 874f47b3856ca6bdb6bc71d48173b8f34ba7b9ca are ancestors of current main (752 and 743 commits ahead / 0 behind respectively). The production gate maps both direct-OpenAI aliases, isolates fallback credentials/API base, and has permanent regression coverage. No duplicate successor is required.
  • the SBOM mapfile rewrite was authored in 131f494922c7ac9336195d1facebb705e5ed75cb as an implementation-level companion to the large-shell linter repair. Current main preserves the semantic contract—LC_ALL=C pathname sorting, exclusion of SHA256SUMS, and per-file sha256sum—with the shorter pipeline; no state escapes the loop subshell and no consumer contract depends on mapfile. Reintroducing the temporary-file/array shape would add machinery without restoring a valid missing behavior, so no duplicate successor is required.
  • sweep completion-order coverage is preserved in Proposed successor test(sweep): make completion-order regression deterministic #2033 and remains incomplete until its exact-head checks terminate and the delta is integrated

The live unresolved thread on dynamic cancel-in-progress beside queue: max remains substantive and intentionally unresolved. The former #1213 dependency is historical and cannot be used as current merge authority.

No reviewer, required check, scanner, permission, ruleset, or cross-repository mutation authority is weakened.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

스케줄러가 실행 호스트별 credential을 선택하고 Actions 실행을 조회하거나 취소합니다. 중앙 dispatch는 정확한 제목으로 중복 실행을 판별하고 비권위 대상 실행 정리를 생략합니다. 병합 mutation은 draft PR을 거부합니다. 워크플로 린터와 Strix fallback 동작도 갱신합니다.

Changes

워크플로와 스케줄러 강화

Layer / File(s) Summary
신뢰된 워크플로 린팅
scripts/ci/lint_github_workflows.rb, tests/test_lint_github_workflows.py, .github/workflows/pr-review-autofix.yml, docs/doctoring/actionlint-modern-schema-and-shellcheck.md
Ruby 린터가 YAML 구조와 concurrency.queue: max를 검증합니다. actionlint와 파일 기반 ShellCheck를 분리 실행하고, 오류와 잘못된 출력을 fail-closed로 처리합니다.
스케줄러 자격 증명과 실행 호스트 인벤토리
scripts/ci/pr_review_merge_scheduler.py, .github/workflows/pr-review-merge-scheduler.yml, .github/workflows/opencode-review-dispatch.yml, tests/test_pr_review_merge_scheduler.py, tests/test_opencode_agent_contract.py, docs/doctoring/fork-head-review-dispatch.md
실행 호스트별 credential을 선택합니다. 실제 선택 토큰과 workflow token을 검증합니다. 기록된 credential 거부 사유를 guidance와 요약에 사용합니다.
디스패치 중복과 병합 방어
scripts/ci/pr_review_merge_scheduler.py, tests/test_pr_review_merge_scheduler.py, docs/doctoring/fork-head-review-dispatch.md, CHANGELOG.md
정확한 repository·PR·head SHA 제목을 workflow name 필터보다 먼저 비교합니다. 중앙 dispatch에서는 대상 저장소의 old-head 정리를 생략합니다. draft PR의 enable_auto_mergemerge_pr 호출을 사전에 차단합니다.
워크플로 실행과 Strix 지원 변경
.github/workflows/opencode-review-dispatch.yml, .github/workflows/exact-artifact-sbom-attestation.yml, scripts/ci/strix_quick_gate.sh, tests/*, docs/doctoring/strix-nvidia-nim-not-found-fallback.md, CHANGELOG.md
대형 shell 블록과 파일 목록 처리를 조정합니다. openai-direct/* fallback을 LiteLLM용 openai/*로 변환합니다. Strix 재시도·스캔 범위·증거 처리·sweep counter·workflow context 변경을 기록하고 검증합니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟡 Moderate · up to 53b53

The current changes can still allow workflows with unsupported concurrency settings, introduce a dependency that conflicts with repository licensing policy, and cause the Strix gate to miss Python files during analysis; these issues should be fixed or explicitly accepted before merging.

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant CentralDispatch
  participant TargetRepository
  participant MergeMutation
  Scheduler->>CentralDispatch: 정확한 dispatch 제목과 head SHA로 실행 확인
  CentralDispatch-->>Scheduler: 일치하는 실행 반환
  Scheduler->>TargetRepository: 중앙 dispatch이면 old-head 실행 정리 생략
  Scheduler->>MergeMutation: 병합 또는 자동 병합 요청
  MergeMutation-->>Scheduler: draft PR이면 RuntimeError 반환
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 75 functions across 10 files. (7 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 중앙 GitHub Actions 인벤토리 할당량 격리라는 주요 변경 사항을 정확하고 간결하게 설명합니다.
Full details: Docstring Coverage

Explanation

Docstring coverage is 72.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 75 functions across 10 files. (7 skipped: 7 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scheduler-actions-read-token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

…-read-token

# Conflicts:
#	CHANGELOG.md
#	tests/test_pr_review_autofix_nvidia_nim_contract.py
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

* fix(ci): lint modern Actions schemas safely

* fix(ci): preserve multiline workflow diagnostics

* test(ci): bound Ruby runtime coverage

* fix(ci): preserve deterministic workflow evidence
github-advanced-security[bot]

This comment was marked as resolved.

github-advanced-security[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor Author

Devin finding "Repository casing blocks valid automation" — confirmed and fixed

Verified against the exact PR head (ae36220ae1519e678ddbd99de87a00e7072f3544): same_repository_head (scripts/ci/pr_review_merge_scheduler.py:1905) and compare_ref_for_pr_head (:963) both compared headRepository.nameWithOwner to the configured target repo with exact ==, while a sibling check in the same file (the stale-run-cancellation gate, repository_dispatch_target(repo).casefold() == repo.casefold() at line 2439) already case-folds. GitHub repository identity is case-insensitive, so a same-repository PR whose GitHub-reported canonical name differed only in case from the configured target would be misclassified as cross-repository — losing branch updates and merge eligibility.

Fix: both functions now casefold() both sides, matching the existing normalization idiom already used elsewhere in this file (repo.casefold() at lines 629 and 2439). same_repository_head also guards the None-headRepository case explicitly via bool(head_repo) and ... (kept as a single expression, not a branching if, to avoid an uncovered branch under the 100%-branch-coverage gate).

Regression test (tests/test_pr_review_merge_scheduler.py): extended test_inspect_pr_blocks_and_waits_for_policy_states with a PR whose headRepository.nameWithOwner is "Owner/Repo" against target "owner/repo", asserting same_repository_head, can_update_pr_head, compare_ref_for_pr_head (bare ref, not owner-prefixed), and the end-to-end inspect_pr decision (update_branch, branch-update actually invoked). Verified it fails against the pre-fix exact-== code (AssertionError: assert False on same_repository_head) and passes against the fix.

Note: I found the identical case-sensitive-== pattern in same_repository_head inside scripts/ci/pr_review_fix_scheduler.py and scripts/ci/pr_auto_rebase.py, but neither file is in this PR's diff, so I left them alone rather than expanding scope — flagging for a follow-up PR/issue if that's wanted.

Devin finding "Supported shells escape correct validation" — confirmed and fixed

Verified against scripts/ci/lint_github_workflows.rb: effective_shell never consulted job-level container:, so a container job with no explicit shell: anywhere in the resolution chain defaulted to bash in the linter, even though GitHub Actions actually runs such a step under sh. Separately, shellcheck_dialect only recognized the bare names "bash"/"sh" (or those names followed by a space), so an absolute-path custom shell template (e.g. /bin/bash --noprofile --norc -eo pipefail {0}, /usr/bin/sh {0}) matched neither branch and was silently skipped — no shell-syntax validation at all for that step.

Fix: effective_shell now defaults containerized jobs (job has a container: key) to sh instead of bash when nothing else in the chain sets a shell. shellcheck_dialect now takes the first whitespace token of the shell string, resolves it to its File.basename, and classifies on that — so "bash", "/bin/bash", "/bin/bash --noprofile --norc -eo pipefail {0}", "sh", and "/usr/bin/sh {0}" all classify correctly.

Regression tests (tests/test_lint_github_workflows.py, added, following the existing subprocess-driven harness pattern with faked actionlint/shfmt):

  • test_linter_treats_unshelled_container_job_step_as_posix_sh — a container job step with no explicit shell asserts shfmt is invoked with ["-ln", "posix", "-tojson"], and a sibling non-container job step still gets bash.
  • test_linter_classifies_absolute_path_shell_templates — absolute-path bash/sh templates each produce a shfmt invocation (previously: zero, since the step was skipped entirely) with the correct dialect.

Both verified to fail against the pre-fix functions (posix-vs-bash mismatch; 0 shfmt records instead of 2) and pass against the fix.

Other unresolved Devin threads on this PR (not in scope, no action taken)

  • "Dynamic cancellation policy remains ambiguous" (lint_github_workflows.rb:40) — a design question about validate_concurrency_queue!'s handling of expression-valued cancel-in-progress, not a concrete bug; left for human/maintainer judgment.
  • Three "Info" threads (mutation token proof, checksum inventory, queue diagnostic exemption) are informational confirmations, not findings requiring a fix.

Validation evidence

  • ruby -c scripts/ci/lint_github_workflows.rb — clean
  • PYTHONPATH=. python3 -m pytest tests -q — 1920 passed, 1 skipped, 21 subtests passed
  • coverage run -m pytest tests -q && coverage report — 100% statements, 100% branches on scripts/ci (pr_review_merge_scheduler.py: 1777/1777 statements, 732/732 branches)
  • interrogate — 100% docstring coverage
  • git diff --check — clean

Pushed to fix/scheduler-actions-read-token (this PR's actual head branch — the branch name given in the task, fix/central-actions-inventory-quota-isolation, does not match the PR's real head ref) at b297581a.


_Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

opencode-review failure on b297581a (job 99272876036) is the standard fail-closed wait-state, not a defect: No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head — the async OpenCode dispatch hasn't posted a verdict for this exact head yet. No action needed beyond waiting for the next dispatch cycle.


Generated by Claude Code

@seonghobae seonghobae added area: ci-cd CI, GitHub Actions, checks, release, or supply chain bug Something isn't working priority: high High-priority or P1 work status: blocked Blocked by conflict, dependency, or required prerequisite type: bug Defect or incorrect behavior labels Sep 2, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Contributor Author

Merge-conflict triage: genuine architectural divergence (pr_review_merge_scheduler.py facade/core split), not attempted

Checked this PR's diff (git diff --name-only origin/main...origin/fix/scheduler-actions-read-token) before attempting the standard merge repair for its dirty mergeable_state. It edits scripts/ci/pr_review_merge_scheduler.py directly — the same file this session found in #1271 (see that PR's comment) to be a pre-split, thousands-of-lines monolith on the PR side versus a 241-line facade re-exporting from the new scripts/ci/pr_review_merge_scheduler_core.py on current main (landed via #1803, after this PR was opened). A text-level git merge cannot reconcile those two shapes of the same file; resolving it correctly means re-deriving this PR's credential-routing/mutation-authorization logic against pr_review_merge_scheduler_core.py as it stands today, not a mechanical conflict resolution — so per this loop's "don't guess on real divergence" standard, no merge was attempted and nothing was pushed.

This PR's own description also records an unresolved external stack dependency (ContextualWisdomLab/.github#1213 "must land on protected main before this PR's required Strix run can use the corrected trusted gate") that is independent of the file-split issue above and would need to be re-checked against current main regardless.

Recommended path: re-derive this PR's Actions-inventory-credential-routing fix directly against current main/pr_review_merge_scheduler_core.py (and re-verify whether #1213's dependency still applies) rather than resolving the conflict in place.


Generated by Claude Code

seonghobae pushed a commit that referenced this pull request Sep 4, 2026
…test-bug fix

Follow-up to this same PR's original entry: this round's continued PR sweep
found #1065 and #1681 conflicting on strix.yml/noema_review_gate.py (same
pattern as the 7 PRs already documented), plus #1271 and #1231 conflicting on
scripts/ci/pr_review_merge_scheduler.py -- confirming the #1803 facade/core
split is now also an active collision surface (4,074-line monolith on each
PR's branch vs. a 241-line facade + separately-evolving core file on main).
Evidence-based comments were left on all 4; no guessed resolution was pushed.

Also records one genuine pre-existing (not merge-caused) test bug found and
fixed while merge-repairing #1655: a jq trailing-newline off-by-one in a new
E2E test, and a coverage gap in opencode_review_normalize_output.py's new
needs-info wrapper (branches only exercised via subprocess, invisible to
coverage.py). Both fixes are test-only, pushed as part of #1655 itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
main replaced the 4063-line scheduler monolith this branch was built on with
a 241-line facade plus a 6222-line core, so all four scheduler conflicts had
ours 656/1322/611/359 lines against theirs 2/17/2/15. That is the #1009 shape,
but it is relocatable here, not a re-implementation: all 16 functions the
branch's hunks anchor on still exist in pr_review_merge_scheduler_core.py.

Method: take main's facade, then replay the branch's own diff against the core
module (git apply --3way with the path rewritten). 15 of 17 hunks landed
cleanly. The two that did not were placement collisions, resolved by applying
the branch's intent at core's existing sites instead of at the branch's:
- core already owns active_workflow_runs (23 references vs the branch's 4) and
  had grown server-side filters and memoization. Kept core's function and
  rerouted its single call to run_github_actions_for_repository(repo, args),
  which is what the branch's version of that function did.
- core calls cancel_stale_pr_runs at a different point in inspect_pr than the
  branch did. Wrapped core's call site with the branch's
  repository_dispatch_target(repo).casefold() == repo.casefold() guard.

Other files:
- .github/workflows/pr-review-merge-scheduler.yml: main deleted the entire
  684-line org-queue-sweep job and pins its absence
  (assert_file_not_contains 'org-queue-sweep'). Took main's side. Provenance
  checked: org-queue-sweep is 4x at the merge base and 4x on the branch, 0x on
  main, and the branch's own change to this file is only +2 lines, so nothing
  the branch authored is lost with the job. One of those two lines
  (SCHEDULER_WORKFLOW_TOKEN) belonged to org-queue-sweep; the other had already
  auto-merged into the job main kept.
- tests/test_opencode_agent_contract.py: the branch pinned
  count('SCHEDULER_WORKFLOW_TOKEN: ...') == 2. One of those two occurrences was
  org-queue-sweep's, so the merged tree has 1. Changed the pin to 1 with the
  reason in a comment.
- tests/test_pr_review_autofix_nvidia_nim_contract.py: REVIEW_DISPATCH_BLOB_SHA
  pins git hash-object on opencode-review-dispatch.yml. Both sides are correct
  for their own tree and both wrong for this merge (branch ea13d12, main
  26e8555). Recomputed from the merged file: d7f7c18.
- tests/test_pr_review_merge_scheduler.py: kept both sides (main's 337 lines and
  the branch's 32). The conflict boundary falls between complete top-level
  functions.
- CHANGELOG.md: kept both entries.

Evidence:
- uvx ruff check --select F821 scripts/ci tests: All checks passed
- full suite, branch head b297581 (unmerged): 1920 passed, 0 failed
- full suite, this merge:                      2919 passed, 0 failed
- PR's own oracle (test_lint_github_workflows.py, test_pr_review_merge_
  scheduler.py, test_pr_review_autofix_nvidia_nim_contract.py): 372 passed
- coverage: TOTAL 100%; pr_review_merge_scheduler_core.py 2557/2557 100%.
  With fail_under = 100 this is the independent proof that both relocated
  edits are reached, not merged-in-but-dead.
- negative control: deleting the SCHEDULER_WORKFLOW_TOKEN workflow line makes
  test_merge_scheduler_uses_escalating_mutation_credentials fail by name
- interrogate: PASSED (minimum 100.0%)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@seonghobae

Copy link
Copy Markdown
Contributor Author

main 병합 완료 (99a1a481) — 리뷰어가 알아야 할 3가지

main이 이 브랜치의 기반인 4063줄 스케줄러 모놀리스를 241줄 facade + 6222줄 core로 교체해서, 스케줄러 충돌 4블록이 ours 656/1322/611/359줄 vs theirs 2/17/2/15줄이었습니다. #1009과 같은 형태지만 재구현이 아니라 재배치였습니다 — 브랜치 헝크가 딛는 함수 16개가 pr_review_merge_scheduler_core.py에 전부 살아 있습니다.

방법: facade는 main 것을 취하고, 브랜치 자신의 diff를 경로만 core로 바꿔 git apply --3way로 재생했습니다. 17개 헝크 중 15개가 그대로 안착했고, 나머지 2개는 의미 충돌이 아니라 배치 충돌이라 core의 기존 자리에 브랜치 의도만 적용했습니다.

  • core는 이미 active_workflow_runs를 갖고 있고(참조 23회 vs 브랜치 4회) 서버사이드 필터와 메모이제이션까지 붙었습니다. core 함수를 유지하고 그 안의 호출 하나만 run_github_actions_for_repository(repo, args)로 돌렸습니다 — 브랜치 판본이 하던 그대로입니다.
  • core는 cancel_stale_pr_runsinspect_pr의 다른 지점에서 호출합니다. 그 호출부를 브랜치의 repository_dispatch_target(repo).casefold() == repo.casefold() 가드로 감쌌습니다.

org-queue-sweep 684줄이 사라집니다 — 이 PR의 손실은 아닙니다

main이 그 잡을 통째로 삭제했고 부재를 계약으로 고정합니다(assert_file_not_contains "org-queue-sweep"). 출처를 확인했습니다: merge-base 4회 / 이 브랜치 4회 / main 0회이고, 이 브랜치가 이 워크플로에 한 변경은 +2줄뿐입니다. 그 2줄 중 하나(SCHEDULER_WORKFLOW_TOKEN)가 org-queue-sweep 소속이었고, 나머지 하나는 main이 남긴 잡으로 이미 자동 병합돼 있었습니다.

REVIEW_DISPATCH_BLOB_SHA — 양쪽 다 틀렸습니다

이 핀은 git hash-object .github/workflows/opencode-review-dispatch.yml입니다. 브랜치는 ea13d12a…, main은 26e85559…를 주장하는데 둘 다 각자 트리에서만 맞고 병합본에는 틀립니다. 병합 파일에서 재계산한 d7f7c18d9fc520e3ae91d58d808ccca9d8e57771로 넣었습니다.

③ 계약 카운트 2 → 1

test_merge_scheduler_uses_escalating_mutation_credentialsSCHEDULER_WORKFLOW_TOKEN 2회를 고정하는데, 그중 하나가 org-queue-sweep 것이었습니다. 1로 바꾸고 이유를 주석에 남겼습니다. 네거티브 컨트롤로 탐지력을 확인했습니다 — env 줄을 지우면 이 테스트가 이름을 찍고 실패합니다.

검증

  • uvx ruff check --select F821 — All checks passed
  • 전체 스위트, 병합 전 브랜치 헤드 b297581a: 1920 passed / 0 failed
  • 전체 스위트, 이 병합: 2919 passed / 0 failed
  • PR 고유 오라클(test_lint_github_workflows.py + 스케줄러/autofix 계약): 372 passed
  • coverage TOTAL 100%, pr_review_merge_scheduler_core.py 2557/2557 100%fail_under = 100이므로 이 수치 자체가 재배치한 두 편집이 죽은 코드가 아니라는 독립 증거입니다
  • interrogate PASSED (minimum 100.0%)

fast-forward 푸시, force push 없음.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor Author

CodeQL compatibility analysis (python) and CodeQL compatibility analysis (actions) failed on this head (99a1a481), both with "CodeQL scan dispatched. The dispatch workflow will rerun this exact failed CodeQL job after publishing its terminal verdict." (jobs 101391596142/101391596251). Confirmed via the job log: VERDICT_STATE=pending — the designed dispatch-and-poll wait state, not a defect.

Same root cause already traced today on .github#1503's identical failure: an org-wide GitHub Actions runner-queue congestion is delaying the underlying codeql-scan-dispatch.yml repository_dispatch runs across multiple PRs simultaneously, not anything in this PR's own diff. Not re-running: this shard's own RUN_ATTEMPT != 1 guard would fail it outright without an authenticated verdict already present, and the dispatch workflow is designed to rerun this exact job automatically once it publishes one. Keeping this PR watched for that.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

noema-review failed on this head (99a1a481, job 101391562686) with the same class of real failure just found and reported on .github#1912: HTTPError: HTTP Error 429: Too Many Requests; caller attempts=1, duration=575.5s, phase=response_error, served_model=deepseek-ai/deepseek-v4-flash-0731.

Not this PR's diff. Corroborating evidence for the contextual-orchestrator pool-failover gap: this run's own preflight found 3 "ready" orchestrator/free routes, but all three needed escalation (attempts: 2) to become ready — nvidia_nim_sub_deepseek_ai_deepseek_v4_flash_0731, openrouter_cohere_north_mini_code_free, and openrouter_dots_studio_dots_3_note_preview_free — while nvidia_nim_deepseek_ai_deepseek_v4_pro_0813/nvidia_nim_sub_deepseek_ai_deepseek_v4_pro_0813 were rejected outright (429/TimeoutError) this time. The actual gateway request still went to the nvidia_nim deepseek-flash route and got a 429 after 575s, with no evidence it fell over to either of the two openrouter alternatives also marked ready.

Already investigating and (if confirmed) fixing this at the source in contextual-orchestrator — see the note on .github#1912 for the same root-cause writeup. Not duplicating that analysis here or re-running (same reasoning: a re-run would likely just re-hit the same gap). Keeping this PR watched.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

New tooling RED: GitHub queue: max syntax vs actionlint 1.7.12 schema

Naruon release/deploy work reproduced a validator/toolchain mismatch without pushing an unsupported workflow key:

  • GitHub's current concurrency documentation supports queue: max for retained pending runs (up to 100), and documents its incompatibility with cancel-in-progress: true.
  • Existing local validator actionlint 1.7.12, given a minimal workflow through stdin using concurrency.queue: max, exits 1 with unexpected key "queue".
  • This is therefore a CI toolchain/schema compatibility RED, not a reason to suppress actionlint, delete the release-ordering policy, or push syntax that the repository's validator currently rejects.
  • Naruon fix(scheduler): rerun the Strix scan job, not a sibling job #1586 intentionally did not push queue: max; that release/deploy owner remains scoped to image digest/runtime deployment and must not duplicate validator ownership.

This PR's remaining-delta ledger already names actionlint/shfmt policy, queue: max compatibility, workflow provisioning as uncarried work, so keep the repair here (or in a verified bounded successor preserving this exact delta).

Acceptance for the toolchain owner:

  1. Reproduce the minimal stdin case with the exact currently governed actionlint binary/version.
  2. Check upstream actionlint release/schema support for GitHub's documented concurrency.queue grammar; do not assume a newer version supports it without executable proof.
  3. If upstream has support, upgrade/pin through the canonical CI-toolchain path with RED→GREEN contracts covering queue: single, queue: max, invalid queue values, and the documented queue:max + cancel-in-progress:true invalid combination.
  4. If upstream has not released support, keep release/deploy policy source Proposed/unapplied and track the upstream capability gap explicitly rather than suppressing actionlint or maintaining a local permissive fork unless a separately justified owner decision is made.
  5. Preserve PR validation semantics (queue: single + trigger-aware cancellation) and scope queue:max only to lossless release/deploy/migration intent where actual target locks, protected revision/version/digest and idempotency are separately verified.

No Naruon source, release permission, or workflow gate should be weakened to make this RED disappear.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head toolchain finding for 99a1a481871f26ee1793338fe401d6373d85281e: current scripts/ci/lint_github_workflows.rb passes actionlint -ignore with QUEUE_DIAGNOSTIC for concurrency.queue.

That implementation predates the now-verified upstream state and conflicts with comment 5565056754's acceptance boundary. GitHub documents queue: max, but actionlint v1.7.12 is still the latest release; upstream issue #657 and PR #654 remain open/unmerged. The local Ruby validator does not make suppressing the released validator's schema error an acceptable protected-main toolchain contract.

Preserve the other #1247/#1231 deltas, but do not land this diagnostic suppression or an unmerged upstream parser. Keep queue:max consumers Proposed/unapplied until upstream native support is merged and released; then pin the immutable released actionlint version and prove positive/negative fixtures, including rejection of queue:max + cancel-in-progress:true. The existing unresolved dynamic-cancellation finding remains valid independently.

seonghobae pushed a commit that referenced this pull request Sep 7, 2026
GitHub documents concurrency.queue, but actionlint 1.7.12 rejects a
minimal queue: max workflow with unexpected key "queue" (exit 1), so the
documented syntax cannot pass the governed validator today.

Verified the cause at the source rather than inferring it from the error
string: actionlint v1.7.12's Concurrency struct in ast.go models only
Group and CancelInProgress, with no queue field, so the key is unknown
to it by construction. The entry says so explicitly and attributes the
observed error text and exit code to the reproduction reported on #1913,
because actionlint is not installed in this container and I did not run
it.

The entry states that this is validator-schema lag rather than evidence
against the feature, and that it is not permission to suppress,
downgrade or exempt actionlint. queue: max stays available to a lossless
release/deploy/migration lane only once the canonical toolchain can
validate it, and only with target locking plus protected
head/tag/version/digest verification and idempotency. Toolchain
ownership is #1231; naruon#1586 owns release/deploy ordering and did not
push the rejected key.

Guidance only, no workflow change.

Gate: 2975 passed, 1 skipped, 21 subtests, coverage 100%, interrogate
100%.

Refs #1231, #1586.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
seonghobae pushed a commit that referenced this pull request Sep 7, 2026
Four related repairs, all documentation and comments; no workflow or
census implementation, and no claim that any queue or 60-job definition
of done is complete.

docs/doctoring/actions-queue-saturation-hourly-sweep.md still read
"Status: active repair evidence" with canonical repair #1630 and
described the 15-minute-to-hourly sweep change as a live production
contract. #1878 (merge 1b65dbc) deleted
the org-queue-sweep source outright and 85f4ef9
folded head coalescing into the scheduler; both are ancestors of
main@c9052e607 and no such job remains. It is now marked HISTORICAL /
SUPERSEDED with those pointers, RCA kept intact.

audit_org_codeql_coverage.py cited that stale document as current
evidence for real queue congestion. The 35-day constant is unchanged and
its rationale stands; only the pointers are corrected, split explicitly
into HISTORICAL records for the removed sweep and #1938's BOUNDED LATER
EVIDENCE, with a note that neither proves current org-wide occupancy and
that this constant is not derived from one.

The triage catalog stated "55 of 60 running jobs" with no method and no
scope. It now carries both: a running-slot count is a count of jobs and
never of runs, so actions/runs?status=in_progress and queued counts are
not occupancy numerators; admit a job only when status is in_progress
AND it holds a real runner assignment, keeping queued work as separate
backlog. The three-repository sample is labelled a bounded precedent
rather than an org census, and the shared-ceiling phrasing is bound to
its 2026-09-04 reading.

Verified independently rather than assumed: no script under scripts/ci/
reads runner_id or runner_name, and audit_org_codeql_coverage.py is a
CodeQL coverage census. Org-wide occupancy is recorded as an open
collection gap instead of being implied by a sample.

Gate: 2975 passed, 1 skipped, 21 subtests, coverage 100%, interrogate
100%.

Refs #1878, #1630, #1938, #1231.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci-cd CI, GitHub Actions, checks, release, or supply chain bug Something isn't working priority: high High-priority or P1 work status: blocked Blocked by conflict, dependency, or required prerequisite type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants