[Bug] WritingQuestion 生成で日英文数不一致時に無効な sentenceIndex が作成される
Resolved 💬 2 comments Opened Jan 25, 2026 by yoshizaki91 Closed Feb 12, 2026
概要
WritingQuestion の自動生成ロジックに2つの異なるコードパスがあり、一方のパスで Math.min() が適用されていないため、日本語と英語の文数が異なる場合に無効な sentenceIndex を持つ問題が作成される。
再現手順
- 会話練習で、日本語と英語の文数が異なる評価結果を得る
- 例: 日本語「絢美も大丈夫みたい。結構寝てくれたよ。」(2文)
- 例: 英語「Ayami seems fine too — she slept pretty well.」(1文 - em-dash は分割されない)
- Writing ページにアクセス
- 「結構寝てくれたよ。」の問題に回答
- 「理想的な表現」が表示されない
原因
2つの問題生成パス
| パス | ファイル | Math.min | step_id |
|------|----------|----------|---------|
| Background Job | process-jobs.ts:generateWritingQuestions | ✅ 使用 | NULL |
| Use Case | writing-use-cases.ts:generateQuestionsFromFeedbacks | ❌ 未使用 | 実際のID |
Background Job パス(正しい実装)
// process-jobs.ts:256
const pairCount = Math.min(japaneseSentences.length, englishSentences.length);
for (let i = 0; i < pairCount; i++) {
questions.push({ sentenceIndex: i, ... });
}
Use Case パス(バグのある実装)
// writing-use-cases.ts:240
const userSentences = splitBySentence(feedback.idealExpression);
for (let sentenceIndex = 0; sentenceIndex < userSentences.length; sentenceIndex++) {
// ❌ 英語の文数をチェックしていない
questions.push({ sentenceIndex, ... });
}
データベースの証拠
同じ source_feedback_id=15 に対して:
id | step_id | speaker | sentence_index | created_at
---|---------|---------|----------------|------------------
67 | NULL | user | 0 | 04:58:52 (Background Job)
80 | 32 | user | 0 | 04:58:54 (Use Case)
81 | 32 | user | 1 | 04:58:54 (Use Case) ← 無効!
- id=67: Background Job で正しく 1 問だけ作成
- id=80, 81: Use Case で誤って 2 問作成(sentence_index=1 は英語が存在しない)
関連する設計上の問題
1. 同じテキストを4回分割している
MessageFeedback
└── idealEnglish: "Ayami seems fine too — she slept pretty well."
├─[生成時] splitByEnglishSentence() → pairCount = min(2,1) = 1
├─[表示時] splitByEnglishSentence() → 再分割
├─[評価時] splitByEnglishSentence() → 再分割
└─[シャドー生成時] splitByEnglishSentence() → 再分割
2. speaker ベースのフィールド選択が4箇所に重複
process-jobs.tswriting-use-cases.tsqueries.tsshadowing-use-cases.ts
3. ユニーク制約がない
SELECT conname, contype FROM pg_constraint WHERE conrelid = 'writing_questions'::regclass;
-- (source_feedback_id, speaker, sentence_index) に対するユニーク制約がない
提案する修正
短期修正(このバグの修正)
writing-use-cases.ts:generateQuestionsFromFeedbacks に Math.min() を追加:
// User 問題
if (feedback.idealExpression && feedback.idealEnglish) {
const userSentences = splitBySentence(feedback.idealExpression);
const englishSentences = splitByEnglishSentence(feedback.idealEnglish);
const pairCount = Math.min(userSentences.length, englishSentences.length);
for (let sentenceIndex = 0; sentenceIndex < pairCount; sentenceIndex++) {
// ...
}
}
// Assistant 問題も同様に修正
長期修正(アーキテクチャ改善)
- WritingQuestion に
englishSentenceカラムを追加
- 生成時に英語テキストを保存
- 表示/評価/シャドー生成時の再分割を不要に
- ヘルパー関数の抽出
getIdealEnglishForSpeaker(feedback, speaker)を共通化
- ユニーク制約の追加
(source_feedback_id, speaker, sentence_index)に対してユニーク制約
影響範囲
- Writing ページ: 理想的な表現が表示されない問題
- Shadowing ページ: 対応する英語がない問題が生成される可能性
- 評価精度: sentenceIndex が無効な場合、間違った英語テキストで評価される
関連コミット
a9ebbbb1: WritingQuestion 自動生成を実装(R-4)8298c937: assistant 問題も生成(この時点で Use Case パスにバグ)b84d5503: splitByEnglishSentence アポストロフィ修正(別問題)4a503842: Shadowing sequence 順序修正(別問題)
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