Skip to content

Add katakana to IPA conversion for SSML phoneme tags#1410

Merged
TinyKitten merged 18 commits into
devfrom
claude/review-issue-feasibility-prwtk
Mar 5, 2026
Merged

Add katakana to IPA conversion for SSML phoneme tags#1410
TinyKitten merged 18 commits into
devfrom
claude/review-issue-feasibility-prwtk

Conversation

@TinyKitten

@TinyKitten TinyKitten commented Mar 5, 2026

Copy link
Copy Markdown
Member

Summary

This PR adds a new katakana-to-IPA (International Phonetic Alphabet) conversion module to support generating phonetic transcriptions for Japanese station and line names. These IPA strings are used in SSML <phoneme> tags for text-to-speech pronunciation.

Key Changes

  • New IPA conversion module (stationapi/src/domain/ipa.rs):

    • Implements katakana_to_ipa() function that converts Japanese katakana text to IPA transcription
    • Handles single characters (basic hiragana/katakana) and two-character combinations (palatalized sounds like キャ, シュ, チョ)
    • Applies phonological rules for:
      • ン (moraic nasal) assimilation based on following consonant place of articulation
      • ッ (geminate) consonant doubling
      • ー (long vowel mark) and オウ/オオ patterns for vowel lengthening
    • Includes comprehensive test suite with 30+ test cases covering major Japanese station names
  • Integration with DTOs:

    • Updated station.rs to generate IPA transcription for station_name_k (katakana station name)
    • Updated line.rs to generate IPA transcription for line_name_k (katakana line name)
    • Updated query.rs interactor to include IPA for StationMinimal responses
    • IPA field is optional (None if conversion produces empty string)
  • Proto updates: Updated proto submodule to include new IPA fields in gRPC message definitions

Implementation Details

  • Uses a two-pass approach: first tries two-character digraph lookups for palatalized sounds, then falls back to single-character lookups
  • Phoneme enum distinguishes between regular IPA strings, moraic nasals, geminates, and long vowel markers
  • Nasal assimilation logic classifies following consonants by place of articulation (bilabial, palatal, velar, alveolar, uvular)
  • Vowel length rules handle common Japanese patterns (e.g., コウ → koː, オオ → oː)
  • All conversions use standard IPA symbols with proper diacritics (e.g., ɕ for palatal fricative, t͡ɕ for affricate)

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ

Summary by CodeRabbit

  • 新機能

    • カタカナ表記を自動で国際音声記号(IPA)に変換する機能を追加しました。
    • 駅・路線・StationMinimal 出力に任意の IPA 表記フィールドを追加し、利用可能な場合は API 応答で返却します(未対応時は空)。
  • テスト

    • 多数のカタカナパターンを検証する網羅的なテストを追加しました。
  • 雑務

    • 内部参照のサブモジュール参照を更新しました。

claude added 4 commits March 5, 2026 12:45
Rule-based converter that handles:
- Palatalized sounds (拗音): キョ→kʲo, チョ→t͡ɕo, ジョ→ʤo, etc.
- Moraic nasal (撥音) assimilation: ン→m/ɲ/ŋ/n/ɴ based on context
- Geminate consonants (促音): ッ doubles following onset
- Long vowels: オウ→oː, オオ→oː, ー→vowelː

Replaces 31 hardcoded IPA mappings in Cloud Functions tts.ts
with systematic pattern-based generation from katakana input.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ
Points to local branch adding optional name_ipa to Station and Line
messages for TTS IPA transcription support.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ
Compute name_ipa from name_katakana using katakana_to_ipa() in:
- Station DTO (From<Station> for GrpcStation)
- Line DTO (From<Line> for GrpcLine)
- StationMinimal construction in route queries

The IPA field is optional and only set when the katakana input
produces a non-empty transcription.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ
@coderabbitai

coderabbitai Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

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: c70c3df3-3288-4235-9520-d6799fa1db9d

📥 Commits

Reviewing files that changed from the base of the PR and between c75b6a1 and c7e7767.

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

📝 Walkthrough

Walkthrough

カタカナをIPAへ変換する新しいドメインモジュール ipa を追加し、katakana_to_ipa(&str) -> Option<String> を駅・路線のDTO/出力へ組み込み name_ipa: Option<String> を注入します。併せて stationapi/proto サブモジュール参照を更新しました。

Changes

Cohort / File(s) Summary
submodule更新
stationapi/proto
サブモジュールのコミット参照を更新(旧: d97e808d6afa1dd010a7361fa852a995d7f0484b → 新: f05b09f37213515a3a7d79d16d714b9c61984e5a
ドメイン公開宣言
stationapi/src/domain.rs
pub mod ipa; を追加してIPA変換モジュールを公開
IPA変換モジュール
stationapi/src/domain/ipa.rs
新規ファイル追加。pub fn katakana_to_ipa(input: &str) -> Option<String> を実装(ディグラフ/単一文字マッピング、撥音・促音・長音などの音韻処理、多数のテスト)。未知文字は None を返す設計。
DTO:路線
stationapi/src/use_case/dto/line.rs
katakana_to_ipa を呼び name_ipa: Option<String> を GrpcLine に追加・設定(空文字は None
DTO:駅
stationapi/src/use_case/dto/station.rs
katakana_to_ipa を呼び name_ipa: Option<String> を GrpcStation に追加・設定(空文字は None
Interactor 出力
stationapi/src/use_case/interactor/query.rs
StationMinimal を構築する箇所に name_ipa を計算して含めるよう変更(該当出力に新しい optional フィールドを追加)

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Interactor
    participant IPA_Module as IPA_Module
    participant Proto as GrpcResponse

    Client->>Interactor: 駅/路線情報要求
    Interactor->>IPA_Module: katakana_to_ipa(name_katakana)
    IPA_Module-->>Interactor: Option<String> (name_ipa)
    Interactor->>Proto: Build GrpcStation/StationMinimal with name_ipa
    Proto-->>Client: Response (includes name_ipa)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GetRoutesMinimal RPCを実装 #1334: StationMinimal の構築・ルート生成ロジックを修正するPR。今回の name_ipa フィールド追加と同箇所を変更しているため関連性が高いです。

Poem

🐰 カタカナ跳ねてIPAの道へ
ぼくは耳をすませて音を数えたよ
鼻が寄って促音がぴょんと弾む
長音はゆっくり伸びて星になる
ぴょん、祝福の小さな足跡

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR タイトルは、カタカナから IPA への変換機能を SSML フォネームタグ用に追加する変更を正確かつ簡潔に説明しており、主な変更を明確に反映しています。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/review-issue-feasibility-prwtk

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

@TinyKitten TinyKitten self-assigned this Mar 5, 2026

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@stationapi/proto`:
- Line 1: リモートで解決できないサブモジュールSHAが原因で CI が止まっているので、stationapi/proto
サブモジュールの参照を修正してください:対象のコミットSHAを到達可能なコミットに更新するか、該当コミットをサブモジュールの正しいリモートリポジトリに push
してから、リポジトリの親で git submodule update --init --recursive
を実行して参照が解決されることを確認してください(必要なら .gitmodules の URL を正しいリモートに修正してください)。

In `@stationapi/src/domain/ipa.rs`:
- Around line 283-285: The branch that detects voiced affricates for gemination
uses next_ipa.starts_with("d͡") which doesn't match this module's mapping for
the voiced affricate (dʑ / ʤ); update the condition in the block that checks
next_ipa (the one pushing into output) to test for the actual mapped symbol
(e.g., next_ipa.starts_with("dʑ") or the mapped "ʤ" variant used elsewhere)
instead of "d͡" so the "ッジ" gemination path behaves consistently with the
module's dʑ/ʤ mapping.
- Around line 225-256: The nasal_for_following function misses the palatal "j"
series, causing sequences like "シンヨ..." to yield "ɴj" instead of palatal
assimilation; update the palatal branch in nasal_for_following to include checks
for 'j' (and any common 'j' combos, e.g. starts_with('j') or starts_with("jʲ"))
so that those inputs return "ɲ" like the other palatal targets.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 525e2427-ea7e-4295-a7c9-b3ad4af91f0d

📥 Commits

Reviewing files that changed from the base of the PR and between fad371d and 28d5446.

📒 Files selected for processing (6)
  • stationapi/proto
  • stationapi/src/domain.rs
  • stationapi/src/domain/ipa.rs
  • stationapi/src/use_case/dto/line.rs
  • stationapi/src/use_case/dto/station.rs
  • stationapi/src/use_case/interactor/query.rs

Comment thread stationapi/proto Outdated
Comment thread stationapi/src/domain/ipa.rs
Comment thread stationapi/src/domain/ipa.rs Outdated

@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.

♻️ Duplicate comments (2)
stationapi/src/domain/ipa.rs (2)

224-231: ⚠️ Potential issue | 🟠 Major

の口蓋同化で j 系が未考慮です。

Line 224-231 の条件だと シンヨ... 系が ...ɴj... になり、口蓋同化されません。j(必要なら ç も)を口蓋分岐に含めてください。

修正案
 fn nasal_for_following(next_ipa: &str) -> &'static str {
@@
     } else if next_ipa.starts_with('ɲ')
         || next_ipa.starts_with("dʑ")
         || next_ipa.starts_with('ʤ')
         || next_ipa.starts_with('ɕ')
+        || next_ipa.starts_with('j')
+        || next_ipa.starts_with('ç')
         || next_ipa.starts_with("ɡʲ")
         || next_ipa.starts_with("kʲ")
     {
         "ɲ" // palatal assimilation
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stationapi/src/domain/ipa.rs` around lines 224 - 231, The palatal
assimilation branch that returns "ɲ" (the conditional checking
next_ipa.starts_with(...) in stationapi/src/domain/ipa.rs) currently omits the
palatal glide 'j' (and optionally 'ç'), so sequences like シンヨ... become ...ɴj...
instead of assimilating; update that conditional (the block inspecting next_ipa)
to also check for next_ipa.starts_with('j') (and add 'ç' if desired) so those
cases are treated as palatal and return "ɲ".

273-277: ⚠️ Potential issue | 🟠 Major

有声破擦音の促音判定が現行マッピングと不一致です。

Line 275 の starts_with("d͡") は、このファイル内の 系表記( / ʤ)に一致しません。ッジ 系の重子音化が意図どおり動かないため、条件を揃えるべきです。

修正案
-                    if next_ipa.starts_with("t͡ɕ")
-                        || next_ipa.starts_with("t͡s")
-                        || next_ipa.starts_with("d͡")
-                    {
+                    if next_ipa.starts_with("t͡ɕ")
+                        || next_ipa.starts_with("t͡s")
+                    {
                         output.push('t');
+                    } else if next_ipa.starts_with("dʑ") || next_ipa.starts_with('ʤ') {
+                        output.push('d');
                     } else {
                         let (onset, _) = split_onset(next_ipa);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stationapi/src/domain/ipa.rs` around lines 273 - 277, The voicing-affricate
check uses next_ipa.starts_with("d͡") which doesn't match the file's "ジ"
mappings (dʑ / ʤ), so update the condition in the block that currently contains
next_ipa.starts_with("t͡ɕ") || next_ipa.starts_with("t͡s") ||
next_ipa.starts_with("d͡") to instead check the actual mapped symbols, e.g.
next_ipa.starts_with("dʑ") || next_ipa.starts_with("ʤ") (keep the t͡ɕ and t͡s
checks as-is) so the sokuon handling that pushes 't' behaves consistently with
the rest of the mapping.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 224-231: The palatal assimilation branch that returns "ɲ" (the
conditional checking next_ipa.starts_with(...) in stationapi/src/domain/ipa.rs)
currently omits the palatal glide 'j' (and optionally 'ç'), so sequences like
シンヨ... become ...ɴj... instead of assimilating; update that conditional (the
block inspecting next_ipa) to also check for next_ipa.starts_with('j') (and add
'ç' if desired) so those cases are treated as palatal and return "ɲ".
- Around line 273-277: The voicing-affricate check uses
next_ipa.starts_with("d͡") which doesn't match the file's "ジ" mappings (dʑ / ʤ),
so update the condition in the block that currently contains
next_ipa.starts_with("t͡ɕ") || next_ipa.starts_with("t͡s") ||
next_ipa.starts_with("d͡") to instead check the actual mapped symbols, e.g.
next_ipa.starts_with("dʑ") || next_ipa.starts_with("ʤ") (keep the t͡ɕ and t͡s
checks as-is) so the sokuon handling that pushes 't' behaves consistently with
the rest of the mapping.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e028ae0-d79e-4339-bbb2-eaf540a073dd

📥 Commits

Reviewing files that changed from the base of the PR and between 28d5446 and 206a36a.

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

claude and others added 3 commits March 5, 2026 13:42
…icate gemination

- Add 'j' and 'ç' to palatal assimilation check in nasal_for_following
  so ン before ヤ行/ヒ行 correctly produces ɲ (e.g. シンヨコハマ → ɕiɲjokohama)
- Fix sokuon (ッ) handling for voiced affricates: replace dead d͡ check
  with actual mapped symbols dʑ/ʤ, geminating with 'd' instead of 't'

@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.

🧹 Nitpick comments (1)
stationapi/src/domain/ipa.rs (1)

271-285: 有声破擦音の促音化ロジックに対する回帰テストを追加してください

Line 277-278 で dʑ/ʤ 分岐を修正していますが、対応するテスト(ッジ/ッジュ 系)が未追加です。今回の修正点に直結するケースを最低1件入れておくと再発防止になります。

🔧 追加例
 #[cfg(test)]
 mod tests {
     use super::*;
@@
     fn test_shin_yokohama() {
         // ン before ヨ(j) → ɲ (palatal assimilation)
         assert_eq!(katakana_to_ipa("シンヨコハマ"), "ɕiɲjokohama");
     }
+
+    #[test]
+    fn test_geminate_voiced_affricate_ji() {
+        // ッ + ジ(ʤi) は stop 部分のみ重子音化して dʤi
+        assert_eq!(katakana_to_ipa("エッジ"), "edʤi");
+    }
 
     #[test]
     fn test_empty() {
         assert_eq!(katakana_to_ipa(""), "");
     }

Also applies to: 345-550

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stationapi/src/domain/ipa.rs` around lines 271 - 285, The geminate-handling
branch for Phoneme::Geminate special-cases voiced affricates (the dʑ/ʤ branch in
the Phoneme::Geminate block that uses find_next_regular and split_onset) but
there's no regression test for the corrected behavior (e.g., geminated 'ッジ' /
'ッジュ' cases); add at least one unit test that constructs an input IPA sequence
containing a geminate before dʑ or ʤ, invokes the code path that calls
Phoneme::Geminate (so find_next_regular and split_onset are exercised), and
asserts the output contains the expected doubled onset ('d' emitted) to prevent
regressions. Ensure the test targets the same logic area (the Phoneme::Geminate
handling) and includes both 'ッジ' and 'ッジュ' variants or at minimum one
representative case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 271-285: The geminate-handling branch for Phoneme::Geminate
special-cases voiced affricates (the dʑ/ʤ branch in the Phoneme::Geminate block
that uses find_next_regular and split_onset) but there's no regression test for
the corrected behavior (e.g., geminated 'ッジ' / 'ッジュ' cases); add at least one
unit test that constructs an input IPA sequence containing a geminate before dʑ
or ʤ, invokes the code path that calls Phoneme::Geminate (so find_next_regular
and split_onset are exercised), and asserts the output contains the expected
doubled onset ('d' emitted) to prevent regressions. Ensure the test targets the
same logic area (the Phoneme::Geminate handling) and includes both 'ッジ' and
'ッジュ' variants or at minimum one representative case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5ac8bc05-d568-41d3-95ab-cb0bcb635dae

📥 Commits

Reviewing files that changed from the base of the PR and between 206a36a and b73c82a.

📒 Files selected for processing (2)
  • stationapi/proto
  • stationapi/src/domain/ipa.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • stationapi/proto

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 19-23: The current code silently skips unknown characters (calling
lookup_single and only pushing on Some, using result.push) which yields
partially broken IPA; modify the converter (the function that iterates chars and
calls lookup_single) to detect unknown characters and propagate that by either
returning Option/Result (e.g., return None or Err on any lookup_single == None)
or by pushing an explicit None token into the result and exposing a detection
flag; update the loop that uses lookup_single and result.push (and the similar
block at lines 27-28) so unknown characters are not silently dropped but instead
cause a fallback/notification path to be returned to the caller.
- Around line 271-283: The geminate handling in Phoneme::Geminate currently
appends the entire onset from split_onset(next_ipa), which causes palatalized
onsets like "kʲ" to be duplicated as "kʲkʲ"; change the logic in the
Phoneme::Geminate branch (the block using find_next_regular, next_ipa,
split_onset, and output) so that instead of output.push_str(onset) you compute
and append only the base consonant (e.g., the first base letter of onset with
diacritics/secondary symbols removed) — for example derive a base_consonant from
onset by stripping palatalization markers like 'ʲ' and any combining/modifier
characters and then call output.push_str(&base_consonant); keep the existing
special-case handling for affricates (t͡ɕ, t͡s, dʑ, ʤ) intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 810d9e49-da0e-46dc-a6b8-42f103c8247f

📥 Commits

Reviewing files that changed from the base of the PR and between b73c82a and 42bd211.

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

Comment thread stationapi/src/domain/ipa.rs Outdated
Comment thread stationapi/src/domain/ipa.rs
claude added 2 commits March 5, 2026 14:07
… onsets

- Change katakana_to_ipa to return Option<String>, returning None when
  input contains characters that cannot be converted instead of silently
  dropping them.
- Fix geminate (ッ) handling for palatalized onsets: only duplicate the
  base consonant (e.g., ッキョ → kkʲo) instead of the full onset
  including palatalization marker (was producing kʲkʲo).
- Update all call sites to use the new Option return type.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 68-71: The IPA mapping for the ジ行拗音 is inconsistent: ('ジ','ャ') =>
"dʑa" and ('ジ','ュ') => "dʑɯ" use dʑ but ('ジ','ョ') => "ʤo" uses ʤ; update the
('ジ','ョ') mapping to use "dʑo" so all three entries ('ジ','ャ'), ('ジ','ュ'),
('ジ','ョ') consistently use dʑ in the IPA mapping in ipa.rs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 230e3589-fe3e-43c1-8288-eb1be85512a6

📥 Commits

Reviewing files that changed from the base of the PR and between 42bd211 and c2bc39f.

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

Comment thread stationapi/src/domain/ipa.rs Outdated
('ジ','ョ') was using "ʤo" while ('ジ','ャ') and ('ジ','ュ') used "dʑ".
Updated to "dʑo" for consistency.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ
@TinyKitten

Copy link
Copy Markdown
Member Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Reviews resumed.

@TinyKitten

Copy link
Copy Markdown
Member Author

@coderabbitai 残指摘を教えてください

@coderabbitai

coderabbitai Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# List all review comments on PR `#1410`
gh pr view 1410 --repo TrainLCD/StationAPI --json reviews,comments

# Also get review comments (inline)
gh api repos/TrainLCD/StationAPI/pulls/1410/comments --paginate | jq '[.[] | {id: .id, path: .path, line: .line, body: .body, user: .login, html_url: .html_url}]'

# Get issue-level comments
gh api repos/TrainLCD/StationAPI/issues/1410/comments --paginate | jq '[.[] | {id: .id, body: .body, user: (.user.login), html_url: .html_url}]'

Length of output: 58047


@TinyKitten これまでの指摘を確認しました。現状は以下の通りです。


✅ 対応済みの指摘(全6件)

箇所 内容 対応コミット
stationapi/proto サブモジュールSHAがリモートで解決不能でCIブロック d81ce84
ipa.rs L256 nasal_for_followingj 系が未分類(シンヨ → ɴj になる問題) d81ce84〜d6c27a1
ipa.rs L283 ッジの促音化で starts_with("d͡") がマッピングと不一致 d81ce84〜d6c27a1
ipa.rs L22 未知文字をサイレントスキップして部分的なIPAを返す問題 c964915
ipa.rs L293 促音で拗音オンセット全体を重ねて kʲkʲ になる問題 c964915
ipa.rs L68–71 ('ジ','ョ') のみ ʤo(他は )で表記不整合 2ca98e6

⚠️ 残指摘(1件 · Nitpick)

stationapi/src/domain/ipa.rs

ッジ / ッジュ の有声破擦音促音化に対する回帰テストが未追加です。dʑ/ʤ 分岐の修正に直結するケースを最低1件追加しておくと、将来的な再発防止になります。

#[test]
fn test_geminate_voiced_affricate_ji() {
    // ッ + ジ(dʑi) → stop部分のみ重子音化して ddʑi
    assert_eq!(katakana_to_ipa("エッジ"), Some("eddʑi".to_string()));
}

🔄 進行中

最新コミット (2ca98e6) に対するレビューが現在進行中です(まもなく結果が投稿されます)。

@TinyKitten

Copy link
Copy Markdown
Member Author

@coderabbitai 後出しジャンケンが多すぎますよ。まとめて指摘するように善処してください。

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 194-195: コメントと実装が不一致しているため、関数 split_onset
のドキュメントを実装に合わせて書き直してください:関数は常に (&str, &str) を返すので「vowel 開始時は
None」と書かれている説明を削除し、母音開始時は onset が空文字列 ("") で remainder
は元の文字列を返す、という旨に変更してください(関数名 split_onset を参照して対象箇所を修正)。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ffeb2790-65dd-4581-8950-a6837d4e0af0

📥 Commits

Reviewing files that changed from the base of the PR and between c2bc39f and 2ca98e6.

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

Comment thread stationapi/src/domain/ipa.rs Outdated
@coderabbitai

coderabbitai Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

Tip

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

@TinyKitten ご指摘、誠に申し訳ございません。レビューコメントを小出しにしてしまい、ご不便をおかけしました。

今後は、レビュー時にすべての指摘をまとめて一度に提示するよう努めます。後から追加で指摘することのないよう、初回レビューで網羅的に確認するよう改善いたします。


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

Timestamp: 2026-03-05T14:23:40.539Z
Learning: In the TrainLCD/StationAPI repository, the maintainer TinyKitten strongly prefers that ALL review issues be raised together in a single comprehensive review pass. Do NOT raise additional issues incrementally across multiple review rounds after the initial review (no "後出しジャンケン"). Ensure the first review is exhaustive and complete.

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.

The comment said "or None if starts with a vowel" but the function
returns (&str, &str), with an empty onset when the string starts
with a vowel.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ

@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: 1

🧹 Nitpick comments (1)
stationapi/src/domain/ipa.rs (1)

561-571: ッジ 系は語中の回帰テストを1件追加すると安心です

現状の カッジ / カッジュ に加えて、エッジ のような語中ケースも固定しておくと今後の回帰を防ぎやすいです。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stationapi/src/domain/ipa.rs` around lines 561 - 571, Add a regression test
for geminate "ッジ" in medial position by extending the test suite (near
test_geminate_ji and test_geminate_ju) to include a case like ipa("エッジ") and
assert the expected output (e.g., "edʤi"); update the test function names or add
a new test function (e.g., test_geminate_ji_medial) so the ipa(...) behavior for
in-word gemination is covered and protected from future regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 289-293: 現在の分岐は onset が複数子音(例: "dz")のとき
strip_secondary_articulation(onset) で得た base を丸ごと output.push_str してしまい "dzdz…"
のようになるので、base の先頭の基底子音のみを重ねるよう修正してください — 具体的には現在の output.push_str(&base)
を、strip_secondary_articulation(onset) の結果から先頭の文字だけを取り出してそれを push する処理に置き換え(たとえば
base.chars().next() を使って先頭文字を取得してから push
する)、onset/split_onset/strip_secondary_articulation の既存変数を活かす形で実装してください。

---

Nitpick comments:
In `@stationapi/src/domain/ipa.rs`:
- Around line 561-571: Add a regression test for geminate "ッジ" in medial
position by extending the test suite (near test_geminate_ji and
test_geminate_ju) to include a case like ipa("エッジ") and assert the expected
output (e.g., "edʤi"); update the test function names or add a new test function
(e.g., test_geminate_ji_medial) so the ipa(...) behavior for in-word gemination
is covered and protected from future regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1345d0ab-a378-42fd-bdf5-37424e0a1e0a

📥 Commits

Reviewing files that changed from the base of the PR and between 2ca98e6 and c75b6a1.

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

Comment thread stationapi/src/domain/ipa.rs
For onsets like "dz", strip_secondary_articulation returns the full
string, causing "dzdz..." duplication. Now only the leading character
of the base is pushed, matching the intended gemination behavior.

https://claude.ai/code/session_01Pjo9E2fzdLZEkvNqxXAPeQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants