[Fix] 수도권 공식 시간표를 전국 후보 시간표에 적재 - #910
Conversation
seq 124 후보에는 수도권 4호선 2정차 pilot만 있어 canary 신도림→강남 후보가 0개였다. - lib/kric-capital-timetable-records: KRIC 전체_도시철도운행정보(파일 id 900)에서 정차 순서를 명시한 수도권 13개 노선(서울 1~9호선·신분당·우이신설·신림·공항)을 정규화 trip으로 읽는다. 문법·시각 역전 행은 사유와 함께 격리하고, 1호선 원천 손상 행 453건은 행 집합 hash로 고정해 미적재(#902에서 보강). - lib/official-line-timetable: 원천 중립 노선 적재기. 역 미매칭·노선 trip 0·운행일 종류 trip 0·격리 5% 초과는 실패. 일반열차 비인접 정차 격리. trip_id는 결정적 단축형(<접두>-<노선>-<운행일>-<sha 12자>). - lib/external-stop-times: 공식 원천(수도권·인천) trip·stop_time을 결정적 gzip 파일로 분리하고 팩에는 sha·건수만 결속. 원천 공통 provenance는 섹션 헤더, trip별 providerRecordHash. 펼칠 때 sha·요약·FK· provenance·고아·중복을 검사(build-datapack·후보 accessibility 입력·anti-cheat guard). - prepare: capitalScheduleAdmissionEvidence snapshot 입력(정책 신선도 유도), 4호선 pilot 교체, 적재 보고서. - register-kric-capital-timetable: 수집본 → projection snapshot·inventory 증거 등록. - anti-cheat: KRIC S1101 907열차(원천 2분 간격 10정차)만 원천 행 hash로 고정 제외. Refs #899 Refs #862
collect-kric-nationwide-timetable-file.mjs로 2026-10-02T15:57:05.773Z 수집(raw sha256 218f76dd…, 기존 광주 retained와 같은 원본). register-kric-capital-timetable.mjs로 수도권 13개 노선 11,922행 projection snapshot과 inventory capitalScheduleAdmissionEvidence를 등록. Refs #899
…2T17:01:35.688Z) 공식 refresh-nationwide-candidate.mjs(--evaluated-at 2026-10-02T17:01:35.688Z --release-sequence 125 --requested-by data-operator-lead --approved-by data-release-authority). 후보 ID nationwide-candidate-20261002-seq125. 팩 JSON 57.9MB, nationwide-official-stop-times.json.gz 4.0MB (수도권·인천 공식 trip·stop_time). 노선별 적재·격리는 nationwide-capital-timetable-report.json. Refs #899
Refs #899
…1:18:19.409Z) 공식 refresh-nationwide-candidate.mjs(--evaluated-at 2026-10-02T21:18:19.409Z --release-sequence 125 --requested-by data-operator-lead --approved-by data-release-authority). 팩·외부 시간표 파일 바이트는 같다. Refs #899
|
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: 5
🎯 Linked issue & acceptance criteria audit
- Linked issue: #899 [Fix]
수도권 지하철 공식 시간표를 전국 데이터팩에 적재 - Goal summary: Load official capital timetables into the nationwide candidate without estimates.
- Acceptance criteria verified: 3/3
| ID | Acceptance criterion | Status | Evidence |
|---|---|---|---|
| C1 | Failing test first for per-line trips and representative pair stop_times | PASS | tools/datapack/capital-official-timetable.test.mjs |
| C2 | Collection, registration and nationwide candidate loading path extended | PASS | tools/datapack/register-kric-capital-timetable.mjs |
| C3 | No synthetic or estimated timetable for lines without a source | PASS | tools/datapack/lib/official-line-timetable.mjs |
🛡️ Adversarial audit evidence
- Falsifiability verified: No (Failed: Pinned set or-guard, expand orphan and empty-trip checks, collision guard survived)
- Hollow assertions detected: 0
- Production backdoors detected: 0
- Ground-truth sources verified:
Anti-cheat exemption probes killed on source id and row hash operandsCommitted snapshot recount of trips and one-sided stops via the parserdocumentation fragment check reports in sync at head 869b9106Issue 899 body and QA decisions on line scope and pinned line 1 rows
🤖 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/datapack/capital-official-timetable.test.mjs:108-109`
Could the PR body record why the tool and data commits are not split, or could
the data commits move to a follow-up PR?
- `@tools/datapack/lib/external-stop-times.mjs:196-208`
Could a helper craft sidecar content with a valid sha and binding that contains
an orphan stop_time, a trip without rows, and a header with an extra field, with
each expected to fail in expandExternalStopTimes?
- `@tools/datapack/lib/official-line-timetable.mjs:231-231`
Could tests be added for a same-count set with one different row hash and for a
count-only change, each expecting QUARANTINE_ALLOWANCE_MISMATCH?
- `@tools/datapack/lib/official-line-timetable.mjs:275-275`
Could a test inject a stub or two trips with the same provider key and assert
TRIP_ID_COLLISION?
- `@tools/datapack/lib/official-line-timetable.mjs:289-290`
Could the QA decision on zero-dwell normalization be recorded in the issue body,
or could the missing side be preserved so the router sees the source value?
---
Outside diff comments:
None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: CLAUDE.md files, data repo PR template, and aquila-review skill defaults
Review profile: ASSERTIVE
Plan: Aquila fallback
Run ID: N/A (Aquila fallback)
Review source: Aquila CLI
Repository visibility: public GitHub repository
Trigger:
QA-requested discovery review of PR 910 at head 869b910
Base:
main@b25a8c8b49938a610964d58d0ada6cdc12a91a74
Head:
fix/capital-official-timetable-899@869b91069acd58580ac645104ef4f4a0a5b168ef
Command:
aquila-review discovery via post-review.mjs on AquilaXk/easysubway-data PR 910
📥 Commits
Reviewing files changed in this pull request between:
- Base:
b25a8c8b49938a610964d58d0ada6cdc12a91a74 - Head:
869b91069acd58580ac645104ef4f4a0a5b168ef
📒 Files selected for processing (7)
tools/ci/guard-datapack-anti-cheat.mjstools/datapack/capital-official-timetable.test.mjstools/datapack/lib/external-stop-times.mjstools/datapack/lib/external-stop-times.test.mjstools/datapack/lib/kric-capital-timetable-records.mjstools/datapack/lib/official-line-timetable.mjstools/datapack/lib/official-line-timetable.test.mjs
📜 Review details
건수는 같고 행 하나만 다른 경우와, 행 집합은 같고 고정 건수만 다른 경우를 각각 QUARANTINE_ALLOWANCE_MISMATCH로 실패시키는 테스트를 더했다. probe-falsifiability로 official-line-timetable.mjs:231의 '!==→===', '||→&&' mutant가 모두 죽는 것을 확인했다. Refs #899
- expand는 결속 요약 계산 전에 최상위·섹션 키, 헤더, 행 열 수를 닫힌 계약으로 확인한다 (모르는 필드·헤더 불일치·열 수 불일치는 실패). - sha·결속을 다시 맞춘 변조 파일로 ORPHAN_STOP_TIME·TRIP_WITHOUT_STOP_TIMES·SECTION·CONTENT· ROW_SHAPE가 각각 expand에서 실패하는 테스트를 더했다. 각 검사를 무력화한 mutant 6개가 모두 죽는다. Refs #899
같은 provider key를 가진 서로 다른 원천 행이 같은 trip_id로 모이면 실패하는지 고정했다. official-line-timetable.mjs의 충돌 검사를 무력화한 mutant가 이 테스트로 죽는다. Refs #899
QA 결정(2026-10-03): 원천이 정차에 시각 하나만 준 경우 그 값을 정차 시각(도착 = 출발)으로 쓰는 것을 허용하되 숨기지 않는다. - stop_time.timeSource: PROVIDER_ARRIVAL_AND_DEPARTURE / SINGLE_PROVIDER_TIME_ARRIVAL / SINGLE_PROVIDER_TIME_DEPARTURE - 보고서 lines[].singleProviderTimeStopCount(기점·중간·종점) - 외부 시간표 파일 schemaVersion 3: 선택 열 timeSource(없는 행은 null, 펼칠 때 키 없음) - 두 시각이 모두 없으면 지금처럼 실패한다(테스트 고정). Refs #899
…0-02T21:55:02.841Z) 공식 refresh-nationwide-candidate.mjs(--evaluated-at 2026-10-02T21:55:02.841Z --release-sequence 125 --requested-by data-operator-lead --approved-by data-release-authority). 외부 시간표 파일 schemaVersion 3. Refs #899
|
|
No description provided. |



Related issue
Closes #899
Refs #862
Refs #902
Refs #903
Summary
Changes
tools/datapack/lib/kric-capital-timetable-records.mjstools/datapack/lib/official-line-timetable.mjs: 원천 중립 노선 적재기입니다. #903도 같은 진입점을 씁니다.<접두>-<노선>-<운행일>-<sha 12자>. 충돌하면 실패합니다.tools/datapack/lib/external-stop-times.mjs: 공식 원천(수도권·인천) trip과 stop_time을 결정적 gzip 파일로 분리합니다.release/nationwide-official-stop-times.json.gztimeSource는 선택 열입니다.stop_time.timeSource에SINGLE_PROVIDER_TIME_ARRIVAL또는SINGLE_PROVIDER_TIME_DEPARTURE를 표기합니다.singleProviderTimeStopCount에 남깁니다. 예: 공항선 중간역 7,528건tools/datapack/prepare-nationwide-candidate-run.mjscapitalScheduleAdmissionEvidence가 가리키는 snapshot을 입력으로 씁니다. 신선도는official_static_timetable_confirmation(P7D) 정책으로 유도합니다.release/nationwide-capital-timetable-report.json을 씁니다.tools/datapack/register-kric-capital-timetable.mjs: 수집본에서 projection snapshot과 inventory 증거를 만듭니다.tools/ci/guard-datapack-anti-cheat.mjscontracts/datapack/server-route-bundle-build-contract.json·schema·테스트218f76dd…). projection snapshot은 11,922행입니다.nationwide-candidate-20261002-seq125입니다.Scope
Included
Excluded
Ownership / dependencies
official-line-timetable·external-stop-times진입점을 씁니다.tools/ci/data-test-ownership.json의 owner 행이 충돌했습니다. data899와 data903 행을 모두 남겼습니다.도구와 데이터를 한 PR에 담은 이유
Contract & Compatibility
kric-nationwide-timetable-file에capitalScheduleAdmissionEvidence를 추가했습니다.externalTransitStopTimes로 외부 파일 sha를 결속합니다. 팩 JSON 자체는 build specfixtureSha256이 결속합니다.expandExternalStopTimes를 거쳐야 수도권·인천 시간표를 봅니다.Version impact
Product gate impact
Provenance impact
Version decision
nationwide-candidate-20261002-seq125). 발행은 이 PR 밖에서 합니다.server-route-bundle-build-contract.jsonmaxTotalDecompressedBytes를 58720256에서 201326592로 올렸습니다.release-request-nationwide-candidate-20261002-seq125Verification
노선별 적재 (원천 trip / 적재 trip / stop_time / 격리)
line-472a81add377seoul-2line-41a8c75ec9d8seoul-4line-80fc4d5350d4line-3f41718e0833line-15b3b8a93259line-2b2d9eaa53d0line-f0e747248a31shinbundangline-30886152e4f8line-aefa08ccc0a9line-e9e9a5b520a4b4e52aa3…)만 허용합니다. 건수나 행 집합이 바뀌면 실패합니다.KRIC 파일과 live API(
subwayTimetable, 평일) 비교같은 역의 평일 시각 multiset이 몇 건 일치하는지 셌습니다(파일 / API / 일치).
canary probe 재현
RouteBundleSqliteRuntimeCompiler·JourneyRaptorAdapter를 썼습니다. 상한은 로컬에서만 192MiB 이상으로 바꿨습니다.표의 숫자는 각 시각·지역별 후보 경로 수이고, 괄호 안은 첫 후보의 소요 시간과 환승 수입니다.
검증 표
capital-official-timetable.test.mjs3건이 기존 코드에서 실패하고("1호선 trip 0건", "서울역→청량리 stop_times 없음", "pilot 2역") 변경 뒤 4건이 통과합니다. lib 3종 테스트는 21건 통과입니다.subwayTimetable실측 비교(위 표). run-rc-full로 release-candidate 전 단계 재현: 상한 192MiB 이상에서ALL RC STEPS PASSED, 이전 상한 56MiB에서는E_SERVER_BUNDLE_DECOMPRESSED_BUDGET통합 테스트 결과
server-route-bundle-build-contract정본 hash. 상한 값을 바꿔서 생긴 실패라 이 PR에서 고쳤습니다.bundle-component-contract"contract mutations fail closed". origin/main(b25a8c8)에서도 로컬로 똑같이 실패해, 이 PR과 무관한 기존 실패입니다.--check: IN SYNC크기
Not run
Risk
Rollout / Recovery
Review focus
external-stop-times)이 provenance 정보를 잃지 않는지, 그리고 결속 불일치가 실패로 이어지는지Checklist