Repository navigation
[CI] ITX 승격 뒤 파생 재결속 자동화: 입력 팩 고정·출력 팩 파생·재결속 workflow (#979) - #980
Conversation
…된 증거에서 파생 - apply-itx-topology --derive-fixture: 입력 fixture에서 같은 팩·index를 결정적으로 만들고 커밋된 증거와 한 글자라도 다르면 실패한다(증거는 쓰지 않는다). - ADMITTED_TOPOLOGY_INPUTS 허용 목록을 없애고 입력 팩 식별을 coverage contract의 topologyInputPackIdentity에서 읽는다. - ci.yml·datapack-release.yml·ownership manifest·stage-local의 pin을 입력 팩(mobile 573aefdb)으로 바꾸고, 파생 출력 팩 sha는 증거를 가리키게 한다(discovery derivedProfileSha256). - 승격마다 mobile 커밋·workflow pin이 바뀌지 않는다. Refs #979
후보 spec·입력 manifest·preparation의 ITX pin은 OCI에 게시된 입력을 가리키므로 승격 PR이 바꾸지 않는다. 병합 뒤 전국 후보 준비가 새 원천으로 다시 묶는다. ITX 소유 테스트를 data979 소유로 등록한다. Refs #979
- coverage contract 테스트: 승인·게이트 두 승격 모드 모두 구조와 근거를 검증하고, 운행일·신선도·요일을 literal 대신 규칙으로 확인 - activate-current-source-set 테스트: 버전 증거 경로와 build 시각을 현재 artifactId stamp에서 도출 Refs #979
|
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 |
zlib은 gzip 헤더 OS 바이트를 실행 플랫폼으로 채워(macOS 19, Linux 3) 압축 본문이 같아도 팩 sha256이 달랐다. linux/amd64 컨테이너(node 24.19.0)에서 파생이 pack.outputSha256 불일치로 실패하는 것을 재현했고, 고정 뒤 같은 컨테이너에서 팩 sha와 index sha가 증거·mobile 4d419569와 일치한다. 불일치 오류에는 달라진 필드를 적는다. Refs #979
- 현재 contract 기준으로 build spec의 ITX pin을 다시 계산하는 helper(current-itx-bound-build-spec)를 route graph·current admission·datapack-tools 테스트가 쓴다. - refresh-nationwide-candidate 테스트는 게이트 승격 근거 파일(영수증·정책·직전·기준선 원천)도 복사한다. - activate-current-source-set 테스트는 게이트 승격 contract에 repositoryRoot를 넘긴다. Refs #979
관측 시각 literal(2026-10-05)과 승인 URL 주입 가정을 없애고, 게이트 승격이면 작업 트리 영수증을 근거로 쓴다. Refs #979
AquilaXk
left a comment
There was a problem hiding this comment.
Actionable comments posted: 7
🎯 Linked issue & acceptance criteria audit
- Linked issue: #979 [CI] ITX promotion derivative rebinding and raw capture ledger reconciliation
- Goal summary: A promotion pull request alone must pass required CI without human edits.
- Acceptance criteria verified: 3/5
| ID | Acceptance criterion | Status | Evidence |
|---|---|---|---|
| AC1 | A gate-mode promotion PR alone turns Data contracts green with no manual commit | PASS | tools/datapack/rebind-itx-promotion.mjs and .github/workflows/itx-current-promotion.yml |
| AC2 | Literal tests derive from the contract so no one edits expectations by hand | PASS | tools/datapack/apply-itx-topology-to-bundled-pack.test.mjs |
| AC3 | The input pack allowlist is contract-based and a mismatching identity fails | PASS | tools/datapack/apply-itx-topology-to-bundled-pack.mjs |
| AC4 | Topology evidence and pack regenerate and the mobile fixture pin is paired | FAIL | PR 980 body states the mobile PR is replaced by a branch and tag |
| AC5 | The raw capture sha is reconciled against the source ledger row | FAIL | PR 980 body section Excluded states this criterion is left unmet |
⚡ Tiered triage & token efficiency
- Non-code files skipped: 0
- AST symbols extracted: 0
- Estimated token savings: 0%
| Category | Count | Status |
|---|---|---|
| Skipped non-code files | 0 | TIER-1 SKIPPED |
| AST semantic symbols | 0 | TIER-2 EXTRACTED |
🛡️ Adversarial audit evidence
- Falsifiability verified: Yes (Validation mutants killed 4 of 4; derive comparison probed by CLI only)
- Hollow assertions detected: 0
- Production backdoors detected: 0
- Ground-truth sources verified:
Issue 979 body acceptance criteriaLocal derive run against the committed evidence filePinned input pack sha in ci.yml compared with the contract identity
- Mutation testing evidence:
topologyInputPackIdentity lines 388, 389, 391: 4 of 4 mutants killed
🤖 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/ci.yml:44-44`
Could the issue body record that the branch and tag must be kept, and could the
manual path document that the rebind tool is the follow-up step?
- `@.github/workflows/itx-current-promotion.yml:12-12`
Could the PR switch to Refs #979, or split the ledger reconciliation and the
dispatch check into a follow-up issue before the closing keyword is kept? The issue
body could also record the mobile branch-and-tag substitution as a QA-approved
decision.
- `@tools/datapack/apply-itx-topology-to-bundled-pack.mjs:407-407`
Could the comment name the real step and could main keep a single variable for the
option?
- `@tools/datapack/apply-itx-topology-to-bundled-pack.mjs:1171-1173`
Could a small test stage the pinned input pack, copy the evidence with one altered
digit, and assert the mismatch error names pack.outputSha256? That keeps the
immutable-mode gate falsifiable on any runner.
- `@tools/datapack/apply-itx-topology-to-bundled-pack.mjs:1209-1209`
Could the apply tool assert the same Node and SQLite runtime before computing, and
fail with a clear message, or record the SQLite version in the evidence so a
mismatch names its cause?
- `@tools/datapack/apply-itx-topology-to-bundled-pack.test.mjs:35-42`
Could the test recompute the station, served-station, and directed-edge counts
directly from the source stationSequences with a short independent loop, and assert
them against the evidence? That would restore a second oracle without a literal per
promotion.
- `@tools/datapack/test-fixtures/itx-synthetic-collection.mjs:31-35`
Could one scenario remove or add a served station in the synthetic completeness
data, and then assert that the evidence topology counts, the derived pack rows, and
the alignment fixtures all follow the change?
---
Outside diff comments:
None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository CLAUDE.md, issue 979 body, and the aquila-review skill rules
Review profile: ASSERTIVE
Plan: Aquila fallback
Run ID: N/A (Aquila fallback)
Review source: Aquila CLI
Repository visibility: public GitHub repository
Trigger:
Single discovery review of PR 980 at head 88b437b, requested by the QA owner
Base:
main@c80d3508d9ebc2c79ea8fd5dec0c2039cd4be7a5
Head:
automation-itx-rebinding-979@88b437bed5426584112e70a2529619bed832ae20
Command:
node post-review.mjs input.json payload-1.json --repo AquilaXk/easysubway-data --pr 980
📥 Commits
Reviewing files changed in this pull request between:
- Base:
c80d3508d9ebc2c79ea8fd5dec0c2039cd4be7a5 - Head:
88b437bed5426584112e70a2529619bed832ae20
📒 Files selected for processing (9)
.github/workflows/ci.yml.github/workflows/itx-current-promotion.ymltools/ci/automation-pr-evidence.mjstools/ci/data-test-ownership.jsontools/datapack/apply-itx-topology-to-bundled-pack.mjstools/datapack/apply-itx-topology-to-bundled-pack.test.mjstools/datapack/rebind-itx-promotion.mjstools/datapack/rebind-itx-promotion.test.mjstools/datapack/test-fixtures/itx-synthetic-collection.mjs
📜 Review details
변이(servedStationCount 14→15)는 이 단언이 실패로 잡는다. Refs #979
팩 바이트가 SQLite 패치 버전에 묶여, 다른 런타임에서는 불투명한 해시 불일치로 실패했다. 계산 전에 실제 버전을 적어 거부한다. 증거 스키마에 SQLite 버전을 추가하는 것은 build-datapack·build-server-timetable-snapshot의 exact-key 검증과 불변 고정된 과거 버전 증거에 걸려 이 PR에서 하지 않는다. Refs #979
대조 조건을 꺼 둔 변이는 이 테스트가 실패로 잡는다. Refs #979
…동 승인 승격도 --rebind로 같은 재결속을 탐 (#980 F6) - ci.yml 5개 job·datapack-release·승격 workflow가 checkout 전에 data-fixture/itx-979 태그가 기대 커밋을 가리키는지 확인한다. 태그가 사라지거나 옮겨지면 원인을 적어 실패한다(보호 규칙 대신 CI 검사). checkout ref는 태그, 커밋 고정은 stage의 rev-parse 검증이 맡는다. - discovery manifest에 fixture profileRef(태그)를 추가하고 모양을 닫았다. - 승격 CLI에 --rebind를 추가했다. 게이트·사람 승인 승격 모두 승격 직후 같은 재결속 도구를 탄다. 승격 workflow는 fixture를 승격 전에 stage하고 --rebind를 쓰며 별도 재결속 step을 없앴다. 수동 절차는 workflow 머리말에 적었다. Refs #979
|
No description provided. |
|
No description provided. |
|



Related issue
Refs #979
Refs #981
Refs #870
Refs #977
Refs #969
Refs #636
Summary
ADMITTED_TOPOLOGY_INPUTS허용 목록, mobile fixture 고정값(ci.yml5개 job·datapack-release.yml·소유권 manifest)이 함께 어긋난다. seq127([Data] seq127 재발행을 위한 P7D 원천 갱신과 전국 후보 재생성 통합 #940)에서 이 단계는 수동 후속 커밋이었다.Changes
apply-itx-topology-to-bundled-pack.mjs: 코드의ADMITTED_TOPOLOGY_INPUTS허용 목록을 없애고 입력 팩 식별을 contract의topologyInputPackIdentity에서 읽는다(식별이 없거나 잘못되면 거부). 새 옵션--derive-fixture <apps/mobile>: 고정 입력 fixture에서 팩·index를 파생하고 증거는 쓰지 않으며, 계산한 증거가 커밋된 증거와 다르면ITX_FIXTURE_DERIVATION_MISMATCH로 실패한다(시계에 묶이지 않는 immutable 모드).rebind-itx-promotion.mjs(신규): 승격 근거를 다시 검증한 뒤 입력 fixture에 새 topology를 적용해itx-cheongchun-topology-evidence.json과 버전 증거itx-cheongchun-topology-evidence-<stamp>.json을 만들고, 5권역 alignment fixture의packSha256만 새 팩에 맞춘다(그 밖의 값이 바뀌면 실패).itx-current-promotion.yml: 승격 직후 고정 mobile 입력 fixture checkout·stage, 재결속 step을 추가했다. 커밋 step은 허용 경로(원천 승격 4 + 재결속 7)의 정본인itxPromotionAllowedPaths와 바뀐 경로 집합이 정확히 같을 때만 진행한다.automation-pr-evidence.mjs의itx-promotion단계도 같은 경로 집합을 요구한다.ci.yml(5개 job)·datapack-release.yml: mobile fixture를 입력 팩(mobile573aefdb, 팩 sha609a7409)으로 고정하고 Node 설정 뒤에 파생 step을 넣었다. "Re-verify" step은 파생된 팩의 기대 sha를 workflow literal이 아니라 커밋된 증거(pack.outputSha256)에서 읽는다.datapack-release.yml의 Node도 CI와 같은24.19.0으로 고정했다(SQLite 버전에 묶인 바이트를 만들기 때문).data-test-discovery.mjs: fixture 파일 기대 해시를 JSON 증거에서 읽는derivedProfileSha256({jsonPath, pointer})을 추가했다. 모양이 틀리거나 값이 sha256이 아니면INVALID_FIXTURE_DERIVED_HASH다.data-test-ownership.json의 mobile-v19 pin·fixtureStageContracts를 입력 팩으로 바꾸고 새 테스트를data979소유로 등록했다.stage-local-mobile-fixture.mjs: 로컬 staging도 입력 팩 검증 뒤 파생하고 증거 sha와 대조한다.itx-cheongchun-coverage-contract.test(두 승격 모드 검증, 운행일·요일·신선도 규칙),activate-current-source-set.test,apply-itx-topology-to-bundled-pack.test,itx-promotion-gate.test(정책 측정 근거 snapshot까지만 이력 재생하고 이후 게이트 승격은 영수증 존재로 확인),datapack-tools.test(작업 트리 원천을 읽는 route graph 검사는 현재 contract 기준 임시 build spec 사용).test-fixtures/itx-synthetic-collection.mjs·rebind-itx-promotion.test.mjs: 합성 수집(실제 후보 생성기) → 승격 → 재결속 → CI가 하는 파생을 격리 worktree에서 끝까지 돌리는 종단 테스트. 시나리오 4개: 7일 뒤 수집, 현재 원천들과 같은 날 수집, 운행역 제거·추가(자동 게이트가 막아 사람 승인 승격으로 처리, 증거·파생 팩의 간선이 따라감).--rebind: 게이트·사람 승인 승격이 같은 재결속을 탄다.apply-itx-topology는 Node 24.19.0·SQLite 3.53.3 런타임 가드를 둔다.documentation-fragment.json) 갱신.Scope
Included
573aefdb(브랜치·태그data-fixture/itx-979): 병합 대상이 아니다. checkout은 태그 ref로 하고, 각 job이 checkout 전에 태그가 기대 커밋을 가리키는지 먼저 검사한다(지우면 안 된다). 기존data-fixture/itx-938선례처럼 브랜치와 태그로만 보존한다(앱 번들 팩을 입력 팩으로 되돌리는 커밋이라 mobile main에 병합하면 안 된다).Excluded
release/source-snapshots.json행)과 영수증 대조: 원천 inventory·거버넌스 정책·신선도 SLA 등록과 OCI 게시 권한(datapack-release-check환경 secret)이 얽힌 별도 원천 온보딩이라 이 PR에서 구현·검증할 수 없다. 후속 이슈 #981에서 다룬다(메인 결정: 변수 켜기의 선행 조건이 아니다).prepare-nationwide-candidate-run)가 버전 증거를 읽어 새 원천으로 다시 묶는다.Ownership / dependencies
data-test-ownership.json, 문서 파편,automation-pr-evidence)과 겹칠 수 있다. 병합 시점에 충돌을 맞춘다.Contract & Compatibility
list --query korail)·source-candidates.json의 기존 id만 쓴다.--derive-fixture가 입력 fixture에서 현재 출력 팩·index·증거를 그대로 재현한다).4d419569)에서 입력 팩(573aefdb)으로 한 번 바뀐다. 이후 승격은 pin을 바꾸지 않는다.Version impact
Product gate impact
Provenance impact
Version decision
Verification
apply-itx테스트: 허용 목록 의존 3건 RED → contract 기반 GREEN. (2) CI 첫 실행에서 5개 job이ITX_FIXTURE_DERIVATION_MISMATCH로 RED였고, linux/amd64 컨테이너(node 24.19.0)에서pack.outputSha256만 달라지는 것을 재현했다(원인: zlib gzip 헤더 OS 바이트가 macOS 19·Linux 3). OS 바이트 고정 뒤 같은 컨테이너에서 팩 sha16497931…와 index sha7e5ca038…가 증거·mobile4d419569와 일치(GREEN). (3) discoveryderivedProfileSha256, 증거 단계 허용 경로(11), 승격 workflow 계약, 재결속 종단 테스트(시나리오 2개)--derive-fixture상태에서 required-pr 전체를 격리 worktree로 실행했다. mobile-v19 profile: exit 0. 기본 profile 4 shard: shard 2·4 통과, shard 1·3은 이 macOS 개발 환경에서 승격 전 main에서도 같은 테스트가 실패하는 2개 파일(bundle-component-contractICU,collect-korail-itx-cheongchun-timetable임시 경로 심볼릭 링크 25건; 실패 집합 동일)만 실패했다. 후보 pin 입력은 실제 공개 OCI 읽기(GET)로 받았다.33221968:Data contracts(mobile-v19, shard 1~4 포함)·SonarCloud·CodeQL·CodeRabbit 전부 successITX_FIXTURE_DERIVATION_MISMATCH에 달라진 필드를 적는다),--derive-fixture는 증거를 쓰지 않는다. fallback 없음Not run
force_collectdispatch로 확인Risk
datapack-tools일부 테스트(8개)의 build 시계는 원천들의 수집 시각 최댓값이라 ITX 수집 시각이 Incheon 원천 신선도(24시간) 밖으로 앞서면 그 테스트가 실패한다. 수집 시각을 직전 수집 7일 뒤로 합성했을 때 이 8개가 정확히 이 사유로 실패했고, 수집 시각을 현재 원천들과 같은 날로 합성했을 때는 통과했다. 실제 승격은 Incheon 갱신 PR이 병합된 main 위에서 열려야 안정적이다. (2) raw capture 원장 대조가 없어SOURCE_BINDING·FETCH_ERRORS는 승격 시점 PASS 기록만 남는다.Rollout / Recovery
Data contractsgreenReview focus
--derive-fixture가 시계에 묶이지 않는 immutable 모드로 증거 불일치를 거부하는지itxPromotionAllowedPaths)과 workflow의 정확 일치 검사Checklist