fix(active-session): 親 pid 起動時刻で呼び出し元 Claude Code を同定#6
Merged
Conversation
複数 Claude Code ウィンドウ並行起動時、findActiveSession が mtime 降順 + 直近 5 分以内のイベントフィルタで「真にアクティブ」を選ぼうとしていたが、 subagent や別ウィンドウのイベントで mtime/lastEvent が頻繁に touch されるため、 呼び出し元 Claude Code とは別のセッションを誤検出し、cumulativeUncached が 他セッション分を映してしまっていた(実測: 自セッション 82k に対し 696k を返す)。 stdio MCP server は呼び出し元 Claude Code から spawn されるので、 process.ppid が Claude Code の pid になる。/proc/<ppid>/stat (field 22) と /proc/stat:btime と CLK_TCK=100 から親の wall-clock 起動時刻を算出し、 各 session JSONL の first_ts と最も近いものを 120 秒 tolerance で選ぶ ことで、呼び出し元自身のセッションを高精度に同定できる。 - observers/claude_code.ts: readProcessStartMs / resolveSessionByParentPid を追加。findActiveSession に parentPid 引数(任意)を追加し、解決成功時は resolution='parent-pid'、失敗時は既存の mtime-recent ヒューリスティクスに フォールバック - mcp/resources.ts / mcp/tools.ts: process.ppid を渡す - ActiveSessionPayload に resolution フィールドを追加(観測性のため) - watch.ts / timer/adaptive.ts: 親が Claude Code ではない standalone daemon なので引数を渡さず、従来通り mtime-recent で動く Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #6 のローカル検証中、npm link 直後の /mcp 再接続で initialize 応答が 30s タイムアウトする事象を 1 度観測。直接実行 (cogsync mcp < /dev/null) では コールド 0.66s で完了するため、本体ロジックの問題ではなく spawn 直後の FS/シンボリックリンク race と推定。ただし MCP サーバ側で全く診断ログが 出ていなかったため、再発時に原因を絞れる材料を持っていなかった。 - mcp/server.ts: boot / config-loaded / handlers-registered / connected の 4 段階で stderr に JSON line を出す。stdout は JSON-RPC 専用なので 必ず stderr 側に書く(MCP プロトコル要件)。SIGTERM/SIGINT で確実に exit するよう明示ハンドラを登録(旧プロセス→新プロセスの race を減らす) - index.ts: program.parseAsync に top-level catch を追加し、想定外の 例外を必ず stderr に書いて非ゼロ終了する。MCP サーバが無音で落ちる事故を防ぐ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
なぜこれを作ったか
複数 Claude Code ウィンドウを並行起動していると、
findActiveSessionが呼び出し元とは別のセッションを誤検出していた。具体的にはget_recommended_actionがコンテキスト膨張閾値 150k を超えたと警告するが、実態は呼び出し元セッションのコンテキストではなく、別ウィンドウ(または subagent)のセッションを映していた。実測: 当該 Claude Code 自身のセッション (
3f6af495-...) は 28 turns / uncachedSum 82k だが、findActiveSessionは別の長寿命セッション (c8c746d0-..., 311 turns / 696k) を返していた。原因は、
findActiveSessionが「mtime 降順 + 直近 5 分のイベントフィルタ」で active を決めていたところに、別ウィンドウや subagent の書き込みが頻繁に mtime / lastEvent を touch するため、呼び出し元とは無関係なセッションが mtime トップに上がってしまうこと。何を入れたか
src/observers/claude_code.tsreadProcessStartMs(pid)を追加(Linux 限定で/proc/<pid>/statから wall-clock 起動時刻を算出)。resolveSessionByParentPid(logDir, parentPid, toleranceMs=120_000)を追加(親プロセス起動時刻と各 JSONL の first_ts を突き合わせ、最も近いものを返す)。findActiveSessionにparentPid?: number引数を追加し、解決成功時はresolution='parent-pid'、失敗時は既存の mtime-recent にフォールバックsrc/mcp/resources.tsfindActiveSessionにprocess.ppidを渡す。ActiveSessionPayloadにresolutionフィールドを追加src/mcp/tools.tssafeReadLatestSession経由でprocess.ppidを渡すtests/active-session.test.tsreturnでスキップ)設計判断
process.ppidが Claude Code のプロセス ID になり、その起動時刻と session JSONL の first_ts は必ず数秒以内に一致する。確実な同定が可能。lastUser最新で選ぶ → 「ユーザが最後に発言した窓」になるだけで、呼び出し元の窓追従にはならない。並行ウィンドウで他方の入力に引っ張られる。却下。/proc/<ppid>/fdで開いている jsonl を探す → Claude Code は JSONL を append のたび open/close するため fd には載らない。確認済み、却下。clientInfo._meta経由で session id を受け取る → Claude Code 側が現状 session id を渡していない。本 PR では着手しない。readProcessStartMsはplatform() !== 'linux'で即 null を返す。macOS / Windows は今のところ Claude Code 利用者の主要環境ではないため、フォールバックの mtime-recent で従来通り動作(精度低下は受け入れ)。findActiveSessionの追加引数は optional で default null。watch.ts / timer/adaptive.ts は parent が Claude Code ではない(cogsync 自身が親)ため引数を渡さず、従来挙動を維持。スコープ外
ps -o lstart,wmic process等)。需要が出てから別 PR で。_meta経由で Claude Code から session id を直接受け取るプロトコル拡張。Claude Code 側の対応待ち。cumulativeUncachedの閾値 (150_000) 再調整。本 PR は active session の同定問題のみ修正。閾値は別途バックテストで。検証方法
npm run typecheckが通るnpm testが 29/29 pass する(新規 8 + 既存 21)mcp__cogsync__get_recommended_actionを呼び、それぞれ自セッションのトークン量を反映した rationale が返ることを確認cogsync://state/active-sessionresource を読み、resolution: "parent-pid"が返ることを確認(並行ウィンドウありの環境)cogsync watch) で従来通り mtime-recent ベースで動くことを確認(回帰確認)依存
なし。