Repository navigation
[CI] ITX-청춘 원천 승격을 QA 승인 코멘트 없이 자동 이상 판정 게이트로 전환 (#870 3단계) - #978
Conversation
- --auto-gate: 승인 코멘트 없이 게이트를 같은 입력으로 다시 계산해 PASS일 때만 승격하고 영수증을 원천 옆에 남긴다. - 승인 코멘트와 게이트를 함께 받으면 어느 쪽도 쓰지 않는다. - build-datapack·apply-itx-topology·build-server-timetable-snapshot이 같은 판정 함수를 쓴다. Refs #977
- decide-itx-current-promotion: 공급자 호출 전에 EXPIRED·SAFETY_LEAD·BEST_DAY로 수집 여부를 정하고 일정 시뮬레이션으로 끊김 없음을 고정한다. - automation-pr-evidence: 단계 itx-promotion(원천 행 하나, 허용 경로 네 개)과 본문 생성. - 등록부: 실패 보고, claim 접두어, 직렬화 그룹, KST 하루 한 번 공급자 호출 예산. Refs #977
…기 실행은 변수로 꺼짐) Refs #977
|
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 |
AquilaXk
left a comment
There was a problem hiding this comment.
Actionable comments posted: 6
🎯 Linked issue & acceptance criteria audit
- Linked issue: #977 ITX promotion automatic anomaly gate
- Goal summary: Replace the QA approval comment with an automatic gate and a dormant App PR.
- Acceptance criteria verified: 6/6
| ID | Acceptance criterion | Status | Evidence |
|---|---|---|---|
| C1 | gate judges coverage, trips, first and last times, binding and fetch errors | PASS | tools/datapack/itx-promotion-gate.mjs |
| C2 | history replay and boundary tests | PASS | tools/datapack/itx-promotion-gate.test.mjs |
| C3 | promotion recomputes the gate and consumers verify the new mode | PASS | tools/datapack/lib/itx-promotion-authority.mjs |
| C4 | decision before provider call and schedule simulation | PASS | tools/ci/decide-itx-current-promotion.mjs |
| C5 | dormant workflow with App token PR and evidence block | PASS | .github/workflows/itx-current-promotion.yml |
| C6 | required CI green on this pull request | PASS | tools/ci/itx-current-promotion-workflow.test.mjs |
🛡️ Adversarial audit evidence
- Falsifiability verified: Yes (Probed 7 gate comparisons and 2 authority checks; all mutants turned tests RED)
- Hollow assertions detected: 0
- Production backdoors detected: 0
- Ground-truth sources verified:
decide-itx-current-promotion 364-day simulation reproduced locally with 0 gap days and 156 collectionstools/datapack/itx-promotion-gate-policy.json measuredBasis versus gate tests
🤖 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/itx-current-promotion.yml:79-95`
Could a follow-up issue for rebinding be linked in the PR body and the issue
before merge, with the variable documented as blocked until it closes? Would a
contract test asserting the variable stays unset help?
- `@.github/workflows/itx-current-promotion.yml:186-187`
Could the `printf` into `GITHUB_ENV` move above `git push`, given that the
cleanup step exits cleanly when the remote branch is absent?
- `@tools/ci/guard-itx-current-collection-budget.mjs:21-27`
Should `decide-itx-current-promotion` report a WAIT state when the topology
workflow already entered its collector today, or should the guard failure be
classified as a non-anomaly skip? A test using two workflow contexts on the same
KST day could pin the chosen behavior.
- `@tools/datapack/itx-promotion-gate-policy.json:14-18`
Would setting `tripCountDeltaPermille` and `tripMembershipDeltaPermille` to 0 be
preferable, with the boundary tests following? Should the tuple limits move to 0
as well, since stable history shows 0?
- `@tools/datapack/itx-promotion-gate-policy.json:19-20`
Could the limits be set to the measured values (0 and 240) and the boundary
tests updated accordingly?
- `@tools/datapack/lib/itx-promotion-authority.mjs:80-80`
Should `verifyItxGatePromotion` read the committed policy file, require byte or
deep equality with `receipt.policy`, and fail otherwise? Could `build-datapack`
and the other consumers call it, and a RED test cover a receipt with widened
limits and a rebound sha?
---
Outside diff comments:
None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: CLAUDE.md, ~/.claude/CLAUDE.md, PR template full.md, linked issue 977 body
Review profile: ASSERTIVE
Plan: Aquila fallback
Run ID: N/A (Aquila fallback)
Review source: Aquila CLI
Repository visibility: public GitHub repository
Trigger:
Discovery review of the self-authored PR on its current head.
Base:
main@ea111a98073a784116975d4636bfb23cbf4d158c
Head:
ci/itx-auto-promotion-977@e26d5f98f0eb288db4a8c5e6644b8c7d4e5c9947
Command:
aquila-review discovery PR 978
📥 Commits
Reviewing files changed in this pull request between:
- Base:
ea111a98073a784116975d4636bfb23cbf4d158c - Head:
e26d5f98f0eb288db4a8c5e6644b8c7d4e5c9947
📒 Files selected for processing (5)
.github/workflows/itx-current-promotion.ymltools/ci/guard-itx-current-collection-budget.mjstools/datapack/itx-promotion-gate-policy.jsontools/datapack/itx-promotion-gate.mjstools/datapack/lib/itx-promotion-authority.mjs
📜 Review details
- 한도는 이력 안정 구간의 관측값(0)이다. 직전 승인본 대비만 보면 매번 조금씩 빠지는 drift를 놓친다. - 기준선 = 마지막 owner 승인 원천. 게이트 승격이 baselineArtifactPath/Sha256으로 이어받고 BASELINE_* check를 영수증에 남긴다. Refs #977
- verifyItxGatePromotion: 영수증의 policy를 쓰지 않고 커밋된 itx-promotion-gate-policy.json과 같아야 한다. 지표(직전·기준선 대비)와 커밋된 완전성 증거로 계산하는 결속·수집 오류 check(COMMITTED_*)를 원천 파일에서 다시 계산해 대조한다. - raw capture·replay에 의존하는 SOURCE_BINDING·FETCH_ERRORS는 저장소에 raw가 없어 재계산할 수 없다. 영수증의 PASS와 raw sha 형식만 본다(원장 대조는 ITX 원천이 원장에 없어 후속 이슈). - build-datapack·apply-itx-topology·build-server-timetable-snapshot·activate-current-source-set이 verifyCurrentItxPromotion을 호출한다. Refs #977
…료 (F4) - guard에 probe(--probe)를 더해 공급자 호출 전에 같은 KST 날의 수집 여부를 실패 없이 읽는다. - 승격 판정: WAIT(ITX_COLLECTED_TODAY). topology 갱신 판정: WAIT_ITX_COLLECTED_TODAY(ITX 수집이 필요한 DUE·EXPIRED·REUSE_CLAIM에서만). - 두 workflow가 같은 날 겹치는 경우를 양방향으로 테스트한다. Refs #977
|
|
No description provided. |



Related issue
Closes #977
Refs #870
Refs #969
Refs #636
Refs #979
Summary
/approve-itx-current artifactId=<id> sha256=<sha> policy=itx-snapshot-anomaly-v1)를 단 뒤에만--promote-candidate가 쓴다. 승격을 실행하는 workflow는 없고 수집 workflow는 dispatch 전용이다. 현행 정책itx-snapshot-anomaly-v1은ZERO_TOLERANCE라 이력 10개 중 4개 구간이 사람 승인을 받았다.itx-promotion-gate-v1)가 통과시킨 수집분만 App 토큰 PR로 승격한다. 게이트가 막으면 승격하지 않고 job이 실패해 [Fix] 원천 갱신 workflow 실패를 이슈로 드러내고 광주 보관 시간표 갱신에 수동 실행 경로 추가 #926 경로로 실패 이슈가 열리거나 갱신된다. 수동 승인 경로는 override로 그대로 있다. 정기 실행은 저장소 변수DATAPACK_SCHEDULED_ITX_PROMOTION이true일 때만 돌고 기본은 꺼짐이다.Changes
tools/datapack/itx-promotion-gate.mjs,itx-promotion-gate-policy.json: 요일별 지표 게이트(역·OD 커버리지, 편수, 열차 구성, 정차 순서, 시각 tuple 제거·추가, 첫차·막차 이동)와 원천 결속(raw capture sha·후보 sha·직전 snapshot·오프라인 replay 계보)·수집 오류 판정. 순수 함수이고 실행 파일은 PASS 0, BLOCK 3, 오류 1로 끝난다.collect-korail-itx-cheongchun-timetable.mjs:--auto-gate --provider-capture --replay-evidence. 영수증을 믿지 않고 같은 입력으로 게이트를 다시 계산해 PASS일 때만 원천·완전성 증거·게이트 영수증을 쓰고 contract를 갱신한다. 승인 코멘트와 게이트를 함께 받으면 어느 쪽도 쓰지 않는다.lib/itx-promotion-authority.mjs: 승격 모드CURRENT_CANDIDATE_GATE_PASSED의 구조 검증과, 커밋된 영수증을 두 원천 파일에서 다시 계산해 대조하는 재검증.build-datapack·apply-itx-topology-to-bundled-pack·build-server-timetable-snapshot이 같은 판정 함수를 쓴다(승인 모드와 같은 강도).tools/ci/decide-itx-current-promotion.mjs: 공급자 호출 전에COLLECT·WAIT·OPEN_PR·BLOCKED_BY_PENDING_PR를 정한다..github/workflows/itx-current-promotion.yml: 판정 -> 예산 가드 -> 수집 -> 오프라인 replay -> 게이트 -> 승격 -> 허용 경로 네 개만 스테이징 -> push -> App 토큰 Draft PR.force_collectdispatch 입력을 둔다.automation-pr-evidence.mjs: 증거 블록 단계itx-promotion(원천 행 하나, 허용 경로 네 개)과itx-promotion-body.current-capital-topology-refresh.yml: 판정 전에 probe를 읽고--itx-collected-today를 넘기는 두 줄과 대기 notice step만 더했다. 다른 step 조건은 그대로다.report-refresh-failure([Fix] 원천 갱신 workflow 실패를 이슈로 드러내고 광주 보관 시간표 갱신에 수동 실행 경로 추가 #926),refresh-open-pr-age(claim 접두어automation/977-itx-promotion-, 직렬화 그룹),guard-itx-current-collection-budget(KST 하루 한 번 예산 공유),data-test-ownership, 문서 파편.Scope
Included
Excluded
provider:korail-traveler-train-run-plan·run-info·tago-train-schedule-fares만 쓴다)ADMITTED_TOPOLOGY_INPUTS, mobile fixture 고정값)과 raw capture 원장 대조 자동화: 후속 이슈 [CI] ITX 승격 뒤 파생 재결속(literal 테스트·topology 입력 허용 목록·증거와 팩·mobile fixture 재핀)과 raw capture 원장 대조 자동화 (#870 3단계 후속) #979. 아래 Risk 참고.itx-current-collection.yml의 동작Ownership / dependencies
Contract & Compatibility
node tools/ci/api-catalog.mjs list --query korail)와source-candidates.json의 기존 id만 쓴다.sourceTimetableArtifact.promotion에 모드CURRENT_CANDIDATE_GATE_PASSED가 추가된다(키:gate{policyId,receiptPath,receiptSha256},gatedArtifactSha256,previousArtifactPath,previousArtifactSha256). 영수증은tools/datapack/sources/<artifactId>-promotion-gate.json. 현재 contract 값은 바뀌지 않는다.CURRENT_CANDIDATE_OWNER_APPROVED경로와 값은 그대로다(기존 테스트 전부 통과).Version impact
Product gate impact
Provenance impact
Version decision
게이트 한도와 측정 근거
비교 단위는
itx-snapshot-anomaly-v1과 같다(역·OD·열차·정차 순서·시각 tuple, 요일 유형별). 한도는 승인된 이력 snapshot 10개(전환 9회: 안정 5, 변동 4)에서 잰 관측 최대값이고,tools/datapack/itx-promotion-gate.test.mjs가 이력에서 다시 계산해 정책 파일의measuredBasis와 대조한다. 리뷰 F2·F3에 따라 근거 없는 여유(5%, 300초)를 모두 없앴다.baselineArtifactPath/Sha256으로 이어받고, 같은 한도를 기준선 대비로도 적용한BASELINE_*check를 영수증에 남긴다. 기준선이 직전 원천이면(승인 승격 바로 다음) 추가 check는 없다.build-datapack,apply-itx-topology-to-bundled-pack,build-server-timetable-snapshot,activate-current-source-set)가verifyItxGatePromotion을 부른다. 영수증에 적힌 정책을 쓰지 않고 커밋된itx-promotion-gate-policy.json과 같은지 강제하며, 지표(직전·기준선 대비)와 커밋된 완전성 증거로 계산하는 결속·수집 오류 check를 원천 파일에서 다시 계산해 대조한다. raw capture·replay에 의존하는SOURCE_BINDING·FETCH_ERRORS는 raw가 저장소에 없어 영수증의 PASS와 raw sha 형식만 본다. raw sha를 원천 원장과 대조하려면 ITX raw capture가 원장에 등록돼야 하는데 현재 원장에 ITX 원천이 없다. 이는 [CI] ITX 승격 뒤 파생 재결속(literal 테스트·topology 입력 허용 목록·증거와 팩·mobile fixture 재핀)과 raw capture 원장 대조 자동화 (#870 3단계 후속) #979 범위다.수집 일정
신선도 규칙(첫 평일·토·일 운행일 중 가장 늦은 날의 다음 날 00:00 KST)에서 계산한 수집 요일별 확보 기간: 일·월 7일, 화 6일, 수 5일, 목 4일, 금·토 3일(공휴일은 더 늘릴 뿐이다). 최대 7일이라 주 1회 수집은 매주 몇 시간 끊긴다.
0 18 * * *)에 실행하고, 공급자 호출 전 판정이 필요한 날에만 수집한다. 이유는 셋이다:EXPIRED(이미 만료),SAFETY_LEAD(만료 2일 이하: 그날 실패해도 하루 재시도 여유가 남는다),BEST_DAY(7일 확보일이고 만료를 3일 이상 늘린다). 사람 dispatch의force_collect는FORCED.SAFETY_LEAD), 끊긴 날 0일. 어느 한 번의 수집이 실패해도(앞 40회 각각) 다음 날 재시도로 끊기지 않고, 연속 실패가 이어지면 끊긴다.guard-itx-current-collection-budget에 등록). 같은 날 다른 workflow가 이미 수집했다면(F4) 판정 단계가--probe로 이를 읽어 승격은WAIT(ITX_COLLECTED_TODAY), topology 갱신은WAIT_ITX_COLLECTED_TODAY로 정상 종료한다(가드 실패 이슈를 만들지 않는다). 양방향 겹침을 테스트로 고정했다.Verification
fcf56eaef(모듈 없음으로 전체 실패) -> GREENd5f92d4eb(24개 통과). 승격 경로·소비자·판정·증거 단계·workflow 계약은 구현 전 로컬에서 실패(RED)를 확인한 뒤 같은 커밋에 구현했다.node --test tools/ci/*.test.mjs397 pass / 0 fail.apply-itx-topology-to-bundled-pack78,build-datapack-current-admission22,build-server-timetable-snapshot23,itx-cheongchun-coverage-contract10, 게이트 24, 승격 권한 10 pass. 공식 Node 24.19.0(SQLite 3.53.3)로 실행.f5bdab846:Data contracts(mobile-v19, shard 1~4 포함)·CodeQL·SonarCloud 모두 SUCCESS. https://github.com/AquilaXk/easysubway-data/actions/runs/37422124765git add는 경로 네 개를 명시한다.Not run
datapack-tools.test.mjs(524초)datapack-tools는 CI shard가 돈다.workflow_dispatch로 한 번 실행(변수는 꺼진 채). 변수는 [CI] ITX 승격 뒤 파생 재결속(literal 테스트·topology 입력 허용 목록·증거와 팩·mobile fixture 재핀)과 raw capture 원장 대조 자동화 (#870 3단계 후속) #979 병합 뒤 QA 보고 후에만 켠다.collect-korail-itx-cheongchun-timetable.test.mjs는origin/main그대로도 25개가 실패한다(OUTPUT_PATH_INVALID계열, 이 PR과 무관, 실패 이름 목록이 변경 전후 동일). 새 테스트 6개는 통과한다. Linux CI가 판정한다.Risk
itx-cheongchun-coverage-contract2,apply-itx-topology-to-bundled-pack1,activate-current-source-set1,verify-production-pack-artifact-identity10). 실제 승격은 여기에 더해apply-itx-topology-to-bundled-pack의ADMITTED_TOPOLOGY_INPUTS(원천 sha 키 허용 목록)와 topology 버전 증거·팩 sha,ci.yml의 mobile fixture 고정값(mobile 레포의 팩 커밋)이 새 원천에 묶여 있다(seq127 PR #940의 후속 커밋들이 이 목록이다). 후보 build spec이 contract sha를 고정하므로 후보 재생성도 필요하다. 이 PR은 승격까지만 자동화하고 파생 재결속은 후속 이슈 #979에서 자동화한다(이 PR 병합 뒤 바로 구현). #979가 병합되기 전에는DATAPACK_SCHEDULED_ITX_PROMOTION을 켜지 않는다.Rollout / Recovery
DATAPACK_SCHEDULED_ITX_PROMOTION이 꺼진 채 병합. 켜는 순서는 [CI] ITX 승격 뒤 파생 재결속(literal 테스트·topology 입력 허용 목록·증거와 팩·mobile fixture 재핀)과 raw capture 원장 대조 자동화 (#870 3단계 후속) #979 병합 -> QA 보고 -> 변수 켜기 -> 첫 정기 실행의 PR 작성자·CI·본문 증거 블록 확인.ITX promotionnotice(WAIT 사유), 승격 PR 본문의easysubway-automation-pr:v1블록(단계itx-promotion), 실패 이슈.--approval-url)로 같은 승격을 직접 할 수 있다.Review focus
itx-promotion-gate-policy.json, 전부 이력 관측 최대값)와 기준선 대비 누적 drift 검사Checklist