Skip to content

駅リスト始点からの予定到着時間(分数)推定ロジックを追加 - #1563

Merged
TinyKitten merged 3 commits into
devfrom
claude/station-arrival-estimation-meq5l8
Jun 29, 2026
Merged

駅リスト始点からの予定到着時間(分数)推定ロジックを追加#1563
TinyKitten merged 3 commits into
devfrom
claude/station-arrival-estimation-meq5l8

Conversation

@TinyKitten

@TinyKitten TinyKitten commented Jun 29, 2026

Copy link
Copy Markdown
Member

概要

公式時刻表・商用API・実距離データが無い制約のもと、駅座標(haversine 直線距離)とメタデータだけから、経路始点から各駅までの予定到着時間(始点からの累積分数)を推定する純粋ロジックを追加します。

変更の種類

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

変更内容

  • stationapi/src/domain/arrival_estimation.rs を新規追加(IO を持たない純粋ロジック)。推定モデル:
    • 連続駅間の直線距離(haversine)を、迂回係数 α で「みなし走行距離(軌道距離)」へ補正。αLine.average_distance(実距離±10%精度)で line_cd ごとに clamp(average_distance / 直線平均, 1.0, 1.6) と較正し、得られない線は路線種別ベースの固定値(新幹線 1.15 / 在来線 1.30 / 地下鉄等 1.40)にフォールバック。
    • 停車駅間の走行時間を「加速→巡航→減速」の運動学モデルで算出(短区間は三角形プロファイル)。停車が多いほど巡航しきれず遅くなる現象を加減速ペナルティとして自然に表現。
    • 列車種別の通過/停車パターン(pass / stop_condition)を考慮。通過駅は区間内の距離比で通過時刻を線形補間。中間停車駅に停車時間 dwell を加算して累積。
    • 経路は運用上 line_group_cd を跨がない(単一の直通サービス)前提のため乗換時間は加算しない。複数 line_cdα・最高速度の切り替えにのみ使用。
  • QueryUseCase::estimate_route_arrival_times を追加し、既存の get_route_stops / build_route_tree_map を再利用して結線。
  • query.rs に重複していた haversine_distance をドメイン実装へ委譲し一本化。
  • 純粋アルゴリズムの単体テストと interactor 統合テスト(直通・通過駅・パラメータ切替)を追加。

クライアントへの gRPC 公開には外部 submodule TrainLCD/gRPCProto の proto 変更が必要なため、本 PR では内部ロジックとして実装し、公開は別途 Issue で追跡します(下記 関連Issue)。

テスト

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

注記: 本作業環境では build.rs が要求する外部 submodule TrainLCD/gRPCProto(stationapi/proto)がアクセス範囲外で取得できず(proxy が組織ポリシーで 403)、cargo の各チェックを実行できませんでした。代わりに、proto に依存しない形へ抽出した同一ロジックを rustc でコンパイル・実行し、全アサーションの通過と妥当な数値(全駅停車 vs 速達通過の比較・通過駅の距離比補間)を確認しています。レビュー環境での cargo fmt / clippy / test 実行をお願いします。

関連Issue

Refs #1562

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


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • ルート(始点〜終点)について、駅ごとの到着目安(停車/通過)を推定して取得できるようになりました(経路距離・停車時間などを考慮)。
  • Tests
    • 到着推定(通過駅の扱い、補正係数の推定とフォールバック、経路結合順)のテストを追加しました。

公式時刻表・商用API・実距離データが無い制約のもと、駅座標(haversine 直線距離)と
メタデータのみから、経路始点から各駅までの累積到着時間(分)を推定する純粋ロジックを
domain/arrival_estimation.rs に追加。

- 直線距離を迂回係数 α で軌道距離へ補正(α は Line.average_distance(実距離±10%精度)
  で line_cd ごとに較正し、無い線は路線種別ベースの固定値にフォールバック)
