初めての待受けの起点を早める

初参加の読み始め位置を「参加した時点」から「その日の 0 時と 6 時間前の古い方」に変える。テストへの影響を先に洗い出す

📅 作成: 2026-09-21 / 更新: 2026-09-22

i260920-01(利用者からの提案)の実装計画。一度サーバー本体 (server.mjs・store.mjs・time.mjs)だけ先に直して動作確認したところ、既存のテストが連鎖的に壊れることが分かった。その洗い出しと対策を先に固めてから、あらためて実装する。

目次

  1. 何を作るか
  2. 分かった問題 (テストへの影響)
  3. 対策
  4. 作るものと確かめること

何を作るか

初めての接続 (カーソルが無い状態)の起点を、現行の「参加した時点 (getMaxSeq)」から、「その日の 0 時」と「6 時間前」のうち古い方に変える。深夜早い時間帯 (例: 0 時台)に初めて繋いだ場合、「その日の 0 時」だけだと直近 1 時間程度しか遡らない。6 時間前を下限として併記することで、日をまたいだ直後でも一定の幅を確保しつつ、日中は「その日の 0 時」で当日分をまとめて拾える形になる。

変える箇所

server.mjs の getCursor(...) ?? getMaxSeq(...) という起点ロジック (handleJoin・handlePoll の 2 か所)。getMaxSeq(roomId) の代わりに、新しい起点 (「0 時」と「6 時間前」の古い方より前の最後の msg_seq)を返す関数に差し替える。

関連する既存課題内容
i260909-01(済)現行の「参加した時点=getMaxSeq」という設計そのものを扱った課題。読んでいても初回は踏むという報告を受け、wait 起動時の案内 (recent の見本を出す)を足す形で対応済み。今回の提案は、この設計自体を変える恒久対策の位置づけ
i260908-01(済)getCursor(...) ?? getMaxSeq(...) という起点ロジックの実装箇所を扱ったバグ修正。今回変更するのは同じ箇所

分かった問題 (テストへの影響)

テストスイート全体が「初参加=いまから (未来分のみ)」という前提でルームを使い回している。実装を入れた瞬間、既存テストが連鎖的に壊れた。public ルームだけでもテスト内で数百件の発言がすでに積まれており、新しい参加者が「6 時間前・当日 0 時のどちらか古い方」から読むと、他のテストが積んだ過去分をすべて未読として受け取ってしまう。

実際に確認できた壊れ方の例 (tests/server.test.mjs)。

テスト名壊れ方
since を省略すると、参加した時点から待つ「過去のぶんは返らない」の前提が崩れ、それまでのテストが積んだ 27 件が pending/messages に出る
位置はルームごとに別々同様に「dev は初めてなので今から」が崩れる

この 2 件以外にも波及する可能性が高い(未確認)。新規 connector_id で join/poll を呼び「空で返る」ことを前提にしているテストは、テストファイル全体でいくつあるか数え直す必要がある。

なぜ気づかなかったか

これまでの初回起点 (getMaxSeq=いま)は、時刻に依存しない値だったため、テスト同士が同じ public ルームを共有していても互いに干渉しなかった。今回の変更は時刻ベースの起点を持ち込むため、「同じルームを使い回すテスト設計」自体と相性が悪い。

対策

案を 2 つ比較する。

案内容長所短所
A (推奨)
テストごとに専用ルーム
初回起点の影響を受けるテストは、room_id をテスト固有の使い捨て名にする (他のテストの発言と混ざらない)本番のロジックには手を入れない。テストの独立性が上がる (本来望ましい設計)該当テストの洗い出しと書き換えが要る (件数次第で作業量が増える)
B
テスト用に基準時刻を差し替え可能にする
initialSeq が使う「いま」を注入可能にし、テストから「6 時間より前」を明示的に作るルームの使い回しを変えずに済む本番コードにテスト専用の分岐が増える。「同期 API は〜」と同種の、プロダクションコードへのテスト都合の混入になりやすい

A を採用 (利用者の承認済み)。理由: 本番ロジックを単純に保てること、そして「テストが同じルームを共有して過去ログに依存する」設計自体が、今回の機能追加とは無関係にも脆さを抱えていたため (ついでに直す価値がある)。

A の具体的な進め方

  1. tests/server.test.mjsを通しで読み、「新規 connector_id で参加 → 空を期待する」テストを洗い出す
  2. 該当テストのうち、room_id を明示していないもの (=既定の public を使っているもの)に、そのテスト専用の room_id を明示する。命名は既存の使い捨てルームの慣習 (sandbox-other・sandbox-archived)に合わせ、sandbox-cursor-* にした(sandbox-cursor-empty・sandbox-cursor-recent・sandbox-cursor-room2)
  3. public・dev など複数テストで共有されているルーム名は、よほど「共有されていることを検証したい」テスト (在席・複数ルーム待受け等)以外では使わない方針にする

ルームを分けただけでは足りなかった。「初参加は空」と主張していた既存テストの前提自体が、今回の機能追加 (直近分は初参加でも届く)と正面から矛盾する。ルームを分離したうえで、アサーションを新しい仕様 (直近の投稿は初参加でも届く)に合わせて書き換えた。「空のルームでは、初めての参加でも何も届かない」 (本当に何も無い場合)と、「直近に投稿された分は、初めての参加でも届く」 (i260920-01 の本題)の 2 本に分けている。

作るものと確かめること

ファイル変えること
src/server/time.mjsjstTodayMidnight() を追加 (その日の 0 時を nowJst と同じ書式で返す)
src/server/store.mjsgetSeqBefore(roomId, ts) を追加 (ts より前の最後の msg_seq。1 件も無ければ 0)
src/server/server.mjsinitialSeq(roomId) を追加し、handleJoin・handlePoll の getMaxSeq(...) フォールバックを置き換える
tests/server.test.mjs・tests/client-wait.test.mjs2 章の対策 A に沿って、影響を受けるテストのルームを使い捨て名にする
notes/40_issues/issues.html実装後、i260920-01 を完了に更新

確かめること

  1. 全テストが通ること (このセッションで確認した 2 件を含め、影響を受ける分すべて)
  2. i260909-01 の案内文 (「参加より前の発言は待ちません」)を、新しい起点に合わせて見直す

境界 (ちょうど 0 時・ちょうど 6 時間前)専用の単体テストは見送った。時刻を差し替え可能にするテスト専用フックを本番コードに足すと、3 章で退けた「案 B」 (テスト都合の分岐を本番に混入させる)に逆戻りするため。getSeqBefore 自体は ts を素直に受け取る関数なので、境界の正しさ (sent_at < ts)はコード読解で確認できる。