Skip to content

Queue delay invalidates its own dispatches: base_sha equality fails 12 of 16 validate-pr-metadata runs #1931

Description

@seonghobae

opencode-review-dispatch.yml의 메타데이터 검증이 큐 대기 시간 때문에 실패합니다. 대기가 길수록 실패율이 오르고, 실패가 재시도를 부르고, 재시도가 대기를 늘리는 자기강화 구조입니다.

#1927·#1929(낡은 인가 변수)와 독립된 원인이고, 그쪽을 고쳐도 남습니다. 수정 대상이 설정 값이 아니라 검증 의미론이라 별건으로 올립니다.

측정

opencode-review-dispatch.yml의 실패 run 중 actor=github-actions[bot]인 것(= 인가를 통과하는 신원) 44건 전수를 의존 순서로 재분류했습니다. 스텝을 run 간에 합산하면 하류 캐스케이드가 중복 계산되므로, validate-pr-metadata → coverage-source-tree → coverage-evidence → opencode-review에서 처음 실패한 job을 근본 원인으로 잡았습니다.

16  validate-pr-metadata | Bind workflow inputs...        36%
14  coverage-evidence    | Measure test and docstring     32%   ← #1883 이 해소
 6  opencode-review      | Wake exact-head required...    14%
 8  나머지 (각 1~2건)

최대 원인 16건을 ##[endgroup] 이후의 실행 출력만 읽어 다시 갈랐습니다. 그 앞은 스크립트 소스 에코라 모든 에러 문구를 포함하고 있어서 어떤 가설이든 확증됩니다.

9  repository_dispatch metadata does not match the live pull request: base_sha
3  rejected closed, missing, or malformed live metadata   (state=closed)
4  repository_dispatch authorization rejected             (#1927/#1929)

12/16이 큐 지연의 결과입니다.

실제 로그

Authorized repository_dispatch actor=github-actions[bot] sender=github-actions[bot]   ← 인가 통과
##[error]... does not match the live pull request: base_sha.
  supplied_base=main/76969152...   live_base=main/5d55a31e...
  supplied_head=...fd964d24        live_head=...fd964d24                              ← head 는 일치

head는 맞고 base만 어긋납니다. 디스패치는 보낸 시점의 base SHA를 싣는데, 큐에서 기다리는 동안 main이 전진합니다. state=closed 3건도 검증 도달 시점에 PR이 이미 닫힌 것이라 같은 기전입니다.

드리프트가 사실상 확정적입니다

오늘 origin/main의 시간당 커밋 수입니다.

09시 2 · 10시 2 · 11시 6 · 13시 5 · 14시 6 · 17시 11 · 18시 3 · 19시 1

그리고 실측된 완주 실행 하나가 **총 15시간 37분, 그중 실제 계산 약 73초(대기 99.87%)**였습니다. 시간당 1~11회 움직이는 브랜치에서 15시간을 기다리면 base가 안 움직일 확률은 사실상 0입니다.

핵심: 이 검사는 데이터 의존이 아니라 staleness 정책입니다

opencode-review-dispatch.yml의 실제 데이터 경로입니다.

:186  검증   [ "$SUPPLIED_BASE_SHA" = "$live_base_sha" ] || mismatches+=("base_sha")   ← 불일치면 exit 1
:199  출력   printf 'base_sha=%s\n' "$live_base_sha"                                    ← live 를 내보냄
:295  소비   PR_BASE_SHA: ${{ needs.validate-pr-metadata.outputs.base_sha }}
:332         git -C "$fetch_dir" checkout --detach "$PR_BASE_SHA"

SUPPLIED_BASE_SHA는 비교에만 쓰이고 버려집니다. 하류가 실제로 체크아웃하는 값은 live_base_sha입니다. 즉 supplied와 live가 달라도 파이프라인은 live로 정상 동작합니다.

동등성 요구가 지키는 것은 "디스패치 시점과 검증 시점 사이에 base가 안 움직였다"는 보장이고, 현재 조건에서 그 보장은 거의 항상 거짓입니다.

head_sha는 다릅니다. :188에서 같은 방식으로 비교하지만, 그건 "이 리뷰가 디스패치된 바로 그 커밋을 대상으로 한다"는 exact-head 규율의 근간입니다. head는 엄격히 유지되어야 합니다.

판단이 필요한 지점

base_sha 동등성을 푸는 것이 기술적으로 안전하다는 것까지가 측정으로 말할 수 있는 전부입니다. 남는 질문은 설계입니다.

  • base 드리프트를 허용하면 coverage가 디스패치 당시와 다른 base에서 측정됩니다. 그 차이가 판정에 영향을 주는지는 이 리포의 커버리지 계약이 정할 문제입니다.
  • 대안으로 허용 범위(예: live base가 supplied base의 후손이면 통과)를 두면 보장을 완전히 버리지 않고 드리프트를 흡수할 수 있습니다.

어느 쪽이든 신뢰 경계에 관한 결정이라 근거만 올립니다.

재현

R=repos/ContextualWisdomLab/.github/actions
gh api "$R/workflows/opencode-review-dispatch.yml/runs?status=failure&per_page=100" \
  --jq '.workflow_runs[] | select(.actor.login=="github-actions[bot]") | .id'
# 각 run 에 대해 validate-pr-metadata job 의 로그에서 ##[endgroup] 이후만 읽을 것.
# 그 앞은 스크립트 소스 에코이며 모든 에러 문구를 포함한다.

관련: #1927, #1929, #1925, #1883

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions