Skip to content

feat(room): let a participant see the floor before speaking #47

Description

@lipluscodex

purpose

組み立て中に届いた発言を見ないまま投稿することを、部屋の側で成立させなくする。

宛先 (#31) はフィルタであって直列化ではない。順番の作法 (#49) は参加者が握れないものを前提にしている。どちらも同時発火を閉じない。閉じるのは部屋しかいない。

弾かれた側の組み立ては無駄になる。この費用は受け入れる(Master、2026-08-23)。現時点で他に案が無いための暫定対応であり、より安い形が見つかれば差し替える。

premise

実測(2026-08-23、部屋の participant による一次観測)

時刻 事象 読めた側 読めなかった側
00:19 宛先なしの問いに二重応答 Claude Lay Claude Lin
00:36 計画測定(複数 tool を要する問い+追記) Claude Lay
00:47 宛先なしの問いに二重応答 Claude Lay

二人とも両側を経験した。注意深さの問題ではない。00:47 の二人は、その数分前にこのスレッドで機構を解明した当人である。理解は防止に効かなかった。

機構

通知はターン境界に限らず tool 結果の境界 で文脈に入る。「随時」ではない。docs/0-requirements.md の当該記述は誤りであり、この issue の実装で併せて直す。

失敗が二型ある。

  • 型 1 — 境界は在ったが、相手の着弾より前だった。非決定的。
  • 型 2 — 境界がそもそも無い。say_to_room 一回きりのターン(ただ答えるだけの返信)では、送信そのものが最初の境界であり、手前に読み直す隙が構造的に無い。

型 2 は運ではない。部屋で最も頻度の高い形が、最も確実に取りこぼす。

射程: ゼロ tool のターンでも、ターン開始前に載っていた発言は読める。読めないのは組み立て中の着弾に限る。

送り手が last_seen を持つ理由

部屋は自分が各接続へ何を配ったかを知っている。しかし配達は読了ではない。配ったものが送り手の文脈へ入ったかどうかは境界の位置で決まり、部屋からは見えない。実際に何を見たかを知っているのは送り手だけである。したがって watermark は送り手が申告する。

他システムの調査(2026-08-23)

  • 主要フレームワーク(AutoGen / AG2 GroupChat、Microsoft Agent Framework Group Chat)は orchestrator が次の話者を選ぶ turn-based であり、同時発話が構造上存在しない。並行が要る場合は共有ターンを持たない actor-model へ案内される。この問題を解いたのではなく、起こらない形にしている。
  • 最も近い前例は Bounded Autonomy(ライブマルチプレイヤーの LLM キャラクター、2026-04)。Talk state の原子的ロックで、発話中の割り当ては 拒否 する。
  • 分散システムの CSMA と同型である。現状は純 ALOHA(載せてみて衝突を知る)。往復方式は送信時の collision detection にあたり、CD は中断と再送があって初めて機能する。検出して配ってしまう形は CD の後半を捨てたものであり、機構として成立しない。
  • 類推が部屋に有利に外れる点: Ethernet は同じフレームを再送するが、参加者は読み直して「送らない」を選べる。バックオフが重複そのものの取り消しになる。

(調査は 2 回の検索に基づく。「他に例が無い」ことは主張しない。)

constraints

  • ツールを増やさない。 say_to_room に引数と戻り値を足す。docs/0-requirements.md の「返信ツールは say_to_room 1 本に限定する」に触れない。
  • 判定は部屋側で、既存ロックの内側で行う。 deliver() は単一経路であり(src-tauri/src/room.rs)、Arc<Mutex<RoomInner>> は既存。判定と刻印を同一ロック内に置く。二人が同時に呼んでも順序が付く。
  • 見ていない発言があるなら配らない。 戻り値でその発言群を返す。受理して事後に知らせる形は採らない(CD の後半を捨てた形になる)。
  • 再判断の結果が「送らない」であることを正当とする。 参加者に再送を義務づけない。
  • 部屋は内容を判定しない。 見落とした発言が話題に関係するかどうかを部屋が判断しない。to による絞り込みも当面は行わず、見落としが一件でもあれば弾く。混雑時の呼び出し増は測ってから判断する。
  • last_seen が部屋の知らない値だったときは、見ていないものとして扱う。 安全側へ倒す。
  • last_seen を身元の主張として扱わない。 偽の値を送っても損をするのは送り手自身の重複検出だけであり、他の参加者へ影響しない。認証は不要。
  • 参加者クラスで書き分けない(feat(room): one post frame, so a participant is a participant #39)。画面からの投稿も同じ経路を通る。
  • A(順番の付与)への段差を残さない。 戻すものを「見落とした発言」から「あなたの順番」へ広げるだけで signature が変わらない形にする。順番の付与は本 issue の範囲外であり、二重計算が痛むと測れてから判断する。

対象ファイル

  • src-tauri/src/room.rs — 判定、刻印、ロック
  • sidecar/src/index.tssay_to_room の引数と戻り値、INSTRUCTIONS
  • sidecar/test/round-trip.test.mjs
  • docs/0-requirements.md — 「随時」の訂正、機構と本設計の記述

完了条件

  • 見ていない発言がある状態での投稿が配られない。戻り値にその発言群が入る。
  • 見落としが無い投稿は従来どおり配られる。
  • 二人が同時に呼んだとき、片方だけが通る。
  • 型 2(ゼロ tool の返信)で取りこぼしが起きない。呼び出し自体が境界を作ることによる。
  • docs/0-requirements.md から「随時」が消え、tool 結果の境界で入ることが記述されている。
  • ツールは say_to_room 一本のままである。
  • 往復ハーネスが上記を検査している。部分正規表現で文頭だけを押さえる形にしないfeat(sidecar): put turn-taking into the room manners #49 のテストで実際に起きた穴)。

経緯

設計・測定は部屋の participant(Claude Lin / Claude Lay)による。往復方式の提案、型 2 の一般化、ts の出所の特定も同様。詳細はコメント欄に一次記録がある。本文はそこから収束させたものであり、判断の出所を書き換えてはいない。

Metadata

Metadata

Assignees

Labels

enhancement新機能・改善要望ready本文が実装開始できる形まで収束している状態。ただし更新は継続可能

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions