Skip to content

[Fix] 원천 갱신 workflow 실패를 이슈로 드러내고 광주 보관 시간표 갱신에 수동 실행 경로 추가 - #926

Merged
AquilaXk merged 10 commits into
mainfrom
fix/refresh-failure-issue-860
Oct 4, 2026
Merged

AquilaXk merged 10 commits into
mainfrom
fix/refresh-failure-issue-860

Conversation

@AquilaXk

@AquilaXk AquilaXk commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Related issue

Refs #860
Refs #870

Summary

  • Problem:
    • 원천 갱신 workflow 4개가 2026-09-04~09-20에 2시간마다 실패했다. 실패를 알리는 경로가 없어 2주 넘게 아무도 몰랐고, 결국 수동 비활성화(disabled_manually)됐다.
    • 9/20 마지막 실패 원인(run 로그 기준)
      • current-capital-topology-refresh(run 35508995939): Prepare current ITX collection의 ITX current collection quota guard failed. 그날 첫 ITX 수집이 실패한 뒤 KST 하루 1회 한도 가드가 나머지 run을 모두 막았다. 일부 run은 capital topology transport NETWORK_TIMEOUT(run 35491747180)으로 실패했다.
      • kric-current-facility-refresh(run 35507969487): Recover claimed refresh의 no valid artifacts found to download. 남은 claim을 회수하려면 원래 run의 artifact가 필요한데, 보관 14일이 지나 영구히 회수할 수 없었다.
      • retained-gwangju-timetable-refresh(run 35508796441): retained timetable claim commit is invalid. 형태가 맞지 않는 claim 브랜치가 남아 매번 회수 단계에서 실패했다.
      • seoul-current-accessibility-refresh(run 35508666263): closed Seoul refresh claim requires manual resolution. 닫힌 갱신 PR의 claim 브랜치가 남아 fail-closed로 멈췄다.
    • 공통점은 자동 갱신 PR이 병합되지 않고 claim이 쌓인 것이다. 지금(2026-10-04) automation/* claim 브랜치는 원격에 0개다.
    • retained-gwangju-timetable-refresh에는 schedule만 있다. 그래서 [Fix] 수동 비활성화된 원천 자동 갱신 workflow 5개 복구 #860 완료 조건인 수동 dispatch 검증을 할 수 없다.
  • Outcome:
    • 4개 workflow는 실패하면 workflow별 열린 이슈를 하나 만든다. 다시 실패하면 이슈 본문 상태 블록에 run을 쌓고, 댓글 알림은 하루 한 번만 단다(같은 run은 다시 쓰지 않는다).
    • 광주 보관 KRIC 시간표 갱신을 workflow_dispatch로 실행할 수 있다.

Changes

  • tools/ci/report-refresh-failure.mjs(신규)
    • 대상은 원천 갱신 workflow 4개다. 그 밖의 workflow 이름이 들어오면 GitHub 호출 전에 거부한다.
    • 열린 이슈를 한 번 조회해, github-actions 봇이 만들고 제목이 정확히 [Fix] 원천 자동 갱신 실패: <원천> (<file>)이며 workflow 표지(<!-- easysubway-refresh-failure:<file> -->)가 있는 이슈만 센다(리뷰 F2).
      • 0개: 이슈를 만든다. 본문은 목표·배경(실패 run 링크)·완료 조건·실패 상태 블록과 Refs #860, Refs #870이다.
      • 1개: 이미 보고한 run이면 아무것도 쓰지 않는다. 마지막 알림 뒤 24시간 안이면 본문 상태 블록만 갱신하고, 지났으면 댓글 1개를 단 뒤 상태를 갱신한다(리뷰 F1).
      • 2개 이상: 가장 오래된 이슈에 그대로 기록한 뒤, 이슈 번호와 "하나만 남기고 나머지를 닫으면 정상 보고" 안내를 남기고 REFRESH_FAILURE_REPORT_DUPLICATE_ISSUES로 실패한다(리뷰 F2).
    • gh는 PATH 대신 고정 경로에서 찾고, 그 경로 해석과 실행기를 테스트로 덮는다(리뷰 F3).
    • 이슈 목록 응답이 배열이 아니면 중복 이슈를 만들지 않고 실패한다.
  • 4개 갱신 workflow
    • 권한 블록을 갱신 job 레벨로 옮기고 issues: write를 추가했다. workflow 레벨은 permissions: {}다(리뷰 F4).
    • 마지막 단계로 if: ${{ failure() }} 보고 단계를 추가했다. continue-on-error는 쓰지 않는다.
  • retained-gwangju-timetable-refresh.yml에 입력 없는 workflow_dispatch를 추가했다. 갱신 여부는 기존 decide(CURRENT면 외부 호출 전에 종료)가 그대로 판정한다.
  • tools/ci/data-test-ownership.json에 새 테스트를 등록했다(owner data870).

Scope

Included

  • 실패 이슈 보고, 광주 보관 시간표 dispatch 경로, 계약 테스트

Excluded

  • workflow 재활성화(gh workflow enable): QA 승인 대상이라 메인 세션이 한다.
  • ITX 수집을 topology 갱신에서 분리하는 구조 변경([Refactor] ITX-청춘 시간표 갱신을 데이터 레포 단독 경로로 분리 #857 범위)
  • KRIC 편의시설 claim 회수가 14일 artifact 보관에 묶인 구조. 이번 PR의 실패 이슈로 14일 안에 드러나게만 한다.
  • Slack 알림: data 저장소에 SLACK_RELEASE_WEBHOOK_URL secret이 없다(Data Pack Release run 37109648483 로그 SLACK_RELEASE_WEBHOOK_URL is not configured). secret 설정은 QA 승인 대상이다.

Ownership / dependencies

Contract & Compatibility

  • Source / API / schema contract: 변경 없음
  • Artifact / provenance identity: 변경 없음
  • Backward compatibility: 성공 run에는 보고 단계가 실행되지 않는다(failure()).
  • Migration or cutover: 없음

Version impact

  • no version change
  • datapack release only
  • route-map artifact change
  • data contract change
  • product gate JSON change
  • CI workflow·계약 테스트 change

Product gate impact

  • release/product-gates/** 영향 없음
  • 변경한 gate의 근거를 갱신했습니다.
  • 검증되지 않은 지원 범위 claim을 추가하거나 확대하지 않습니다.

Provenance impact

  • source inventory·geometry provenance manifest 영향 없음
  • 제공처·라이선스·갱신 시점·적용 범위를 갱신했습니다.
  • 공식 source로 확인되지 않은 값을 배포 artifact에 추가하지 않습니다.

Version decision

  • datapack version: 변경 없음
  • data contract: 변경 없음
  • route-map artifact / product gate: 변경 없음
  • promotion request id: 해당 없음

Verification

Check Result / Evidence
Focused RED → GREEN 계약 테스트를 먼저 썼다. 변경 전 workflow에서 current-capital-topology-refresh.yml needs issues: write와 retained workflow_dispatch 정규식 불일치로 2건 실패. 변경 후 node --test tools/ci/report-refresh-failure.test.mjs: 8/8 통과
Affected integration node --test 갱신 workflow 계약·decide·delivery·ITX workflow 테스트 7개 파일: 53/53 통과. actionlint 4개 workflow: 오류 없음. data-test-discovery verify: 통과. anti-cheat guard: PASS
Required CI Data contracts 결과는 PR check에서 확인
Live provider / release Not required — reason: 외부 원천을 호출하지 않는다. 실제 gh issue list(읽기)로 열린 이슈를 조회해 계획만 출력하는 건식 실행을 했다(이슈 생성 없음).
Security / data integrity 새 권한은 issues: write 하나다. 본문에는 run URL만 넣고 경로·secret을 넣지 않는다(테스트로 고정).

Not run

  • Check: 실제 실패 run에서의 이슈 생성
  • Reason: workflow 4개가 disabled_manually이고, 재활성화·dispatch는 QA 승인 뒤 메인 세션이 한다.
  • Rerun owner / condition: 메인 세션이 재활성화 뒤 첫 실패(또는 검증 dispatch) run에서 이슈가 만들어지는지 확인한다.

Risk

  • Level: Medium
  • Main risk: 실패가 이어지면 같은 이슈에 2시간마다 댓글이 쌓인다. 실패를 숨기지 않기 위해 의도한 동작이다.
  • Failure behavior: 보고 단계가 실패해도 job은 이미 실패 상태다. 갱신 결과를 성공으로 바꾸지 않는다.
  • Candidate / admission / publication state on failure: 변경 없음
  • Fallback or degraded-success path introduced: No

Rollout / Recovery

  • Rollout or promotion: 병합 뒤 QA 승인으로 workflow를 다시 켤 때부터 동작한다.
  • Monitoring / success signal: 실패 run마다 [Fix] 원천 자동 갱신 실패: … 이슈 또는 댓글이 생긴다.
  • Rollback or recovery: 이 커밋을 되돌린다.
  • Existing artifact / schema compatibility after rollback: 영향 없음

Review focus

  • 중복 이슈 판정(표지 기준)과 실패 시 동작
  • 보고 단계가 각 workflow 마지막에 있고 failure()에서만 도는지

Checklist

  • 이슈 범위와 실제 diff가 일치합니다.
  • 관련 없는 변경이나 다른 owner의 surface를 포함하지 않았습니다.
  • 위험에 필요한 검증과 미실행 사유를 기록했습니다.
  • 실패·호환성·promotion·recovery 동작이 명확합니다.
  • current failure를 이전·stale·alternate 결과의 성공으로 바꾸지 않습니다.
  • GitHub PR Review 객체가 있는지 확인했습니다. CodeRabbit status check만으로는 리뷰 완료로 보지 않습니다.
  • CodeRabbit Review 객체가 없으면 지원되는 Codex CLI 폴백 Review를 단일 GitHub PR Review로 게시했습니다.
  • datapack 배포 영향이 있는 경우 release workflow 상태를 확인했습니다.

- 원천 갱신 workflow 4개(수도권 topology·KRIC 편의시설·광주 보관 KRIC 시간표·서울 접근성)는
  2026-09-04~09-20 동안 2시간마다 실패했지만 아무도 알림을 받지 못했다(#860).
- 각 workflow 마지막 단계에서 실패 시 report-refresh-failure로 workflow별 열린 이슈를 하나 만들고,
  다시 실패하면 그 이슈에 run 링크를 댓글로 붙인다. 같은 workflow 이슈가 둘 이상이면 고르지 않고 실패한다.
- 광주 보관 KRIC 시간표 갱신은 schedule만 있어 #860 완료 조건의 수동 dispatch 검증을 할 수 없었다.
  workflow_dispatch를 추가한다(입력 없음, 판정은 기존 decide 그대로).
- RED: 새 계약 테스트가 변경 전 workflow에서 issues: write·실패 단계·workflow_dispatch 부재로 실패.

Refs #860
Refs #870
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0c26fe57-af19-42f8-bb37-5f86239a4ee7
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

SonarCloud S4036(PATH 의존 실행)·S6353 지적을 반영한다. tools/route-map/svg-crop/render-svg.mjs의
git 고정 경로 탐색과 같은 방식으로 /usr/bin/gh 등에서만 gh를 찾고, 없으면 REFRESH_FAILURE_REPORT_GH_EXECUTABLE로 실패한다.

Refs #860

@AquilaXk AquilaXk left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🎯 Linked issue & acceptance criteria audit
ID Acceptance criterion Status Evidence
AC-ALERT Repeated failures raise an alert instead of piling up silently PASS tools/ci/report-refresh-failure.mjs
AC-DISPATCH Each workflow can be run once through workflow_dispatch PASS .github/workflows/retained-gwangju-timetable-refresh.yml
🛡️ Adversarial audit evidence
  • Falsifiability verified: Yes (Probe on lines 44 and 46 of the reporter killed mutants by assertion failure.)
  • Hollow assertions detected: 0
  • Production backdoors detected: 0
  • Ground-truth sources verified:
    • gh issue list JSON shape number and body
    • Issue 860 body acceptance criteria
    • ubuntu-latest gh install path /usr/bin/gh
  • Mutation testing evidence: probe lines 44 and 46 killed; line 42 has no supported operator
🤖 Prompt for all review comments with AI agents
Could we verify each finding against the current code and keep only those that
still apply? Could we make the smallest validated fix and briefly note why any
finding no longer applies?

Inline comments:
- `@.github/workflows/seoul-current-accessibility-refresh.yml:8-11`
  Would moving the permissions block under the refresh job match the least-privilege
  intent for later edits?
- `@tools/ci/report-refresh-failure.mjs:39-44`
  Would restricting the match to issues created by the workflow token, or to a
  dedicated label, avoid false duplicates? Alternatively the duplicate error could
  name the issue numbers so the log points to the cleanup.
- `@tools/ci/report-refresh-failure.mjs:46-55`
  Could the comment path skip a run URL that the issue already mentions, and throttle
  to one comment per day, so a long outage stays readable? A test with the same run id
  twice would pin the behavior.
- `@tools/ci/report-refresh-failure.mjs:92-98`
  Could resolveGh accept an injectable existence check so a test can cover the found
  and missing cases, with `GH_EXECUTABLE` asserted for the missing case?

---

Outside diff comments:
None.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Aquila review of easysubway-data PR 926 using CLAUDE.md and the issue 860 body

Review profile: ASSERTIVE

Plan: Aquila fallback

Run ID: N/A (Aquila fallback)

Review source: Aquila CLI

Repository visibility: public GitHub repository

Trigger:
Manual discovery review requested by QA for the draft PR at current head

Base:
main@53f01fc5c4c5d2b7630c2c6dcdb79608200eaa1c

Head:
fix/refresh-failure-issue-860@7731176798f04c0889050eeea7e3648bd659ce7a

Command:
node aquila-review/scripts/post-review.mjs input.json payload-1.json --repo AquilaXk/easysubway-data --pr 926

📥 Commits

Reviewing files changed in this pull request between:

  • Base: 53f01fc5c4c5d2b7630c2c6dcdb79608200eaa1c
  • Head: 7731176798f04c0889050eeea7e3648bd659ce7a
📒 Files selected for processing (4)
  • .github/workflows/retained-gwangju-timetable-refresh.yml
  • .github/workflows/seoul-current-accessibility-refresh.yml
  • tools/ci/report-refresh-failure.mjs
  • tools/ci/report-refresh-failure.test.mjs
📜 Review details

Comment thread .github/workflows/seoul-current-accessibility-refresh.yml Outdated
Comment thread tools/ci/report-refresh-failure.mjs Outdated
Comment thread tools/ci/report-refresh-failure.mjs Outdated
Comment thread tools/ci/report-refresh-failure.mjs
#926 리뷰 F1: 2시간마다 도는 갱신 workflow가 계속 실패하면 같은 이슈에 하루 12개 댓글이 달리고,
같은 run을 재실행하면 같은 링크가 다시 붙었다.
- 이슈 본문에 상태 블록(마지막 보고 시각, 보고한 run 최근 20개)을 둔다.
- 이미 상태 블록이나 댓글에 있는 run은 아무것도 쓰지 않는다(skip).
- 마지막 알림(이슈 생성 또는 알림 댓글) 뒤 24시간 안의 실패는 본문 상태만 갱신한다(status).
- 24시간이 지나면 댓글 1개를 단 뒤 상태를 갱신한다(comment). 댓글을 먼저 달아 본문 갱신이 실패해도 run이 남는다.
- 상태 블록이 없는 열린 이슈는 추정하지 않고 REFRESH_FAILURE_REPORT_STATUS_BLOCK으로 실패한다.
RED: 상수만 둔 상태에서 새 반복 시나리오(3일 2시간 간격 36 run → 이슈 1·댓글 2·상태 33) 등 7건 실패.

Refs #860
#926 리뷰 F2: 표지 문자열만 보고 이슈를 고르면, 사람이 표지를 인용한 이슈 하나로 중복 판정이 나서
이후 모든 보고가 영구히 멈췄다.
- github-actions 봇(gh JSON login app/github-actions)이 만들고 제목이 정확히 같은 열린 이슈만 센다.
- 중복이면 가장 오래된 이슈에 이번 실패를 그대로 기록(상태·하루 1회 댓글)하고, 댓글에 다른 이슈 번호를 적는다.
  그다음 REFRESH_FAILURE_REPORT_DUPLICATE_ISSUES로 이슈 번호와 "하나만 남기고 나머지를 닫으면 정상 보고" 안내를 남기고 실패한다.
RED: 새 테스트 2건(사람이 인용한 이슈 무시, 중복 시 기록 계속과 복구 안내)이 변경 전 코드에서 실패.

Refs #860
#926 리뷰 F3: 모든 테스트가 runGh를 주입해 resolveGh·defaultRunGh가 한 번도 실행되지 않았다.
- resolveGh는 파일 확인 함수를 주입받는다. 후보 목록·순서(/usr/bin/gh 우선)·없음 시 GH_EXECUTABLE 실패를 단언한다.
- defaultRunGh는 실행 파일 해석을 주입받는다. 임시 실행 파일로 인자·stdin 전달과 비정상 종료 시 마지막 stderr 줄을 단언한다.
RED: 새 테스트가 export 부재(GH_CANDIDATES)로 실패.

Refs #860
#926 리뷰 F4: issues write를 workflow 레벨에 두면 나중에 추가되는 job도 그 권한을 물려받는다.
4개 갱신 workflow의 권한 블록을 갱신 job으로 옮기고 workflow 레벨은 permissions: {}로 둔다(권한 집합 자체는 그대로).
RED: 계약 테스트가 "must not grant permissions at workflow level"로 실패.

Refs #860
@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

No description provided.

@sonarqubecloud

sonarqubecloud Bot commented Oct 4, 2026

Copy link
Copy Markdown

AquilaXk added a commit that referenced this pull request Oct 7, 2026
- 삭제할 때마다 ::notice와 GITHUB_STEP_SUMMARY에 branch·producer run·conclusion·분류 reason·보고 action을 남긴다
- #926 보고 본문은 producer run의 conclusion을 그대로 적고 claim 삭제 사실을 포함한다. 이미 기록된 run도 삭제는 comment로 남기고 같은 삭제는 한 번만 기록한다
- remover도 공유 판정의 분류가 여전히 ABANDONED인지 확인한다(게시 step이 시작된 run의 claim은 거부)

Refs #995
AquilaXk added a commit that referenced this pull request Oct 7, 2026
* [Fix] KRIC 전국 시간표 파일 수집이 본문 수신 중 30초 한도로 끊기던 문제 수정 (#995)

연결·헤더 한도(30초)와 본문 수신 한도(5분)를 나누고, 본문 시간 초과는 BODY가 아니라 TIMEOUT으로 드러낸다.
504 run 37399282636이 17.9MB 본문을 받는 중 정확히 30초에 KRIC_TIMETABLE_FILE_BODY로 실패한 원인이다.
재시도·대체는 넣지 않는다(요청은 1회).

Refs #995

* [Fix] PR 없는 claim 브랜치를 소유 workflow가 스스로 복구·정리하도록 하기 (#995)

claim 브랜치(provider 접근 전에 push하는 빈 커밋)가 PR 없이 남으면 소유 workflow가 만든 run과 게시 증거로 판정한다.
- 공유 모듈 claim-orphans: ACTIVE(run 진행 중, 기다림)·RECOVERABLE(출력 커밋 또는 receipt artifact, DUE·CURRENT와 무관하게 복구)·ABANDONED(빈 claim뿐, 보고 후 삭제)
  run 조회는 고아마다 gh run view 한 번, Not Found는 끝난 run, 그 밖의 gh 오류는 fail closed, claim 50개 상한
- remove-orphan-claims: #926 실패 보고를 먼저 하고 지운다. PR이 열려 있거나 닫혀 있거나 run이 진행 중이면 지우지 않고 실패한다. sha lease
- 광주 보관 시간표는 CURRENT에서도 claim을 판정한다(504 사례). 서울 접근성·KRIC 편의시설·수도권 topology 갱신이 같은 판정을 쓴다
- KRIC 복구 artifact는 게시 receipt가 있을 때만 올린다. 등록·재확인 workflow의 정리도 보고 경로를 거친다

Refs #870
Refs #969
Closes #995

* [Fix] SonarCloud 지적 정리: 정렬 비교 함수, 인지 복잡도, top-level await (#995)

- topology 정리 대상 claim 정렬에 비교 함수를 둔다(S2871, 신뢰성 gate 실패 원인)
- 삭제 CLI·수집기·topology 판정의 큰 함수를 나눠 인지 복잡도를 15 이하로 낮춘다(S3776)
- 중첩 삼항 제거(S3358), promise chain 대신 top-level await(S7785)

Refs #995

* [Test] RED: claim 정리가 게시 step까지 갔는지로 판정하도록 하는 테스트 (#995 F1)

게시 여부를 receipt 표지가 아니라 만든 run의 step(게시 step 시작 여부)으로 판정한다.
- 게시 step 이전 실패는 삭제, 게시 step 이후 실패는 삭제하지 않고 CLAIM_ORPHAN_PUBLISHED_UNREGISTERED
- run 기록 없음·step 정보 없음은 빈 claim이라도 실패
- 광주·서울·KRIC 수집/게시 step 분리를 위한 controller phase와 workflow 계약
- KRIC decision.json·journal.json 항상 업로드

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] claim 정리를 receipt 표지가 아니라 게시 step 시작 여부로 판정 (#995 F1)

- 만든 run의 step 기록(gh run view --json jobs)으로 OCI 게시 step이 시작됐는지 판정한다.
  게시 step 이전 실패는 ABANDONED(삭제), 시작된 뒤 출력 커밋·보존 증거가 없으면 CLAIM_ORPHAN_PUBLISHED_UNREGISTERED(삭제하지 않고 실패)
- run 기록 없음(Not Found)·step 정보 없음은 빈 claim이라도 CLAIM_ORPHAN_RUN_UNAVAILABLE·STEPS_UNAVAILABLE로 실패
- 광주·서울·KRIC의 수집과 게시·등록을 서로 다른 step으로 나눈다(controller phase collect/publish, KRIC finalize step)
- KRIC은 decision.json·journal.json을 항상 업로드한다
- 분리 전 step에서 실패한 504 run은 로그로 게시 전 실패가 확인된 명시 표(VERIFIED_PRE_PUBLICATION_RUNS)로만 ABANDONED
- claim-orphans 헤더·emptyClaim 주석을 사실대로 고친다(빈 claim은 게시되지 않았다는 증거가 아니다)

Refs #995

* [Test] RED: 삭제 guard 강화 테스트 (#995 F2)

- lease는 판정 시점(--refs)의 sha, 그 뒤 브랜치가 움직였으면 거부
- push 직전에 빈 claim(ahead_by 1, files 0)과 run 상태를 다시 확인하고 출력이 있는 브랜치는 거부
- 병합된 PR의 잔여 claim은 예외
- 6개 workflow의 정리 step이 판정 시점 ls-remote 파일을 --refs로 넘긴다

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] 삭제 guard 강화: 판정 시점 sha lease와 push 직전 재확인 (#995 F2)

- 삭제 lease는 판정 시점(--refs)의 sha다. 그 뒤 브랜치가 움직였으면 지우지 않는다
- 보고 전과 push 직전에 만든 run이 completed인지, 브랜치가 빈 claim(ahead_by 1, 제목 일치, 변경 파일 0)인지 다시 확인한다
- 출력이 있는 브랜치는 어느 workflow에서 넘겨도 거부한다(등록·재확인 포함). 병합된 PR의 잔여 claim은 예외
- 6개 workflow의 정리 step이 판정 시점 ls-remote 파일을 --refs로 넘긴다

Refs #995

* [Test] RED: 삭제 기록과 보고 본문 테스트 (#995 F3)

- 삭제할 때마다 notice와 step summary에 branch·producer run·conclusion·분류 reason·보고 action
- 보고 본문은 producer run의 conclusion을 그대로 적고 삭제 사실을 포함한다. 이미 기록된 run도 삭제는 comment로 남긴다
- remover도 게시 step이 시작된 run은 거부한다

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] claim 삭제 기록과 보고 본문 보강 (#995 F3)

- 삭제할 때마다 ::notice와 GITHUB_STEP_SUMMARY에 branch·producer run·conclusion·분류 reason·보고 action을 남긴다
- #926 보고 본문은 producer run의 conclusion을 그대로 적고 claim 삭제 사실을 포함한다. 이미 기록된 run도 삭제는 comment로 남기고 같은 삭제는 한 번만 기록한다
- remover도 공유 판정의 분류가 여전히 ABANDONED인지 확인한다(게시 step이 시작된 run의 claim은 거부)

Refs #995

* [Test] RED: KRIC Abandon claim에 PR이 붙으면 실패하는 검사 복원 (#995 F4)

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] KRIC Abandon claim에 PR이 붙으면 실패하는 검사 복원 (#995 F4)

- Abandon 커밋을 쓰는 workflow는 PR이 붙은 claim의 커밋도 증거로 수집하고, 닫은 claim에 PR이 붙으면 상태와 무관하게 이름 있는 이상으로 실패한다
- recover step의 Abandon 경로가 언제 닿는지 주석으로 남긴다

Refs #995

* [Test] RED: 본문 한도 5분의 근거를 상수와 테스트로 고정 (#995 F5)

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] 본문 한도 5분의 근거를 상수로 고정 (#995 F5)

관측한 파일 크기(17,949,564 bytes)를 최소 처리량 60KB/s로 받는 시간을 분 단위로 올림한 값이다. 근거를 상수 주석과 테스트에 남긴다.

Refs #995

* [Fix] SonarCloud 지적 정리: 미사용 변수, 인지 복잡도, 의도적 순차 await (#995)

Refs #995

* [Test] RED: Abandon으로 닫힌 KRIC claim 삭제 허용과 이슈 본문 마커 검사 (#995 F2·F3 잔여)

이 커밋은 의도적으로 실패한다(RED).

Refs #995

* [Fix] Abandon으로 닫힌 KRIC claim 삭제를 허용하고 이슈 본문 마커도 검사 (#995 F2·F3 잔여)

- isClosedOutClaim(abandonedSubject를 쓰는 workflow의 claim 제목 + Abandon 제목 두 커밋, 변경 파일 0)을 판정과 remover가 공유한다. remover는 빈 claim 또는 닫힌 claim만 지우고 재판정이 CLAIM_CLOSED_OUT ABANDONED여야 한다
- 판정의 CLAIM_CLOSED_OUT도 같은 엄격한 조건을 쓴다(내용이 바뀐 Abandon 브랜치는 내용이 있는 브랜치)
- 삭제 기록 마커를 이슈 본문에서도 찾는다(이슈 생성 때 본문에 적은 삭제를 comment로 되풀이하지 않는다)

Refs #995
AquilaXk added a commit that referenced this pull request Oct 7, 2026
* [Chore] 외부 스케줄러 dispatch를 정기 실행과 같은 의미로 맞추고 스케줄러 중단을 실패 이슈로 감시 (#1001)

- 변수 게이트 정기 workflow 4개: App(easysubway-release-chain[bot])의 dispatch는 DATAPACK_SCHEDULED_* 변수를 따른다
- datapack-expiry-alert: dispatch 입력 target으로 점검 job을 고른다
- data-workflow-scheduler-watchdog: App dispatch heartbeat를 점검하고 #926 실패 이슈로 알린다(DATAPACK_SCHEDULER_WATCHDOG 기본 꺼짐)

* [Fix] 리뷰 반영: 사람 allow list 게이트, dispatch target별 heartbeat, 대기열 유지, 식 평가 테스트 (#1001)
AquilaXk added a commit that referenced this pull request Oct 7, 2026
…#870 전체 자동화) (#1014)

* [Test] 정기 갱신 4종 자동 병합 정책의 반증 테스트 추가 (RED)

기록된 실제 갱신 PR(#937 #965 #1003 #1009 #1010 #1011)의 변경 파일·원장 행·inventory 변경 필드를 fixture로 두고
단계별 경로 allowlist·소유 항목·소유 필드·원장 방식, 증거 블록 검증, 게이트 재계산, emitter, recreate redispatch,
workflow 배선을 구현 전에 고정한다. 추가 경로·정책 필드 변경·소유 밖 항목·위조된 head의 반증을 포함한다.

Refs #1012
Refs #969
Refs #870

* [CI] 정기 갱신 4종 PR에 증거 블록을 싣고 자동 병합 정책·게이트 재계산·재생성 경로에 올리기 (GREEN)

- refresh-stage-contracts: 단계별 경로 규칙(added·modified)·소유 inventory 항목과 필드·원장 방식·게이트 재계산(evaluateRefreshStage)의 정본
- automation-pr-evidence: 단계 gwangju-timetable-refresh·capital-topology-refresh·kric-facility-refresh·seoul-accessibility-refresh를 기존 단계 뒤에 더한다
- automation-pr-policy: API diff와 증거 경로의 정확 대조, 파일별 변경 종류, 게이트 재계산을 새 단계에 적용한다
- refresh-automation-pr: workflow가 push 전에 증거 본문을 만들고 어긋나면 push·PR 전에 실패한다
- automation-pr-recreate: 새 단계 4종의 뒤처진 PR을 닫고 같은 workflow를 다시 실행한다
- 4개 workflow의 PR 본문을 증거 블록이 든 본문 파일로 바꾼다(새 PR·복구 경로 모두)

Refs #1012
Refs #969
Refs #870

* [Test] falsifiability probe로 드러난 검사 틈을 닫는 반증 추가 (#1012)

Refs #1012

* [Test] fixture helper가 생산자 신원 규칙을 따르는 topology snapshot과 출처 표식 pack을 합성하도록 (#1012)

리뷰 F1·F2·F4의 반증을 쓰기 위한 선행 정비다. 동작은 바뀌지 않는다.

Refs #1012

* [Test] topology snapshot 신원을 본문에서 다시 계산하는 반증 추가 (#1014 F2, RED)

선언된 contentSha256·lineCount·totalEdgeCount, 본문 간선 변조, 노선 해시, 노선 집합, 직전 snapshot 변조와
등록 workflow의 원본 sha 대조 코드 근거를 구현 전에 고정한다.

Refs #1012

* [CI] topology snapshot 신원을 생산자 검증 함수로 본문에서 다시 계산하고 원본 출처 경계를 계약에 명시 (#1014 F2, GREEN)

requireCurrentSourceSeparatedCapitalTopology로 head와 직전 snapshot의 노선 해시·개수·contentSha256·노선 집합을 다시 계산한다.
원본 응답의 출처는 병합 뒤 등록 workflow가 OCI 원본으로 확인한다(rawSha256 = sha256(topologyBytes), 영수증 rawObjectSha256 대조).

Refs #1012

* [Test] topology 자동 경로가 제거를 허용하지 않고 추가는 2% 이내만 허용하는 반증 추가 (#1014 F4, RED)

간선·역 제거, 같은 수 교체, 같은 노선 치환, 추가·수정 합산 한도, 전용 override 사용 여부를 구현 전에 고정한다.

Refs #1012

* [CI] topology 자동 경로에서 제거를 허용하지 않고 추가·수정은 전용 override 2%까지만 허용 (#1014 F4, GREEN)

- 직전 노선별 역·간선 집합이 새 집합의 부분집합이 아니면 REFRESH_GATE(같은 수로 교체해도 제거로 잡힌다)
- 추가·수정된 간선 합이 capital-route-topology 전용 override(sourceOverrides, maxRowDeltaRatio 0.02)를 넘으면 SOURCE_COUNT_DELTA
- 정책 파일에 전용 override를 더하고 이를 고정하던 기존 테스트 두 곳을 맞춘다

Refs #1012

* [Test] canonical pack을 구조 diff로 비교해 표식 밖 변경을 막는 반증 추가 (#1014 F1, RED)

빈 pack, 접근성 값·정차 시각 변경, 간선 추가·삭제, 배열 순서·길이, 표식 키에 엉뚱한 값, 다른 원천의 표식, 키 구성 변경,
읽기 실패를 구현 전에 고정한다. 대조군은 기록된 갱신처럼 표식만 새 snapshot·증거 시각으로 바뀐 pack이다.

Refs #1012

* [CI] canonical pack을 base·head 구조 diff로 비교해 출처 표식 밖 변경을 PACK_CONTENT로 막기 (#1014 F1, GREEN)

바뀔 수 있는 키는 sourceSnapshotId·updatedAt·lastVerifiedAt·reviewedAt뿐이고 값은 소유 원천의 직전→새 snapshot id, 증거 시각과 정확히 같아야 한다.
그 밖의 키·값·키 구성·배열 길이와 순서가 달라지면 위반이다. 실제 갱신 #936 #952 #965 #1003의 pack diff가 모두 통과한다.

Refs #1012

* [Test] Seoul 입력 파일의 evidenceHash를 새 snapshot에서 다시 계산하는 반증 추가 (#1014 F3, RED)

Refs #1012

* [CI] Seoul 입력 파일의 evidenceHash를 생성 코드의 계산 함수로 새 snapshot에서 다시 계산해 대조 (#1014 F3, GREEN)

materialize-accessibility-source-input의 두 해시 계산을 이름 있는 함수로 내보내 생성 코드와 정책이 같은 구현을 쓴다(동작 불변).
계산 방식을 아는 행 목록(routeEdges, accessibilityStatusEvidence)만 허용한다.

Refs #1012

* [Test] 허용 밖 경로의 실제 동작(push 전 거부)과 계약 주석의 일치를 고정 (#1014 F5, RED)

Refs #1012

* [Docs] 계약 주석을 허용 밖 경로의 실제 동작(push 전 실패, #926 보고)에 맞춘다 (#1014 F5, GREEN)

Refs #1012

* [Test] probe로 드러난 틈(소유 원천 표식 종류, 역만 제거, 해시 방식 모르는 입력 목록) 반증 보강 (#1014)

Refs #1012
This was referenced Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge FIFO 병합 큐 대상 — 코디네이터가 순서대로 update-branch 후 auto-merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant