feat(history): delete a topic from the list (topic-index crate, room_log, room.rs, session.rs, pty.rs, index.html, main.ts, styles.css, CI, docs) - #120
Conversation
…es/topic-index) 索引とディレクトリの照合を `crates/topic-index/` へ出した。`docs/0-requirements.md` の「テストの配置」が既に正しい形として名指していたもので、`AppHandle` への依存を 外せば `cargo test` の対象になる。#119 の削除がこれを load-bearing にした——索引の 項目だけを消してファイルを残す削除は、次の読み出しの照合がそのまま元へ戻すためである。 移したもの: `LoggedPost` / `Topic` / `TopicIndex`、索引の読み書き、孤立ファイルの 照合、題の生成、一行の解析、そして `delete`。`delete` はファイルを先に、項目を後に 消す——この順序が load-bearing であり、逆順が「復活する削除」になる。 テスト 8 件。中心は `removing_only_the_entry_lets_the_next_read_resurrect_the_topic` で、項目だけを消す形を実際に走らせ、次の読み出しでトピックが戻ることを見る。#117 の 状態(項目は在るがファイルが無い)を消せることと、一ファイル名でない id の拒否も含む。 `src-tauri` 側の配線は次のコミットで行う。 #119 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`room_delete_topic` を足した。三つの行為をこの順で行う。 1. そのトピックで走っているセッションを終える(決定4)。トピックが消えれば 戻り道も消えるため、走らせたままにするとどのトピックにも属さないセッションが 残る。どのトピックの席かは起動時の事実であり、`RunningSession` が `topic_id` を持つようにした——トピックの `sessions` から引くと、以前ここで走り今は別の トピックで走っているアカウントに届いてしまう。走っていることを理由に削除を 拒まない(決定3)。 2. ファイルと索引の項目を消す(決定1、`room_log::delete_topic`)。順序が逆だと 決定4が禁じた状態——トピックが消えてセッションが残る——になる。 3. 部屋がそのトピックに居たなら新しいトピックへ移る(決定6)。起動直後と同じ 状態を使い回す。移った先を画面へ返す——画面は自分の現在トピックを持っており、 消えたトピックを指したままだと、描いている会話と記録先が食い違う。 `room_log` 側は crate への配線に置き換えた。`PtyState::kill_each` は `kill_all` をリストへ絞ったもので、失敗を報告しない理由も同じ(#96)。 #119 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
一覧の行に ❌ を足した。押すと `#topic-delete-dialog` が開き、そこで答える—— 削除は取り消せず、ログは git に載っておらず写しも無いため、確認の一段は必須である (決定2、決定1から導かれること)。`#end-dialog` / `#quit-dialog` と同じ作法であり、 CSS も同じ規則で描く。三つ目の問いに三つ目の写しを作らない。 ダイアログは二行を持つ。一行目はトピック名と、何が消えるか(発言の記録と、 セッションへの戻り道)。二行目はそのトピックで走っているセッションの名前であり、 走っていなければ出さない——決定4でセッションが止まる以上、ログの話だけをする ダイアログは、止まったセッションを不意打ちにする。走っているかどうかはアプリへ 毎回訊く。画面の写しは最後に更新された時点のものでしかない。 題の無い行には ❌ を出さない(決定5)。そう読まれる行は二つあり、どちらもここから 消す理由が無い——まだ何も言われていない現在のトピック(索引に無く、消すものが無い) と、索引に行があってファイルが無いトピック(#117)である。 行は flex のトラックになった。`.pick` が残りを取るため、長い題は ❌ を押し出さずに 省略される。 #119 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…carries it 「部屋のログ」に削除の項を足した——ファイルと索引の項目の両方を消すこと、 ファイルが先であること、そして逆順が黙って復活する削除になること。 「トピック」に決定 1-6 を書いた。三つの行為(セッション → 保存 → 部屋)の順序と、 その順序がなぜそれでなければならないかを含む。「トピックの一覧」に行の `❌` と ダイアログの作法を足し、「未実装」から「トピックの削除」を落として「実装済み」へ 移した。 「テストの配置」を書き直した。#115 の時点で「照合は読んで確かめられる範囲を出て いる、crate へ出すのが正しい形である、この issue の範囲では行っていない」と書いて あったものが、#119 で行われた。削除は照合の裏返しであり、読んで確かめられる性質の ものではない。CI の表に `crates/topic-index` の行を足した。 「受容したトレードオフ」の #115 の行を現状へ更新し、起動途中の席(`Seat::Starting`) が削除から見えないことを新しい行として足した。 #119 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`openTopicDeleteDialog` は走っているセッションをアプリへ訊いてからダイアログを 開く。その await をまたいで二度目の ❌ が入ると、二つの呼び出しが絡む——二度目が 一度目のトピックと一文目を上書きし、そのあと一度目の読みが返ってダイアログが開く。 出るのは、片方の名前ともう片方のセッションを載せた問いである。二度目の読みが返ると `showModal()` が既に開いた dialog に対して投げる。 問いが立っている間は開かない形にした。`deletingTopic` はダイアログから出るどの 経路でも消えるため、これで詰まる状態は無い。 #119 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
smileygames
left a comment
There was a problem hiding this comment.
自己レビュー(親 / auto モード)
brake 1 は適用外。本リポジトリは USER_REPO5 であり、rules/evolution/initiator-autonomy.md の self-evolution PR 定義の条件②(LI_PLUS_REPO のガバナンス面)を満たさない。
merge は保留する。 auto モードに人間ゲートは無いが、#48 の顛末(本文の粒度が意図と違い、下流の誰も気づけなかった)を踏まえ、Master の確認を待つ。
受け入れ基準の照合
| 決定 | 実装 | 結果 |
|---|---|---|
| 1 ファイルも索引も消す | crates/topic-index の delete。両方を落とす |
pass |
| 2 確認ダイアログ | #topic-delete-dialog。#end-dialog の作法に合わせた |
pass |
| 3 走っていても消せる | 走行を理由に拒まない | pass |
| 4 走っている CLI を止める | pty_state.kill_each(seats.running_in_topic(...)) を削除の先頭で |
pass |
| 5 空タイトル行にボタンを出さない | 出していない | pass |
| 6 開いているトピックを消したら新規へ | state.enter_topic(TopicRef::new(...))。移動先を戻り値で画面へ返す |
pass |
設計として評価する点
- 止めるセッションを
sessionsマップではなく起動時のtopic_idで引いている。 マップで引くと、このトピックで一度走って現在は別トピックに居るアカウントまで巻き添えにする。指示に無い気づきであり、実機でしか踏まない類の欠陥を先に塞いでいる。 - 三つの act の順序に理由が書かれている。 ストアを先にして失敗すると「トピックは消えたのにセッションは走っている」形になり、それは決定4が禁じた状態そのもの。順序が設計判断として明示されている。
- 削除後の移動先を戻り値で画面へ返す。 画面が消えたトピックを指したまま次の投稿を別のトピックへ記録する、という食い違いを構造で塞いでいる。
- 要求したテストが要求どおりの形で入っている。
removing_only_the_entry_lets_the_next_read_resurrect_the_topicは、索引だけ消すと復活することを実際に示してから、正しい削除なら消えたままであることを示す。復活の経路を仕様として固定した。
スコープ
crates/topic-index への切り出しは #119 の要求より広い。#119 は対象ファイル表を持たないため超えるべき線が引かれておらず、scope-exceed の対話確認は発火しない。線を引かなかったのは親の書き落としである。
その上で妥当と判断する。CI は src-tauri に対して cargo check のみを走らせ、cargo test を走らせない(tauri ツリーをリンクしたテストバイナリが GNU ターゲットで読み込めない。docs/0-requirements.md テストの配置 に run 32431917979 付きで記録済み)。要求したテストを src-tauri に置いても走らないどころかコンパイルもされない。加えて #115 の時点で「AppHandle 依存を外して crate へ出すのが正しい形。この issue の範囲では行っていない」と repo 自身が書いており、この切り出しはその名指しの移動にあたる。CI にもテスト実行ステップが追加されている。
本文の矛盾(親の瑕疵、修正済み)
#119 の前提に「削除ボタンは #117 の手動の逃げ道にもなる」と書いたまま、Master の決定5(空タイトル行にはボタンを出さない)を受けた際に前提側を直さなかった。同じ行について本文が食い違ったまま実装へ渡っている。
実装 AI がこれを発見し、決定を優先して正しく実装した上で報告している。本文は修正済み。#117 の行はどの経路でも消せないまま残るという結論に変わりはない。
持ち越し
#quit-dialogに固有 CSS が無い(#85 以来の既存状態、未スタイルの<dialog>として描画)。実装は#topic-delete-dialogに#end-dialogの規則集合を共有させたが、範囲外の面の描画を変えないため#quit-dialogは畳み込まなかった。判断として正しい。follow-up issue の候補。Seat::Startingの席は PTY を持たないため削除で止められない。その起動がトピック消滅後に完了すると、セッション id が孤児になる。閉じるには seats ロックと index ロックを spawn を跨いで保持する必要があり、狭い窓を受け入れて受容したトレードオフに記録した。黙らせずに書いた点を評価する。
規約面
PR タイトル純 ASCII(非 ASCII バイト 0)。PR 本文 Closes #119、日本語。コミット 6 本すべてタイトル純 ASCII、本文に日本語と #119 参照。docs 同 PR。CI 緑、mergeStateStatus=CLEAN。
判定
self-review pass。実機確認を経て merge する。
実機確認の結果(親 / 2026-08-28)
決定の照合
復活しないことを再起動で確認した。 決定4の分離が実物で効いている二つのセッションを別トピックで走らせ、片方のトピックを削除した。
ダイアログが要件より一段深い走行中のセッションを持つトピックで押すと、ダイアログに赤字で一行増える。
どのアカウントが止まるかを名指ししており、別トピックで走っている Lin には触れていない。issue の「セッションが止まることを述べる必要がある」より踏み込んでいる。 付随して確認できたこと
見つかったこと(この PR の受け入れは妨げない)
判定受け入れ基準は全て満たしている。merge する。 |
Closes #119
トピックを一覧から消せるようにした。行の
❌が確認のダイアログを開き、答えるとlogs/main/{topic_id}.jsonlと索引の項目の両方が消え、そのトピックで走っていたCLI セッションが終わり、開いていたトピックだった場合は部屋が新しいトピックへ移る。
保存の側は
crates/topic-index/へ出した。docs/0-requirements.mdの「テストの配置」が #115 の時点で正しい形として名指し、範囲外として見送っていたものである。#119 が
それを load-bearing にした——索引の項目だけを消す削除は、次の読み出しの照合が黙って
元へ戻す。走らせて見るしかない性質のものであり、crate のテストの中心がそれである。