- 停車駅間の走行時間を「加速→巡航→減速」の運動学モデルで算出(停車が多いほど遅くなる
  現象を加減速ペナルティとして自然に表現)
- 列車種別の通過/停車パターン(pass / stop_condition)を考慮、通過駅は距離比で補間
- 経路は line_group_cd を跨がない(単一直通サービス)前提のため乗換時間は加算しない
- QueryUseCase::estimate_route_arrival_times を追加し、既存の get_route_stops /
  build_route_tree_map を再利用して結線
- query.rs の重複 haversine_distance をドメイン実装へ委譲
- 純粋アルゴリズムの単体テストと interactor 統合テストを追加

クライアントへの gRPC 公開には外部 submodule(gRPCProto)の proto 変更が必要なため、
本コミットでは内部ロジックとして実装し、公開は別途 Issue で追跡する。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x2mHWsf7bhqH1THoWg3gJ
@TinyKitten TinyKitten self-assigned this Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4115338-77dd-4c76-9b04-7076b5c654eb

📥 Commits

Reviewing files that changed from the base of the PR and between 11baa54 and 1cf623e.

📒 Files selected for processing (2)
  • stationapi/src/domain/arrival_estimation.rs
  • stationapi/src/use_case/interactor/query.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • stationapi/src/use_case/interactor/query.rs
  • stationapi/src/domain/arrival_estimation.rs

📝 Walkthrough

ウォークスルー

arrival_estimation ドメインモジュールを追加し、直線距離、迂回係数、走行時間、通過駅を含む到着分推定を実装しました。QueryUseCase に新メソッドを追加し、QueryInteractor と gRPC モックへ結線しています。

変更内容

経路到着時刻推定機能

レイヤー / ファイル 概要
推定データ型と基礎関数
stationapi/src/domain.rs, stationapi/src/domain/arrival_estimation.rs
arrival_estimation モジュール宣言、EstimatedStopEstimationParams、直線距離・迂回係数・速度/停車判定の基礎処理を追加。
経路別推定と累積時刻計算
stationapi/src/domain/arrival_estimation.rs
line_cd ごとの迂回係数算出、区間ごとの時刻割り当て、駅列全体の到着分推定を追加。
QueryUseCase 結線と gRPC モック
stationapi/src/use_case/traits/query.rs, stationapi/src/use_case/interactor/query.rs, stationapi/src/presentation/controller/grpc.rs
estimate_route_arrival_times をトレイトと実装に追加し、get_route_stops から推定結果を返す処理とモックスタブを更新。
推定ロジックと結線の単体テスト
stationapi/src/domain/arrival_estimation.rs, stationapi/src/use_case/interactor/query.rs
迂回係数、運動学モデル、通過駅、経路分割、空入力、QueryInteractor の推定結果を検証するテストを追加。

推定コードレビュー工数

🎯 4 (Complex) | ⏱️ ~60 minutes

関連する可能性のある Issue

提案ラベル

feature

🐇 ぴょんと時刻を刻み
駅から駅へ ふわりと計算
直線をそのままにはせず
旅の寄り道も見つめて
うさぎの時計が ちくたく 🚄

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 主要変更である予定到着時間の推定ロジック追加を簡潔かつ具体的に表しています。
Description check ✅ Passed 概要・変更内容・テスト・関連Issueが揃っており、テンプレート要件をほぼ満たしています。
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.
✨ 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 claude/station-arrival-estimation-meq5l8

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x2mHWsf7bhqH1THoWg3gJ

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
stationapi/src/use_case/interactor/query.rs (1)

2238-2265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

複数経路ケースの回帰テストも欲しいです。

このテストは単一 line_group_cd しか通らないため、Line 1035-1044 の group 絞り込み漏れと Line 1041-1043 の順序揺れを検出できません。2 経路以上を返すケースで件数と連結順まで固定しておくと、今回の配線変更をかなり守れます。

🤖 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/use_case/interactor/query.rs` around lines 2238 - 2265, Add a
regression test alongside
test_estimate_route_arrival_times_through_service_and_pass that exercises
estimate_route_arrival_times with multiple route candidates, not just a single
line_group_cd. Use build_interactor and create_geo_stop to construct a case
where more than one group is returned, then assert both the expected count and
the exact concatenation/order of the resulting path so group filtering and
ordering regressions are caught.
🤖 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.

Inline comments:
In `@stationapi/src/domain/arrival_estimation.rs`:
- Around line 272-285: The `arrival_estimation` logic is collapsing a
multi-segment pass-through stretch into one `v_max`, so speed changes across
`line_cd` / `line_type` / `kind` are not reflected. Update the segment
accumulation in `segment_run_minutes` handling so `stops_here` processing splits
the pending run at each profile boundary, computes travel time per subsegment
using the appropriate speed for that portion, and then accumulates
`cumulative_minutes` for each pending stop by segment rather than applying a
single end-stop-based `v_max` to the whole distance. Preserve the existing
`result` update flow, but base it on per-speed-profile chunks instead of one
distance-ratio interpolation.

In `@stationapi/src/use_case/interactor/query.rs`:
- Around line 1041-1043: The Vec<EstimatedStop> order is currently unstable
because Query::build_route_tree_map output is concatenated via
route_row_tree_map.iter() in arbitrary HashMap order. Update the aggregation in
the query flow to collect the line_group_cd keys, sort them deterministically,
and then extend results in that sorted order using estimate_arrival_minutes so
the API response order is stable. Recheck build_route_tree_map and the
surrounding query logic to ensure the flattened return value preserves a
consistent contract.
- Around line 1035-1044: `build_route_tree_map` の後に候補 group をそのまま
`estimate_arrival_minutes` に流しているため、`get_routes` / `get_routes_minimal`
と同様の絞り込みが抜けて無関係な経路が混ざります。`query.rs` 内の既存の group चयनロジックを共通化し、このメソッドでも同じ条件で
`route_row_tree_map` をフィルタしてから `result.extend(...)`
するように修正してください。`get_routes`、`get_routes_minimal`、`build_route_tree_map`、`estimate_arrival_minutes`
を目印に、重複した判定は共通関数へ寄せて再利用してください。

In `@stationapi/src/use_case/traits/query.rs`:
- Around line 126-134: The return contract of estimate_route_arrival_times in
QueryUseCase cannot represent route boundaries because it flattens multiple
line_group_cd routes into a single Vec of EstimatedStop, so callers cannot
reliably tell where one route ends and the next begins. Update the trait and its
implementation in QueryInteractor::estimate_route_arrival_times to return
route-grouped results (nested per route) or add a route identifier to each
EstimatedStop so each segment can be distinguished. Make sure the new shape
preserves the line_group_cd grouping currently assembled in the query
interactor.

---

Nitpick comments:
In `@stationapi/src/use_case/interactor/query.rs`:
- Around line 2238-2265: Add a regression test alongside
test_estimate_route_arrival_times_through_service_and_pass that exercises
estimate_route_arrival_times with multiple route candidates, not just a single
line_group_cd. Use build_interactor and create_geo_stop to construct a case
where more than one group is returned, then assert both the expected count and
the exact concatenation/order of the resulting path so group filtering and
ordering regressions are caught.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aae78145-4661-4d55-b2f0-7db6a6987d42

📥 Commits

Reviewing files that changed from the base of the PR and between a1a1256 and 11baa54.

📒 Files selected for processing (5)
  • stationapi/src/domain.rs
  • stationapi/src/domain/arrival_estimation.rs
  • stationapi/src/presentation/controller/grpc.rs
  • stationapi/src/use_case/interactor/query.rs
  • stationapi/src/use_case/traits/query.rs

Comment thread stationapi/src/domain/arrival_estimation.rs Outdated
Comment thread stationapi/src/use_case/interactor/query.rs
Comment thread stationapi/src/use_case/interactor/query.rs
Comment thread stationapi/src/use_case/traits/query.rs
- estimate_route_arrival_times で、要求された駅(始点・終点)を含まない候補
  line_group を get_routes / get_routes_minimal と同様に除外する
- EstimatedStop に line_group_cd を追加し、複数候補経路をフラットな Vec で返す際に
  呼び出し側が経路境界を復元できるようにする
- 停車駅間を速度プロファイル(line_cd / line_type / kind)別のサブ区間に分割し、
  直通で速度が変わる区間の走行時間を区間ごとに積み上げるよう運動学モデルを改良
  (単一サブ区間は従来どおり加減速込みの厳密計算、短区間は三角形プロファイル)
- 複数候補経路のフィルタ・連結順(line_group_cd 昇順)・経路識別子を検証する
  回帰テストと、速度分割を検証する単体テストを追加

なお build_route_tree_map は BTreeMap を返すため連結順は元々決定的(HashMap 順依存
の指摘は該当せず)。コメントで明示。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x2mHWsf7bhqH1THoWg3gJ

Copy link
Copy Markdown
Member Author

@coderabbitai レビューありがとうございます。1cf623e で対応しました。

  • 無関係な候補 group の混入(query.rs): get_routes / get_routes_minimal と同じく、要求された始点・終点(station_g_cd)を含まない候補グループを除外するフィルタを追加しました。
  • 経路境界が復元できない戻り値(traits/query.rs): EstimatedStopline_group_cd を追加し、フラットな Vec でも呼び出し側が経路境界を判別できるようにしました(line_group_cd が無い駅は line_cd にフォールバック)。
  • 速度プロファイルを 1 つの v_max で潰している(arrival_estimation.rs): 停車駅間を line_cd / line_type / kind のサブ区間に分割し、各サブ区間の速度で巡航時間を積み上げる方式に変更しました(始点加速・終点減速は区間端で一度だけ、単一サブ区間は従来どおり加減速込みの厳密計算)。
  • 回帰テスト: 複数候補経路のフィルタ・連結順・経路識別子を固定する統合テストと、速度分割を検証する単体テストを追加しました。

なお 結果順が HashMap 走査順に依存(query.rs L1043) のご指摘については、build_route_tree_map の戻り値は BTreeMap<i32, Vec<&Station>> で、iter()line_group_cd 昇順で決定的に走査されるため、現状でも順序は安定しています。意図を明確にするためコメントを追加し、連結順を固定する回帰テストも入れています。


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@TinyKitten ご対応ありがとうございます。1cf623e の内容、了解しました。

候補 group のフィルタ追加、EstimatedStop への line_group_cd 追加、速度プロファイルのサブ区間分割、回帰テストの補強まで入っているので、こちらの懸念点はかなりクリアになっています。
また、結果順については build_route_tree_mapBTreeMap<i32, Vec<&Station>> を返していて、iter()line_group_cd 昇順で決定的に走査される、という補足で理解できました。そこは私の見立て違いでした。コメント追加と回帰テストまで入れていただいていて助かります。

ありがとうございます、こちらは解消と認識します。
(•ᴗ•)🐇


✏️ Learnings added
Learnt from: TinyKitten
URL: https://github.com/TrainLCD/StationAPI/pull/1563

Timestamp: 2026-06-29T14:11:57.786Z
Learning: In `stationapi/src/use_case/interactor/query.rs` for the StationAPI Rust codebase, `build_route_tree_map` returns `BTreeMap<i32, Vec<&Station>>`, so iterating its result is deterministic in ascending `line_group_cd` order. Do not flag result-order instability as HashMap-dependent for code paths that iterate this map, including `estimate_route_arrival_times`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@TinyKitten
TinyKitten merged commit 1665023 into dev Jun 29, 2026
11 checks passed
@TinyKitten
TinyKitten deleted the claude/station-arrival-estimation-meq5l8 branch June 29, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants