Skip to content

ops: three required workflows each boot a runner for the same "Detect changed scope" job #1976

Open

Description

@seonghobae

측정

PR 하나(#1975, head 8c6b052e)가 실제 작업 전 단계에서 만든 체크런 13개입니다.

queued   Detect changed scope        ← strix.yml
queued   Detect changed scope        ← security-scan.yml
queued   Detect changed scope        ← sast-semgrep.yml
queued   Detect CodeQL languages
queued   Detect Python
queued   Admit current pull request head
queued   admit-current-head
queued   gitleaks (secret scan)
queued   required-workflow-bootstrap
queued   scan-pr-queue
skipped  cancel-closed-pr-runs
skipped  cancel-superseded-opencode-review-runs
skipped  cancel-superseded-pr-runs

Detect changed scope 가 세 번 있습니다. 세 워크플로가 각각 선언합니다.

grep -rln "Detect changed scope" .github/workflows/
  .github/workflows/strix.yml
  .github/workflows/security-scan.yml
  .github/workflows/sast-semgrep.yml

같은 것을 계산하는 잡 셋이 각각 러너를 하나씩 잡습니다. 검출/입장 계열까지 세면 13개 중 5개가 본 작업 전의 게이트 잡입니다.

왜 이게 지금 비싼가

희소 자원이 러너-분이 아니라 큐 슬롯입니다. 같은 시각 측정입니다.

actions/runs?status=queued   total_count 196
디스패치 레인 실측 (#1929)   대기 44분 22초 / 실행 3초

3초짜리 잡도 44분치 슬롯을 씁니다. 그러니 "가벼운 검출 잡"이라는 직관이 여기서는 틀립니다. PR 하나가 본 작업 전에 슬롯 다섯 개를 소비하고, 그 중 셋은 서로 같은 답을 계산합니다.

왜 단순 합치기가 아닌가

중복이 실수가 아니라 규정된 패턴입니다. CLAUDE.md 는 required workflow 에 트리거 수준 필터(paths, branches, types)를 절대 넣지 말고 잡 수준 changed-scope 게이트로 건너뛰라고 못박습니다. 조직 ruleset 이 on: 필터를 버리기 때문입니다. 그리고 실행이 skipped 가 아니라 success 로 끝나도록 출력 의존 if: 가 없는 잡을 하나 남기라고도 합니다.

즉 워크플로가 셋으로 나뉘어 있는 한, 검출 잡도 셋입니다. 워크플로를 합쳐야 검출이 하나가 됩니다 — 하나의 Detect changed scope 가 needs: 로 세 잡을 먹이는 형태로요.

결정이 필요한 지점

합치면 required context 이름이 바뀝니다. .github 는 조직 ruleset 이 아니라 14개 이름 붙은 컨텍스트의 classic branch protection 을 쓰고, 사라진 이름은 영원히 Pending 으로 남습니다. 그 재설정은 소유자 조치입니다.

세 워크플로의 정확한 컨텍스트 이름과 ruleset 파일 목록 영향은 아직 확인하지 않았습니다. 확인 없이 합치면 안 됩니다.

  • (가) 세 보안 워크플로를 한 파일로 합치고 검출 잡을 공유. PR 당 슬롯 2개 절약. 컨텍스트 개명이 따라오고 branch protection 재설정이 필요.
  • (나) 현행 유지. PR 당 슬롯 3개를 검출에 계속 지출.

이 이슈가 주장하지 않는 것

큐 적체의 주된 원인이라고 말하지 않습니다. 같은 시각 표집에서 최대 점유자는 성공률 0인 CodeQL Scan Dispatch(표집의 39%, #1929)입니다. 이건 그것과 별개의, 더 작고 소유자 조치 없이는 못 고치는 지출입니다.

🤖 Generated with Claude Code

Activity

  1. seonghobae commented on Sep 6, 2026

    @seonghobae
    ContributorAuthor

    정정: 필수 컨텍스트는 12개이고, Detect changed scope 는 그 안에 없습니다

    제 오류입니다. 이슈 본문에 "14개 이름 붙은 classic branch protection" 이라고 썼는데 틀렸습니다. 실측 12개입니다. peer 1 이 잡아 주었고, 제 실행으로 재현했습니다.

    gh api repos/ContextualWisdomLab/.github/branches/main/protection
      required_status_checks.contexts  →  12    (strict: true)
    
    CodeQL compatibility analysis (actions)   CodeQL compatibility analysis (python)
    Detect CodeQL languages                   coverage-evidence
    dependency-review                         noema-review
    opencode-review                           osv-scan
    required-workflow-bootstrap               scan-pr-queue
    scorecard                                 trivy-fs
    

    CLAUDE.md 가 아직 14로 적혀 있어 그걸 인용했습니다. 다만 문서 탓으로 돌리지 않겠습니다 — 12라는 실측값은 제 작업 노트에 이미 있었고, 확인하지 않고 체크인된 숫자를 인용한 것은 제 잘못입니다. #1965 가 그 문서를 12로 고치는 PR인데 아직 병합 전입니다.

    이 정정이 이슈의 논거를 바꿉니다

    본문에서 "합치면 required context 이름이 바뀌고 사라진 이름이 영원히 Pending 으로 남는다"고 썼습니다. Detect changed scope 에는 그 위험이 적용되지 않습니다.

    'Detect changed scope' in contexts  →  False
    

    필수 컨텍스트가 아니므로, 그 잡을 합치거나 없애도 Pending 영구화가 없습니다.

    위험 등급을 둘로 나눕니다

    세 워크플로의 jobs: 를 파싱해 각 잡이 발행하는 이름을 실측했습니다.

    strix.yml
      changed-scope        -> 'Detect changed scope'
      admit-current-head   -> 'Admit current pull request head'
      cancel-superseded-pr-runs / strix / publish-manual-pr-evidence-status
      → 필수 12개와 겹침 없음
    
    sast-semgrep.yml
      changed-scope        -> 'Detect changed scope'
      semgrep              -> 'Semgrep (multi-language SAST)'
      → 필수 12개와 겹침 없음
    
    security-scan.yml
      changed-scope        -> 'Detect changed scope'
      osv-scan             -> 'osv-scan'            ← 필수
      dependency-review    -> 'dependency-review'   ← 필수
      trivy-fs             -> 'trivy-fs'            ← 필수
      scorecard            -> 'scorecard'           ← 필수
      gitleaks             -> 'gitleaks (secret scan)'
    

    security-scan.yml 혼자 필수 12개 중 4개를 발행합니다. 나머지 둘은 0개입니다.

    • (A) 낮은 위험 — Detect changed scope 중복 제거. 필수 컨텍스트가 아니므로 branch protection 재설정이 필요 없습니다. 소유자가 이것만 먼저 승인할 수 있습니다.
    • (B) 높은 위험 — 워크플로 파일 통합. security-scan.yml 을 옮기면 필수 이름 네 개가 걸립니다. 반대로 strix.yml 과 sast-semgrep.yml 끼리는 필수 이름을 하나도 안 건드립니다. 통합을 한다면 그 둘이 먼저이고, security-scan.yml 은 잡 이름을 보존하는 방향(다른 것을 이 파일로 흡수)이어야 합니다.

    이 정정이 안 바꾸는 것

    CLAUDE.md 의 잡 수준 게이트 규정은 그대로이므로, 워크플로가 셋인 한 검출 잡도 셋이라는 구조는 유효합니다. 큐 슬롯 지출도 그대로입니다. 바뀐 것은 어느 쪽이 소유자 조치를 필요로 하는가이고, 이제 (A)는 필요 없습니다.

    🤖 Generated with Claude Code

  2. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Progress link, 2026-09-13: #2147 removes one of the three Detect changed scope runner boots — sast-semgrep.yml's gate is folded into its single consumer semgrep as a step-level guard (classifier runs after harden-runner, the four expensive steps and the final enforce step gate on steps.scope.outputs.code). The job keeps if: github.event.action != 'closed' with no needs. term, so a doc-only PR still gets one job that concludes success; the enforce step needed its own guard because a step-skipped Run Semgrep leaves rc empty ('' != '0'). Measurement basis is #1904's table (security-scan has 4 consumers → keep; sast-semgrep and strix have 1 → overhead).

    Remaining after #2147: strix.yml (1 consumer, same shape) — deliberately not touched yet because it is a multi-PR hot file; security-scan.yml's gate stays (amortized across 4 gated jobs). Net when both single-consumer folds land: 3 → 1 Detect changed scope boots per PR.

  3. seonghobae commented on Sep 14, 2026

    @seonghobae
    ContributorAuthor

    Progress: #2147 merged to main as 7f0702938 (2026-09-14 01:03Z) — sast-semgrep.yml no longer boots a separate changed-scope runner; the classifier is a step inside the semgrep job. Remaining: the same fold in strix.yml (hot file, 40+ open PRs touching it) and security-scan.yml. Detect changed scope is not a required context on main, so removing the job from a workflow does not strand branch protection.

  4. seonghobae commented on Sep 14, 2026

    @seonghobae
    ContributorAuthor

    Landed: #2147 merged 2026-09-14 01:03Z (main ≥ 7f07029). sast-semgrep.yml no longer boots a Detect changed scope runner; the classifier runs as a step inside semgrep. Remaining from the measured three: strix.yml (single consumer, same fold shape; still a multi-PR hot file) and security-scan.yml (four consumers, amortized — keep). Net so far: 3 → 2 gate boots per PR org-wide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions