Skip to content

perf: manager_list の受信箱の内訳を、同じ会話の2回目から前回と同じなら1行に畳む - #5471

Merged
takecchi merged 6 commits into
mainfrom
perf/manager-list-query-fold
Oct 29, 2026
Merged

takecchi merged 6 commits into
mainfrom
perf/manager-list-query-fold

Conversation

@takecchi

Copy link
Copy Markdown
Owner

何を直したか

manager_list を q で1件だけ引く呼びでも、同じ会話の2回目以降に、末尾の「受信箱の未処理の合図」の内訳(種類・送信元・同一本文・器の入れ替え回数・齢)が毎回全文で出ていた。これを、同じ内訳なら件数と全文の在りかを示す1行に畳む。

  • 畳みは既存の DigestSessionDelta.fixedInTurn(ToolContext.foldFixed)に乗せた。行の「前回と同じ」(perf: manager_list は前回と変わらない行を「前回と同じ」の1行に畳む #5438)と同じ流儀で、鍵に内訳の指紋を入れ、古い版は supersedes で捨てる。
  • 指紋は観測時刻(毎回変わる)を除いた内訳の全文。件数・種類・送信元・齢の段が1つでも変われば全文に戻る。A→B→A と変わっても2回前の A を「同じ」と言わない。
  • 見出し(⚠ クローンの受信箱に未処理の合図が N 件ある(最も古いものは…))は畳まず毎回出す。人間起点の滞留の行は、畳む回も件数と「まだ片付いていない分」の件数を残す。
  • 畳んだ行から全文の在りかを示す: 「内訳(計 N 件)は前回と同じ(観測 … 時点の値。… 全文は前の一覧のとおり。引き直しは manager_list に refetch: true。⚠ 器の入れ替え回数は配られた回数ではない…)」。誤読に効く結論(配られた回数ではない・同一本文の件数は上下にぶれる・配達されていないとは言えない)は畳んだ行にも残した。refetch: true は内訳も全文で出し直す(説明文も更新)。
  • 常に全文: 読めない受信箱の行が在る回、サブエージェントの呼び(NO_FIXED_FOLD)。行の ⚠ / lost / failed / quota-stopped / runner-vanished は既存の managerRowAlwaysFull のまま触っていない。
  • compaction・新会話・usage 不明・失敗ターン・20ターン毎(forgetFixed)・再起動で全文へ戻るのは、foldFixed の口が持つ既存の仕組みのまま。

原因(なぜ q で引くときに畳まれていなかったか)

q 付きだと畳みを飛ばす条件は無かった。別経路でも、鍵が違うのでもない。q の有無にかかわらず manager_list は同じ fold を通る(tools.ts の manager_list ハンドラ冒頭で context.foldFixed を取り、件数行・絞り込みの注記・印の意味・行・受信箱の固定の言い回しに渡している)。

実測(下)では、変更前(origin/main)でも冒頭の注意書き(COUNTS_RUNNING_FULL 等)は2回目に参照へ畳まれていた。畳まれていなかったのは受信箱の内訳の「値」の側だった。#5390 以降の畳みは「固定の言い回し」だけを fold に包み、数・時刻・種類の内訳は「毎回の値」として畳まない設計(inbox-backlog.ts の InboxBacklogFold の注記)で、内訳の行は人間起点の行も含め、同じ中身でも毎回全文で出ていた。q で1件だけ引くと本体の行が短くなるので、この残りが応答の大半を占めて目立つ。

したがって「約2,000字」のうち、冒頭の注意書きは(この実測の範囲では)2回目以降すでに畳まれている。この PR で畳むのは、残っていた受信箱の内訳。冒頭の注意書きの側で、依頼文のとおり毎回全文になる経路があれば、それはこの実測では再現していない(下の「測っていないこと」)。

測ったこと

本番と同じ経路で測った: createClone(fake SDK。getContextUsage を持つ fake、mcpServerFactory で ToolContext を捕まえ、createCloneTools の manager_list ハンドラを呼ぶ。ターンは1回回して会話を成立させてある)。同じセッションで manager_list {q: "mgr-target"} を2回呼び、応答の文字数を比べた。台帳は3本(q に当たるのは running の1本)、受信箱の滞留は12件(人間起点6件を含む)。

1回目 2回目
変更前(origin/main 98bb42c) 1,502 字 1,104 字
変更後 1,502 字 736 字

2回目は 368 字(約33%)減。1回目は変わらない(全文が会話に載る回)。測定は packages/core/src/clone-manager-list-query-fold.test.ts の最初の試験に一時的に console.log(first.length, second.length) を足して、変更前は tools.ts を origin/main に戻して実行した(測定用の出力はコミットしていない)。

測っていないこと

  • 実運用の滞留の中身(私の fixture は12件・送信元が散らばる形)。滞留が多様なほど内訳の行は長くなり、畳める量は増える。
  • 「1件で約2,000字」の再現。この fixture の1回目は 1,502 字で、2,000字には届かない。
  • 本物の SDK・本物の CLI が付ける tool_use_id(_meta)の経路。試験では _meta を渡さない呼び(本体扱いで畳む)と、PreToolUse hook で印を立てたサブエージェントの呼びを別々に確かめた。

落とした判断材料が無い理由

  • 内訳の値(件数・種類・送信元・齢の段)は、変わったら全文に戻る。同じ中身のときだけ畳み、畳んだ行にも合計件数と観測時刻を残す。
  • 見出し行と、読めない受信箱の行が在る回は畳まない。⚠ は落とさない。
  • 注意書きの文言そのものは一文字も消していない(今回触っていない)。
  • 全文は会話の上の最初の一覧に在り、refetch: true でいつでも出し直せる。

試験

clone-manager-list-query-fold.test.ts(10本、本番と同じ createClone 経路)。追加した試験ごとに、修正を一時的に戻して落ちることを確認した:

戻した修正 落ちた試験
畳みを無効化(常に全文) 2回目で短くなる・内訳が同じなら1行・refetch・compaction/新会話/失敗後(畳まれている前提の確認)など6本
指紋を固定値にした(内訳が変わっても同じ扱い) 内訳が変わったら全文/A→B→A の2本
supersedes を外した A→B→A
読めない行の除外を外した 読めない行が在る回は畳まない
控えを foldFixed の外(モジュールの Set)に置いた compaction/新会話/失敗後/変わったら全文/A→B→A など5本
サブエージェントの呼びにも foldFixed を渡した サブエージェントの呼びは常に全文

既存の試験を1本反転した(3点セット)

tools-manager-list-fold.test.ts の「受信箱の滞留」は「数・時刻・内訳は毎回出る」を期待していた。

  • 変えた事実: 内訳の行(内訳(計 N 件)・種類・器の入れ替え回数・齢)は初回だけ全文で、同じ内訳の2回目は「前回と同じ」の1行を期待する。見出し・人間起点の滞留・配達待ち行列は毎回出る期待のまま。
  • なぜ必要か: 同じ中身の内訳を毎回全文で出すのが、q で1件引く呼びの応答の大半を占めていたため(依頼の目的そのもの)。
  • 保証が弱くなっていない理由: 札に残る結論(配られた回数ではない・配達されていないとは言えない・足しても引いても意味が無い・この数は上下どちらへもぶれる)の期待は残してあり、内訳が変わったときに全文へ戻ることは新しい試験が見ている。

触っていない領域

claude-provider.ts の窓(#5467)、ALT-DEV-Y の A1/A3(記憶索引・manager_send・approvals_list の固定文・固定文ラベル・memory-update diff)。docs/ と AGENTS.md は変更していない。

検証: build・typecheck・lint・format:check・pnpm test を通した。

q で1件だけ引く manager_list でも、2回目以降に毎回全文で出ていた「受信箱の未処理の合図」の内訳(種類・送信元・同一本文・器の入れ替え回数・齢)を、
同じ内訳なら件数と全文の在りかを示す1行にする。固定の言い回し(注意書き)は既に #5390 などで畳まれており、残っていたのは値の側だった。

畳みは DigestSessionDelta.fixedInTurn(ToolContext.foldFixed)に乗せる。鍵に観測時刻を除いた内訳の指紋を入れ、古い版は supersedes で捨てるので、
内訳が変われば全文、A→B→A と変わっても2回前の A を「同じ」と言わない。compaction・新会話・usage 不明・失敗ターン・20ターン保険・再起動は同じ口で全文へ戻る。
読めない受信箱の行が在る回・サブエージェントの呼びは畳まない。refetch: true で全文を出し直せる。見出し(件数・最も古い時刻)は毎回出す。
@takecchi
takecchi marked this pull request as draft October 28, 2026 22:23
@takecchi

Copy link
Copy Markdown
Owner Author

レビューで NG。読めない行が在る回と、受信箱が空の回に、内訳の控えを捨てない。そのため A→B(読めない行あり)→A や A→空→A で、直前に見せたものと違うのに「前回と同じ」と畳む。直したら ready に戻す。

レビュー指摘2点。
- 読めない行が在る回は `&&` で fold が呼ばれず控えが古いまま残り、A → B(読めない行あり)→ A の3回目が「前回と同じ」と畳まれた。
  読めない行の回も全文の指紋で fold を呼んで控えを最新にし、出力は常に全文にする。
- 受信箱が空(読めない行だけの回を含む)の回に控えを捨てていなかったので、A → 空 → A の3回目が畳まれた。空の回で控えを捨てる。
どちらも、直す前の版で落ちる試験を足した。inbox-backlog.ts の注記と既存の試験名も新しい挙動に合わせた。
@takecchi
takecchi marked this pull request as ready for review October 28, 2026 23:52
@takecchi
takecchi marked this pull request as draft October 29, 2026 00:14
@takecchi

Copy link
Copy Markdown
Owner Author

再レビュー NG(head c942d41)。前回の3点はコード上は直っていて、#5479 の系統2のスイッチでも止まります。残りは試験です。

clone-manager-list-query-fold.test.ts の createClone に TOKEN_SAVING_ENABLED_ENV を渡し、
畳みが切り(env が空)のときは同じ内訳で2回呼んでも2回とも全文で
「内訳(計 N 件)は前回と同じ」が出ない試験を足す。
@takecchi
takecchi marked this pull request as ready for review October 29, 2026 00:29
@takecchi
takecchi merged commit 26adcd7 into main Oct 29, 2026
10 of 11 checks passed
@takecchi
takecchi deleted the perf/manager-list-query-fold branch October 29, 2026 00:45
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.

1 participant