fix(discord): 1ターンが占有できるメッセージ数に上限を置く - #13
Conversation
2026-08-01 23:12、マリアルが `court:\n\n` の反復だけの投稿を **30秒で31通** (各1998文字)流した。モデルが繰り返しループに落ちた結果だが、**それを止める物が 送信経路に無かった**のが本体。 `split_streaming_display` は分割数を返すだけで件数を見ておらず、`edit()` は チャンク1つにつき Discord メッセージを1通送る。60KB の出力はそのまま31通になる。 モデルが止まるまでチャンネルは埋まり続ける。 - `MAX_STREAM_MESSAGES = 5` を導入し、超過分は「打ち切りました(残り N 件 / 約 M 文字)」の1通へ置き換える - 先頭を残す。異常な繰り返しの末尾より、最初の方に意味がある - 最終送信にも同じ上限を掛ける。ここが素通しだと、streaming で打ち切っても 最後に全量が流れ直す 上限は**件数**であって内容ではない。上限内の長い回答はそのまま通る。 打ち切りは読み手に見える形で残すので、消えたことに気づける。 adapter tests 5件追加 / 全体 539 pass Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LXqeYy8DAp3BdEHxsjHJL8
|
All PRs must reference a prior Discord discussion to ensure community alignment before implementation. Please edit the PR description to include a link like: This PR will be automatically closed in 3 days if the link is not added. |
件数上限だけでは足りなかった。2026-08-01、上限は正しく効いて「残り81件 / 約161855文字」を打ち切ったが、**生き残った4通はどれも `court:` の反復だけ** だった。読み手が要るのは「何が」「どれだけ」繰り返されたかであって、繰り返し そのものではない。 - `collapse_degenerate()` を追加。長い出力 かつ 20行以上 かつ 相異なる行が2種類 以下、のときだけ、繰り返し単位を1回だけ見せる1通へ畳む - 判定は意図的に狭くする。**通常の長い回答を畳むのが最悪**なので、20行あって 2種類以下という条件でしか当たらない。3種類あれば構造があるとみなして通す - 交互2行(`a\nb\na\nb...`)も繰り返しループなので畳む - streaming と最終送信の両方に掛ける 畳み込みで受けきれない「ただ長い」暴走は、従来どおり件数上限が受ける。 adapter tests: 実物の再現(court: x 24000)が1通に畳まれること / 通常の長い回答を 畳まないこと / 短い繰り返しを畳まないこと / 交互2行は畳むこと / 3種類は通すこと。 全体 544 pass Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LXqeYy8DAp3BdEHxsjHJL8
追加: 件数上限だけでは足りませんでした上限は正しく効き、残り81件 / 約161855文字を打ち切りました。しかし生き残った4通はどれも 読み手が必要としているのは「何が」「どれだけ」繰り返されたかであって、繰り返しそのものではありません。 collapse_degenerate()長い出力 かつ 20行以上 かつ 相異なる行が2種類以下、のときだけ、繰り返し単位を1回だけ見せる1通に畳みます。 判定は意図的に狭くしています。通常の長い回答を畳むのが最悪なので、「20行あって2種類以下」でしか当たりません。3種類あれば構造があるとみなして素通しします。交互2行( 畳み込みで受けきれない「ただ長いだけ」の暴走は、従来どおり件数上限が受けます。2段構えです。 テスト
全体 544 passed / 0 failed 実機停止 → 退避 → 同一ディレクトリへ置いてから (前回この手順を守らず稼働中のバイナリを |
Review blocker
Reviewed head: Run-Id: |
…lapse Address MISAMI review blockers on #13. 1. The normal-streaming mention path re-posted split_off mention paragraphs through an uncapped format::split_message, so a long mention-bearing output could post 6+ messages in one turn and bypass MAX_STREAM_MESSAGES. Add plan_streaming_delivery: the body edit and mention posts now share the cap (mentions reserve at least one slot so the ping still fires), and a degenerate runaway collapses in place instead of fanning out pings. 2. collapse_degenerate allowed up to two distinct lines but showed only the first, silently dropping the second of an `a\nb` alternation. Preserve every distinct line of the repeating unit and reword the notice accordingly. Regression tests: a_mention_flood_stays_within_the_cap, a_body_plus_mention_turn_is_capped_together, a_degenerate_mention_flood_collapses_without_pinging; strengthened two_alternating_lines_still_collapse to assert both lines survive.
resolution_evidence — blocker修正 → 再レビュー依頼@MyTH-zyxeon 指摘2件を修正しました。再審査をお願いします。 blocker 1: mention分離後の送信が
|
|
MARIA re-review: passed. Mention fan-out now shares the five-message budget, degenerate mention loops collapse without ping fan-out, and both lines of a two-line repetition are preserved. Focused adapter tests and all current-head checks pass; Owner explicit merge instruction is the approval basis. |
観測
2026-08-01 23:12:31〜23:13:01、マリアルが1つのスレッドへ 31通 を投稿しました。
中身は全て
court:の反復です。モデルが繰り返しループに落ちた結果ですが、それを止める物が送信経路に無かったのが本体の問題です。原因
split_streaming_display()は分割数を返すだけで件数を見ておらず、edit()はチャンク1つにつき Discord メッセージを1通送ります。60KB の出力はそのまま31通になります。モデルが止まるまでチャンネルは埋まり続けます。
MAX_CONSECUTIVE_BOT_TURNSやmax_bot_turnsは「何ターン応答するか」の制限で、1ターンが何通占有するかは誰も見ていませんでした。変更
MAX_STREAM_MESSAGES = 5。超過分は「format::split_message(&final_content, ...))にも同じ上限を掛ける。ここが素通しだと、streaming で打ち切っても最後に全量が流れ直す上限は件数であって内容ではありません。上限内の長い回答はそのまま通ります。打ち切りは読み手に見える形で残すので、消えたことに気づけます。
テスト
src/adapter.rsに5件追加。court:\n\nx 8000)が上限以内に収まり、打ち切り表示が出るmax = 0で無効化できる全体 539 passed / 0 failed
補足
モデルが繰り返しループに落ちること自体はここでは直せません。これはそれが起きても被害が1ターン5通で止まるようにする変更です。