fix(session): choose the resume line only when its transcript exists (mcp-config crate, session.rs, room_log, main.ts, docs) - #132
Conversation
…(mcp-config crate, session.rs, room_log, main.ts, docs) 再開の線は「トピックに id が記録されている」と「アカウントが再開の線を持つ」の 二つだけで選ばれており、その id の会話が実在するかを見ていなかった。記録は spawn が返った直後に書かれるため、プロセスが立っただけで会話のできなかった回の id が 残る。以後その(アカウント, トピック)の組は押すたびに再開の線へ入り、失敗して から記録を外す道(#127)のほかに落ちる先が無い。#131 判定に三つめを足す。記録された id が在り、アカウントが再開の線を持ち、その id の 会話がファイルとして在るときだけ再開である。在るものから選ぶ形にすれば、無い会話 へ戻ろうとする状態がそもそも作れない。実在しなければ失敗を待たずにその場で記録を 外し、通常起動として立て、外したことを状態行で述べる。 見るのはファイルの有無だけである。CLI の出力も終了コードの値も読まず、中身も読ま ない。保存の形への依存は `crates/mcp-config/` の `transcript_path` 一つに閉じた。 `claude` は `~/.claude/projects/<作業ディレクトリのスラッグ>/<セッション id>.jsonl` に置き、スラッグは英数字でない文字を一つずつ `-` へ畳んだものである(2026-08-29、 実機の `~/.claude/projects/` の二例から確定。テストが持つ)。CLI が増えるときに 差し替える場所はここだけになる。判定できない場合——ホームディレクトリが解決でき ない、CLI が保存先の名前を切り詰める長さである——は記録を残し、これまでどおり 再開の線へ入る。 作業ディレクトリの解決を行の解決より前へ移した。会話の記録はその作業ディレクトリ の下に在るため、ディレクトリを持たない起動で記録を外す形にはできない。 #127 の復帰は残す。会話が在るのに CLI が戻ることを拒む場合は、この事前判定では 防げないためである。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
smileygames
left a comment
There was a problem hiding this comment.
AI セルフレビュー(execution_mode = auto、#131 に対して)。
受け入れ基準
四つの決定を diff で確認した。満たしている。
- 決定1(transcript の実在を条件に足す) —
resolve_launchがcwdを受け取り、transcript_foundを三つめの条件として通す。記録された id・再開の線・ファイルの実在が揃ったときだけ再開の線を返す。 - 決定2(無ければその場で外す) —
room_log::forget_sessionを id 一致で呼び、dropped_resumeをLaunchLine→StartedSession→main.tsへ運ぶ。状態行は三つめの文として独立している(「戻る先の会話が見つからなかったため、このトピックの再開先は外しました。」)。ordinary な起動と読めてしまう形を避けている。 - 決定3(依存を一箇所に閉じ、docs に書く) —
crates/mcp-configのtranscript_path一関数に閉じ、doc に Claude Code のレイアウトと codex の異なるレイアウトを併記。docs/0-requirements.mdにも記載。 - 決定4(#127 の復帰を残す) — 触れていない。
forget_sessionの doc が二つの呼び手を持つ理由を記録している。
判定の向きを確認した
「分からない」を安全側へ倒しているかが、この変更で一番効く点である。transcript_found を読んだ。
let Ok(home) = app.path().home_dir() else { return true };
match transcript_path(&home, cwd, session_id) {
Some(path) => path.is_file(),
None => true,
}
home が引けない場合と、slug が 200 文字上限を超えて CLI 側が短縮+ハッシュを付ける場合の両方が true、すなわち従来どおり再開の線を取る。見ていないことを根拠に記録を落とさない。 逆向きに倒すと実在する会話を捨てるため、この向きが正しい。残差は #127 が拾う。
前提の確認が本文を超えている(良い方向)
slug 規則を、本文が求めた「二例からの確定」ではなくインストール済みバイナリに当てて確定している。規則は cwd.replace(/[^a-zA-Z0-9]/g, "-")——区切り文字ではなく英数字以外すべてであり、畳む単位は UTF-16 コードユニット。テストは絵文字(2 ダッシュ)と日本語を含む経路で、実測 2 例も別テストで固定している。本文の推測より強い根拠に置き換わった。
逸脱(記録する)
本文の target files は session.rs / room_log.rs / docs/0-requirements.md の三つだが、実際は crates/mcp-config/src/lib.rs(+3 テスト)と src/main.ts が加わっている。
main.tsは決定2 が要求する。状態行は画面に在るため、本文の決定から直接導かれる。crates/mcp-configは実装側の判断である。CI はsrc-tauriをテストできず(GNU ターゲットのリンカ事情、docs 記載)、slug 規則は黙って壊れる文字列処理である。同 crate は既に CLI 知識(SESSION_ID_PLACEHOLDER、フラグ検査)の置き場であり、決定3 の「依存を一箇所に閉じる」を実際に満たすのはこちらである。session.rsに置けば一箇所ではあるがテストが無い。
判断: 受け入れる。 二つとも本文の決定に反しておらず、決定を実際に満たす側である。target files の列挙が私の側で不足していた。
ただし手続きとして、rules/operations/main-agent-procedures.md の scope-exceed dialogue confirm はコミット前に発火していない。実装側に対話面が無いためであり、本来は親へ報告 → 親が Master へ確認、が正しい経路である。この点は Master へ別途報告する。
CI
check / CI ともに success(df873d3)。mergeStateStatus = CLEAN。ローカルでも cargo test 三 crate(mcp-config 33 / room-floor 13 / topic-index 10)が通っている。
版数
patch。観測できる変化だが規模は限定的。
未確認として残るもの
実機未確認。#127 / #130 の経緯があるため、この経路こそ実機で踏む価値がある——索引に死んだ id が在る状態で起動し、再開の線に入らず通常起動になり、状態行が外したと言うこと。マージの門ではないため止めない。
次: 自己レビュー通過につき、auto モードの直接マージへ進む。
何をしたか
再開の線を選ぶ条件に「その id の会話がファイルとして在ること」を足した。記録された id が在り、アカウントが再開の線を持ち、会話が実在する——三つ揃ったときだけ再開である。実在しなければ、失敗を待たずにその場で記録を外し、通常起動として立てて、外したことを状態行で述べる。
これまでは前の二つだけで選んでいた。記録は spawn が返った直後に書かれるため、プロセスが立っただけで会話のできなかった回の id が残り、以後その(アカウント, トピック)の組は押すたびに再開の線へ入っていた。在るものから選ぶ形にすれば、無い会話へ戻ろうとする状態がそもそも作れない。
変更点
resolve_launchが作業ディレクトリを受け取り、再開の線を選ぶ前に会話の実在を見る(決定1)。実在しなければroom_log::forget_sessionでその id の記録を外し、通常起動の行を返す(決定2)。LaunchLine→StartedSessionを通って画面へ渡り、状況行が述べる。resumed_fromと同時には立たない——外したことが、この行が通常起動である理由だからである。crates/mcp-config/のtranscript_path一つに閉じた(決定3)。claudeは~/.claude/projects/<作業ディレクトリのスラッグ>/<セッション id>.jsonlに置き、スラッグは英数字でない文字を一つずつ-へ畳んだものである(2026-08-29、実機の~/.claude/projects/の二例から確定)。CLI が増えるときに差し替える場所はここだけになる。制約の遵守
判定できない場合
ホームディレクトリが解決できないとき、および作業ディレクトリが長く CLI が保存先の名前を切り詰めるとき(そのハッシュはアプリには作れない)は、判定せずに記録を残し、これまでどおり再開の線へ入る。見ていないことを根拠に記録を外すことはしない。そこは #127 の復帰が受け止める。
テスト
crates/mcp-configに 3 件追加した:実機で確認した二例、英数字でない文字の畳み方(UTF-16 の単位で数えること込み)、CLI が名前を切り詰める長さ。CI と同じ範囲をローカルで通した:
npm run build/npm run sidecar:check/npm run sidecar:test/cargo check/ 三つの crate のcargo test(33 + 13 + 10 件、すべて pass)。実機確認は未了であり、docs の「未実装」へその旨を書いた。
Closes #131