Skip to content

UV_PROJECT_ENVIRONMENT が子プロセスへ漏れ、利用者の uv run が NDF の共有の環境を作り直す(並列の計画が動いたまま finished で終わる) #2509

Closed

Description

@takemi-ohama

起票者の推定

この課題の本文(下の「依頼(原文)」)とコメントは、carul の並列の計画の記録を調べた AI が書いた。利用者の指示の原文は本文にもコメントにも無い。そのため本文の条件はすべて起票者の推定として扱い、承認ゲート 1 で利用者が確かめる。

# 条件 推した出所 この要求での扱い
S1 状態の一覧(relay.py ls)が 0 以外で終わった回の観測は捨て、レーンの状態を変えない。行が無いレーンを止まったと読むのは、一覧が成功した回だけにする 本文の「直し方の案」1 行目・受け入れ条件 1 受け入れ条件 1・2・3
S2 一覧の失敗が続くときは、停滞(stall)と同じく問いにする 本文の「直し方の案」1 行目 受け入れ条件 4。続く長さは前提 3
S3 NDF のスクリプトが自分を共有の環境で起動し直した後、UV_PROJECT_ENVIRONMENT を自分の環境変数から外し、子プロセスへ渡さない 本文の「直し方の案」2 行目・コメント(2026-11-04) 受け入れ条件 5・6
S4 利用者のコマンドを起動する共通の箇所(スプリントのステップの実行・ラッパーの子の環境変数)で外す 本文の「直し方の案」2 行目の「もしくは」 採らない。起点(起動し直した直後)で外せば、その下のすべての子プロセスに効くため(前提 1)
S5 ラッパー(relay.py)が起動する子の claude の環境変数からも外す 本文の「直し方の案」2 行目・コメント 受け入れ条件 7
S6 finished で終わった計画を、レーンが動いたまま打ち直したときの戻り方を用意する(start が一覧の running を見て、記録を作り直すかを問う) 本文の「直し方の案」3 行目 含まない。受け入れ条件 1〜4 で誤った finished の原因を断つ。原因が断てた後も要るかは、使った結果で決める
S7 受け入れ条件 2 を「子の環境変数に UV_PROJECT_ENVIRONMENT が無い」へ差し替える コメント(2026-11-04)。本文へ反映済み 受け入れ条件 5・6
S8 1 と 2 の回帰テストを scripts/tests/ に置く 本文の受け入れ条件 3 受け入れ条件 9

目的

  • 状態の一覧が一時的に失敗しても、並列の計画が取り消せない finished で終わらないようにする
  • NDF のスクリプトの下で打つ利用者の uv run --project <x> が、NDF の共有の環境(~/.cache/ndf/venv/<版>)を作り直さないようにする。あわせて、利用者のテストが自分のプロジェクトの環境で走るようにする

前提

  • 前提 1: NDF のスクリプトが共有の環境の uv run の下で動くのは、lib/deps.py の require() が自分を起動し直した経路だけである。起動し直した後の require() の中で外せば、そのスクリプトが起動するすべての子プロセス(スプリントのステップ・ラッパー・ラッパーの子の claude とその Bash)に効く。設計でこの経路のほかに UV_PROJECT_ENVIRONMENT を共有の環境へ向けて子へ渡す箇所が見つかれば、その箇所も同じ条件で外す
  • 前提 2: 外すのは NDF が設定した値(共有の環境、または require() がリポジトリの根の .venv へ向けた値)だけである。利用者が自分のシェルで設定した UV_PROJECT_ENVIRONMENT は、ラッパーが起動する子の claude へもそのまま渡す。利用者の設定を NDF が黙って消さないため(共通原則 C6)
  • 前提 3: 一覧の失敗が続いたと見なす長さは、停滞の区切り(stall_seconds()。NDF_PARALLEL_STALL_MINUTES で変えられる)を使う。新しい設定値は足さない
  • 前提 4: uv run が子へ渡す VIRTUAL_ENV は、利用者の uv run --project <x> では使われず、共有の環境を変えない。この課題では扱わない。確かめた結果(2026-11-05、uv の手元の版): 別の環境を指す VIRTUAL_ENV を付けて uv run --project <別のプロジェクト> を打つと、<別のプロジェクト>/.venv を作ってそこで動き、VIRTUAL_ENV の指す環境の pyvenv.cfg の更新時刻は変わらなかった
  • 前提 5: 本文の「手元の回避」で退避した耐久の記録と、手元で常駐させた見張りは、この課題の変更の対象ではない

対象範囲

含む:

  • 並列の計画のオーガナイザーの観測が、一覧の失敗を見分け、失敗した回の観測でレーンの状態を変えないこと
  • 一覧の失敗が続くときに、計画を終えずに利用者へ問うこと
  • NDF のスクリプトの子プロセスと、ラッパーが起動する子の claude へ、NDF が設定した UV_PROJECT_ENVIRONMENT を渡さないこと
  • 上の 2 つの回帰テスト

含まない:

  • finished で終わった計画を、レーンが動いたまま打ち直したときの戻り方(S6)
  • ラッパーの環境の作り方(--no-managed-python で 3.14 と 3.13 が入れ替わること)の変更。共有の環境が作り直されなくなれば入れ替わりは起きない
  • 利用者のリポジトリの uv run の書き方の変更(carul の AGENTS.md など)

ドメインイベント

# イベント 引き金 失敗したとき 順序の前提
E1 NDF のスクリプトが共有の環境で自分を起動し直した 外部パッケージが import できない状態で require() を呼んだ uv が無い・環境を作れない → 終了コード 69 か uv の終了コード(既存の振る舞い) —
E2 起動し直したスクリプトが、NDF の設定した UV_PROJECT_ENVIRONMENT を自分の環境変数から外した E1 の後の require() で import が通った 外し損ねる → 子の uv run --project <x> が共有の環境を作り直す(この課題の不具合)。受け入れ条件 5・6 で防ぐ E1
E3 スクリプトが利用者のコマンドかラッパーを子プロセスで起動した スプリントのステップ・並列の計画の起動 子のコマンドの失敗は既存の扱い E2
E4 ラッパーが子の claude を起動した レーンの起動(spawn)・起こし直し 起動できない → 既存の拒否の扱い E3
E5 オーガナイザーが状態の一覧を観測した 観測の間隔(NDF_PARALLEL_POLL) 一覧が 0 以外で終わる → E6 —
E6 オーガナイザーが失敗した回の観測を捨てた E5 の一覧が 0 以外で終わった — E5
E7 オーガナイザーが一覧の失敗が続くことを利用者へ問うた E6 が停滞の区切りより長く続いた 問いを送れない → 既存の問いの扱い E6
E8 オーガナイザーが全レーンの停止を見て計画を終えた 成功した一覧で全レーンが止まっている(既存の条件) — E5 が成功している

用語

用語 意味
共有の環境 NDF のスクリプトとラッパーが使う Python の環境(~/.cache/ndf/venv/<版>。NDF_DEPS_VENV で変えられる)。lib/deps.py の venv_dir() が置き場を決める
状態の一覧 relay.py ls --json の出力。レーンごとの状態(running・awaiting_approval・stopped など)を持つ

受け入れ条件

  • 1. 前提: 並列の計画が動いていて、各レーンの状態が記録されている
    操作: 状態の一覧が 0 以外で終わる(ラッパーの extras を抜いた共有の環境、またはテストの差し替え NDF_PARALLEL_RELAY で再現する)
    結果: その回の観測の後も、計画の各レーンの状態は観測の前と同じである
  • 2. 状態の一覧が 0 以外で終わる間、parallel.py run は finished を返さず、耐久の記録にも finished が残らない
  • 3. 状態の一覧が 0 で終わり、起動済みのレーンの行が無いときは、そのレーンを止まったと読む(既存の振る舞いを保つ)。全レーンがそう読めたときは、既存の条件どおり計画を終える
  • 4. 状態の一覧の失敗が停滞の区切り(前提 3)より長く続くと、オーガナイザーは利用者へ問いを 1 件出す。問いの本文には一覧の終了コードと標準エラーの末尾 1 行が入る。同じ区切りの間に同じ問いを重ねて出さない
  • 5. deps.require() で共有の環境へ起動し直した NDF のスクリプトが子プロセスで env を打つと、出力に UV_PROJECT_ENVIRONMENT が無い
  • 6. 前提: 共有の環境を作り、pyvenv.cfg の中身と更新時刻を控える
    操作: deps.require() で起動し直した NDF のスクリプトの子プロセスとして、requires-python が共有の環境の Python と合わない別のプロジェクトで uv run --project <別のプロジェクト> python -c pass を打つ
    結果: 共有の環境の pyvenv.cfg の中身と更新時刻が変わらず、共有の環境の Python で import psutil が通る
  • 7. ラッパーが起動する子の claude の環境変数に、共有の環境を指す UV_PROJECT_ENVIRONMENT が無い。親の環境変数に残っていた場合(古い版の NDF のスクリプトから起動された場合)も同じである
  • 8. 利用者が自分で設定した UV_PROJECT_ENVIRONMENT(共有の環境とも、require() が向けたリポジトリの根の .venv とも違う値)は、NDF のスクリプトの子プロセスとラッパーの子の claude へそのまま渡る
  • 9. 受け入れ条件 1〜8 の回帰テストが plugins/ndf/scripts/tests/ にあり、変更前のコードでは失敗し、変更後のコードでは通る
  • 10. 起動し直した後の子プロセスが別のグループの外部パッケージを要るとき、その子は自分で起動し直して動く(require() の既存の振る舞いが退行しない。既存の test_deps.py が通る)

非機能の条件

大項目 条件
可用性 状態の一覧の 1 回の失敗で、並列の計画が取り消せない形で終わらない(受け入れ条件 1・2)
システム環境 利用者のプロジェクトの uv run は、そのプロジェクトの環境(既定では <プロジェクト>/.venv)を使う。NDF の共有の環境の Python の版と extras が、利用者のプロジェクトの requires-python と依存に左右されない

影響

対象 影響
公開インタフェース 変わらない(コマンドの引数・終了コード・統一 JSON レポートの形は同じ。オーガナイザーの問いの種類が 1 つ増える)
データ 変わらない(耐久の記録の形は同じ)
既存の振る舞い NDF のスクリプトの子プロセスとラッパーの子の claude が、NDF の設定した UV_PROJECT_ENVIRONMENT を継がなくなる。オーガナイザーが一覧の失敗を止まったと読まなくなる

検証手段

項目 手段
テスト uv run --frozen --project . --all-extras pytest plugins/ndf/scripts/tests -q -n 4
静的解析・型検査 リポジトリの CI と同じ検査(python3 scripts/check-skill-frontmatter.py ほか、PR の CI)
手動確認 リリース後テストで、並列の計画を 2 レーン以上で流し、レーンのスプリントが利用者のリポジトリで uv run --project <x> を打った後も共有の環境の pyvenv.cfg の更新時刻が変わらないことを見る

前提とする取り決め

項目 参照先 / 決めたこと
プロジェクト構造 AGENTS.md。変更はプラグインのスクリプト(plugins/ndf/scripts/)に置く。実験版の置き場は使わない(既定で働く振る舞いのため安定版の経路)
コーディング規約 AGENTS.md の「最小限のコード実装」。.md の文言を照合するテストを書かない
テスト戦略 受け入れ条件 1〜4 はオーガナイザーの観測の単体テスト(一覧の差し替えで失敗を作る)。受け入れ条件 5〜8 は子プロセスを実際に起動する結合テスト(一時ディレクトリに作った Python の環境で、本文の再現手順を通す)

境界

区分 内容
常に行う 既存テストの実行、変更範囲内の命名の統一
確認してから行う 問いの種類の追加(承認ゲート 1 で見る)
行わない 依頼範囲外のリファクタリング、ラッパーの環境の作り方の変更、耐久の記録の手での修正

未決

項目 誰が決めるか 期限
起票者の推定 S1〜S8 の扱い(特に S4 を採らず S6 を含まないこと) 利用者 承認ゲート 1

依頼(原文)

書き手: 起票者(carul の並列の計画の記録を調べた AI)、日付: 2026-11-04。下は要求を書く前の課題の本文の全文である。同じ日のコメント( #2509 (comment) )の内容は、本文へ反映されている。

何が困っているか

並列の計画で 3 本のレーンが動いている途中に、オーガナイザーの耐久ワークフロー(parallel.py run)が「全レーンが止まった」と判断し、finished で終わる。実際はレーンは 3 本とも動いていて、それぞれ周回 1 のスプリントを流していた。

finished は耐久の記録に残る。そのため parallel.py start を打ち直しても、resumed: true で同じ finished を返すだけで、オーガナイザーは戻らない。レーンが配布の依頼や承認ゲートの依頼を送っても、受け取る側がいなくなる。

原因は 2 つが重なっている。

  1. NDF のスクリプトが子プロセスへ UV_PROJECT_ENVIRONMENT=~/.cache/ndf/venv/<版> を引き継ぎ、利用者のリポジトリで打つ uv run --project <x> が共有の環境をそのプロジェクトの環境として作り直す。同期は exact なので、ラッパーの extras が抜ける
  2. step_observe が relay.py ls --json の失敗を見ない。失敗して items が空のときも、全レーンを「行が無い = stopped」と読む

具体例: carul の計画 l20261104(2026-11-04、NDF 10.27.16)

時刻(UTC) 出来事
22:12 parallel.py start l20261104 で 3 レーン(l20261104-ux・-api・-cust)が起動した
22:12〜 各レーンが supervise.py queue を uv run --quiet --frozen --project <プラグイン> --extra md --extra mdtable ... で流し始めた
22:19:46 ~/.cache/ndf/venv/10.27.16 が丸ごと作り直された(ディレクトリ・.gitignore・CACHEDIR.TAG の時刻がすべてこの時刻)。bin/python は uv 管理の cpython-3.13 を指していた
22:19 relay.py ls が ndf-relay: ラッパーの環境(/home/ubuntu/.cache/ndf/venv/10.27.16)が無い。/ndf:install-wrapper を打ち直す で終了コード 3 を返すようになった。器はあり、bin/python も動いた。ラッパーの extras(procs・locks・md・versions・terminal)が import できず、runtime.ready() が偽になっていた
22:19 parallel.py wait が action: finished を返した。items は 3 レーンとも state: stopped だった
22:20 relay.py status で環境を作り直すと relay.py ls は 3 レーンとも running と答えた。このときの pyvenv.cfg は version_info = 3.14.4(home = /usr/bin)で、作り直しのたびに Python が 3.13 と 3.14 の間で入れ替わっている
22:20 parallel.py start を打ち直したが、resumed: true の finished が返るだけだった

共有の環境が作り直される理由

lib/deps.py が uv run に渡す UV_PROJECT_ENVIRONMENT=~/.cache/ndf/venv/<版> が、その下で動く NDF のスクリプトの子プロセスへそのまま引き継がれる。レーンのスプリントは、利用者のリポジトリのテストを子プロセスで打つ。carul の AGENTS.md には uv run --project infra pytest infra/tests があり、この uv run は引き継いだ変数を読んで、NDF の共有の環境を carul の infra のプロジェクトの環境として同期し直す。

  • carul の infra/pyproject.toml は requires-python = ">=3.13,<3.14" なので、3.14 の環境は捨てられ、uv 管理の 3.13 で作り直される
  • 同期は exact なので、NDF の extras(ラッパーの procs・locks・md・versions・terminal を含む)はすべて消える

22:19:46 に環境が 3.13 で作り直されたことと、その後に relay.py ls が失敗したことは、どちらもこれで説明できる。NDF の uv run の経路だけなら、3.14 の環境をそのまま使う(作り直さない)。

再現(別の置き場で):

T=$(mktemp -d)/venv; R=<プラグインの根>
# ラッパーと同じ作り方で NDF の環境を作る
UV_PROJECT_ENVIRONMENT=$T uv sync --frozen --quiet --no-managed-python --project $R \
  --extra procs --extra locks --extra md --extra versions --extra terminal --inexact
grep version_info $T/pyvenv.cfg              # 3.14.4。psutil などを import できる
# NDF の uv run の子が引き継ぐ変数のまま、利用者のプロジェクトを uv run する
UV_PROJECT_ENVIRONMENT=$T uv run --quiet --project infra python -c pass   # carul の根で
grep version_info $T/pyvenv.cfg              # 3.13。作り直された
$T/bin/python -c "import psutil"             # ModuleNotFoundError

影響は並列の計画に限らない。

  • NDF の uv run の下から打つ利用者の uv run --project <x> は、どれも NDF の共有の環境を上書きする。同時に動いている NDF のスクリプトとラッパーの import が壊れる
  • 利用者のテストが、自分のプロジェクトの .venv ではなく NDF の置き場で走る。依存とバージョンが混ざり、結果が手元の実行と変わりうる
  • 単独のスプリントでも起きる。並列の計画では 3 レーンが同時に打つので、早く当たる

観測が失敗を見ない

lib/parallel_run.py の step_observe は、relay() の終了コードを捨てる(_, res = relay(Path(main), "ls", "--json"))。_observe_run は行の無いレーンを stopped にし(if st is None and run.lanes[n].get("started"): st = "stopped")、_run_finished が全レーンの停止として終える。1 回の観測の失敗で、計画全体が取り消せない形で終わる。

手元の回避

  1. 共有の環境に全 extras を --inexact で入れた(UV_PROJECT_ENVIRONMENT=~/.cache/ndf/venv/10.27.16 uv sync --frozen --project <プラグイン> --all-extras --inexact)
  2. 耐久の記録 ~/.local/state/ndf/dbos/parallel-<鍵>.sqlite を退避して parallel.py start を打ち直した。動いているレーンは spawn が name-taken を成功として扱うので、二重には起動しなかった
  3. 10 秒ごとに relay.py ls を確かめ、失敗したら 1 を打ち直す見張りを常駐させた

直し方の案

  • step_observe:relay.py ls が 0 以外で終わったら、その回の観測を捨てる(状態を変えない)。続けて失敗するときは、stall と同じく問いにする。行が無いことを stopped と読むのは、ls が成功したときだけにする
  • 共有の環境:deps.py が os.execve で起動し直した後、NDF のスクリプトの中で UV_PROJECT_ENVIRONMENT を os.environ から外す(再起動の判定は REEXEC_ENV で行う)。もしくは、利用者のコマンドを起動する共通の箇所(supervise_lib のステップの実行、relay_lib/claude.py の子の環境)で必ず外す。relay.py の子の claude の環境からも外す
  • finished で終わった計画を、レーンが動いているまま打ち直したときの戻り方を用意する。たとえば start が relay.py ls の running を見て、記録を作り直すか問う

受け入れ条件

  1. relay.py ls が失敗を返す間(ラッパーの extras を抜いた環境で再現する)も、parallel.py run は終わらず、レーンの状態を変えない
  2. NDF のスクリプトの子プロセスとして打った uv run --project <別のプロジェクト> が、NDF の共有の環境を変えない(pyvenv.cfg と時刻が変わらない)。子の環境に UV_PROJECT_ENVIRONMENT が無い
  3. 1 と 2 の回帰テストが scripts/tests/ にある

進行

モード: — / 進め方: auto

  • 要求と受け入れ条件 — 2026-11-05 16:30
  • 作業場所の用意 — 2026-11-06 05:32
  • 設計 — 2026-11-05 16:35
  • 素材の収集と出典の確定
  • ドキュメント再構成 — 2026-11-05 16:40
  • ドキュメントレビュー
  • 計画 — 2026-11-06 05:32
  • 実装 — 2026-11-06 05:32
  • 構造改善 — 2026-11-06 09:21
  • 実装レビュー — 2026-11-06 09:49
  • 完了判定 — 2026-11-06 06:22
  • Pull Request — 2026-11-05 19:21
  • 確定仕様化 — 2026-11-05 19:20
  • 後片付け — 2026-11-05 19:56
  • デプロイ
  • 体裁レビュー
  • リリース後テスト — 2026-11-05 19:27
  • 振り返り — 2026-11-05 19:27
  • 棚卸し — 2026-11-05 19:56

人の判断待ち(開発ループ lroot3)

振り返り: #2586 (comment)

根本原因の束(2026-11-06)

carul から届いた課題を根本原因で束ねた(利用者の指示「ひとつづつ直すのではなく根本原因を見つけて対処してください」)。この課題は #2649(束 C)・#2624(束 D) に入る。1 件ずつ直さず、束の根本原因を直した後に、この課題の再現の手順を 1 回通して閉じるか残すかを決める。

即時修正(2026-11-06)

連鎖の起点 2 か所を即時修正で直した(利用者の指示、オーガナイザー経由): #2651 (マージ済み。マージコミット 5718005)

直したこと(設計 issues/issue-2509-design.md の I1・I2・I5・I6・I7):

  • plugins/ndf/scripts/lib/deps.py: 起動し直す前の利用者の UV_PROJECT_ENVIRONMENT を NDF_DEPS_SAVED_UV_PROJECT_ENVIRONMENT へ退避し、import が通って戻るときに release_project_env で戻す(無ければ外す)。共有の環境を指す値は is_shared_venv で判定して外す
  • plugins/ndf/scripts/relay_lib/runtime.py の enter: 共有の環境を指す UV_PROJECT_ENVIRONMENT を外す(古い版から継いだ値も)
  • plugins/ndf/scripts/lib/parallel_run.py: step_observe が一覧の終了コード code と標準エラーの末尾 1 行 err を返す。_observe_run は code が 0 以外ならレーンの状態・最後に観測した時刻・待ち・問いを変えずに戻り、その後は finished にしない。code の無い古い記録は成功として読む
  • 受け入れ条件 1〜3 の回帰テスト: plugins/ndf/scripts/tests/test_parallel_run.py・test_deps.py・test_relay.py

残り(この課題の実装として残す):

  • F2・I3・I4: 一覧の失敗が停滞の区切りより長く続いたときに利用者へ問う仕組み(_track_ls_failure・問いの種類 observe・parallel_answer.py・parallel.md)と、成功に戻ったら答えていない問いを外すこと。今は失敗が続く間、計画は終わらずに観測を続けるだけで、利用者へは届かない

振り返り: #2683 (comment)

Activity

  1. takemi-ohama commented on Nov 4, 2026

    @takemi-ohama
    ContributorAuthor

    原因を特定した: UV_PROJECT_ENVIRONMENT が子プロセスへ漏れる

    本文では「ラッパーとスクリプトで Python の選び方が違う」ことを原因 1 に挙げた。調べ直すと、これは本当の原因ではなかった。NDF の uv run の経路は、3.14 の環境をそのまま使う(作り直さない)。

    本当の原因は、lib/deps.py が uv run に渡す UV_PROJECT_ENVIRONMENT=~/.cache/ndf/venv/<版> が、その下で動く NDF のスクリプトの子プロセスへそのまま引き継がれることである。レーンのスプリントは、利用者のリポジトリのテストを子プロセスで打つ。carul の AGENTS.md には uv run --project infra pytest infra/tests がある。この uv run は引き継いだ変数を読み、NDF の共有の環境を carul の infra のプロジェクトの環境として同期し直す。

    • carul の infra/pyproject.toml は requires-python = ">=3.13,<3.14" なので、3.14 の環境は捨てられ、uv 管理の 3.13 で作り直される
    • 同期は exact なので、NDF の extras(ラッパーの procs・locks・md・versions・terminal を含む)はすべて消える

    22:19:46 に環境が 3.13 で作り直されたこと、その後に relay.py ls が失敗したことは、どちらもこれで説明できる。

    再現(別の置き場で)

    T=$(mktemp -d)/venv; R=<プラグインの根>
    # ラッパーと同じ作り方で NDF の環境を作る
    UV_PROJECT_ENVIRONMENT=$T uv sync --frozen --quiet --no-managed-python --project $R \
      --extra procs --extra locks --extra md --extra versions --extra terminal --inexact
    grep version_info $T/pyvenv.cfg              # 3.14.4。psutil などを import できる
    # NDF の uv run の子が引き継ぐ変数のまま、利用者のプロジェクトを uv run する
    UV_PROJECT_ENVIRONMENT=$T uv run --quiet --project infra python -c pass   # carul の根で
    grep version_info $T/pyvenv.cfg              # 3.13。作り直された
    $T/bin/python -c "import psutil"             # ModuleNotFoundError

    影響は並列の計画に限らない

    • NDF の uv run の下から打つ利用者の uv run --project <x> は、どれも NDF の共有の環境を上書きする。同時に動いている NDF のスクリプトとラッパーの import が壊れる
    • 利用者のテストが、自分のプロジェクトの .venv ではなく NDF の置き場で走る。依存とバージョンが混ざり、結果が手元の実行と変わりうる
    • 単独のスプリントでも起きる。並列の計画では 3 レーンが同時に打つので、早く当たる

    直し方(原因 1 の案を差し替える)

    • deps.py が os.execve で起動し直した後、NDF のスクリプトの中で UV_PROJECT_ENVIRONMENT を os.environ から外す。外すのは子プロセスへ渡さないためで、NDF の再起動の判定には REEXEC_ENV を使う。もしくは、利用者のコマンドを起動する共通の箇所(supervise_lib のステップの実行、relay_lib/claude.py の子の環境)で必ず外す
    • relay.py の子の claude の環境からも外す
    • 受け入れ条件の 2 を次に差し替える: 「NDF のスクリプトの子プロセスとして打った uv run --project <別のプロジェクト> が、NDF の共有の環境を変えない(pyvenv.cfg と時刻が変わらない)。子の環境に UV_PROJECT_ENVIRONMENT が無い」

    原因 2(step_observe が relay.py ls の失敗を見ずに stopped と読む)は、別の欠陥として残る。環境が壊れる理由がほかにあっても計画が取り消せない形で終わらないよう、こちらも直す。

  2. changed the title [-]並列の計画: 共有の環境の作り直しで relay.py ls が失敗し、レーンが動いたまま耐久ワークフローが finished で終わる[/-] [+]UV_PROJECT_ENVIRONMENT が子プロセスへ漏れ、利用者の uv run が NDF の共有の環境を作り直す(並列の計画が動いたまま finished で終わる)[/+] on Nov 4, 2026
  3. added 3 commits that reference this issue on Nov 5, 2026
  4. takemi-ohama commented on Nov 5, 2026

    @takemi-ohama
    ContributorAuthor

    事例(carul、2026-11-05、v10.27.24)

    21:35 UTC ごろ、共有の環境 ~/.cache/ndf/venv/10.27.24 が作り直され(ディレクトリの更新時刻)、ラッパーの依存 ptyprocess(extra terminal)が抜けた。その後、relay.py restart l20261104-ux が次で断られた。

    ndf-relay: ラッパーの環境(/home/ubuntu/.cache/ndf/venv/10.27.24)が無い。/ndf:install-wrapper を打ち直す
    

    relay.py status を打っても直らなかった(ready() は procs・locks・md・versions・terminal の import を見るが、status の作り直しは terminal を戻さなかった)。uv pip install --python ~/.cache/ndf/venv/10.27.24/bin/python ptyprocess==0.7.0 で戻した。

    同じ時刻にレーンは uv run --project backend ... などを打っており、この課題の原因(UV_PROJECT_ENVIRONMENT の漏れで共有の環境が作り直される)と合う。あわせて、ラッパーのエラー文が「環境が無い」と読める点も、足りない依存の名前を出すとよい。

  5. takemi-ohama commented on Nov 6, 2026

    @takemi-ohama
    ContributorAuthor

    スプリント(スプリント lroot4-1の後片付け)を通りました

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions