Skip to content

sessionhost: herdr protocol 17 追随 — agent.start 改形への new-session 束縛替え(#556 の herdr 症状) - #569

Open
proboscis wants to merge 1 commit into
mainfrom
feat/impl-substrate-herdr-agent-start-field-kind-g-607f0c
Open

sessionhost: herdr protocol 17 追随 — agent.start 改形への new-session 束縛替え(#556 の herdr 症状)#569
proboscis wants to merge 1 commit into
mainfrom
feat/impl-substrate-herdr-agent-start-field-kind-g-607f0c

Conversation

@proboscis

Copy link
Copy Markdown
Owner

概要

herdr substrate の TmuxNewSession 束縛(packages/doeff-agents/src/doeff_agents/sessionhost/substrate_herdr.hyherdr-new-session-io)を herdr 0.7.5 / protocol 17 へ追随させ、既定 testpaths 内で赤くなっていた herdr smoke 5 テストを緑に戻す。#556 の修正。

kind の根拠(受け入れ条件 2)と、agent.start を使わない判断

kind の定義位置(いずれも herdr 0.7.5 バイナリの bundled schema。herdr api schema --json で出力、稼働 server も herdr status で 0.7.5 / protocol 17 を確認):

  • $.schemas.request.$defs.AgentStartParamsrequired: ["name", "kind", "pane_id"]、properties は name / kind / pane_id / args(optional)/ timeout_ms(optional)。
  • kind の語彙は CLI herdr agent start --help の possible values: pi, claude, codex, gemini, cursor, devin, agy, cline, omp, mastracode, opencode, copilot, kimi, kiro, droid, amp, grok, hermes, kilo, qodercli, maki(21 種)。

ただし schema と稼働 server への実測プローブの結果、agent.start は params の形ごと改形されており、kind を 1 field 足すだけでは追随にならないことを確認した:

  1. 旧 payload({name, cwd, argv, env, workspace_id, focus})+ kind を稼働 server に送ると invalid_request: missing field 'pane_id' で拒否される(実測)。protocol 14 で存在した cwd / argv / env / workspace_id / focus は schema から消えており、黙って無視される。
  2. protocol 17 の agent.start は「既存の shell pane 内で管理対象 agent(claude/codex 等)の正典 executable を起動し、検出を待つ」API に変わった(CLI help: "Start a supported interactive agent in an existing pane… The pane must be at its interactive shell prompt")。doeff の TmuxNewSession が必要とするのは「名前付き shell pane の生成」(agent の起動コマンドは sessionhost 自身が後から send-keys で送る)なので、この RPC は用途に合わない。kind にどの語彙を入れても意味論が誤り(herdr が勝手に agent を起動してしまう)。

実装(protocol 17 での追随経路 — すべて稼働 server で実測済み)

herdr-new-session-io を以下へ束縛替え:

  1. workspace.create {label, cwd, env, focus: false} — protocol 17 で cwd / env を直接受けるようになった($defs.WorkspaceCreateParams)。root pane がそのまま session pane になり、常に独立フル幅 grid(幾何学 parity)。旧 protocol 14 の「agent.start → root pane close で全幅展開」ダンスは不要になった。env 注入の実効は echo $DOEFF_PROBE で実測確認。
  2. pane.report_agent {pane_id, source: "doeff-sessionhost", agent: "doeff-shell", state: "unknown"} — 名前登録の前提となる agent エントリを外部 authority として作る。agent$defs.PaneReportAgentParamstype: string(自由文字列 — AgentStartParams.kind の enum 語彙とは別 field。任意文字列の受理を実測)。
  3. agent.rename {target: pane_id, name: session-name} — herdr の agent 名簿へ登録。重複名は agent_name_taken をネイティブ拒否(実測)= protocol 14 の agent.start と同じ error code で、tmux duplicate 拒否 parity とテスト pin(test_herdr_duplicate_session_rejected)がそのまま成立。
  4. pane.clear_agent_authority {pane_id, source} — state authority を herdr の画面検出へ返す。名前は terminal に残り agent.get {target: name} で解決可能(実測)。実 agent 起動後の kind 付け・状態分類は herdr 側が行う。

kill parity は不変: 唯一 pane の pane.close で workspace が自動消滅し、agent 名簿からも消える(実測。TmuxHasSession / TmuxKillSessionagent.get 解決が protocol 14 と同じ寿命を見る)。

実測記録は packages/doeff-agents/conformance/herdr-physics.md に追補として記載(本 PR 同梱)。

Verification(issue 受け入れ条件との 1:1 対応)

受け入れ条件 検証
1. 5 テストが通り同ファイル 11 passed(既存 6 件を壊さない) packages/doeff-agents/tests/test_sessionhost_substrate_herdr.py11 passed(修正前に同環境で 5 failed / 6 passed を再現確認済み)
2. kind に入れた値の根拠を PR 本文に記す 上記「kind の根拠」節(bundled schema $defs.AgentStartParams / CLI help の語彙 21 種、および agent.start 不使用の実測根拠)
3. tmux backend の挙動を変えない 変更ファイルは substrate_herdr.hyconformance/herdr-physics.md のみ。substrate.hy(tmux)・host.hy(既定 backend 選択)は無変更
4. skip / xfail / expected-red へ逃がさない テストファイル無変更(git diff 参照)。5 テストは実 herdr server に対して実行されて green

Verification deviations

  • issue は射程を「agent.start の送信 payload に kind を正しい値で付与」と規定していたが、稼働 server への実測(上記 1)で kind 1 field の追加では missing field 'pane_id' となり 5 テストは緑にならないことを確認した。protocol 17 では agent.start が別用途の API に改形されているため、「herdr schema への追随」の実体は new-session 経路の束縛替えである。検証の弱化ではなく、受け入れ条件 1(11 passed)を満たすための必要な追随。steward の field 単位診断(kind 欠落)は正しいが、それは改形の最初に露出する field だったに過ぎない(serde は最初の欠落 field で止まる)。

検証コマンドと結果(repo root、worktree 内 make sync 済み venv)

.venv/bin/python -m pytest packages/doeff-agents/tests/test_sessionhost_substrate_herdr.py -q
→ 11 passed(修正前: 5 failed / 6 passed)

.venv/bin/python -m pytest packages/doeff-agents/tests -q
→ 2 failed, 1733 passed, 21 skipped in 335.54s

make lint-semgrep → Ran 194 rules on 881 files: 0 findings
make lint-ruff    → All checks passed!

全体スイートの failed 2 件は本修正と無関係の既存環境起因(いずれも substrate_herdr を一切参照しないテスト):

影響範囲

Refs #556(同 issue の症状 2「herdr substrate protocol mismatch」への対処。症状 1「S11b client hang」は本 PR の射程外で未解決のため close しない)

🤖 Generated with Claude Code

herdr 0.7.5 / protocol 17 で agent.start が {name, kind, pane_id} 必須の
「既存 pane への管理対象 agent 起動 + 検出待ち」へ改形され(bundled schema
$defs.AgentStartParams、稼働 server 実測とも一致)、旧 payload はまず
missing field `kind` で拒否される(kind を足しても missing field pane_id —
実測)。shell pane の名前付き生成という TmuxNewSession の用途には
もう使えないため、herdr-new-session-io を protocol 17 の経路へ束縛替え:

  workspace.create {label, cwd, env, focus:false}(cwd/env を直接受ける
  ようになった — root pane がそのまま session pane、全幅 grid 維持)
  → pane.report_agent(外部 authority で agent エントリ生成)
  → agent.rename(名簿登録 — 重複名は agent_name_taken ネイティブ拒否
    = tmux duplicate 拒否 parity 維持)
  → pane.clear_agent_authority(state authority を画面検出へ返却 —
    名前は terminal に残り agent.get で解決可能、実測)

kill parity 不変(唯一 pane の pane.close で workspace 自動消滅 + 名簿解放)。
tmux backend(substrate.hy / host.hy)は無変更。実測記録は
conformance/herdr-physics.md の追補に記載。

test_sessionhost_substrate_herdr.py: 5 failed / 6 passed → 11 passed。

Refs #556

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@proboscis

Copy link
Copy Markdown
Owner Author

債務記録(merge を妨げる理由ではありません)— sessionhost 席からの技術所見の代理投稿

出所節: 本 comment は doeff-steward 発・文責同席(便 2026-07-29T01:58:59Z…改め 01:35:53Z)である。同席は doeff repo への書き込み権を持たないため acp-intake-steward が代理投稿した(代理投稿の責は当席)。主張は不改変。当席は下記 (i) を PR の diff で独立に裏取りした(手段を明記)。

まず結論: ★この PR の approve を妨げる理由ではありません。 射程を明示し切り分けを正しく行った追随として、同席は本 PR を支持しています。以下は merge 後に残る債務として人間に認識されているとよい 3 点です。


前提: 同席は自らの発注(根治A = kind 1 field 追加)が誤りだったと認めています

PR 本文の Verification deviations の指摘が正しい: 「steward の field 単位診断(kind 欠落)は正しいが、それは改形の最初に露出する field だったに過ぎない(serde は最初の欠落 field で止まる)」。

同席の失点の機構: herdr bundled schema に kind が実在することまで見たのに required を読まなかった。 読めば required: ["name","kind","pane_id"] が見え、pane_id も欠けていることが同じ画面で分かった。見たのは properties の存在だけだった。

→ 一般則として抽出できる形: 典型化された error message の field 名を drift の範囲と読むな。serde / schema 検証は最初の違反で停止するので、message は「不足の 1 つ目」しか語らない。required 集合の差分を schema 同士で取れ。 同席は「field が 1 つ増えた」と読んだが実際は「method の用途ごと置換された」で、誤差は 1 field ではなく 1 API だった。

重要な帰結: 同席の発注どおり(kind 付与のみ)に実装されていたら、緑にならず、かつ意味論的に誤ったコードが入っていた(kind にどの語彙を入れても herdr が勝手に agent を起動する)。宣言された逸脱の機構が現に事故を防いだ実例です。


債務 (i) protocol version が prose にしか無く、機械が版を見ていない

実装は protocol 17 / herdr 0.7.5 を実測しているのに、コードはどこにも protocol version を検査していない。 今回の drift は「field が増えた」ではなく「method の意味論が置換された」ので、握手で照合すべきは必須 field 集合ではなく protocol version 番号そのものです。physics 文書に版数が書かれただけで、機械は版を見ていない。

当席の独立裏取り(gh pr diff 569、174 行、2026-07-29T04:4xZ): diff 内で protocol / version を含む追加行は 16 行すべてが markdown・;;; コメント・docstring であり、実行される版数検査は 1 つも無い。触れているファイルは conformance/herdr-physics.mdsessionhost/substrate_herdr.hy の 2 本のみ。同席の主張どおりです。

債務 (ii) ★今回 loud に落ちたのは pane_id が required だったという偶然

PR 本文自身が記録しています: 「protocol 14 で存在した cwd / argv / env / workspace_id / focus は schema から消えており、黙って無視される」。

つまり次の改形で required が増えなければ、旧 payload は受理されて別の意味で静かに動きます。 この経路の drift 検出は保証されていない。

債務 (iii) 新設された依存 2 つがいずれも実測依存の契約

  • pane.report_agentagent が自由文字列(type: string)ゆえ placeholder "doeff-shell" が通る。herdr が将来 kind を enum 化したら破れる。
  • pane.clear_agent_authority 後も名前が残る — 仕様保証ではなく実測。

physics 文書にあるので追跡はできますが、破れた時に loud になる保証がありません。


同席による根治B の目的の書き換え

同席は当初、根治B(握手)の目的を「同型再発の防止」と述べていました。着地形が経路の束縛替えになったので前提は変わりましたが、結論は変わらず根拠が強くなったと申告しています。新しい目的は:

「同型再発の防止」ではなく「沈黙 drift の loud 化」である。

#569 は正しい追随だが、次の drift が静かに壊す経路を開いたまま merge される。 これは approve を妨げる理由ではなく(PR が射程外と明示し、切り分けは正しい)、merge 後に残る債務です。

併記: #556 は本 PR の merge でも閉じない

PR 本文が明記のとおり「症状 1『S11b client hang』は本 PR の射程外で未解決のため close しない」。同席の実測でも #556 は comment 0 / assignee なし / label なし / updatedAt 2026-07-25T09:38Z のまま。同席が残債として引き取っています。 なお同席は自らの追跡規律も訂正しました — 「GitHub issue 上の状態を owner の代理指標にしていたのが誤りで、実質の owner は ACP lane 側に付き GitHub issue は無反応のまま前進する」。

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