Repository navigation
[Fix] 전국 후보 갱신이 멈춘 원장 쓰기 자동화를 PT2H까지만 기다리고 스케줄러 App dispatch로 깨울 수 있게 수정 - #1035
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
보호 admission의 topology snapshot이 원장에 등록되기 전에 후보를 만들면 후보의 capitalTopologyAdmission(옛 reverification)이 inventory admission과 어긋나 PR CI의 후보 build 테스트가 실패하고, 그 후보 PR이 열려 있는 동안 후보 갱신이 막힌다. Refs #870
AquilaXk
left a comment
There was a problem hiding this comment.
Actionable comments posted: 2
🎯 Linked issue & acceptance criteria audit
- Linked issue: #1032 Candidate refresh waits indefinitely on stuck ledger writers and scheduler wake
- Goal summary: Cap the writer wait, wait for topology registration, let the App wake refresh.
- Acceptance criteria verified: 4/4
| ID | Acceptance criterion | Status | Evidence |
|---|---|---|---|
| AC-1 | Writers open longer than PT2H are not waited for and are reported | PASS | tools/ci/automation-pr-state.mjs:121 |
| AC-2 | Unregistered topology admission blocks the candidate as pending registration | PASS | tools/ci/decide-nationwide-candidate-refresh.mjs:90 |
| AC-3 | The scheduler App may wake the refresh by workflow_dispatch without inputs | PASS | .github/workflows/nationwide-candidate-refresh.yml:41 |
| AC-4 | Scheduled role only for schedule or an App dispatch with actor binding | PASS | tools/datapack/lib/scheduled-release-authority.mjs:129 |
🛡️ Adversarial audit evidence
- Falsifiability verified: Yes (Actor, role, and age-cap mutants, including the equal-age boundary, were killed.)
- Hollow assertions detected: 0
- Production backdoors detected: 0
- Ground-truth sources verified:
Issue 1032 criteria and the external scheduler heartbeat dispatcher loginRun record fields actor and triggering_actor checked by the release candidate gate
🤖 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:
- `@tools/ci/decide-nationwide-candidate-refresh.mjs:90-93`
Could the notice or the owning workflow report state how long a registration
may stay pending before a person is alerted, so the wait stays visible?
- `@tools/ci/plan-datapack-release-chain.mjs:51-51`
Could the workflow also pass github.actor so the plan and decision require both
values to equal the App, matching the later run record check?
---
Outside diff comments:
None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: aquila-review SKILL.md, repository CLAUDE.md, and PR 1035 and issue 1032 text
Review profile: ASSERTIVE
Plan: Aquila fallback
Run ID: N/A (Aquila fallback)
Review source: Aquila CLI
Repository visibility: public GitHub repository
Trigger:
Discovery review requested for the current change set of PR 1035
Base:
main@7aace42175f995bab8acff4e30a9fa7376add9d8
Head:
fix/candidate-refresh-stuck-writer-dispatch-1032@01cc22ffe90b846a789eb225460c75ad07b8b968
Command:
node aquila-review/scripts/compile-review-payload.mjs input.json --output payload-1.json
📥 Commits
Reviewing files changed in this pull request between:
- Base:
7aace42175f995bab8acff4e30a9fa7376add9d8 - Head:
01cc22ffe90b846a789eb225460c75ad07b8b968
📒 Files selected for processing (7)
.github/workflows/nationwide-candidate-refresh.ymltools/ci/automation-pr-state.mjstools/ci/decide-nationwide-candidate-refresh.mjstools/ci/ledger-writers-idle.mjstools/ci/plan-datapack-release-chain.mjstools/datapack/lib/scheduled-release-authority.mjstools/datapack/schema/release-request.schema.json
📜 Review details
|
No description provided. |
|
No description provided. |
|



Related issue
Closes #1032
Refs #870
Summary
Data Pack Release가 2026-10-07T19:15Z부터release-pin-drift((a)(b)(d)(e))로 매번 실패했다. 후보 갱신 판정은 입력 변경을 정확히 감지했지만(run 37678888180:BLOCKED_BY_PENDING_PR, stalePathssource-snapshots.json·source-inventory.json) 원장 쓰기 자동화가 열려 있는 동안 기다리고 그 기다림에 상한이 없었다. 기다리게 한 대상이 스스로 멈춰 있었다: 서울 claimautomation/639-…-37673242104(게시 뒤 Finalize 게이트 오류로 PR 없이 남아CLAIM_ORPHAN_PUBLISHED_UNREGISTERED사람 확인 대기), 광주 PR Refresh retained Gwangju timetable #1019(head가 [Fix] 광주 정기 갱신 head 앞섬에서 깨지던 fixture 롤포워드를 native admission 결속으로 수정 #1023 수정 전이라 CI 빨강, 재생성이 24시간 3회 상한AUTOMATION_PR_RECREATE_LOOP). 또 후보 갱신은 GitHub schedule로만 돌아 6~7시간 간격이었다.workflow_dispatch로 깨울 수 있다.Changes
automation-pr-state.mjs:LEDGER_WRITER_WAIT_LIMIT = "PT2H".pendingLedgerWriters가maxAgeMs·now·branchTimes를 받으면 브랜치 마지막 커밋이 상한보다 오래된 PR·claim을expired로 알리고 기다리지 않는다(상한과 같은 나이는 기다림, 나이 미상·미래 시각은 기다림, 잘못된 시각은 실패, 상한을 안 주면 기존 동작과 출력 동일).branchCommitTimes는 로컬origin/*ref의 committer date를 UTC로 읽는다.decide-nationwide-candidate-refresh.mjs: 위 상한을 적용하고 무시한 대상을expiredBlockers·expired_blockers출력으로 남긴다.--actor를 받아 스케줄러 App의 dispatch는 schedule과 같이 CURRENT에서 아무것도 하지 않는다(FORCED 아님).decide-nationwide-candidate-refresh.mjs·decide-capital-topology-registration.mjs: STALE이고 기다릴 원장 쓰기 자동화가 없어도 보호 admission(inventory)의 수도권 topology snapshot이 원장에 등록되지 않았으면BLOCKED_BY_PENDING_REGISTRATION으로 후보를 만들지 않는다(capitalTopologyRegistrationState). 등록 전 후보는 후보 spec의capitalTopologyAdmission(옛 reverification,20261005)이 inventory admission(20261007)과 어긋나 PR CI의candidate build spec release identity테스트가 실패하고, 그 후보 PR이 열려 있는 동안 후보 갱신이 막힌다(재결속 PR [Data] 파생 산출물을 현재 원천 head에 다시 결속 #1037 head에서 후보를 모의 재생성해 확인).ledger-writers-idle.mjs:--max-age로 push 직전 재확인에도 같은 규칙을 쓴다(후보 갱신 workflow만 사용, 다른 workflow 호출은 변경 없음).nationwide-candidate-refresh.yml: dispatch 입력을 선택으로, job 게이트를(사람 dispatch) || DATAPACK_SCHEDULED_CANDIDATE_REFRESH == 'true'로, 판정·plan에ACTOR: github.triggering_actor전달, 멈춘 대상 경고 step 추가.scheduled-release-authority.mjs·plan-datapack-release-chain.mjs·release-request.schema.json: 정기 역할은schedule또는 스케줄러 App(easysubway-release-chain[bot])이 시작한workflow_dispatch에서만 인정. dispatch run의gateRun에actor를 결속하고 GitHub run 기록의actor·triggering_actor가 둘 다 그 App이어야 통과(사람이 재실행하면 거부). App은 사람 역할(2인 승인)을 입력으로 요청할 수 없고, 사람은 정기 역할을 입력으로 넣을 수 없다.automation-pr-recreate주석 정정, 입력 선택화에 맞춘 workflow 계약 테스트 갱신.Scope
Included
Excluded
easysubway-platformplatform-data-workflow-scheduler-contract.json의excluded→workflows이동)과 heartbeat 정책(external-scheduler-heartbeat.json) 등록: platform 배포가 선행돼야 하므로 별도 PROwnership / dependencies
Contract & Compatibility
release-request.schema.json의gateRun에 선택 속성actor추가(workflow_dispatchrun에서만 필수, 코드가 강제). 외부 API 사용 없음(카탈로그 대조 대상 아님).gateRun(eventschedule)은 그대로 유효.--actor·--max-age를 주지 않으면 이전 동작과 출력이 같다. 사람 dispatch는 항상 돌고 2인 역할 입력 검증은 plan이 계속 한다(빈 입력은 실패).Version impact
Product gate impact
Provenance impact
Version decision
Verification
node --test tools/ci/ledger-writers-idle.test.mjs→SyntaxError: ... does not provide an export named 'LEDGER_WRITER_WAIT_LIMIT',tools/datapack/lib/scheduled-release-authority.test.mjs→... 'SCHEDULER_APP_LOGIN', decide·plan·workflow 계약 테스트 다수 실패. GREEN(구현 후): ledger-writers-idle 8/8, decide-nationwide-candidate-refresh 14/14, scheduled-release-authority 11/11, plan-datapack-release-chain 24/24, nationwide-candidate-refresh-workflow 15/15node --test --test-concurrency=1로 영향 파일 + workflow 열거 테스트 19개 파일 303/303 통과(automation-pr-policy·recreate·list-bounded, build/refresh-nationwide-candidate, verify-release-request-binding, scheduler heartbeat·gate 등).actionlint오류 없음{"state":"BLOCKED_BY_PENDING_PR",…,"blockedBy":[1030,1031]}(둘 다 생성 15분 이내라 상한 안에서 기다림, 상한 규칙의 비회귀 확인). 후보 갱신 도구를 파생 재결속 PR head(#1033 d1b0d2c)에서 로컬로 돌리면(OCI 발행만 건너뜀)release-pin-drift(a)(b)(d)(e)가 모두 통과, main 그대로에서는 4건 모두 실패. 같은 모의에서 등록 전 후보는candidate build spec release identity가capital current topology admission identity mismatch로 실패해 등록 대기를 추가했다. 등록 대기 판정은 현재 main에서{"state":"BLOCKED_BY_PENDING_REGISTRATION",…,"registrationSnapshotId":"capital-route-topology-20261007"}를 출력한다workflow_dispatch에 정기 역할 입력 거부, App의 사람 역할 요청 거부, 재실행(triggering_actor≠App) 거부,actor없는 dispatch gateRun 거부를 각각 테스트로 고정.GITHUB_TRIGGERING_ACTOR는 Actions 컨텍스트 값이며 입력이 아니다Not run
deterministic-release클래스 전체와refresh-nationwide-candidate실제 OCI 발행apps/mobile외부 fixture와 OCI PAR 시크릿이 로컬에 없다(EXTERNAL_FIXTURE_MISSING). full regression은 CI에 위임Risk
Rollout / Recovery
expired_blockers출력·경고, 후보 PR 생성, RCValidate ITX-청춘 coverage contractgreenactor는 dispatch run에서만 생긴다).gateRun.actor포함)가 main에 들어온 뒤 revert하면 그 후보의 gateRun 형식을 거부하므로 그 후보는 schedule run으로 다시 만들어야 한다.Review focus
releaseRoleEventViolations·gateRunViolations·gateRunRecordViolations의 행위자 결속이 사람 승인 우회를 막는지pendingLedgerWriters의 상한 경계(같은 나이=대기, 나이 미상=대기)와branchCommitTimes가 실제 checkout의refs/remotes/origin/*를 읽는지Checklist