Skip to content

fix(session): choose the resume line only when its transcript exists (mcp-config crate, session.rs, room_log, main.ts, docs) - #132

Merged
smileygames merged 1 commit into
mainfrom
issue-131-gate-resume-on-transcript-existing
Aug 29, 2026
Merged

fix(session): choose the resume line only when its transcript exists (mcp-config crate, session.rs, room_log, main.ts, docs)#132
smileygames merged 1 commit into
mainfrom
issue-131-gate-resume-on-transcript-existing

Conversation

@smileygames

Copy link
Copy Markdown
Member

何をしたか

再開の線を選ぶ条件に「その id の会話がファイルとして在ること」を足した。記録された id が在り、アカウントが再開の線を持ち、会話が実在する——三つ揃ったときだけ再開である。実在しなければ、失敗を待たずにその場で記録を外し、通常起動として立てて、外したことを状態行で述べる。

これまでは前の二つだけで選んでいた。記録は spawn が返った直後に書かれるため、プロセスが立っただけで会話のできなかった回の id が残り、以後その(アカウント, トピック)の組は押すたびに再開の線へ入っていた。在るものから選ぶ形にすれば、無い会話へ戻ろうとする状態がそもそも作れない。

変更点

  • resolve_launch が作業ディレクトリを受け取り、再開の線を選ぶ前に会話の実在を見る(決定1)。実在しなければ room_log::forget_session でその id の記録を外し、通常起動の行を返す(決定2)。
  • 外した id は LaunchLineStartedSession を通って画面へ渡り、状況行が述べる。resumed_from と同時には立たない——外したことが、この行が通常起動である理由だからである。
  • 保存の形への依存は crates/mcp-config/transcript_path 一つに閉じた(決定3)。claude~/.claude/projects/<作業ディレクトリのスラッグ>/<セッション id>.jsonl に置き、スラッグは英数字でない文字を一つずつ - へ畳んだものである(2026-08-29、実機の ~/.claude/projects/ の二例から確定)。CLI が増えるときに差し替える場所はここだけになる。
  • 作業ディレクトリの解決を行の解決より前へ移した。会話の記録はその作業ディレクトリの下に在るため、ディレクトリを持たない起動で記録を外す形にはできない。
  • bug(session): a session id recorded on spawn poisons every later resume when the CLI never created the conversation #127 の復帰(失敗した再開のあとに記録を外す)は残す(決定4)。会話が在るのに 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

…(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 smileygames left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI セルフレビュー(execution_mode = auto、#131 に対して)。

受け入れ基準

四つの決定を diff で確認した。満たしている。

  • 決定1(transcript の実在を条件に足す) — resolve_launchcwd を受け取り、transcript_found を三つめの条件として通す。記録された id・再開の線・ファイルの実在が揃ったときだけ再開の線を返す。
  • 決定2(無ければその場で外す) — room_log::forget_session を id 一致で呼び、dropped_resumeLaunchLineStartedSessionmain.ts へ運ぶ。状態行は三つめの文として独立している(「戻る先の会話が見つからなかったため、このトピックの再開先は外しました。」)。ordinary な起動と読めてしまう形を避けている。
  • 決定3(依存を一箇所に閉じ、docs に書く) — crates/mcp-configtranscript_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 モードの直接マージへ進む。

@smileygames
smileygames merged commit 945c31d into main Aug 29, 2026
2 checks passed
@smileygames
smileygames deleted the issue-131-gate-resume-on-transcript-existing branch August 29, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(session): choose the resume line only when the transcript it names actually exists

1 participant