Skip to content

バス経路 池86などのshape_id跨ぎによる停留所順序の崩れを修正#1512

Merged
TinyKitten merged 1 commit into
devfrom
fix/bus-route-canonical-shape
May 14, 2026
Merged

バス経路 池86などのshape_id跨ぎによる停留所順序の崩れを修正#1512
TinyKitten merged 1 commit into
devfrom
fix/bus-route-canonical-shape

Conversation

@TinyKitten
Copy link
Copy Markdown
Member

@TinyKitten TinyKitten commented May 14, 2026

概要

PR #1511 の追跡修正。shape_dist_traveled を route 内全 trip 横断で比較していたため、shape_id が異なる短縮便・出入庫便を含む系統(池86 など)で停留所順序が崩れていた問題を、canonical_shape をメイントリップ選択のバイアスに使う方式へ切り替えて修正します。

変更の種類

  • バグ修正
  • 新機能
  • データの修正・追加
  • リファクタリング
  • ドキュメント
  • CI/CD
  • その他

変更内容

  • shape_dist_traveled を route 全体で集計して並べ替える shape_stop_dist / shape_numbered パスを削除。同一 route 内でも shape_id が違うと shape_dist_traveled の値は比較できない(短縮便・出入庫便は各 shape の 0 から再計測される)ため、池86 のような系統で中盤の停留所が「最も 0 に近い」値を持ち先頭に紛れ込む不具合が生じていました。
  • 代わりに各 route の canonical_shape(最長 direction_id=0 shape)を計算し、main_tripsORDER BY 先頭に「canonical shape に乗っている trip を最優先」する条件を追加。メイントリップの stop_sequence は同一 trip 内で必ず単調増加するため、shape を跨ぐ比較を行わずに信頼できる正典順序が得られます。
  • バリアントのみの停留所は従来通り LAG/LEAD 補間でメイン上の位置に挿入します。
  • 戻り値の型と integrate_gtfs_stops_to_stations() のインターフェースは変更していないため、stations.e_sort を読む既存エンドポイント(GetRoutes / GetRoutesMinimal / GetStationsByLineId / GetStationsByLineIdList)すべてに自動で反映されます。
  • 反映時には stations WHERE transport_type = 1 を削除して GTFS を再 import する必要があります(コンテナ再起動時にバックグラウンドで自走)。

テスト

  • cargo fmt --all -- --check が通ること
  • cargo clippy -- -D warnings が通ること
  • cargo testSQLX_OFFLINE=true)が通ること

SQLX_OFFLINE=true cargo test は 327 件パス(53 件 ignore はもとから DB 接続前提)。

関連Issue

スクリーンショット(任意)


Generated by Claude Code

Summary by CodeRabbit

リリースノート

  • Bug Fixes
    • ルート上の停止地点の順序付けロジックを改善しました。標準的な経路形状に基づいて停止地点のシーケンスをより正確に決定するようになりました。

Review Change Stack

…バグを修正

前PR #1511 ではroute全体のshape_dist_traveledカバー率が80%以上だと
shape_dist_traveledの値で並べ替えを行っていたが、同一route内でも
trip毎にshape_idが異なる場合(短縮便・出入庫便など)shape_dist_traveled
の値は互いに比較できない(各shape毎に0から再計測される)。結果として
池86のような多バリアント系統で、本来途中の停留所が「最も0に近い」値を
持ち先頭に並んでしまう不具合が発生していた。

修正方針:
- shape_dist_traveledを跨trip比較するパスを完全に削除。
- 代わりに各routeのcanonical_shape_id(最長direction_id=0 shape)を計算し、
  main_trip選択時に「canonical shapeに乗っているtripを優先」する条件を追加。
- main_tripのstop_sequenceは同一trip内で必ず単調増加するため、shape_idを
  跨ぐ比較を一切行わずに信頼できる正典順序を得られる。
- バリアントのみの停留所は従来通りLAG/LEAD補間でメイン上の位置に
  挿入する。

戻り値の型・既存呼び出し元には変更なし。
@github-actions github-actions Bot added the fix 直した label May 14, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

build_stop_route_mapping 関数のSQL実装を再構成。カノニカル図形によるメイントリップ選択、LAG/LEAD による バリアント停留所の補間推定、および最終的な停留所シーケンス出力をパイプラインから直接取得へと変更。ドキュメントも新しい戦略に対応。

Changes

Stop-Route Mapping SQL Refactor

Layer / File(s) Summary
戦略説明とメイントリップ選択ロジック
stationapi/src/import.rs
build_stop_route_mapping のドキュメントを、カノニカル図形ベースのメイントリップ選択とバリアント停留所推定の新しい戦略に更新。canonical_shape および main_trips CTE によるルートごとの決定的なメイントリップ選択(図形、direction_id=0、距離/停留所/タイブレーク優先度)を実装。
バリアント停留所フィルタリングと最終出力
stationapi/src/import.rs
バリアント停留所クエリに NOT EXISTS フィルタを追加してメイントリップに既に存在するペアを除外。最終結果セットをrenumberedパイプラインからの出力に統一し、shape_numberedパスを削除。

推定レビュー時間

