Skip to content

リリースチャンネル分岐の第 3 段階: 取得と自動置き換え - #48

Merged
limit7412 merged 52 commits into
masterfrom
claude/update-auto-apply-tezzcs
Aug 30, 2026
Merged

リリースチャンネル分岐の第 3 段階: 取得と自動置き換え#48
limit7412 merged 52 commits into
masterfrom
claude/update-auto-apply-tezzcs

Conversation

@limit7412

@limit7412 limit7412 commented Aug 28, 2026

Copy link
Copy Markdown
Owner

issue #45 の第 3 段階(取得と自動置き換え)。第 1 段階 #46 と第 2 段階 #47 はマージ済みで、base は master

KxNotifyUtils の installer.cr の「常駐中は取得と検証まで、置き換えは次の起動」という分担を踏襲しつつ、単一 exe ではなく ZIP 配布(app/ + cli/ + ランチャー)に合わせて置き換えの実行主体を変えている。実行中の App は app\ 配下の DLL を掴んでいて自分では置き換えられないため、取得した ZIP の中の CLI を更新ヘルパとして起動し、App の終了を待ってからディレクトリを入れ替えてもらう。ヘルパは展開先から動くので、置き換える対象のどれも掴まない。

変更内容

Core

  • GitHubReleaseRepository.DownloadAsync: ZIP を取得しながら SHA-256 と宣言された大きさを照合する。宣言を超えた時点で打ち切り、照合を通らなければファイルを残さない。応答ヘッダまでを既定のタイムアウトで待ち、本体の読み取りは呼び出し側から渡された期限(App の寿命 + 30 分)に委ねる(数十〜百数十 MB を想定)
  • UpdateStage: 取得した ZIP と記録(tag / digest / size / 配布物の名前 / 取得元のインストール先 / stable の印)の置き場所。置き場所は %AppData%\VRCToolsDataSync\update\<インストール先のハッシュ> とインストール先ごとに分ける(同じ ZIP を複数の場所へ展開したコピー同士が互いの取得を奪い合わないため)
    • 取得は incoming.zip へ書き、照合を通ってから置き換え待ちの対へ昇格させる。昇格は「新しい記録を横へ書く → 古い記録を横へ退避する → ZIP を入れ替える → 新しい記録を置く」の順。正規の場所に触る前に落ちれば前の対が無傷で残り、ZIP の入れ替えに失敗した場合も退避した記録を戻す。最後の付け替えは短く待ってやり直す
    • 付け替えまで済まなかった場合は、次の起動が横に残った記録(新・旧)を ZIP の大きさと digest で突き合わせ、合うほうを正規の名前へ置いて仕上げる。読めない・動かせないものがある間は「判断できない」として、その回は何も捨てない
    • 展開の前に、同じ場所へ展開される項目が複数ないかを見る(区切りの書き方・...・末尾の点と空白をそろえて突き合わせる)。同じ場所がファイルとディレクトリの両方になる組み合わせ、展開先の外を指す項目、Windows では作れない名前(予約された装置名・使えない文字)も断る。展開後の大きさ・項目数・項目名の総量にも上限を置き、大きさの合計は足す前に突き合わせる(目録の値で折り返させないため)
    • 展開の前に、前回の展開先を消してから置き場所の空きを確かめる。展開そのものが失敗した場合は、同じ ZIP で何回失敗したかを数え、2 回目までは取得を残して次の機会へ回す(一時的に掴まれている場合など)。3 回続いたら配布物の問題として取得ごと捨てる。数は昇格と展開の成功で 0 に戻す
    • 適用の直前と次の起動で、チャンネル適合・アーキテクチャ・インストール先・実行中との版の前後・記録との照合をやり直し、通らないものはその場で捨てる(別のインストール先のものだけは相手のために残す)
  • UpdateInstaller: app / cli の入れ替え。重い複製(.new の用意)を先に済ませ、正規の位置に触るのは短いリネームだけにする。複製が途中で失敗したら作りかけを消す。正規の位置に触る前に、app / cli のディレクトリ・実行ファイル・本体アセンブリの存在を確かめ、前回が残した .new / .old を消してからインストール先のドライブの空きを確かめる(空き不足は UpdateCapacityException で分け、取得を捨てさせない)。失敗したら退避した .old を戻し、戻せなかった状態は UpdateRollbackException で区別する。ランチャーは .cmd.new へ書き切ってから置き換える。入れ替え中のログはすべて best-effort(ログの失敗が巻き戻しを飛ばさない)。FindInstallRoot は配布 ZIP の形(<ルート>\app\ + ランチャー)だけを認め、手元ビルドの作業ツリーを誤って置き換えない
  • RunningVersion.OfFile: 動いていない一式に埋め込まれた版を読む。適用の前に、展開した app / cli が記録のタグどおりの版かを確かめるのに使う

Cli

self-update apply --source --target --wait-pid --wait-started --relaunch(ヘルプ非表示)。起動直後に適用のロックの待ちへ入り(呼び出し元が終わる時点で待ち行列に居るため、放棄されたロックを受け取れる)、取れたら呼び出し元の終了を確かめ、App の多重起動の抑止も掴んでから UpdateInstaller で入れ替え、App を起動し直す。抑止も掴むのは、入れ替えの最中に起動した App が旧 app\ を掴んで入れ替えを失敗させたり、置き換え済みの一式をもう一度置き換えさせたりするため(既に別の App が動いていれば、正規の位置に触らずに引き下がる)。呼び出し元は番号だけでなく開始時刻でも見分ける(番号の使い回しで無関係なプロセスを待たないため)。巻き戻し済みの失敗では staged を捨ててから現行版を起動し直し、同じ失敗を繰り返さない。巻き戻し失敗は終了コード 7、staged の対が残ってしまった場合は 8、インストール先の空き不足は 9 で区別する(9 では staged を残したまま現行版を開き直す。開き直す際は見送りの指定 --skip-update-apply を渡し、その App がまた同じ取得を渡してくる往復を避ける。空きを作れば次の起動がそのまま適用する)。

App

  • 起動シーケンスの先頭(多重起動の抑止の後、App 構築の前)で staged を照合し、あればヘルパへ渡して終了する。ロックを取れなければ更新には一切触らず、そのまま起動を続ける。見送りの指定つきで起動された回は、照合にも入らずそのまま立ち上がる
  • 適用のロックは Global\VRCToolsDataSync.Update.Apply.<インストール先のハッシュ>Global\ なのは、接頭辞が無いと対話セッションごとの名前空間に作られ、置き場所とインストール先は共有されるのにロックだけが互いに見えなくなるため。専用の背景スレッドが所有し、外からは合図だけで手放せる(Mutex の所有権はスレッドに紐づくため)
  • ヘルパを起こした後は、適用のロックも多重起動の抑止も手放さずにプロセスを終える。手放してから終わると、その隙に裏の取得の昇格が先に握って展開元を消したり、起動した別の App が app\ を掴んだままヘルパの入れ替えに巻き込まれたりする
  • ヘルパは起こした後 3 秒生きているかを見る。自己完結のランタイムを欠いた一式なら apphost がすぐ落ちるので、そこで取得を捨てて起動を続ける。展開した一式の版が記録のタグと合わない場合も捨てる(-Version を渡し忘れたビルドが添付されると、適用と再起動を繰り返して復旧の材料まで失う)
  • 終了の直前にヘルパの生死を見る。終了時 Push が長引いてヘルパが待ちきれずに降りていた場合、そのまま終わると画面が閉じたきりになるので、抑止とロックを手放してから現行版を開き直す(取得は残っているので、開き直した App が改めて渡す)
  • 退避した .old と不要になった取得の片付けは、ウィンドウを立てられた後(CleanUpAfterSuccessfulStart)に行う。新版が初期化の途中で失敗しても、旧版と取得済み ZIP の両方が復旧の材料として残る。後始末は取得と同じ入り口を通し、返した後に待たせていた取得を拾う。チャンネルを読めない場合は突き合わせ自体を見送る(stable として見ると test の取得を捨てる)
  • UpdateManager: 確認で見つけた版に配布物が付いていれば常駐中に自動取得する(通知を抑止した版も対象。抑えたのは繰り返しの通知であって取得ではない)。取得は 1 本ずつで、走っている間に来た要求は置いておき、終わった側が拾う。取得の前・昇格の前・適用ロックを取った後に保存済みのチャンネルと突き合わせ、確認の最中に切り替えられた場合は追随する。取得を省くのはタグ・digest・大きさ・stable の印がすべて一致する場合だけ
  • 画面に「{tag} を取得済み。次回起動時に適用されます」の行と「再起動して適用」ボタン。適用は通常の終了シーケンス(終了時 Push を含む)を通る。ヘルパへ渡した後は設定の保存を受け付けない(ヘルパは渡した時点のチャンネルで照合を済ませており、後から変えられると保存済みの設定と適用される版が食い違う)。終了が取り消された場合(ログオフの取り消し等)は、起こしたヘルパを止めてロックを返し、設定の保存も受け付け直す

README

自動アップデートの節を追加。リリース節の書き換え(第 1 段階分)は #46 へ入れた。

検証

  • テストを追加: 取得時の照合(宣言超過・不足・digest 不一致で残らない)、staged の判定(チャンネル適合・アーキテクチャ・インストール先・版の前後・破損・置き場所とロックの分離)、昇格の中断からの復旧(ZIP の入れ替え失敗で前の対が残る・付け替えだけ済まなかった対の仕上げ・新旧 2 つの記録から ZIP に合うほうを選ぶ・判断できない間は捨てない)、展開の門(展開先の衝突・ファイルとディレクトリの衝突・展開先の外・Windows で作れない名前・失敗の数え方)、ディレクトリ入れ替え(成功・巻き戻し・巻き戻し失敗の区別・実行ファイルと本体アセンブリの欠落の検出・残骸の片付け・FindInstallRoot の判定)、埋め込まれた版の読み出し。入れ替えは実ディレクトリで確かめている
  • ヘルパの起動と実機での置き換えは Linux 環境で確認できないため、テスト版プレリリースでの実機確認に委ねる

設計上の判断(レビューで見てほしい点)

  • 自動取得: 新しい版が見つかると ZIP(数十〜百数十 MB)を確認の裏で取得する。KxNotifyUtils(8 MB 前後の exe)と同じ振る舞いだが、従量制の回線では重いかもしれない。取得を手動ボタンに変える選択肢はある
  • 待ちの上限: ヘルパが呼び出し元の終了を待つ上限は 65 分。終了時 Push の合計に上限は無いので、これは「Push が終わるまで」ではなく「適用のロックを握ったまま待ち続けてよい長さ」として置いている。待ちきれずに降りても取得は残り、App の側が開き直すので、利用者から見れば 1 往復多くかかるだけになる。終了時 Push そのものに全体上限は置いていない(時間切れで保存されないまま終わるという、別の失い方になるため)
  • 展開の失敗の扱い: 例外の種類では一時的な失敗(ウイルス対策ソフトのロックなど)と恒久的な失敗(Windows で作れない名前など)を見分けられない。回数で分け、続いた場合だけ捨てる形にした。恒久的な失敗でも 3 回の起動を空振りするが、正しい取得を 1 回の偶発的な失敗で捨てるよりは軽いと判断した
  • 置き換え単位: app\cli\ はリネームで入れ替え、ランチャー .cmd は 1 ファイル置き換え。ランチャーの置き換え失敗は警告に留める(旧ランチャーでも相対参照で新しい app を起動できる)

積み残し

🤖 Generated with Claude Code

https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC


Generated by Claude Code

@limit7412

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d91937afd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateApplier.cs Outdated
Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
limit7412 pushed a commit that referenced this pull request Aug 28, 2026
Codex レビュー (#48) の指摘への対応。

- 退避した .old と staged の後始末を、起動シーケンスの先頭からウィンドウ
  構築後へ移す。先頭で消すと、置き換え直後の起動が初期化の途中で失敗した
  場合に復旧の材料を両方失う。先頭の照合は破棄なし (discardMismatches:
  false) で行う
- 適用に失敗して巻き戻した場合、ヘルパは staged を捨てて現行版を起動し
  直す。残すと次の起動がまた同じ適用へ引き渡し、書き込めない場所に置かれた
  環境では現行版すら開けなくなる
- 入れ替え前の検証で app / cli の実行ファイルの存在も見る。digest は ZIP が
  配布物そのものであることまでしか保証しない
- 取得に打ち切り (30 分 + 破棄時のキャンセル) を渡す。本文の読み取りは
  HttpClient のタイムアウトの外にあり、止まった取得が取得の直列化を
  持ち続けると以後の取得がすべてスキップされる
- ヘルパの終了待ちを 10 分へ延ばす。終了時の同期は大きな DB で数分かかり
  うる。待ちきれない場合は staged を残し、次の起動で適用し直す

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
claude added 4 commits August 28, 2026 14:52
新しい版の ZIP を常駐中に取得して SHA-256 と大きさを照合し、
%AppData%\VRCToolsDataSync\update に置き換え待ちとして保管する
(issue #45 第 3 段階)。置き換えは次の起動の先頭で行う。

実行中の App は app\ 配下の DLL を掴んでいて自分では置き換えられないため、
展開した新しい一式の cli を更新ヘルパ (self-update apply) として起動し、
App の終了を待ってから app / cli をリネームで入れ替えてもらう。重い複製を
先に済ませて正規の位置に触るのは短いリネームだけにし、失敗したら退避した
.old を戻す。戻せなかった状態は別の例外と終了コードで区別する。

適用の直前と次の起動では、チャンネル適合・実行中との版の前後・記録との
照合をやり直し、通らないものはその場で捨てる。画面には取得済みの行と
「再起動して適用」ボタンを足した。

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
チャンネルの選び方、確認と通知のタイミング、取得と照合、次の起動での
置き換えの仕組み、手元ビルドが対象外であることを書く。

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
第 3 段階で IReleaseRepository へ取得を足したとき、確認のテストの偽物へ
実装を足し忘れてビルドが落ちていた。確認の判断だけを見るテストであり
取得へは到達しないため、呼ばれない実装として埋める。

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
Codex レビュー (#48) の指摘への対応。

- 退避した .old と staged の後始末を、起動シーケンスの先頭からウィンドウ
  構築後へ移す。先頭で消すと、置き換え直後の起動が初期化の途中で失敗した
  場合に復旧の材料を両方失う。先頭の照合は破棄なし (discardMismatches:
  false) で行う
- 適用に失敗して巻き戻した場合、ヘルパは staged を捨てて現行版を起動し
  直す。残すと次の起動がまた同じ適用へ引き渡し、書き込めない場所に置かれた
  環境では現行版すら開けなくなる
- 入れ替え前の検証で app / cli の実行ファイルの存在も見る。digest は ZIP が
  配布物そのものであることまでしか保証しない
- 取得に打ち切り (30 分 + 破棄時のキャンセル) を渡す。本文の読み取りは
  HttpClient のタイムアウトの外にあり、止まった取得が取得の直列化を
  持ち続けると以後の取得がすべてスキップされる
- ヘルパの終了待ちを 10 分へ延ばす。終了時の同期は大きな DB で数分かかり
  うる。待ちきれない場合は staged を残し、次の起動で適用し直す

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
@limit7412
limit7412 force-pushed the claude/update-auto-apply-tezzcs branch from 85dfa75 to 086524d Compare August 28, 2026 05:52
Base automatically changed from claude/update-check-notify-tezzcs to master August 29, 2026 05:02
@limit7412
limit7412 marked this pull request as ready for review August 29, 2026 05:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96f851ffd8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
Comment thread src/VRCToolsDataSync.App/App.xaml.cs
claude added 2 commits August 29, 2026 07:22
Codex レビュー (#48) の指摘への対応。

- 取得は一時の場所 (incoming.zip) へ書き、照合が通ってから置き換え待ちの
  対へ昇格させる。正規の場所へ直接書くと、取得済みの版がある状態で次の
  取得が途中で失敗したときに、適用できたはずの前の版まで失う
- 取得を省く判定でタグだけでなく digest と大きさも見る。同じタグへ配布物を
  上げ直す運用 (release.yml の --clobber) があり、タグだけで済ませると
  差し替え前のものを適用し続ける
- 入れ替えの最中のログを best-effort にする。ログの出力先が書き込み不可だと
  ロガーが例外を投げ、巻き戻しを通らずに抜けて、新しい app と古い cli が
  混ざった一式が残る
- 後始末を UpdateManager 経由にして、済んだことを画面へ伝える。直接呼ぶと
  適用の済んだ取得が消えたことが伝わらず、「次回起動時に適用されます」の
  行が押すまで残る

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e5ad1283e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs Outdated
Comment thread src/VRCToolsDataSync.App/Program.cs Outdated
Codex レビュー (#48) の追加指摘への対応。

- 取得した配布物の名前を記録へ残し、適用の前に実行中のプロセスと突き合わせる。
  ARM64 の Windows ではネイティブの版とエミュレーションの x64 版が同じ
  置き場所を共有しうる。名前を持たない古い記録も適用しない
- ランチャーは同じディレクトリの一時ファイルへ書き切ってから置き換える。
  直接上書きすると、書いている途中で容量が尽きた場合に欠けたランチャーが
  残り、通常の起動手段ごと壊れる
- 適用に失敗したときの再起動は、取得済みのものを消せた場合だけにする。
  消せないまま開き直すと、次の起動がまた同じ適用へ入って失敗し、開いては
  閉じるのを繰り返す。消せない場合は片付ける先を伝えて終える (終了コード 8)
- 適用をクロスプロセスのロックで囲う。ヘルパは適用の全体で握り、App は
  起動の先頭から展開とヘルパ起動まで握る。これが無いと、ヘルパの実行中に
  起動された App が同じ展開先を作り直し、動いているヘルパの足元を崩す

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25ac076158

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
Codex レビュー (#48) の追加指摘への対応。

- 記録へ取得時のインストール先を残し、適用の前に突き合わせる。配布 ZIP を
  複数の場所へ展開していると、どのコピーも同じ置き場所を共有する。合わない
  ものはここでは捨てない (相手のコピーが適用できるように)
- 取得した ZIP の昇格を、適用と同じロックの下で行う。昇格は staged の ZIP を
  入れ替えて展開先を消すため、適用と重なると起動前のヘルパを消したり、
  動いているヘルパの展開元を欠いたりする
- ヘルパの流れの上にあるログを best-effort にする。入れ替えの後にログが
  例外を投げると、staged の破棄にも App の起動し直しにも辿り着かず、
  「再起動して適用」がアプリを閉じるだけになる

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@limit7412

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30e61a9923

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
「再起動して適用」で、取得済みの照合をロックの外で行っていた。照合と展開の
間に裏の取得が別の ZIP を昇格させると、確かめたものとは違う版が展開される。
照合・インストール先の判定・ヘルパ起動を一つのロック区間にまとめた。

置き場所も分ける。複数の場所へ展開したコピーが update\ を共有すると、
一方が取った更新を他方が「取得済み」と見て取得を省く一方、インストール先が
違うので適用はできず、相手が片付けるまで更新できない行き止まりに入る。
インストール先のハッシュで 1 段掘って分けた。

使われなくなった TrySpawnUpdaterWithLock を削除した。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149RhLaw1THcTkR6i5f6xLC
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@limit7412

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52ef6728cc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
予約された装置名 (CON / LPT1、CON.dll のような形も含む) と使えない文字
(? * | " < > :・制御文字) を含む項目名を、展開の前に断るようにした。これらは
Windows ではその名前のファイルを作れないため、ExtractToDirectory が途中で
IOException を投げる。従来はその失敗を捨てる判断に使えず、取得済みの ZIP が
残り続けて起動のたびに同じ失敗を繰り返していた。

あわせて、名前の規則を 1 つずつ数え上げる形から抜けられるようにした。展開の
前に空き容量を確かめ、足りなければ IOException で断って取得は残す。その先の
展開で落ちた場合は、容量以外の理由、つまり Windows で作れない形の配布物と
みなして InvalidDataException にそろえる。呼び出し側はこれを見て取得ごと
捨てるので、同じ ZIP での失敗が繰り返されない。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0df9e6cf99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs
Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
前の変更で、空き容量を確かめた後の展開の失敗をすべて配布物の問題として
扱ったが、それではウイルス対策ソフトが一瞬掴んだ場合や、確認の後に空きが
尽きた場合にも、正しい ZIP を捨てて数百 MB の取り直しを強いる。例外の種類
では一時的なものと見分けられないため、同じ ZIP で何回失敗したかを数える形へ
変えた。2 回目までは投げ直して取得を残し、3 回目で配布物の問題として扱う。
数は昇格 (新しい ZIP) と展開の成功で 0 に戻す。数は照合に使う対とは別の
ファイルに置き、書きかけで落ちても対に触らないようにしている。

あわせて 2 点。

- 非圧縮の大きさの合計を、足す前に上限と突き合わせるようにした。項目の
  大きさは ZIP の目録の値をそのまま受け取るので、桁を偽られると足し算が
  折り返し、負の合計として上限も空き容量の確認もすり抜ける
- インストール先の空き容量を、複製に入る前に確かめるようにした。複製の
  途中で尽きると、ヘルパはそれを置き換えの失敗として扱い、取得しておいた
  ZIP まで捨ててしまう。UpdateCapacityException で分け、ヘルパは取得を
  残したまま現行版を開き直す (終了コード 9)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc39eb9a0e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
空き不足で置き換えを断念したヘルパは、取得しておいたものを残したまま App を
開き直す。しかし開き直された App は起動シーケンスの先頭で同じ取得を見つけ、
またヘルパへ渡す。ヘルパはまた同じ空き不足で断念して開き直す。利用者が外から
空きを作るか取得を消すまで、この往復が続く。

App に見送りの指定 (--skip-update-apply) を渡せるようにし、容量不足の経路だけ
これを付けて開き直すようにした。指定つきで起動された App はその回だけ適用へ
入らず、そのまま立ち上がる。取得は残るので、空きができた後の起動で適用し直す。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dc8461eff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
Comment thread src/VRCToolsDataSync.App/Program.cs
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs Outdated
3 点。

- 昇格の最後の付け替え (記録を正規の名前へ置く) だけが失敗した場合、新しい
  ZIP は正規の場所に居るのに記録が無い形で止まり、次の起動の片付けが片方だけ
  の状態として ZIP まで捨てていた。横に残っている記録を置き直してから捨てる
  判断に入るようにした。置き直した対が食い違っていれば、その後の照合が digest
  と大きさで気付いて捨てる
- 更新ヘルパが、置き換えの間だけ App の多重起動の抑止も掴むようにした。掴んで
  いないと、入れ替えの最中に起動した App が旧 app\ を読み込んで掴み、入れ替え
  を失敗させたり、置き換え済みの一式をもう一度置き換えさせて退避した旧版を
  上書きさせたりする。呼び出し元とは別の App が既に動いている場合は、正規の
  位置に触らずに引き下がる (待つと、あちらが適用のロックを待っている場合に
  噛み合わない)。App を起動し直す前には必ず手放す
- 同じ場所がファイルとディレクトリの両方になる ZIP (app/foo と app/foo/bar.dll
  など) を展開の前に断るようにした。名前としては重なっていないので項目名の
  突き合わせでは通るが、展開すれば必ず失敗する。一時的な失敗と見分けられず、
  数回の空振りを経てから捨てられていた

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f02ccec337

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs
2 点。

- 昇格で古い記録を消していたため、その後の ZIP の入れ替えに失敗すると、正規の
  場所に前の ZIP だけが残り、適用できたはずの前の版まで失っていた。消さずに
  横へ退避し、入れ替えに失敗したら戻すようにした。戻せなかった場合は次の起動の
  片付けが拾う (新しい記録があれば仕上げ、退避した古い記録しか無ければ戻す)
- インストール先の空きを測る前に、前回の失敗が残した .new を消すようにした。
  PrepareAndSwap も複製の前に消すが、測る時点では残っているため、消せば足りる
  状況でも容量不足として断り続けていた

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3c49bdada

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
展開の空き容量の確認が、前回の展開先が残ったままの空きを見ていた。インストール
先が別ドライブにある場合、そちらの容量不足で staged を残して終わったヘルパが
完成済みの展開先を残すため、次の適用では残骸の分だけ空きが足りないと判断され、
その先の削除に到達しないまま繰り返す。削除を EnsureExtractable より前へ移した。

なお incoming.zip は測る対象から外していない。取得中のものかもしれず、消すと
走っている取得を壊すためである。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cc926ff8e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateApplier.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
Comment thread src/VRCToolsDataSync.Cli/Program.cs
4 点。

- 昇格の途中で止まった状態の復旧を、記録の名前ではなく ZIP との照合で決める
  ようにした。「古い記録を退避する → ZIP を入れ替える」の間で電源が落ちると、
  ZIP は前のままで横に新旧 2 つの記録が並ぶ。新しいほうを名前で選ぶと合わない
  対になり、両方捨てられていた
- ZIP の項目数と項目名の総量に上限を置いた。中身が空の項目は展開後の大きさに
  現れないため、数で押し切られると突き合わせ用の集合と展開先の両方を使い切る。
  自動適用は画面を出す前に走るので、そうなると App が開かなくなる
- 更新チャンネルを読めない場合に stable として扱っていたため、後始末の突き合わせ
  で test の取得がチャンネル外と判定され、正しい取得を捨てていた。「読めない」を
  区別し、その場合は突き合わせ自体を見送る (次の起動が拾う)
- ヘルパが呼び出し元の終了を待ちきれずに降りた場合、App はそのまま終わるため、
  利用者から見ると「再起動して適用」で画面が閉じたきりになっていた。終了の
  直前にヘルパの生死を見て、居なければ抑止とロックを手放してから開き直す

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19eafb629b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs
Comment thread src/VRCToolsDataSync.App/ViewModels/MainPageViewModel.cs
3 点。

- 昇格の仕上げが「読めない・動かせない」で終わった場合も、そのまま片方だけの
  状態として ZIP を捨てていた。仕上げの結果を「不要 / 済んだ / 分からない」で
  返し、分からない場合はその回の片付けを中止する。記録の読み出しも、壊れている
  (捨ててよい) と読めない (次へ回す) を投げ分ける
- インストール先の空きを測る前に、前回の置き換えが残した .old も消すようにした。
  .new と同じく PrepareAndSwap が次に消す対象で、数に入れたまま測ると、消せば
  足りる状況でも断り続ける。現行版のそろいは先に確かめており、複製に失敗しても
  現行版は無傷なので、この時点で消してよい
- ヘルパへ渡した後は設定の保存を受け付けないようにした。ヘルパは渡した時点の
  チャンネルで照合を済ませているため、終了時 Push を待つ間に stable へ変えて
  保存されると、保存済みの設定と適用される版が食い違う。終了が取り消された場合
  (ヘルパも止めている) は受け付け直す

Copy link
Copy Markdown
Owner Author

@codex review

前回のレビュー(19eafb6)以降の変更点:

  • 昇格の仕上げの結果を「不要 / 済んだ / 分からない」の 3 値にし、判断できない場合はその回の片付けを中止するようにした(a61fd8c
  • インストール先の空きを測る前に、.new に加えて .old も片付けるようにした(a61fd8c
  • ヘルパへ渡した後は設定の保存を受け付けないようにした(a61fd8c

Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a61fd8c83c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.App/ViewModels/MainPageViewModel.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs Outdated
Comment thread src/VRCToolsDataSync.App/Services/UpdateManager.cs
3 点。

- 前回が残した .new / .old を消せない場合、正規の位置に触っていないのに一般の
  失敗として扱われ、ヘルパが取得済みの ZIP まで捨てていた。空き不足と同じ
  「見送り」に倒す。空き不足の UpdateCapacityException を UpdateDeferredException
  の下へ移し、ヘルパは基底のほうで捕まえる
- 設定の保存を止める時点を、ヘルパを起こした後から適用の準備に入る時点へ
  early に移した。準備にはヘルパの生存確認の 3 秒が含まれ、その間も画面は
  操作できるため、渡した後に保存される窓が残っていた。準備に失敗した場合は
  下ろす
- 取得を省いてよいかを、記録どおりかではなく ZIP との照合で決めるようにした。
  常駐中に ZIP だけが壊れた場合、記録だけを見て省くと次の起動でそれが捨てられ、
  適用にもう一度の再起動が要る。確認は 24 時間に 1 度なので、ここで数百 MB を
  読む負担は許容する。読めなかった場合は省く側に倒す (掴まれているだけのこと
  があり、そこで取り直させない)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 561af120ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/VRCToolsDataSync.Cli/Program.cs
Comment thread src/VRCToolsDataSync.Core/Update/UpdateInstaller.cs Outdated
Comment thread src/VRCToolsDataSync.Cli/Program.cs Outdated
Comment thread src/VRCToolsDataSync.Core/Update/UpdateStage.cs
3 点。

- 更新ヘルパがログの置き場所を作れない場合に、その場で落ちていた。親の App は
  「起きてすぐ落ちたヘルパ = 壊れた配布物」と見なして取得を捨てるため、ログを
  書けないことの代償が数百 MB の取り直しになる。ログ無しで続行するようにした
- ディレクトリの後始末を「あるか見てから消す」から「消しに行って、無かった
  だけを成功として分ける」に変えた。Directory.Exists は権限や一時的な失敗でも
  false を返すため、消せていないものを消せたことにして先へ進み、正規の位置で
  失敗して取得まで捨てていた。展開先を消せない場合も、展開の失敗と同じ数え方に
  乗せる (何度やっても消せないなら、取得を持ち続けても適用できない)
- 展開の失敗の数に、記録の digest を添えるようにした。数を消し損ねた場合や昇格の
  直後に落ちた場合、新しい ZIP が前の ZIP の回数を引き継ぎ、1 度つまずいただけで
  捨てられていた
@limit7412
limit7412 merged commit 5f87c0a into master Aug 30, 2026
1 check passed
@limit7412
limit7412 deleted the claude/update-auto-apply-tezzcs branch August 30, 2026 08:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be206c1eb3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// どの ZIP の回数かを、記録の digest で見分ける。数を消す側が失敗した場合や、
// 昇格の直後に落ちた場合、前の ZIP の回数がそのまま残る。それを引き継ぐと、
// 新しい ZIP が 1 度つまずいただけで捨てられる。
var generation = TryLoadMetadata()?.DigestHex ?? string.Empty;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 読み取り失敗した世代を空文字へまとめないでください

前回指摘後に追加された世代分けでも、展開失敗時に staged.json が一時的に読めないと TryLoadMetadata() が null を返し、すべての ZIP が空文字の同一世代として数えられます。前の ZIP で空文字世代の失敗数が 2 まで残り、昇格時に extract-failures を削除できなかった場合、新しい正常な ZIP はメタデータ読み取りと展開が一度だけ同時に失敗しただけで 3 回目と判定され、InvalidDataException 経由で破棄されます。世代は既に検証済みのメタデータから渡すなど、取得不能時に共有値へフォールバックしないでください。

AGENTS.md reference: AGENTS.md:L3-L5

Useful? React with 👍 / 👎.


try
{
Move(current, backup);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge プロセス中断後に正規ディレクトリを復元してください

更新ヘルパがこの移動を終えた直後から .new を正規名へ移すまでに電源断や強制終了が起きると、app は存在せず app.oldapp.new だけが残ります。例外処理による巻き戻しはプロセス終了時には走らず、ランチャーも app\VRCToolsDataSync.App.exe を直接起動するだけなので、次回起動で更新を再開するコードへ到達できず、利用者が手作業でディレクトリを戻すまで App を起動できません。ランチャーまたは別の常駐しない起動経路で中断状態を検出し、正規名が欠けていれば .old を復元できるようにしてください。

AGENTS.md reference: AGENTS.md:L3-L5

Useful? React with 👍 / 👎.

{
var fresh = Path.Combine(_targetDirectory, part + ".new");
ClearLeftover(fresh);
CopyDirectory(Path.Combine(_sourceDirectory, part), fresh);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 複製中の一時的な I/O 失敗でも staged を保持してください

ウイルス対策ソフトが展開元のファイルや作成中の app.newcli.new を一時的に保持すると、この複製は IOException または UnauthorizedAccessException を投げます。この時点では正規の appcli にまだ触れていませんが、例外は UpdateDeferredException に変換されず CLI の一般失敗処理へ届くため、正常な staged ZIP とメタデータまで破棄されます。作りかけの .new を片付けた後、残骸削除の失敗と同じ見送りとして伝え、ロックが外れた次回に同じ取得を再利用してください。

AGENTS.md reference: AGENTS.md:L3-L5

Useful? React with 👍 / 👎.

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.

2 participants