feat(account): make an account a thing that exists whether it is running - #54
Conversation
`TabConfig` を `Account` へ移し、同一性を id に置く。名前と色はアカウントの属性へ降り、`cli_kind` は読み手が居ないため落とした(#17)。`.mcp.json` の登録鍵はアカウント id から導出するため、改名しても稼働中のセッションの登録が迷子にならない。二重起動は「一つのアカウントは一つの部屋に一席まで」として拒否する。 - `config.rs` — `Account { id, name, command, args, cwd, hue }`。`tabs` を serde alias で読むため既存の `config.json` はそのまま移行でき、`cli_kind` は未知フィールドとして落ちる。 - `session.rs` — `RoomSeats`(account id → 席)。claim / hold / release は既存ロックの内側で行い、稼働判定は PTY へ問う。解放の呼び忘れで席が残る形にしない。 - `pty.rs` — 終了したセッションを map から外す。席の自己解放はこの liveness に乗っており、待機をロックの外へ出す副次的な直しも入る。 - `crates/mcp-config` — 登録鍵をアカウント id の関数へ。改名で鍵が動かないことをテストで押さえた。 部屋は変えていない。protocol も `room-participants` の意味も据え置きで、アカウントは画面と config の側の概念にとどまる。 Refs #53 Refs #17 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
アカウントを作成・編集・削除する面を入れ、名簿を「アカウント一覧 ⋈ 稼働中の名簿」として描く。突き合わせはアカウント id で行い、名前では結ばない。起動していないアカウントも名簿に並び、オフラインと分かる。 - ランチャの行がアカウントの行になった。名前・色・作業ディレクトリ・起動オプションはそのアカウントのものであり、編集したその場で保存する。起動時に宣言する値ではなくなった(#40 の機構をアカウントが置き換える)。 - 名簿は部屋の名簿をそのまま並べ、席を持たないアカウントを「未起動」として下に足す。宛先の選択肢は部屋の名簿だけを出所とするため、オフラインのアカウントは構造上そこへ出ない。 - 二重起動は画面でも理由を出して止める。判定の権威はアプリ側(`seated_accounts`)にあり、画面はそれを読むだけで自分の数え方を持たない。 - 新規アカウントの既定名は既存と重ならない番号を取る。同じ名前を名乗る参加者が並ぶ状態(#40)を既定値で作らない。 - 起動行のプレビューはアカウント id に追従するため、改名しても動かない。 Refs #53 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
実装と同一 PR で docs を追随させる。アカウント、一つのアカウントは一つの部屋に一席まで、`.mcp.json` の登録鍵をアカウント id から導出すること、既存設定からの移行を記述した。 - `docs/0-requirements.md` — 「参加の時点の名乗り」を「アカウント」へ置き換え。#40 の機構をアカウントが置き換えつつ目的を保つ理由、id と名前の役割分担、オフラインを名簿に出して宛先に出さない理由、席の規則が部屋に対して閉じていること(複数ルームの検討を先回りで潰さないため)を書いた。 - 参加者パネルの節が「名簿の出所は部屋の名簿だけ」と述べていた箇所を訂正した。宛先の選択肢の出所は部屋の名簿だけであり、名簿の列にはそれに加えて未起動のアカウントが並ぶ。 - 切り分け手順の 3 と 5 を、名簿にオフラインのアカウントが並ぶことと、鍵が名前では引けないことに合わせた。 - 未実装にアカウント面の実機確認を、決まっていないことに「人間をアカウントにするか」を足した。 - `README.md` — 対象ファイル一覧には無いが、この変更で偽になる文言(名前は起動のたびに選ぶ、鍵は名前由来、タブ設定として保存)を含むため同一 PR で直した。事実の追随のみ。 Refs #53 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
smileygames
left a comment
There was a problem hiding this comment.
セルフレビュー(auto モード / 人間チェックなし)
完了条件の照合
| #53 の完了条件 | 結果 |
|---|---|
| アカウントを作成・編集・削除できる。名前 / 作業ディレクトリ / 起動オプション / 色 | 満たす |
| 起動していないアカウントが名簿に並び、オフラインと分かる | 満たす(未起動表示) |
| オフラインのアカウントが宛先の選択肢に出ない | 満たす。下記のとおり構造上そうなる |
| 稼働中のアカウントが宛先の選択肢に出る | 満たす |
| 同じアカウントを同じ部屋で二重に起動できない。理由が画面に出る | 満たす |
改名しても .mcp.json 登録が迷子にならない |
満たす。テスト renaming_an_account_leaves_its_registration_where_it_was |
既存 AppConfig から移行できる |
満たす。serde alias |
| protocol が変わっていない | 満たす。親側で確認 |
cli_kind が消えている(#17) |
満たす |
「部屋を変えない」を親側で確認した
本 issue の最重要制約なので、報告ではなく差分で見た。
git diff --name-only origin/main...origin/issue-53-accounts に src-tauri/src/room.rs / sidecar/ / crates/room-floor/ が 1 件も現れない。PROTOCOL_VERSION は 4 のまま。
アカウントの概念が部屋の層へ漏れていない。
席の原子性を確認した
RoomSeats::claim(src-tauri/src/session.rs)は、単一のロック取得の内側で「取られているか」を判定して Seat::Starting を挿入する。判定と確保が割り込めない。
Seat::Starting は issue に無い着想であり、良い。 席の生存を PTY に問う設計だけだと、起動を決めてから PTY が生まれるまでの窓が空く。二つの起動が両方とも「PTY が無い=空席」と読む。Starting はその窓を塞いでおり、二つ目のプロセスが生まれる前に負けた側を弾く。
seated() が retain で死んだ席を掃くのも妥当。解放が呼び出しではなく問い合わせになっているので、解放し忘れでアカウントが締め出される経路が無い。rules/model/subtractive-structural-beauty.md の「実行が保証されない手順は構造へ置き換える」に沿う形。
席の規則が部屋を単位に書かれている
コード内コメントに次のとおりある。
a rule remembered as "an account runs once" would outlive the reason for it and block that case later, when nobody remembers why the line was drawn
指示どおり。機構は作られておらず、記述だけが部屋を単位にしている。
宛先の除外が構造上成り立っている
renderAddressees は participants(room-participants 由来=稼働中の接続)だけを読む。オフラインのアカウントは別系統で描かれるため、選択肢に入りようがない。フィルタで落としているのではなく、出所が違う。是認する。
移行
serde の #[serde(alias = "tabs")] 一行。cli_kind は未知フィールドとして serde が捨てる。移行コードが存在しない形になっており、subtractive-structural-beauty の binary に沿う。
対象ファイル超過(1 件、是認する)
src-tauri/src/pty.rs。席の自己解放が「このセッションは生きているか」を必要とし、終了した PTY が map に残り続けていたため所属判定が意味を持たなかった。追加は is_running() と、reader スレッドでのエントリ回収(wait() をロックの外へ出す変更を伴う)。
制約からの強制であり、機能追加ではない。端末表示にも終了ボタンにも触れていないことを差分で確認した。隣接 issue へ滲み出していない。
実機未確認(明示)
docs/0-requirements.md の未実装節に記載済み。阻却事由としない。
繰越
TabSessions { tab_id } に旧語彙が残る点を実装側が報告している。これは未使用の会話ログ永続化型であり、#48 が「既存の TabSessions 系はこのモデルに合わないため、流用ではなく作り直す」と既に定めている。新規起票は不要。
リリース種別
minor と判定する。config の on-disk 鍵が tabs → accounts へ変わり、アカウントの作成・編集・削除 UI と未起動表示が加わる。構造変更かつ user observable。
自己レビュー通過。auto モードのため人間チェックはなく、このままマージへ進む。
Closes #17
cli_kindに書き手も読み手も無くなっていた。アカウントへの移行でフィールドごと落とした。Closes #53
アカウントを、起動していなくても存在する durable な同一性として導入した。作る、残る、起動する、止める。名簿は「今つながっている人」ではなく「誰が居るか」を示す面になった。
変えたこと
TabConfigをAccountへ。 同一性をidに置き、名前・色・作業ディレクトリ・起動オプションはすべて編集できる属性へ降ろした。#40 が直した欠陥は「タブが起動の手段でしかなく、同一性を持てなかった」ことであり、同一性が無いところに名前を付ける唯一の形が「起動ごとに宣言する」だった。構造的な同一性ができたので名前と色はそこへ移り、起動時宣言では持ちようがなかったもの——動いていないアカウントにも名前と色がある——を得た。#40 の目的はより強い形で満たされている。名簿は「アカウント一覧 ⋈ 稼働中の名簿」。突き合わせはアカウント id で行う。 名前では結ばない。名前は衝突しうるものになり、稼働中に改名されることもあるため、名前で結べば両方の場合に別のアカウントを掴む。画面は部屋の名簿をそのまま並べ、席を持たないアカウントを「未起動」として足す。宛先の選択肢の出所は部屋の名簿だけであるから、オフラインのアカウントは構造上そこへ出ない。
一つのアカウントは一つの部屋に一席まで。 同じ誰かが一つの部屋に二つの接続で居ることを認めない。台帳(
RoomSeats)は掃除と確保を一度のロック取得で行い、二つの起動が同じ空席を通り抜ける形にしていない。理由は画面に日本語で出る。規則を「アカウントが一度だけ動く」と書かなかったのは意図である。ルームは今 1 つなので実装上は見分けが付かないが、複数ルームは検討事項として残っており、一つのアカウントが二つのルームで席を持つのは意図した形である。射程は機構から読めないため docs とコードのコメントに書いた。複数ルームは実装していない。
.mcp.jsonの登録鍵をアカウント id から導出。 名前が編集できるようになったため、名前由来の鍵は改名のたびに動く。稼働中のセッションの登録は古い鍵の下に取り残され、そのセッションを持つ CLI のコマンドラインには古いserver:タグが載ったままで、後から書き換える経路が無い。id は不変であるから改名の費用がゼロになる——名前を編集可能にできるのはこの性質による。#45 の刈り込み条件は維持した。既存
AppConfigの移行は serde の別名一つ。tabsをaccountsとして読み、cli_kindは未知フィールドとして落ちる。手元の作業ディレクトリと起動オプションは形が変わらないため、移行手続きを持つ必要が無かった。部屋は変えていない
src-tauri/src/room.rs/sidecar//crates/room-floorは 1 行も触っていない。PROTOCOL_VERSIONは 4 のまま、room-participantsは稼働中の接続を返し続け、#39 の接続キー設計にも #47 の床にも触れていない。アカウントは画面と config の側の概念にとどまっている。判断したこと
席の解放を誰かの呼び出しに委ねなかった。 解放を呼び忘れるとそのアカウントはアプリ再起動まで部屋へ入れなくなる。終了したセッションが PTY の一覧から外れることを稼働の定義にして、忘れうる解放そのものを消した。
登録鍵の読みやすさより同一性を採った。 id は不透明であるため、鍵は名前由来だったときより読みにくい。どのアカウントのものかはエントリ内の
LIPLUS_AGENT_NAMEから読む。鍵が読みにくいのは 1 回の参照で済み、鍵が動くのは登録が行方不明になることである。新規アカウントの既定名は既存と重ならない番号を取る。 同一性は id なので同名でも壊れないが、名指せることが名前の目的である。既定値が同じ名前の参加者を並べるのでは #40 の欠陥を既定で再現することになる。
範囲について
src-tauri/src/pty.rsは issue の対象ファイル一覧に無い。席の自己解放が「セッションが生きているか」を必要とし、終了した PTY が一覧に残り続けていたため入れた(is_runningと、reader スレッドでの回収)。待機をロックの外へ出す直しが副次的に入っている。アカウントごとの端末表示や終了ボタン(issue の対象外)へは踏み込んでいない。README.mdも対象ファイル一覧に無いが、この変更で偽になる文言(名前は起動のたびに選ぶ / 鍵は名前由来 / タブ設定として保存)を含むため同一 PR で直した。事実の追随のみ。design/は触っていない。canvas にはアカウント作成 UI が無く、差分はさらに増えた。design/README.mdの方針どおり実装側を正とし、キャンバスの更新は #46 に残る。検証
CI の 5 コマンドをローカルで実行し、すべて通っている(
npm run build/sidecar:check/sidecar:test/cargo check --target x86_64-pc-windows-gnu/cargo testは mcp-config 15 件・room-floor 11 件)。crates/mcp-configに「改名しても登録が動かない」検査を追加した。実機での操作は未確認。docs の「未実装」に記載済み。