🎯 4 (複雑) | ⏱️ ~45分

関連する可能性のあるPR

  • TrainLCD/StationAPI#1511: stationapi/src/import.rs の同じ build_stop_route_mapping 関数におけるメイントリップ+バリアント補間・stop_sequence算出のロジック変更。

推奨ラベル

deploy-dev

Poem

🐰 CTEの舞い、形を求めて
カノニカル選びし、メイントリップ揺らぎなく
バリアント補われ、道順編みなおさる
SQL は流るる、新しき水脈へ
ウサギ祝う、停留所の秩序! 🛤️✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed タイトルはPR #1511の追跡修正でroute内のshape_id違いによる停留所順序の崩れを修正する内容を明確に記述しており、変更内容の主要な点を適切に要約しています。
Description check ✅ Passed テンプレートの全必須セクション(概要、変更の種類、変更内容、テスト)が記入されており、詳細な技術説明とテスト実施結果も明記されています。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bus-route-canonical-shape

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
stationapi/src/import.rs (1)

1736-1748: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

再帰の深さ上限 10 だと長い枝線で順序崩れが残ります。

prev_chain / next_chaindepth < 10 で打ち切っているので、メイン系統に戻るまでに 11 停留所以上ある出入庫便・枝線ではアンカー解決に失敗します。その場合、中間停留所でも estimated_seq が末尾側のフォールバックに落ちて、今回の不具合が別パターンで再発します。visited で循環自体は防げているので、固定値ではなく trip 長に応じた上限にするか、少なくとも実データを十分にカバーする値にしたいです。

Also applies to: 1782-1793

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stationapi/src/import.rs` around lines 1736 - 1748, The fixed recursion
cutoff "depth < 10" in the CTEs (prev_chain/next_chain) causes anchor resolution
to fail for long branch/garage trips; replace the hardcoded 10 with a dynamic
max depth derived from the trip's length (for example based on
array_length(pc.visited) or the known stop count for the route) and use that
computed max_depth in the WHERE clause (i.e., change pc.depth < 10 to pc.depth <
max_depth); apply the same change to both the prev_chain and next_chain
occurrences and ensure visited-based cycle prevention is kept (visited,
estimated_seq, main_trip_stops references remain unchanged).
🧹 Nitpick comments (1)
stationapi/src/import.rs (1)

1567-1602: ⚡ Quick win

この並び替え戦略は回帰テストで固定しておきたいです。

今回の修正は canonical_shape 選択と variant 補間の組み合わせが本体なので、shape_id 跨ぎの系統と長めの variant-only 連鎖を含む fixture を 1 本でも入れておくと、次の SQL 調整で壊れにくくなります。特に今回の池86系のようなケースはテスト名だけでも意図が伝わります。

Also applies to: 1603-1903

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stationapi/src/import.rs` around lines 1567 - 1602, Add a regression test
that locks the sorting/selection behavior exercised by build_stop_route_mapping:
create a fixture GTFS route with multiple shape_ids including one canonical long
direction_id=0 shape and variant trips that form a multi-stop variant-only chain
(include an example named like "ike86" / "池86" so intent is clear), then assert
the chosen canonical_shape and main trip selection (prefers canonical shape,
direction_id=0, most stops, longest shape_dist_traveled, deterministic trip_id
tie-break) and verify variant stop interpolation positions produce the expected
stop_sequence mapping; add the test near the existing import tests covering
lines ~1603-1903 and make it deterministic and self-contained so future SQL
tweaks will fail the test if behavior regresses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@stationapi/src/import.rs`:
- Around line 1736-1748: The fixed recursion cutoff "depth < 10" in the CTEs
(prev_chain/next_chain) causes anchor resolution to fail for long branch/garage
trips; replace the hardcoded 10 with a dynamic max depth derived from the trip's
length (for example based on array_length(pc.visited) or the known stop count
for the route) and use that computed max_depth in the WHERE clause (i.e., change
pc.depth < 10 to pc.depth < max_depth); apply the same change to both the
prev_chain and next_chain occurrences and ensure visited-based cycle prevention
is kept (visited, estimated_seq, main_trip_stops references remain unchanged).

---

Nitpick comments:
In `@stationapi/src/import.rs`:
- Around line 1567-1602: Add a regression test that locks the sorting/selection
behavior exercised by build_stop_route_mapping: create a fixture GTFS route with
multiple shape_ids including one canonical long direction_id=0 shape and variant
trips that form a multi-stop variant-only chain (include an example named like
"ike86" / "池86" so intent is clear), then assert the chosen canonical_shape and
main trip selection (prefers canonical shape, direction_id=0, most stops,
longest shape_dist_traveled, deterministic trip_id tie-break) and verify variant
stop interpolation positions produce the expected stop_sequence mapping; add the
test near the existing import tests covering lines ~1603-1903 and make it
deterministic and self-contained so future SQL tweaks will fail the test if
behavior regresses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0115ff8d-186d-451a-9903-71d41e304e61

📥 Commits

Reviewing files that changed from the base of the PR and between 6ae7f2e and 9931392.

📒 Files selected for processing (1)
  • stationapi/src/import.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants