throughline 0.10.2 → 0.10.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +88 -27
  2. package/README.ja.md +83 -49
  3. package/README.md +106 -78
  4. package/bin/throughline.mjs +32 -13
  5. package/docs/00_overview.md +56 -42
  6. package/docs/01_l1_l2_l3_redesign.md +1 -1
  7. package/docs/02_clear_auto_handoff_plan.md +39 -333
  8. package/docs/04_public_release_plan.md +73 -190
  9. package/docs/05_codex_first_roadmap.md +4 -4
  10. package/docs/06_codex_trim_rollback_fix_plan.md +1 -1
  11. package/docs/08_codex_dual_support.md +1 -1
  12. package/docs/09_rollback_context_trim_insight.md +1 -1
  13. package/docs/12_desktop_clear_handoff_plan.md +6 -213
  14. package/docs/15_windows_ci_release_latency_plan.md +6 -87
  15. package/docs/16_readonly_handoff_context_plan.md +7 -38
  16. package/docs/adr/0005-observer-read-pagination.md +1 -1
  17. package/docs/adr/0014-two-phase-handoff-ghost-baton.md +1 -1
  18. package/docs/adr/0019-product-owned-database-migration-acceptance.md +1 -1
  19. package/docs/adr/0021-grok-host-capture.md +1 -1
  20. package/docs/adr/0022-cursor-host-capture.md +39 -0
  21. package/docs/archive/02_clear_auto_handoff_plan.md +350 -0
  22. package/docs/{03_inheritance_on_clear_only.md → archive/03_inheritance_on_clear_only.md} +22 -22
  23. package/docs/{07_codex_trim_implementation_plan.md → archive/07_codex_trim_implementation_plan.md} +8 -8
  24. package/docs/{10_transcript_injection_plan.md → archive/10_transcript_injection_plan.md} +12 -12
  25. package/docs/archive/12_desktop_clear_handoff_plan.md +218 -0
  26. package/docs/{14_observer_completed_turn_feed_plan.md → archive/14_observer_completed_turn_feed_plan.md} +7 -7
  27. package/docs/archive/15_windows_ci_release_latency_plan.md +89 -0
  28. package/docs/archive/16_readonly_handoff_context_plan.md +40 -0
  29. package/docs/archive/README.md +28 -15
  30. package/docs/archive/plan_grok-successor-launch.md +99 -0
  31. package/docs/archive/room-log_throughline_20260830-155052.md +285 -0
  32. package/docs/plan_grok-successor-launch.md +6 -97
  33. package/package.json +19 -11
  34. package/rag/INDEX.md +2 -2
  35. package/src/baton.mjs +11 -9
  36. package/src/cli/handoff-context.test.mjs +36 -0
  37. package/src/cli/help.test.mjs +5 -0
  38. package/src/cli/install.mjs +91 -0
  39. package/src/cli/install.test.mjs +57 -0
  40. package/src/cli/runtime-errors.mjs +9 -3
  41. package/src/cli/runtime-errors.test.mjs +13 -13
  42. package/src/cli/self-update.mjs +402 -0
  43. package/src/cli/self-update.test.mjs +525 -0
  44. package/src/db.mjs +1 -1
  45. package/src/docs-contract.test.mjs +153 -0
  46. package/src/hosts/claude.mjs +1 -0
  47. package/src/hosts/codex.mjs +1 -0
  48. package/src/hosts/cursor.mjs +128 -0
  49. package/src/hosts/cursor.test.mjs +104 -0
  50. package/src/hosts/grok.mjs +1 -0
  51. package/src/hosts/identity.mjs +19 -2
  52. package/src/hosts/identity.test.mjs +27 -4
  53. package/src/hosts/index.mjs +11 -2
  54. package/src/product-ci-contract.test.mjs +14 -0
  55. package/src/prompt-submit.mjs +8 -10
  56. package/src/resume-context.mjs +4 -4
  57. package/src/runtime-error-hook.test.mjs +4 -6
  58. package/src/runtime-error-store.mjs +40 -18
  59. package/src/runtime-error-store.test.mjs +53 -26
  60. package/src/session-merger.mjs +16 -7
  61. package/src/session-merger.test.mjs +27 -0
  62. package/src/session-start.mjs +24 -1
  63. package/src/spike-transcript-writer.mjs +1 -1
  64. package/src/transcript-reader-cursor.test.mjs +43 -0
  65. package/src/transcript-reader.mjs +14 -7
  66. /package/docs/{11_codex_monitor_implementation_plan.md → archive/11_codex_monitor_implementation_plan.md} +0 -0
  67. /package/docs/{13_native_factory_diagnostics_plan.md → archive/13_native_factory_diagnostics_plan.md} +0 -0
  68. /package/docs/{BUGHUB_RUNTIME_ERROR_STORE_PLAN.md → archive/BUGHUB_RUNTIME_ERROR_STORE_PLAN.md} +0 -0
@@ -1,215 +1,8 @@
1
- # 12 — Desktop /clear 引き継ぎ + L2 捕捉完全性 改良プラン
1
+ # 12 — Desktop `/clear` handoff(互換入口)
2
2
 
3
- <!-- 前提: Fable級統括/実装は codex_work・composer 委譲主体(2026-07 時点) -->
3
+ この計画は 2026-07-12 に完了した。実装・実測・NO-GO判断・0.6.0公開までの記録は
4
+ [archive/12_desktop_clear_handoff_plan.md](archive/12_desktop_clear_handoff_plan.md) に移した。
4
5
 
5
- status: **承認済み・実装中**(2026-07-11 オーナー承認。本文書が正本=チェックボックスが TODO を兼ねる)
6
-
7
- ## 統括の型(orchestrate スキル準拠。配置は 02_models.md 決定表の引用必須 2026-07-11 オーナー裁定の書式)
8
-
9
- 配置宣言は正典 dotagents/docs/02_models.md を開いて該当行を写す。引用なしの配置は書かない。本プランの根拠行(引用・2026-07-11 時点):
10
-
11
- - **実装物量**(02_models.md:40):「中位=`gpt-5.6-terra`×medium・codex_work」+「`grok-composer-2.5-fast`=並ぶ第一選択(仕様固定+検証コマンド必須の委譲契約を厳守)」
12
- → 波の割当: 既存ファイル編集を含む波(install/doctor/bin 配線、既存テスト更新)= codex_work(隔離 worktree)。独立新規ファイル生成の波(session-end.mjs 本体・spike ロガー・新規テストファイル)= composer も第一選択、統括が波ごとに選び理由を残す。
13
- - **監査・発見**(02_models.md:36):「`sonnet`×low・Workflow で明示」「中位=`gpt-5.6-terra`×medium・codex_auditor/explore」「`grok-4.5`・grok_agent / `grok -p`(並列 finder に好適)」
14
- → B-2 の保存構造棚卸しは grok 並列 finder + codex_explore の多角スイープ。
15
- - **反証・検証**(02_models.md:37):「主 継承×high・refuter」→ B-1 着手前 refuter・A 設計の追加反証に適用(model 省略=主継承が許されるのは検証・反証・裁定系のみ)。
16
- - **裁定・契約クリティカル**(02_models.md:35):「主 直轄(F)」→ schema v9・バトン上書き規則・捕捉契約変更・settings.json 操作・最終レビュー・コミット。着手前 refuter 1 回(ガードレール常時ON)。
17
- - **オーナー実機操作 = H**(Desktop/VSCode での /clear 操作・最小再現)。
18
-
19
- 委譲は orchestrate スキル references/delegation-contract.md の 8 点セット(file:line 仕様・罠リスト・検証コマンド・合格条件・報告フォーマット・前提再検証義務)。委譲物は統括が diff レビュー + ゲート再実行してから採用。各 Workstream は独立に revert 可能な単位で刻み、波ごとに pathspec 明示コミット。エージェントに branch 切替・commit をさせない。
20
-
21
- ## Context
22
-
23
- 発端は「Claude Code Desktop の `/clear` で自動引き継ぎが発火しない」引き継ぎ書(Caveat: `claude-code-desktop-clear-sessionstart-source-startup-throughline`)。調査の過程で、発火しても**注入の中身が欠ける**別問題(L2 捕捉欠落)をオーナーの実機テストが炙り出した。オーナー裁定により両方を本スコープとする(2026-07-11)。
24
-
25
- - **A: Desktop /clear 引き継ぎ発火** — Desktop は `source:"clear"` を送らない(VSCode 2.1.207 は送る。クライアント実装差で確定、バージョン交絡は棄却済み)。SessionEnd(reason='clear') バトン方式で解決する。
26
- - **B: L2 捕捉の完全性** — 完了済み論理ターンの L2 欠落率: Desktop 27%・VSCode 41%(実会話の欠落例を目視確認済み)。二系統に分解:
27
- - **B-1(Throughline 側で直せる)**: transcript に本文はあるのに bodies に無い欠落。原因は turn-processor が各 Stop で「最後の 1 ペア」しか保存しない設計([src/turn-processor.mjs](../src/turn-processor.mjs) の `getLastTurnPair` 単発保存)=Stop 不発/空振りが永久穴になる。→ 全ターンスキャン・バックフィル型に再設計。
28
- - **B-2(原因未特定・CC/Desktop 側の可能性)**: Desktop で assistant 本文が transcript にそもそも書かれない/大幅遅延する。バグか仕様か未確定。最小再現で条件特定 → upstream 報告はその後に判断(オーナー承認制)。
29
-
30
- ## 調査で確定した事実(2026-07-11 実測・反証済み)
31
-
32
- ### 1. `/clear` はどのクライアントでも UserPromptSubmit hook に届かない
33
-
34
- commit 75d79d7(2026-05-08「/clear writes baton」)は実運用ゼロ発火。決定的証拠は同一セッション内 /tl 対照実験 ×2:
35
-
36
- - 2026-06-28 Novel(VSCode 2.1.195): `/tl` 06:15:38 バトン書込 → 27 秒後 `/clear`。届いていれば trigger:"clear" で上書きされるはずが、後継が消費したバトンは `baton_age_ms:26777` = /tl 時点のまま。
37
- - 2026-07-11 Caveat(Desktop 2.1.205): `/tl` 11:51:21 → `/clear` → 後継 65a01d22 の消費バトンは `baton_age_ms:35591` =同型。
38
- - 2026-07-11 Throughline(VSCode **2.1.207**): `/clear` 3 連発(13:15:46 / 13:16:18 / 13:16:54)でも baton-write.log に trigger:"clear" ゼロ(/tl の 1 件のみ)。最新版でも変わらず。
39
-
40
- docs 整合: ビルトインコマンドは UserPromptSubmit(prompt 送信時)にも UserPromptExpansion(skill / custom command / mcp_prompt 展開時)にも乗らない。prompt-submit.mjs の /clear 分岐は無害な保険として残置。
41
-
42
- ### 2. VSCode と Desktop の /clear 挙動差(クライアント実装差で確定)
43
-
44
- | クライアント | 実測バージョン | /clear の SessionStart | 検証方法 |
45
- |---|---|---|---|
46
- | VSCode (`entrypoint: claude-vscode`) | 2.1.195 / 2.1.199 / **2.1.207** | `source:"clear"` → auto path 発火・merged:true | inheritance-decision.log の source:"clear" 11+3 件、残存 transcript 8 件の entrypoint 実測 |
47
- | Desktop (`entrypoint: claude-desktop`) | 2.1.205 | `source:"startup"`。旧/新どちらの transcript にも /clear 痕跡なし。**後継セッションは /clear 時でなく初回プロンプト送信時に生成**(65a01d22: SessionStart 11:51:56.968 → 初 user prompt 11:51:57.035、/clear はその 16 秒以上前) | 2026-07-11 の Desktop 実測ペア + 当日全 Desktop セッション |
48
-
49
- バージョン交絡(2.1.200+ リグレッション説)は VSCode 2.1.207 実測で棄却。クライアント判別は hook から env `CLAUDE_CODE_ENTRYPOINT`(`claude-desktop` / `claude-vscode`)で可能。
50
-
51
- ### 3. 案A(startup 時間窓フォールバック)不採用の根拠
52
-
53
- - 幽霊セッション: 2026-07-11 だけで user home直下のproject_pathのstartupが **182 件**(03:02〜12:56、最短間隔 0.001 秒、全て bodies=0)。haiku-workdir に 207 件=headless `claude -p` も SessionStart hook を発火する。
54
- - 幽霊がチェーンに入ると MAX_CHAIN_DEPTH=10([src/session-merger.mjs](../src/session-merger.mjs):14)へ数時間で到達し resolveMergeTarget throw → ターン捕捉が恒久停止=ここで記憶が本当に失われる。
55
- - source='startup' は「/clear の後継」と「並行して開いた別窓」を原理的に区別できず、稼働中セッションのレコードを relabel して記憶を split する。「bodies>0 の前任だけ選ぶ」は前任側フィルタなので無効(refuter 検証済み)。
56
-
57
- ### 4. SessionEnd hook 仕様(公式 docs live fetch 2026-07-11)
58
-
59
- - SessionEnd は実在し、matcher が `reason` でフィルタ可能。reason enum: **`clear` / `resume` / `logout` / `prompt_input_exit` / `bypass_permissions_disabled` / `other`**。
60
- - SessionStart source enum: `startup` / `resume` / `clear` / `compact`。
61
- - **SessionEnd hook のデフォルト timeout は 1.5 秒**(/clear にも適用)→ per-hook timeout 明示が必須(サイレント kill によるバトン喪失対策)。
62
- - Desktop が /clear 時に SessionEnd(reason='clear') を実際に発火するかは**未検証**(source を誤ラベルするクライアントなので要実測)→ A Phase 1 spike。
63
-
64
- ### 5. オーナーの 4 セッション連続 /clear テスト(2026-07-11 13:15-13:17, VSCode 2.1.207)
65
-
66
- チェーン 4ef0d886 → c3e4e5d8 → ea60a1c9 → 9e74467d。マージは 3 回全部成功(auto ×2 + baton ×1)だが、**テスト全体で捕捉された L2 は 1 ターンのみ**(書込 13:16:45)。clear #1 (13:15:46)・#2 (13:16:18) の注入時点で DB は空 → 空の記憶を注入 → 体感「引き継げてない」で正解。3 回目の成功は /tl ではなく捕捉が追いついたため。state ファイルの 299 bytes(usage 無し=[src/turn-processor.mjs](../src/turn-processor.mjs) の `!assistantTurn` 早期離脱痕跡)vs 397 bytes(フル実行)が Stop 空振りの証拠。
67
-
68
- ### 6. L2 捕捉欠落の全域調査(論理ターン単位・完了ターンのみ・haiku-workdir 除外)
69
-
70
- | クライアント | セッション | 完了論理ターン | 未捕捉 | 率 |
71
- |---|---|---|---|---|
72
- | claude-desktop (2.1.205) | 13 | 133 | 36 | **27.1%** |
73
- | claude-vscode (2.1.199-206) | 6 | 155 | 63 | **40.6%** |
74
-
75
- - 論理ターン=「user テキスト → 後続 assistant 断片群の最後の断片」。捕捉判定は bodies の (origin_session_id, turn_number=最終断片 index, role='assistant') 存在。
76
- - VSCode 側の欠落は **transcript に本文が現存する**(調査自体が transcript から読めている)= Throughline 側の捕捉漏れ → B-1 で修正可能。
77
- - 実在確認済みの欠落例: f1ad5b6f (WebAICoding) の実会話ターン #1/#3/#6 等。
78
- - 注意: queued メッセージ(連続 user テキスト)が論理ターンを水増しする可能性は残る=率は上限値の目安。
79
-
80
- ### 7. Desktop transcript の assistant 本文欠落(B-2・unconfirmed)
81
-
82
- 本調査セッション自身(d7650b10, Desktop 2.1.205)の実測: assistant エントリ 93 件の内訳 thinking 48 / tool_use 36 / **text 9**。12:44〜13:15 の長いターンには本文断片が約 8 個あったが、transcript に着地したのは 1 個だけ、しかも発話から**約 16 分遅れ**(13:12:48)。残りは transcript・プロジェクトディレクトリ・~/.claude 全域・Desktop の local-agent-mode-sessions のどこにも grep ヒットせず=ローカル永久欠落。短いターン(13:17 以降)の本文は着地している。バグか仕様か(正本がサーバ/アプリ側にある可能性)は未確定。
83
-
84
- ---
85
-
86
- ## Phase 0 — 同期・安全網・正本化(憲法1/2)
87
-
88
- - [x] git 同期状態の確認(origin/main と 0/0・stash なし・untracked `.agents/` は端末ローカル残置がオーナー裁定済み=触らない)
89
- - [x] ベースラインゲート green 確認: `npm test` 549 pass / 0 fail(2026-07-11)
90
- - [x] 本プランを docs/12 として正本化(本文書)
91
- - [x] rag/01-hooks に SessionEnd reason enum を還流([session-end-reasons.md](../rag/01-hooks/raw/session-end-reasons.md))、rag/INDEX.md に Finding 8 追記
92
- - [x] 今日の調査を caveat に記録: public `claude-code-clear-userpromptsubmit-hook`(confirmed)/ private `claude-code-desktop-assistant-transcript-jsonl`(tentative・B-2 で更新)
93
- - [x] 実稼働デプロイ(2026-07-12): ローカルcheckoutをglobal install(symlink化=リポ変更が即時反映。リリース時はregistry版へ戻す)
94
-
95
- ## Workstream B-1 — 捕捉のバックフィル化(先行。A の E2E 品質の前提。挙動修正レーン=挙動差を明文化して個別承認)
96
-
97
- - [x] **B-1 設計の着手前 refuter**: 判定「目的は正当・原設計のままでは採用不可」。修正 7 件を採用: ①群レベル dedup 必須(部分捕捉済み群への再挿入は同一発話の重複ペアを 110 件量産——実在確認: d7650b10 turn14/15。割り込みは tool_result 内に埋まり user 境界として不可視のため 1 群複数 Stop が日常)②前任 transcript path は project_path から決定的導出(state は Stop 不発前任で存在しない)③junk 代表除外(session limit 通知等)④INSERT を 1 トランザクション ⑤created_at は transcript timestamp(now は一括回収で同一 ms に潰れ L2 窓・現在地アンカーの順序が tie で不定化)⑥readTranscript に isSidechain 防御 ⑦resume 直後 transcript の実測 1 回を検証項目に追加。棄却された懸念: 注入肥大化(20 ターンキャップで構造上起きない)・SessionStart レイテンシ(58MB transcript でも 155ms)
98
- - [x] **turn-processor 再設計**: [src/turn-backfill.mjs](../src/turn-backfill.mjs) 新設(全論理ターン群走査 + 群レベル dedup + junk 除外 + timestamp created_at + 単一トランザクション)、turn-processor は毎 Stop でこれを呼ぶ。回収実績は `~/.throughline/logs/backfill.log`。機能検証済み: 実 transcript × 隔離 DB で回収 12 群・冪等(2 回目 0 挿入)・部分捕捉群の重複ガード・junk 0 行・created_at 順 = 会話順 【F: 統括直轄】
99
- - [x] queued メッセージの扱いを明文化: 群 = 「user テキスト → 後続 assistant 断片群」なので、応答前に積まれた先行 queued user は断片 0 の群となり捕捉されない(現行 getLastTurnPair と同等の非対応。将来課題)
100
- - [x] session-start のマージ直後にも同じバックフィルを前任 transcript に対して実行(project path からの決定的導出を優先し、state file は Stop 不発前任のため補助)→ 「/clear 直前ターンの取りこぼし」を注入前に回収。失敗は stderr + `backfill.log` に明示し、注入は継続
101
- - [x] 診断ログ: バックフィルで回収したターン数を stderr ではなく `~/.throughline/logs/backfill.log` に記録(Stop / session-start 共通)
102
- - [x] テスト: 全ターンスキャンの単体(群レベル dedup、冪等性、junk、timestamp、sidechain、path munging)と hook subprocess(multi-turn / state 無し前任)の特性化を追加。`npm test`: 559 pass / 0 fail(2026-07-12)
103
- - [ ] 検証: 欠落率調査スクリプト(付録)を再実行し、新規セッションで欠落 0% を確認
104
-
105
- ## Workstream A — Desktop /clear 引き継ぎ発火(SessionEnd バトン方式)
106
-
107
- ### A Phase 1 — spike 実測(Desktop の SessionEnd 白黒判定)
108
-
109
- - [x] spike ロガー hook(`spike/session-end-logger.mjs`): stdin 全 payload + `CLAUDE_CODE_ENTRYPOINT` + 受信時刻を記録 【A → codex_work `gpt-5.6-terra`×medium で実装、統括が検証 3 本再実行済み。sidecar 側 PROTOCOL_ERROR(報告 envelope の schema 不一致)が出たが成果物は worktree から採用】
110
- - [x] `~/.claude/settings.json` に SessionEnd を一時登録(絶対パス node + 絶対パス spike・timeout 10 明示。バックアップ: `~/.claude-settings-backup-20260711-235419.tar.gz`。撤去 = SessionEnd ブロック削除 + spike ファイル削除)【F: 統括直轄】
111
- - [x] 実測プロトコル 【H: オーナー操作 2026-07-12 15:00-15:10 UTC】: ①Desktop /clear(③はアプリ終了の代わりにセッション削除で実施)②放置 ③削除 ④VSCode /clear。結果:
112
-
113
- | 操作 | SessionEnd 発火 | reason | 備考 |
114
- |---|---|---|---|
115
- | Desktop `/clear`(d93b0d5f) | **即時**(返答 15:05:52 → 15:05:59) | **`other`** | payload は session_id/prompt_id/reason/cwd/transcript_path のみ・判別子なし |
116
- | Desktop 放置(a8ece26f) | 発火せず | — | |
117
- | Desktop セッション削除(675493fb) | 発火(12 秒後) | **`other`** | payload 構造は /clear と完全同一 |
118
- | VSCode `/clear`(fa43271f) | 即時 | **`clear`** | 42ms 後に後継 SessionStart(source=clear)→auto merge。仕組み自体は健全 |
119
-
120
- 副次発見: Desktop のuser home直下の幽霊セッションも SessionEnd(other) を高頻度で発火する。
121
- - [x] 判定: **NO-GO**。Desktop は /clear で SessionEnd を即時発火するが reason を `other` にラベルし、**セッション削除(明示的破棄)と区別不能**。reason=other でバトンを書くと削除セッションの記憶が次セッションに蘇る誤注入 + 幽霊バトン汚染。reason 不問の退行案は不採用(計画どおり)。→ A Phase 2 は実装せず停止、fallback 裁定へ
122
- - [x] spike 撤去: settings.json から SessionEnd 登録を削除(JSON 検証済み)、spike ファイル削除(git 履歴に残存)。実測ログ `~/.throughline/logs/session-end-spike.log` は証拠として保全
123
-
124
- ### A Phase 2 — 本実装(GO の場合のみ。refuter で出た穴 4 件の対策込み)
125
-
126
- > **2026-07-12 NO-GO につき凍結**。Desktop が SessionEnd reason を正しくラベルする(または SessionStart source='clear' を送る)ようになった時点で解凍可。fallback は Phase 1 実測表とともにオーナー裁定: 案C(明文化 + /tl 運用)+ upstream 報告(証拠は二重: SessionStart source=startup 誤ラベル + SessionEnd reason=other 誤ラベル、VSCode 対照つき)。オーナー裁定 (2026-07-12): fallback 案C 採用・upstream 報告提出済み https://github.com/anthropics/claude-code/issues/76704 (修正が入れば auto path がそのまま Desktop で復活する)。
127
-
128
- - [ ] schema v9: `handoff_batons.origin` 列(`'tl' | 'clear-prompt' | 'clear-session-end'`)【F: 統括直轄】
129
- - [ ] バトン上書き規則: 明示 /tl は TTL 内なら自動バトンに上書きされない(明示意思 > 自動)。consumeBaton は origin を返し inheritance-decision.log に `baton_origin` 記録 【F: 統括直轄】
130
- - [ ] `src/session-end.mjs` 新設: reason==='clear' かつ `THROUGHLINE_DISABLE_AUTO_HANDOFF !== '1'` で writeBaton。全イベントを session-end.log に記録。import-safe run() 型 【A: 実装物量 → 02_models.md:40】
131
- - [ ] bin dispatch / install.mjs SC_HOOKS 追加(**per-hook timeout 明示** — 既定 1.5 秒 kill 対策)/ uninstall / doctor 表示 【A: 実装物量 → 02_models.md:40】
132
- - [ ] テスト: baton origin 規則・session-end subprocess・db-schema v9・install 冪等 【A: 実装物量 → 02_models.md:40 → 統括 diff レビュー + ゲート再実行】
133
- - [ ] TTL は /tl と同じ 1 時間(一貫性優先。短縮代替案: clear 由来のみ 5〜10 分に絞る案があったが、Desktop は後継生成が初回プロンプト時なので取りこぼしリスクと引き換え=不採用の記録)
134
-
135
- ### A Phase 3 — E2E・後始末
136
-
137
- - [x] spike hook 撤去(settings.json 復元確認)
138
- - [x] E2E(2026-07-12 実機・緑): Desktop `/tl`(前任 6c58be18)→ `/clear` → 後継 e8bb5bd3 が `triggered_path:"baton"`・merged:true。`backfill.log` に `hook:"session-start" origin:6c58be18`。後継 bodies に前任の全ターン(turn 1/3/5/8、`/tl` 直前の turn 5 含む)。後継モデルが「前のセッションから記憶を引き継いだ」と自覚。→ 0.6.0 リリースへ
139
- - [x] `npm test` 全緑、CLAUDE.md / README / docs 更新、caveat_update で `claude-code-desktop-clear-sessionstart-source-startup-throughline` の resolution 更新(2026-07-12 更新済み)
140
-
141
- ## Workstream B-2 — Desktop transcript 本文欠落の条件特定(調査のみ。実装なし)
142
-
143
- - 2026-07-12 追試 — 本調査セッション自身で欠落が継続再現(15:20 以降の本文 ~8 個中 5 個のみ着地・中間分析テキストが欠落)。短ターン(オーナーのテストセッション 4 本)は全て着地 → 「長い tool 連発ターンで欠ける」仮説と整合。保存構造棚卸しは Claude レーンで実行中(会話実データを外部枠に流さないプライバシー優先の逸脱 — 02_models.md:36 の既定から明示逸脱)。
144
- - [x] 最小再現・条件特定(2026-07-12): 短ターン(1 往復)は本文が必ず着地(オーナーのテストセッション 4 本 + 過去実績)。欠落は**長い tool 連発ターンの中間テキスト**で発生し、同一セッションで 2 回ライブ再現(12:44-13:15 は本文 8 個中 1 個のみ・16 分遅延着地/15:20-15:35 は ~8 個中 5 個)。厳密な断片選択規則は Desktop 内部実装依存で外部から特定不能と判断
145
- - [x] 保存構造の read-only 棚卸し(Claude レーン Explore agent。会話実データを外部枠に流さないプライバシー優先の逸脱): **Desktop の App Support ストア(LevelDB / IndexedDB / SQLite / session JSON)は会話本文を一切保持しない**。3 エンコーディング全域走査で、JSONL に実在する対照プローブすら 0 件。session JSON はメタデータのみ。→ `~/.claude/projects/*.jsonl` が唯一のローカル本文ストアで、**書かれなかった本文はサーバ側のみ=ローカル回収経路なし**(確度: 高)
146
- - [x] 結論を caveat(`claude-code-desktop-assistant-transcript-jsonl`、confidence: reproduced へ更新)と本文書に記録
147
- - [x] **upstream 報告 #2 提出済み**(2026-07-12・オーナー承認済み): [anthropics/claude-code#76706](https://github.com/anthropics/claude-code/issues/76706)(長い tool 連発ターンで assistant text ブロックが transcript JSONL に永久欠落・ローカル回収経路なし・VS Code は正常)
148
-
149
- ## 実装しないこと
150
-
151
- - 案A startup 時間窓フォールバック / reason 不問バトン / prompt-submit の /clear 分岐削除(無害残置)
152
- - B-2 の「修正」実装(原因が CC 側なら Throughline では直せない。B-1 のバックフィルが Throughline 側でできる最大限)
153
-
154
- ## 検証コマンド
155
-
156
- ```bash
157
- npm test
158
- node bin/throughline.mjs doctor
159
- tail -f ~/.throughline/logs/session-end-spike.log # A Phase 1
160
- tail -f ~/.throughline/logs/inheritance-decision.log # A Phase 3 (baton_origin)
161
- ```
162
-
163
- ## 付録 — 欠落率調査スクリプト(B-1 検証用・read-only)
164
-
165
- ```javascript
166
- // node --input-type=module < この内容 (リポジトリルートで実行)
167
- import { getDb } from './src/db.mjs';
168
- import { readTranscript } from './src/transcript-reader.mjs';
169
- import { existsSync, readFileSync } from 'node:fs';
170
- import { join } from 'node:path';
171
- import { homedir } from 'node:os';
172
-
173
- const db = getDb();
174
- const sessions = db.prepare(`
175
- SELECT session_id, project_path FROM sessions
176
- WHERE merged_into IS NULL AND session_id NOT LIKE 'codex:%'
177
- ORDER BY updated_at DESC LIMIT 300
178
- `).all();
179
- const projRoot = join(homedir(), '.claude', 'projects');
180
- const tPath = (p, sid) => {
181
- const f = join(projRoot, p.replace(/[\/.]/g, '-').replace(/^-?/, '-'), sid + '.jsonl');
182
- return existsSync(f) ? f : null;
183
- };
184
- const logicalTurns = (turns) => {
185
- const r = []; let cur = null;
186
- for (let i = 0; i < turns.length; i++) {
187
- if (turns[i].role === 'user') { if (cur) r.push(cur); cur = { lastAsstIdx: -1 }; }
188
- else if (turns[i].role === 'assistant' && cur) cur.lastAsstIdx = i;
189
- }
190
- if (cur) r.push(cur);
191
- return r.filter(lt => lt.lastAsstIdx >= 0);
192
- };
193
- const byClient = {};
194
- for (const s of sessions) {
195
- if (s.project_path.includes('haiku-workdir')) continue; // 再帰ガードで捕捉しない設計
196
- const tp = tPath(s.project_path, s.session_id);
197
- if (!tp) continue;
198
- const lts = logicalTurns(readTranscript(tp));
199
- if (lts.length < 2) continue;
200
- let ep = null;
201
- for (const line of readFileSync(tp, 'utf8').split('\n')) {
202
- try { const e = JSON.parse(line); if (e.entrypoint) { ep = e.entrypoint; break; } } catch {}
203
- }
204
- if (!ep) continue;
205
- const cap = new Set(db.prepare(
206
- `SELECT turn_number FROM bodies WHERE origin_session_id = ? AND role = 'assistant'`
207
- ).all(s.session_id).map(r => r.turn_number));
208
- const scanned = lts.slice(0, -1); // 最終ターンは進行中の可能性 → 除外
209
- const miss = scanned.filter(lt => !cap.has(lt.lastAsstIdx)).length;
210
- byClient[ep] ??= { sessions: 0, turns: 0, missing: 0 };
211
- byClient[ep].sessions++; byClient[ep].turns += scanned.length; byClient[ep].missing += miss;
212
- }
213
- for (const [k, v] of Object.entries(byClient))
214
- console.log(k, v, `${(100 * v.missing / v.turns).toFixed(1)}%`);
215
- ```
6
+ 現行契約は [02_clear_auto_handoff_plan.md](02_clear_auto_handoff_plan.md) を正とする。
7
+ Claude Desktop は `SessionStart source='clear'` を送らないため、組み込み `/clear` の前に
8
+ `/tl` を実行する。VS Code `source='clear'` auto path を使う。
@@ -1,89 +1,8 @@
1
- # Windows CI・リリース待ち時間改修計画
1
+ # Windows CI latency plan(履歴入口)
2
2
 
3
- ## 目的
3
+ この計画は完了し、
4
+ [archive/15_windows_ci_release_latency_plan.md](archive/15_windows_ci_release_latency_plan.md)
5
+ へ移した。旧pathを固定したLattice planとの互換性のため、この入口だけを残す。
4
6
 
5
- ThroughlineのWindows CIがLinux/macOSの約1分に対して16〜18分かかり、定型release
6
- 実用不能な長さへ押し上げている。Windows互換性matrixとowner-only ACL契約を維持したまま、
7
- unit testを5分以内(目標3分以内)へ短縮し、release前の同一candidateに対するCIを1回へ
8
- 集約する。
9
-
10
- ## 現状の実測
11
-
12
- GitHub Actions run `29722650046`(Windows Node 22.13.0)のTAP計測では、次の3テストが
13
- 突出していた。TAP durationはwall timeとして加算せず、job全体の実測約18分をbaselineとする。
14
-
15
- | テスト | `duration_ms` |
16
- |---|---:|
17
- | observer feed: Claude history floor, host/thread switch, cross-host tie, and opaque cursor | 568,093 ms |
18
- | completed turn receipt: bounded store drops only oldest receipts | 559,807 ms |
19
- | completed turn receipt: noisy project cannot evict another project anchor | 436,267 ms |
20
-
21
- 3テストはいずれも256件境界を作るため公開APIを257回呼び、その各mutationでWindows
22
- PowerShellを複数回起動してdirectory/lock/temporary/final storeのACLを検証している。
23
- 境界計算の反復とACL実機検証が結合されていることが主因で、runner一般の遅さではない。
24
-
25
- また現行workflowはmainへのpushごとに9 matrixを新規起動し、同じbranchの旧runをcancelしない。
26
- 短時間の段階commitでWindows 18分runが重複する。
27
-
28
- ## 決定
29
-
30
- 1. completed-turn receiptの大量境界テストは、正規schemaの境界直前storeをfixtureとして用意し、
31
- 最後の1 mutationだけ公開APIで実行する。limit超過、history floor、project分離、cursor判定の
32
- 受入条件は変更しない。
33
- 2. Windows owner-only ACLは専用integration testでdirectory、SQLite lock、final storeを
34
- `windows-acl-test-helper`から外部検証する。大量境界テストからPowerShell反復を除いても、
35
- production ACL契約の実機coverageを失わない。
36
- 3. CIのunit test stepへ`timeout-minutes: 8`を設定する。SLOは5分、目標3分としrunner遅延と分離する。
37
- 4. workflowへevent/ref単位の`concurrency`を設定し、新しいcommitが来た時は同一event/refの
38
- 古いrunだけをcancelする。手動runとpush/PRは相互cancelしない。
39
- 5. OS 3種 × Node `22.13.0`/`22.x`/`24.x`の9 matrixは維持する。互換範囲を速度対策のために
40
- 縮小しない。
41
- 6. `0.8.7`の最終candidateへ実装・version・CHANGELOG・README・正本文書をまとめ、push後CIを
42
- 1回だけrelease gateとして使う。公開後のSHA/CI番号はGitHub Releaseを正本とし、証拠追記だけの
43
- 追加commit/追加CIを作らない。
44
-
45
- ## 非目標
46
-
47
- - Windows ACLの適用・read-back検証、atomic rename、失敗時の旧store保持を弱めない。
48
- - Windows testをskipしない。matrixのOS/Node versionを減らさない。
49
- - completed-turn receiptの256件limit、history floor、cursor、project分離契約を変えない。
50
- - Claude hooks、Codex adapter、DB migration、handoff契約を変更しない。
51
- - release自動publishやcredential保管をworkflowへ追加しない。
52
-
53
- ## 既知の罠
54
-
55
- - fixtureを直接書くだけでは公開APIの境界mutationを検証できない。必ずlimit直前から最後の1件を
56
- `writeCompletedTurnReceipt`で追加する。
57
- - Windowsでfixtureを書き換える時も既存owner-only ACLを保持し、専用ACL testはproduction APIが
58
- 作った実pathを外部helperで検査する。
59
- - `concurrency.cancel-in-progress`は別branch/別PRをcancelしないref単位にする。
60
- - test timeoutはunit test stepへ8分で置き、5分SLOにrunner一時遅延の余白を持たせる。
61
- - 進行中の旧CIを新しいcandidateの成功証拠として流用しない。
62
-
63
- ## 受入条件
64
-
65
- - [ ] 3つの大量境界テストが公開契約を維持したままPowerShell反復を行わない。
66
- - [ ] Windows専用ACL testがdirectory/lock/storeのowner-only ACLを外部検証する。
67
- - [ ] focused testとfull `npm test`がgreen。
68
- - [ ] CI定義にunit test 8分上限とevent/ref単位concurrencyがある。
69
- - [ ] 最終GitHub Actionsで9/9 green、Windows各jobのunit testが5分以内(目標3分以内)。
70
- - [ ] `npm pack --dry-run --json`で公開物を確認する。
71
- - [ ] npm `throughline@0.8.7`、tag/GitHub Release、registry由来global install、
72
- `throughline --version = 0.8.7`、配置skill/hooks/doctorを確認する。
73
-
74
- ## 敵対的検証の反映
75
-
76
- read-only refuterはP0なし、P1を4件報告した。TAP durationをwall timeとして加算しないこと、
77
- temporary ACL失敗時の旧store保持testを加えること、concurrencyへ`event_name`を含めること、
78
- 5分SLOとtimeoutを分離することを採用した。fixture seedと本体の重複ACL検証削減は、最後の公開API
79
- mutation、native final-path ACL test、atomic failure testを同時に置く条件で妥当と裁定した。
80
-
81
- ## 工程
82
-
83
- 工程状態と完了証拠の正本はLattice storeとし、この文書は目的、判断、非目標、受入条件を所有する。
84
-
85
- 1. ベースライン計測と原因同定
86
- 2. 敵対的検証と設計裁定
87
- 3. 安全網とfixture分離
88
- 4. workflow・文書統合
89
- 5. push後CI、npm公開、global install
7
+ 現行のCIrelease契約は [04_public_release_plan.md](04_public_release_plan.md) と
8
+ [ADR 0020](adr/0020-windows-ci-release-latency.md) を参照する。
@@ -1,40 +1,9 @@
1
- # Read-only handoff context
1
+ # Read-only handoff context plan(履歴入口)
2
2
 
3
- ## 目的
3
+ この計画は完了し、
4
+ [archive/16_readonly_handoff_context_plan.md](archive/16_readonly_handoff_context_plan.md)
5
+ へ移した。旧pathを固定したLattice evidence・planとの互換性のため、この入口だけを残す。
4
6
 
5
- 通常 handoff が使う `buildBudgetedResumeContext` の出力を、DB 所有権を変えずにローカルプログラムが
6
- 取得できる read-only CLI として公開する。最初の consumer は AIterm の portable fork だが、I/F は
7
- 特定 consumer や harness に依存させない。
8
-
9
- 実行 ToDo、依存、状態、完了証拠の正本は Lattice plan `readonly-handoff-context` とする。
10
-
11
- ## 完了
12
-
13
- 2026-08-04に`throughline@0.9.0`としてnpm、tag、GitHub Release、global installまで公開した。
14
- focused契約testと全回帰は729 pass/1 skip/0 fail。AIterm v0.23.0の代表cross-harness smokeでは
15
- Codex source memoryをClaudeへ注入し、前後でsource session、`sessions.merged_into`、L1/L2/L3 row所属が
16
- 完全一致することを確認した。公開後の現行ドキュメント全域監査は、Latticeの終端ToDoを再openして
17
- README、作業者入口、配布Codex skill、docs索引、計画、CHANGELOGへ同期した。変更Markdownの
18
- 相対リンク監査とCLI help/handoff-contextのfocused test 5/5を通過した。
19
-
20
- ## 契約
21
-
22
- - `throughline handoff-context --session <id> --json` は session を明示必須とする。
23
- - 既存 DB を `DatabaseSync(..., { readOnly: true })` で開き、作成・migration・書込みをしない。
24
- - `buildBudgetedResumeContext(db, { sessionId, isInheritance: true })` をそのまま使う。
25
- - 成功 JSON は schema、status、sessionId、context だけを返す。renderer 統計は公開しない。
26
- - 引数不正、DB open 失敗、context 不在は非 0 終了とする。
27
-
28
- ## 非目標
29
-
30
- - baton、pending handoff、merge、backfill、通常 SessionStart / UserPromptSubmit の変更。
31
- - Observer projection、Codex 専用 renderer、latest session 推測、project/cwd 照合。
32
- - DB schema 全面診断、hash、cursor、暗号化、daemon、network I/O、retry、cache。
33
- - budget や `excludeOriginId` を CLI option として公開すること。
34
-
35
- ## 受入条件
36
-
37
- - CLI の context が同じ DB に対する既存 budgeted renderer の出力と完全一致する。
38
- - 実行前後で `sessions.merged_into` と L1/L2/L3 の `session_id` が変わらない。
39
- - DB 不在時に DB や親ディレクトリを作らない。
40
- - focused test と全回帰が成功し、公開 package と global install から新 command を実行できる。
7
+ 現行の `throughline handoff-context --session <id> --json` 契約は
8
+ [README.md](../README.md)
9
+ [公開JSON例](throughline-handoff-context.example.json) を参照する。
@@ -10,7 +10,7 @@ Observerは監査対象の完了turnを複数pageで読む。一回のread serie
10
10
  転用できる。
11
11
 
12
12
  この裁定はControlのDecision証拠に使うため、追記可能な
13
- `docs/14_observer_completed_turn_feed_plan.md`へ契約本文を追加せず、wave専用の不変ADRとして置く。
13
+ `docs/archive/14_observer_completed_turn_feed_plan.md`へ契約本文を追加せず、wave専用の不変ADRとして置く。
14
14
 
15
15
  ## Decision
16
16
 
@@ -75,7 +75,7 @@ Accepted(実装済み・live acceptance 済み — 本ADR末尾の記録参照
75
75
  ### 廃止・撤去
76
76
 
77
77
  - SessionStart の注入経路と、それにぶら下がっていた Phase 0-2 spike /
78
- Phase 0-6 `initialUserMessage` テスト分岐(docs/10 で両 no-go 確定済みの実験残骸)。
78
+ Phase 0-6 `initialUserMessage` テスト分岐(docs/archive/10 で両 no-go 確定済みの実験残骸)。
79
79
  - 「UserPromptSubmit は注入しない」規約 — 理由だった「SessionStart との二重注入」が
80
80
  SessionStart 注入の廃止で消滅したため、注入責務ごと UserPromptSubmit へ移す。
81
81
 
@@ -18,7 +18,7 @@ Accepted — 2026-07-20
18
18
  - full test: 実装受入時の `npm test` green
19
19
  - GitHub CI: run `29724249940`、Node 22.13.0/22.x/24.x × macOS/Ubuntu/Windowsの9/9 green
20
20
  - clean pack: 208 files、`src/cli/migrate.mjs`を収録し、並行作業の
21
- `docs/15_windows_ci_release_latency_plan.md`を含まないことを機械確認
21
+ `docs/archive/15_windows_ci_release_latency_plan.md`を含まないことを機械確認
22
22
 
23
23
  ## 公開証拠
24
24
 
@@ -34,7 +34,7 @@ Grok stores turns in `~/.grok/sessions/<encodeURIComponent(cwd)>/<sessionId>/cha
34
34
 
35
35
  Grok 1.0.4 バイナリの hook 出力型は `GateHookJson`(PreToolUse deny/updatedInput)と `StopHookJson`(block/additionalContext/stopReason)だけ。UserPromptSubmit / SessionStart / PostToolUse の stdout は observe。モデルへ文章を渡せる公式口は (1) PreToolUse deny の reason (2) Stop/SubagentStop の block reason / additionalContext / exit2 stderr。初回トークン前の prompt 注入口は無い。Stop 注入は初回返答のあと 2 周目に載る。`01a00cfe` の chat_history 書き込みは updates に乗らず実証済み。capture と handoff-context は生きている。
36
36
 
37
- `/tl` 後の記憶再開は hook stdout や `chat_history.jsonl` 再注入では成立しない。後継経路は Throughline 所有の最小起動に固定する。正本は [plan_grok-successor-launch.md](../plan_grok-successor-launch.md)。
37
+ `/tl` 後の記憶再開は hook stdout や `chat_history.jsonl` 再注入では成立しない。後継経路は Throughline 所有の最小起動に固定する。実装・受入履歴は [plan_grok-successor-launch.md](../archive/plan_grok-successor-launch.md)。
38
38
 
39
39
  - CLI: `throughline grok-continue --session <id>`。`<id>` は `grok:` 接頭辞付き Throughline session id。`--from` は採用しない。
40
40
  - 内部で `handoff-context --session <id> --json` を読む。ready でなければ spawn しない。
@@ -0,0 +1,39 @@
1
+ # ADR 0022: Treat Cursor as a first-class Throughline host
2
+
3
+ Date: 2026-08-24
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ dotagents Wave 5 made Cursor a peer factory harness. Throughline still had only Claude / Codex / Grok adapters. Cursor parent sessions were not captured.
12
+
13
+ Cursor hook envelope is not Claude PascalCase and not Grok camelCase. Official events are `sessionStart`, `beforeSubmitPrompt` (Claude `UserPromptSubmit` 相当), and `stop`. Common fields include `conversation_id`, `workspace_roots`, `cursor_version`, and optional `transcript_path`.
14
+
15
+ L2 lives in `~/.cursor/projects/<slug>/agent-transcripts/<uuid>/<uuid>.jsonl` with role-first rows (`{role, message.content}`), not Claude `{type, message}`.
16
+
17
+ `beforeSubmitPrompt` stdout is `{continue}` only. `sessionStart` may return `additional_context`. Cursor has a single `~/.cursor/hooks.json`; factory hooks already occupy that file.
18
+
19
+ ## Decision
20
+
21
+ - Detect Cursor envelope (`cursor_version` or `hook_event_name` in the Cursor event set) as host=cursor.
22
+ - Normalize to the existing snake_case hook contract and prefix ids with `cursor:`. Strip optional `bc-` from cloud conversation ids when looking up transcripts.
23
+ - Prefer payload `transcript_path`. If absent, derive the agent-transcripts path. Do not invent a Claude-shaped transcript.
24
+ - `throughline install` upserts product hooks into `~/.cursor/hooks.json`. Keep factory / personal commands. Command is absolute `node` + `bin/throughline.mjs`. Do not write factory.json. Do not write bare `throughline`.
25
+ - Cursor `sessionStart` of a new composer conversation is the handoff injection mouth (`additional_context`). Consume pending there. Skip `is_background_agent`. Claude ghost-SessionStart rules stay on Claude.
26
+ - `/tl` writes a baton. Do not auto-launch a successor Cursor chat. The next new conversation's `sessionStart` drinks the baton.
27
+ - Keep Claude, Codex, and Grok adapters unchanged. Do not mix `cursor:` rows into Claude predecessor search.
28
+
29
+ ## Consequences
30
+
31
+ - Cursor capture / restore / `handoff-context` reuse the existing DB after hook fire exists.
32
+ - Live injection in the same conversation after `/tl` is not a Cursor contract (no additional_context on `beforeSubmitPrompt`).
33
+ - Factory apply-cursor-config must keep Throughline commands, matching the existing personal-hook upsert.
34
+
35
+ ## 現在地
36
+
37
+ 公式 Cursor hooks 文書(2026-08-24)とこのMacの
38
+ `~/.cursor/projects/Users-kite-Developer-dotagents/agent-transcripts/<uuid>/<uuid>.jsonl`
39
+ を実測した。公開後の新規 Cursor session 受入は別 H。