# 部屋を見る・部屋に入る — #1456 v3

v2 (#1476) でサーバ側に会話ルームができた。書けるし、CLI から読める。
**アプリからは見えない。**

テーブルを回したユーザーが受け取るのは `agreed · 4 turns` の一行だけで、会話そのもの —
この機能が生み出した唯一の成果物 — はどこにも表示されない。部屋の id すら知らされないので、
`mulmoterminal room read <id>` を打つこともできない。v2 は「記録を残した」が「記録を見せる」を
出していない。ここを埋める。

あわせて、v2 の残件のうち **部屋の再利用と命名** を同じ PR で入れる。理由は独立した機能では
ないから: 部屋が一覧に出るようになると、毎回新しい部屋を掘って捨てていく今の挙動が
そのままゴミの山として可視化される。見せるなら、選べて・名付けられて・消せる必要がある。

## やること

### サーバ

- `DELETE /api/rooms/:room` — same-origin ガード付き。部屋は毎テーブル1つ増えるので、
  一覧を見せるなら片付ける手段が要る。
- `listRooms()` の並び順を **doc と一致させる**。コメントは "newest activity first" と書いてあるのに
  実装は `localeCompare` のアルファベット順だった（#1476 の lint 修正で入った食い違い）。
  mtime の新しい順にする。返す形（`rooms: string[]`）は変えない — CLI が読んでいる。

### UI

- `RoomsOverlay.vue` — 他の全画面オーバーレイ（accounting / prs / files）と同じ形。
  左に部屋の一覧、右に会話、下に投稿ボックス。開いている間だけ `?since=` で差分ポーリング。
- ルートは `/rooms` と `/rooms/:room`。`CONTENT_ROUTES` **には入れない** — 部屋はワークスペースの
  コンテンツではなく、グリッドで起きていることの記録なので、`prs` と同じ扱い。
- `RoundTableMenu` に部屋の入力欄（既存部屋の `datalist` 付き）。**空なら新規**、
  書けばその部屋（既存なら会話が続く）。1つのコントロールで「再利用」と「命名」の両方を満たす。
- テーブル実行中は menu から **watch** で該当部屋を開ける。

### 読めなかったときの扱い

v2 で決めた線をそのまま延長する。API は 500 を返し、**どうするかは呼び手が決める**:

- round table runner → 直前のターンに縮退して会話を続ける（会話を殺さない）
- **オーバーレイ → エラーを出す**（人間が見ているので、空の会話に見せてはいけない）

そのために `useRooms.ts` を分ける: `loadRoom()` が結果型を返す primitive、
`fetchRoom()` は runner 用に握りつぶす薄いラッパ。HTTP の呼び出しは1箇所、方針は2つ。
投稿も同じで、`sendRoomMessage()` が成否を返し、`postRoomMessage()` が runner 用に捨てる。
人間が打った投稿が黙って消えるのは、runner のログが1行落ちるのとは別の重さ。

## やらないこと（#1456 に残る）

- runner をサーバへ移す（タブを閉じるとテーブルが止まる）
- role / @mention / 非同期の部屋
- 部屋の検索・エクスポート
