Repository navigation
[Fix] 전국 정본 팩의 운행 요일 값·노선도 라벨 결함으로 release-candidate 빌드 실패 - #858
Conversation
- canonical-pack-service-calendar-flags.test.mjs: 지역 시간표 통합 출력과 커밋된 전국 정본 팩의 serviceCalendars 요일 값이 모두 boolean인지 검사한다. 현재 main은 부산·대구·대전·광주 16개 달력이 0/1 숫자라 실패한다. - nationwide-route-map-official-rename.test.mjs: 자양(뚝섬한강공원)·불암산(당고개) 두 역을 공식 역사 좌표 파일(data.go.kr 15099316)·MOLIT 역 목록·승인 개명 기록과 대조하고, release-candidate 감사 인자로 커밋된 전국 팩을 감사해 BLOCKER·HIGH 0을 요구한다. 현재 main은 ROUTE_MAP_SOURCE_LABEL_MISMATCH HIGH 2건으로 실패한다. 승인 개명 권역은 팩이 선언한 coverageLineOperatorScopes 조합으로만 인정하는 단위 검사도 추가했다. - data-test-ownership.json에 data854 소유자와 두 테스트를 required-pr로 등록한다.
결함 1: regional-timetable-integrator가 부산·대구·대전·광주 serviceCalendars 16개의 요일 값을 0/1 숫자로 써서 build-datapack boolFlag가 "serviceCalendars.monday must be a boolean"으로 실패했다(870b574, #814 도입). 요일 값을 같은 의미의 true/false로 쓴다. 검사는 그대로 둔다. 결함 2: audit-route-map의 승인 개명(OFFICIAL_RENAME) 판정이 개명 기록 scopeKey의 권역을 pack.id와 비교했다. 7a75638(#800/#801)에서 정본 팩 id가 capital에서 nationwide로 바뀌어, capital 팩에서는 승인 개명으로 통과하던 같은 두 행(자양(뚝섬한강공원)/7호선, 불암산(당고개)/4호선)이 전국 팩에서 ROUTE_MAP_SOURCE_LABEL_MISMATCH HIGH가 됐다. 권역 결속을 팩 id 대신 팩이 선언한 coverageLineOperatorScopes의 정확한 region:operator:line 조합으로 바꾼다. 선언이 없거나 조합이 다르면 전과 같이 HIGH로 막는다(예외 목록·기준 변경 없음). 기존 단위 테스트 fixture에는 capital:seoul-metro:seoul-4 선언을 추가했다.
node tools/datapack/prepare-nationwide-candidate-run.mjs \ --requested-by=data-operator-lead --approved-by=data-release-authority - nationwide-production-canonical-pack.json: 부산·대구·대전·광주 serviceCalendars 16개 x 7요일 = 112개 값이 0/1에서 같은 의미의 true/false로 바뀌었다. 그 밖의 값 차이는 없다(재생성 전 main 입력으로 돌린 결과는 커밋본과 바이트 동일). - candidate-build-spec.json fixtureSha256, hash-evidence.json fixturePath.sha256: a1c21d91… → 9e647a85… - release-request.json buildSpecSha256: 6e7a3947… → b3fe97eb… - nationwide-candidate-preparation.json builderIdentity.gitSha: 생성 시점 HEAD
범위 추가(2026-10-01 QA 결정)의 결함 3·4 실패 테스트. - 결함 3: 지역 시간표 통합 출력과 커밋된 전국 정본 팩의 transitStopTimes가 stationId·lineId·arrivalSeconds·departureSeconds를 갖고, lineId가 trip 노선· stationLines와 맞는지 검사한다. 현재 통합 도구는 stopId·arrivalTimeSeconds· departureTimeSeconds를 쓰고 lineId를 빠뜨려 실패한다. - 결함 4: 칸·문 안내 계약 검사(대상 시설 STAIR/ELEVATOR/ESCALATOR/TRANSFER, 칸 1~10, 문 1~4, 방향 ''/UP/DOWN/INNER/OUTER)와 격리 증거 파일을 요구한다. 현재 생성 도구에 계약 검사·증거 파일이 없고 팩에 계약 밖 행이 있어 실패한다. - data-test-ownership.json에 data854 소유로 required-pr 등록.
결함 3: regional-timetable-integrator가 transitStopTimes를 stopId· arrivalTimeSeconds·departureTimeSeconds로 쓰고 lineId를 빠뜨렸다. build-datapack 계약 필드 stationId·lineId·arrivalSeconds·departureSeconds로 쓰고 각 정차 행에 trip과 같은 노선 id를 싣는다. 시각 값과 산출 방식은 바꾸지 않는다(#855 범위 제외). regional-timetable-integrator.test.mjs의 옛 필드 참조도 계약 필드로 바꿨다. 결함 4: KRIC 칸·문 안내 확대가 station_car_door_hints 계약 밖 행을 팩에 실었다. 생성 단계에서 carDoorHintContractViolations로 대상 시설(STAIR/ELEVATOR/ESCALATOR/ TRANSFER), 칸 1~10, 문 1~4, 방향(''/UP/DOWN/INNER/OUTER, 빠른하차 importer 어휘)을 검사하고, 위반 행은 팩에 싣지 않고 사유·식별자·원문(dtlLoc)·개수를 tools/datapack/release/nationwide-car-door-hint-quarantine.json에 남긴다. 값을 다른 값으로 바꾸지 않는다. WHEELCHAIR_LIFT 계약 확장은 #856.
node tools/datapack/prepare-nationwide-candidate-run.mjs \
--requested-by=data-operator-lead --approved-by=data-release-authority
- nationwide-production-canonical-pack.json
- transitStopTimes 244,325행 수 유지. 지역 202,495행의 필드명만 계약 필드로 바뀌고
lineId가 붙었다. 역·순번·시각 값 차이 0건.
- stationCarDoorHints 435 → 49행, minimumTableRows.station_car_door_hints 435 → 49.
KRIC 파생 404행 중 386행 격리(방향 BOTH 386, 그중 WHEELCHAIR_LIFT 8·문 번호 5 이상 2).
- nationwide-car-door-hint-quarantine.json(신규): 격리 386행의 id·역·노선·방향·시설·
칸·문·원문 dtlLoc·gubun·providerRecordHash·사유와 사유별 개수.
- fixtureSha256·hash-evidence fixturePath.sha256: 9e647a85… → 064fa48a…
- release-request buildSpecSha256: b3fe97eb… → 418a7756…
- nationwide-candidate-preparation builderIdentity.gitSha: 생성 시점 HEAD
- prepare-nationwide-candidate-run.test.mjs: 칸·문 행 수 기대값을 49와
격리 합계(49 + 386 = 435)로 바꿨다.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID:
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: 0
🎯 Linked issue & acceptance criteria audit
- Linked issue: #854 Canonical pack weekday flags and route-map labels block release-candidate builds
- Goal summary: The release-candidate path passes input, route-map audit and datapack build.
- Acceptance criteria verified: 3/3
| ID | Acceptance criterion | Status | Evidence |
|---|---|---|---|
| AC-1 | Weekday flags are booleans from the generator | PASS | tools/datapack/lib/regional-timetable-integrator.mjs |
| AC-2 | Official renames pass the audit without exceptions | PASS | tools/route-map/audit-route-map.mjs |
| AC-3 | Stop time field names and out-of-contract car-door rows quarantined | PASS | tools/datapack/prepare-nationwide-candidate-run.mjs |
🛡️ Adversarial audit evidence
- Falsifiability verified: Yes (Reverting the audit scope binding fails three rename tests.)
- Hollow assertions detected: 0
- Production backdoors detected: 0
- Ground-truth sources verified:
catalog-schema.sql station_car_door_hints CHECKdata.go.kr 15099316 station coordinates and MOLIT station list for both renamed stations
- Mutation testing evidence:
Restoring scope.regionId === pack.id: rename test 1 pass, 3 fail.
🤖 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:
None.
---
Outside diff comments:
None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: aquila-review by Claude Code against issue #854 and hub CLAUDE.md
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 current change set for the automerge review gate
Base:
main@366d83bd16cc3cebb398f41f4397c63fc1b3596d
Head:
fix/canonical-pack-calendar-label-854@fecba49d27ea410b92c180194a529ac52fe2aa47
Command:
node scripts/compile-review-payload.mjs input.json --output payload-1.json
📥 Commits
Reviewing files changed in this pull request between:
- Base:
366d83bd16cc3cebb398f41f4397c63fc1b3596d - Head:
fecba49d27ea410b92c180194a529ac52fe2aa47
📒 Files selected for processing (16)
tools/ci/data-test-ownership.jsontools/datapack/canonical-pack-service-calendar-flags.test.mjstools/datapack/canonical-pack-transit-car-door-contract.test.mjstools/datapack/lib/regional-timetable-integrator.mjstools/datapack/lib/regional-timetable-integrator.test.mjstools/datapack/prepare-nationwide-candidate-run.mjstools/datapack/prepare-nationwide-candidate-run.test.mjstools/datapack/release/candidate-build-spec.jsontools/datapack/release/hash-evidence.jsontools/datapack/release/nationwide-candidate-preparation.jsontools/datapack/release/nationwide-car-door-hint-quarantine.jsontools/datapack/release/nationwide-production-canonical-pack.jsontools/datapack/release/release-request.jsontools/route-map/audit-route-map.mjstools/route-map/nationwide-route-map-official-rename.test.mjstools/route-map/route-map-tools.test.mjs
📜 Review details
|
No description provided. |
|



Related issue
Closes #854
Summary
tools/datapack/release/nationwide-production-canonical-pack.json)의 데이터 결함 때문에 release-candidate 빌드가 입력 생성 다음 단계에서 멈췄다. 노선도 감사는 라벨 불일치 HIGH 2건으로, 데이터팩 빌드는 운행 요일 값 형식으로 실패했다. 이 둘을 고치자 가려져 있던 결함 2건(지역 정차 시각 필드명, 계약 밖 칸·문 안내)이 더 드러났다(이슈 본문 "범위 추가", 2026-10-01 QA 결정).Changes
결함 1: 운행 요일 값이 0/1 숫자 (870b574, #814 도입)
tools/datapack/lib/regional-timetable-integrator.mjs: 부산·대구·대전·광주serviceCalendars16개의 요일 값을 같은 의미의true/false로 쓴다.build-datapack.mjsboolFlag검사는 그대로 둔다.결함 2: 노선도 원천 라벨 불일치 HIGH 2건
OFFICIAL_RENAME, #2470)도 이미 있다. 역 이름·노선 매핑·원천 라벨은 모두 맞다(아래 대조표).tools/route-map/audit-route-map.mjs의 승인 개명 판정이 개명 기록scopeKey의 권역을pack.id와 비교했다. 7a75638([Feat][DataPack] Advance nationwide accessibility pipeline (elevator, barrier-free routes, timetables) and bind nationwide.sqlite pack identity #800/[Feat] Ingest nationwide barrier-free routes and regional accessibility facilities (#800) #801)에서 정본 팩 id가capital에서nationwide로 바뀌면서 이 비교가 깨졌다. 같은 두 행을 커밋된capital-production-canonical-pack.json으로 감사하면 지금도APPROVED_ROUTE_MAP_SOURCE_LABEL_RENAMEINFO로 통과한다.pack.id에서, 팩이 선언한coverageLineOperatorScopes의 정확한region:operator:line조합으로 바꿨다. 선언이 없거나 조합이 다르면 전과 같이 HIGH다. 선언이 없는 capital 팩은 오히려 더 엄격해졌다. 그래서tools/route-map/route-map-tools.test.mjs의 기존 단위 fixture에capital:seoul-metro:seoul-4선언 한 줄을 추가했다.결함 3: 지역 정차 시각 필드명·노선 누락 (#814)
regional-timetable-integrator.mjs:stopId·arrivalTimeSeconds·departureTimeSeconds를 계약 필드stationId·arrivalSeconds·departureSeconds로 바꾸고, 각 정차 행에 trip과 같은lineId를 싣는다. 시각 값과 산출 방식은 바꾸지 않는다.tools/datapack/lib/regional-timetable-integrator.test.mjs: 옛 필드 참조를 계약 필드로 바꿨다.결함 4: 계약 밖 KRIC 칸·문 안내 (#814 Phase 3)
tools/datapack/prepare-nationwide-candidate-run.mjs:carDoorHintContractViolations로 KRIC 파생 행을station_car_door_hints계약과 대조한다. 계약은catalog-schema.sqlCHECK(대상 시설 STAIR/ELEVATOR/ESCALATOR/TRANSFER, 칸 110, 문 14)와 빠른하차 importer(import-car-door-hints.mjs)의 방향 어휘(UP/DOWN/INNER/OUTER, 방향 미상은 빈 문자열)다.tools/datapack/release/nationwide-car-door-hint-quarantine.json에 격리한다. 값을 다른 값으로 바꾸지 않는다.tools/datapack/prepare-nationwide-candidate-run.test.mjs: 칸·문 행 수 기대값을 49로 바꾸고, 격리 합계(49 + 386 = 435)도 검사한다.테스트·소유권
tools/ci/data-test-ownership.json의 data854 소유):tools/datapack/canonical-pack-service-calendar-flags.test.mjstools/route-map/nationwide-route-map-official-rename.test.mjstools/datapack/canonical-pack-transit-car-door-contract.test.mjs재생성 산출물
node tools/datapack/prepare-nationwide-candidate-run.mjs --requested-by=data-operator-lead --approved-by=data-release-authoritynationwide-production-canonical-pack.jsonnationwide-car-door-hint-quarantine.json(신규)candidate-build-spec.jsonfixtureSha256: a1c21d91… → 064fa48a…hash-evidence.jsonfixturePath.sha256: a1c21d91… → 064fa48a…release-request.jsonbuildSpecSha256: 6e7a3947… → 418a7756…nationwide-candidate-preparation.jsonbuilderIdentity.gitSha: 생성 시점 HEADserviceCalendarstransitStopTimeslineId추가. 역·순번·시각 값 차이 0건stationCarDoorHintsminimumTableRows.station_car_door_hintsrelease-pin-drift.test.mjs([Fix] source-inventory 변경 뒤 release 고정 해시 미갱신으로 release-candidate 빌드 실패 #846 드리프트 검사)release-candidate-accessibility-input.test.mjsdocumentation-fragment.json은 갱신하지 않았고,--check와 파편 동기화 게이트가 모두 통과한다.결함 2: 두 역 공식 원천 대조표
nameKo(nameSub))station-f306bbca9985/line-15b3b8a93259(7호선)capital:seoul-metro:line-15b3b8a93259뚝섬유원지→자양(뚝섬한강공원), 서울특별시고시 제2024-109호(2024-02-29 시행)station-871f17171f3c/seoul-4(4호선)capital:seoul-metro:seoul-4당고개→불암산(당고개), 2025-05-15 시행nationwide-route-map-official-rename.test.mjs가 위 값을 원천 파일(EUC-KR CSV)에서 다시 읽어 대조하고, release-candidate 감사 인자로 BLOCKER·HIGH 0을 확인한다.결함 4: 격리 증거 (
tools/datapack/release/nationwide-car-door-hint-quarantine.json)kric-station-convenience-standard,sourceSnapshotId,rawSha256), 적용한 계약, 요약, 격리 행 전체. 각 행은id·stationId·lineId·direction·targetFacilityType·carNumber·doorNumber·gubun·원문dtlLoc·providerRecordHash·reasons를 가진다.generatedCount404,admittedCount18,quarantinedCount386DIRECTION_OUTSIDE_CONTRACT(방향BOTH)BOTH가 없다. 원문dtlLoc에 방향 표기가 없는데 생성 도구가 "양방향"으로 채워 넣었다. 빈 문자열로 바꾸는 것도 값 치환이라 격리했다TARGET_FACILITY_TYPE_OUTSIDE_CONTRACT(WHEELCHAIR_LIFT)DOOR_NUMBER_OUTSIDE_CONTRACT(문 번호 5 이상)BOTH여서, 방향 위반 386행 안에 들어 있다.provenanceKindOFFICIAL_SOURCE는 격리하지 않았다.provenance_kind에는 어휘 제약이 없고,OFFICIAL_SOURCE는 pathway edge·노선도 좌표 등에서 쓰는 저장소 표준 값이다.OFFICIAL일 때만 원천 필드를 필수로 요구한다. 격리되지 않은 KRIC 18행은sourceId·sourceSnapshotId·providerRecordHash를 모두 가진다.Scope
Included
Excluded
WHEELCHAIR_LIFT계약 확장: [Feat] 빠른 하차 칸-문 대상에 휠체어 리프트(WHEELCHAIR_LIFT) 추가 #856Ownership / dependencies
Contract & Compatibility
build-datapack계약과station_car_door_hintsCHECK를 지키도록 생성 쪽을 고쳤다.fixtureSha256·hash-evidence·release-request.buildSpecSha256을 공식 생성 명령으로 다시 맞췄다.sourceSnapshotSetHash와 원천 스냅샷은 그대로다.BOTH·WHEELCHAIR_LIFT·문 5 이상)이었다.Version impact
Product gate impact
Provenance impact
Version decision
nationwide-candidate-20260923-seq122의 입력 고정값만 재산출Verification
RED/GREEN
1fed1962,7278bf08: 수정 전 테스트 커밋)canonical-pack-service-calendar-flags.test.mjs: 2/2 실패 (busan-weekday-2026.monday=1… 112개 값)nationwide-route-map-official-rename.test.mjs: 3/4 실패. HIGHROUTE_MAP_SOURCE_LABEL_MISMATCH2건(station-f306bbca9985/line-15b3b8a93259,station-871f17171f3c/seoul-4). 공식 원천 대조 1개는 데이터가 맞아 통과canonical-pack-transit-car-door-contract.test.mjs: 4/4 실패.stationId: undefined,busan-transportation-timetable:… stationId,lineId,arrivalSeconds,departureSeconds,carDoorHintContractViolations export없음, 계약 밖 칸·문 행 존재canonical-pack-service-calendar-flags.test.mjsnationwide-route-map-official-rename.test.mjscanonical-pack-transit-car-door-contract.test.mjsrelease-pin-drift.test.mjsrelease-candidate-accessibility-input.test.mjslib/regional-timetable-integrator.test.mjsroute-map/route-map-tools.test.mjsprepare-nationwide-candidate-run.test.mjsbuild-nationwide-candidate.test.mjsci/guard-datapack-anti-cheat.test.mjsnode --test --test-concurrency=1 --test-name-pattern "release candidate|production" tools/datapack/datapack-tools.test.mjsnode tools/ci/data-test-discovery.mjs verify --class required-pr: exit 0 (366개, data854 3개 포함)node tools/ci/guard-datapack-anti-cheat.mjs: PASSnode tools/datapack/validate-source-inventory.mjs: exit 0node tools/repo/refresh-documentation-fragment.mjs --check: IN SYNCnode tools/ci/check-documentation-fragment-sync.mjs --base origin/main: "No tracked documentation resources modified"release-candidate 로컬 재현 로그
.github/workflows/datapack-release.ymlrelease-candidate 경로를 같은 인자로 실행했다. build spec은tools/datapack/release/candidate-build-spec.json, 출력과--candidate-fixture-override는os.tmpdir()아래다. 발행·업로드 단계는 실행하지 않았다.build-current-release-candidate-accessibility-input.mjsaudit-route-map.mjs --fail-on BLOCKER,HIGHbuild-datapack.mjs --candidate-fixture-override …serviceCalendars.monday must be a boolean)current.json·current.provenance.json·catalog/생성)transitStopTimes.stationId must be a non-empty string(결함 3)으로 실패했다.CHECK constraint failed: target_facility_type IN (...)(결함 4)으로 실패했다.EASYSUBWAY_DATAPACK_SIGNING_*가 필요하다. CI에서는 워크플로가 시크릿으로 넣고, 로컬에서는 1회성 키를 썼다.3단계 이후 release-candidate 실패 (범위 밖, 보고만)
manifest.keyId is unknownkey id must be production-v1SNAPSHOT_TIME_INVALID·LICENSE_EVIDENCE_MISMATCH,molit-railway-transfer-movement:LICENSE_NOT_REDISTRIBUTABLE, 다수 행CLAIM_SNAPSHOT_BINDING_MISMATCHITX topology evidence pack identity mismatchITX topology source artifact is expiredid === "capital"조회 후속 목록 (release-candidate 경로에서 실행되지 않음)tools/datapack/apply-accessibility-evidence-to-bundled-pack.mjs:overlayReviewedSourcesOnCanonicalRoster(268),syncCanonicalFixture(297),activeReleaseSnapshots(699),currentCandidateReleaseSnapshots(742),main(918·937·961)tools/datapack/register-current-seoul-accessibility-snapshot.mjs(161)syncCanonicalAccessibilityEvidence·retainPreAuthorityRideEdges뿐이다.manifest.activePack정확히-하나 선택으로 고쳐야 한다.Not run
--require-production, server route bundle staging)Risk
BOTH로 채운 값이라 계약 밖이어서 격리했다. 방향 미상 행을 계약에 어떻게 싣을지(빈 문자열 허용 등)는 따로 결정이 필요하다.Rollout / Recovery
Review focus
audit-route-map.mjs승인 개명 권역 결속:pack.id→ 팩이 선언한coverageLineOperatorScopes조합. 선언 없는 팩은 더 엄격해진다.BOTH방향 386행 격리 판단: 계약 어휘에 없는 값을 빈 문자열로 바꾸지 않고 격리했다.Checklist