通知元を親プロセスから推測せず、実行レーン自身に名乗らせる
今回やったこと
無人ジョブの通知に、実際には通知を送っていない別のファイル名が記録される問題を修正した。従来の notify_discord.py は親プロセスのコマンド行から送信元を推定していた。しかし、Claude や Codex などのエージェントが内部で作る一時シェルから通知を呼ぶと、親のコマンド行にレーン名が残らない。その結果、通知元の分類、媒体バッジ、出口監査の入力が不正確になる。
対象は Discord の送信先を増やすことではなく、通知台帳に残る「誰が鳴らしたか」という識別情報を、起動側から確実に渡す設計へ変えることである。
推測が壊れた経路を固定する
実害は、公開後レビューの完了報告が、実際の呼び出し元ではない検証スクリプト名として台帳に入っていたことだった。当該ファイルに notify_discord.py の呼び出しはなく、親プロセスの見た目だけを信じたために、存在しない呼び出し経路を調べることになった。同じログを二重送信する経路や、通知引数が無視される経路の調査も、誤った送信元から始めると遠回りになる。
修正では、レーンを起動する側が NOTIFY_SOURCE を環境変数として設定する。scripts/lib/agent_watchdog.sh の _agent_notify_source は、まず明示された AGENT_NOTIFY_SOURCE、次に既存の NOTIFY_SOURCE を尊重する。どちらも無ければ、レーンのシェルスクリプトをリポジトリ相対パスへ変換する。basename だけにしないのは、複数媒体に同名の run-autodraft.sh があり、衝突するためである。
source "$REPO/scripts/lib/agent_watchdog.sh"
run_with_watchdog 20 probe /bin/bash -c 'echo "$NOTIFY_SOURCE"'
このウォッチドッグによる環境変数の設定は、レーンから呼び出される補助スクリプトの通知元まで一律に上書きしてしまうわけではない。レーンが子プロセスを起動するときだけ、その子孫へレーン名を渡すため、補助スクリプトが自分の通知元を明示した場合は、その名前を残せる。
手書きの送信元を監査で隠さない
エージェントが通知コマンドに --source postreview のような名前を手書きすることもある。この値をそのまま採用すると、同じレーンの通知が複数の綴りへ分散する。そこで解決後の source には配線されたレーン名を残し、手書き値は source_claimed として別に保存する。上書きした事実を捨てないため、誤った主張の発生も後から数えられる。
回帰テスト scripts/test_notify_source_wiring.py は、単なる grep ではなく、実際にウォッチドッグを通して子プロセスへ値が届くことを確認する。明示値の優先、既存環境変数の尊重、ウォッチドッグ無しなら unset のままであること、直起動するレーンと GitHub Actions の通知ステップが自分の名前を持つことを検査する。配線を外した対照群も置くため、テストが常に通るだけの空振りにならない。
実装時に分けた責務
notify_discord.py は通知を送る処理、agent_watchdog.sh は無人レーンから子へ識別情報を渡す処理、notify_exit_audit.py は実装・台帳・実績のずれを確認する処理として分離した。分類を散文だけで管理せず、起動時の環境変数と回帰テストに落としたことで、通知が「届いたか」だけでなく「正しいレーン名で届いたか」まで検査対象になった。
試した環境・バージョンは、リポジトリ内の Bash レーン、Python 通知実装、GitHub Actions の YAML、ウォッチドッグの一時テストレーンである。実 Discord へ依存せず、子プロセスの環境変数と通知台帳の JSONL を検査できる。
更新履歴
- 2026-09-14: 初稿。送信元の推測を起動レーンの自己申告へ変更した実装を記録。
訂正履歴
- なし。