uLoop 導入の進捗表示とカードの情報負荷 (2026-08-12)
ユーザー報告: (1) 導入ボタンを押してから導入されるまでタイムラグがあるが、その間表示が 変わらず何が起きているか分からない。(2) 押したときに展開される UI が説明過多で情報負荷が 高い。
ラグ: 実測済みの既知値。OpenUPM の解決は実エディタで 30.5 秒(2026-08-04 の初回導入
実行)。Apply は Client.Add を投函した時点で成功を返し、AddRequest は
UloopInstallApplyResult.ClientAddRequest に載っているが、UI は誰もポーリングして
いない(v0.18.1 のレビュー対応で「UI はまだ読まない。ポーラの配線が次の一歩」と
明記した宿題)。その間、状態ラベルは「未導入」のまま静的な文が1行出るだけ。
カード(合成プランで実カードを構築して計測): 全体 222px。内訳は タイトル 13px / フルパス2本入りの経路文 27px(約100字) / 常時展開の生 JSON 差分 TextField 124px(207字) / ボタン行。「説明過多」の実体は、パス2本を本文に埋めた文章と、 畳めない生 JSON である。
2a. 進捗の実表示(AddRequest のポーリング)
Section titled “2a. 進捗の実表示(AddRequest のポーリング)”Apply 成功後、返ってきた ClientAddRequest を EditorApplication.update で監視する:
- 未完了: 「導入中… {0}秒」(経過秒を更新)。Apply は無効のまま。
Status == Failure:request.Error.messageを添えた失敗表示(非同期失敗が初めて パネル内で見える — v0.18.1 の caveat の正式な解消)。Status == Success: 解決完了。検出器が依存キーを見て「導入済み」に切り替わる。
ドメインリロード横断: 解決成功はパッケージ取り込み→再コンパイル→リロードを引き起こし、
AddRequest オブジェクトはそこで消える。SessionState に「導入進行中」フラグ+開始時刻を
置き、リロード後の RefreshUloopSection は (a) 検出器が導入済み→フラグ解除、
(b) フラグが新しい(5分未満)→「導入中…」を出し続ける、(c) 古い→
「Package Manager で状態を確認してください」。ポーラを持たない旧状態への退行はない
(現状がまさに (b)(c) 無しの世界)。
2b. カードの整理(v0.19.0 と同じ原則)
Section titled “2b. カードの整理(v0.19.0 と同じ原則)”- 経路文: パスを本文から抜き、1行に。「manifest.json に OpenUPM レジストリを追加し、 Package Manager にパッケージを要求します。」フルパス2本はカードのツールチップへ。
- 差分: 折りたたみ(Foldout)で既定は閉。差分が安全装置であることは変わらない — 見たい人が1クリックで開ける。開いた状態の中身は従来どおり。
- caveat(警告)は画面に残す(v0.19.0 の規則: ホバーしないと読めない警告は警告でない)。
- 「導入を要求しました。〜約30秒〜」という長い静的文は、ライブの進捗表示に置き換わるので 不要になり削除。
却下した代替案
Section titled “却下した代替案”- 進捗バー(パーセント表示): Client.Add は進捗率を公開しない。偽の進捗を描くのは 「観測していない成果を報告しない」原則に反する。経過秒数が正直な最大限。
- 差分を完全にツールチップへ: 207字の JSON はホバー表示に不向きで、 等幅・選択可能であるべき差分の性質にも合わない。折りたたみが正解。
3. 検証計画
Section titled “3. 検証計画”- ポーリング状態機械は純クラスに切り出して EditMode でテーブルテスト。
- 使い捨てプロジェクトを再作成して実際の導入をもう一度実行し、 Pending→Success の実遷移と経過表示、成功後の「導入済み」切り替えを実測する。
- カードは合成プランで再構築して高さを before/after 比較する。
4. 実装後の検証 (2026-08-12)
Section titled “4. 実装後の検証 (2026-08-12)”カード(同じ合成プランで再計測): 222px → 99px。差分は Foldout で既定閉 (開くまで 0px)、経路文は1行、フルパス2本は経路ラベルのツールチップに載っていることを リフレクションで直接確認。caveat と ボタン行は不変。
実導入(使い捨てプロジェクトで2回実行):
- 1回目: Apply 成功 → 26.5秒後に本物の解決失敗(UPM の「manifest.json への アクセスが拒否されました」— 一過性のファイルロック)。状態機械は Installing → FailedAsync を正しく導出。従来この失敗は完全に不可視だった (成功と同じ「開始しました」だけが出て、状態は永遠に「未導入」のまま)。 仕込んだ失敗ではなく、偶発した本物の失敗で FailedAsync 経路が検証されたことになる。
- 2回目(再試行): Installing(0.2秒)→ Succeeded(21.8秒)。 このとき AddRequest.IsCompleted はまだ False のまま検出器が先に立った — 「Succeeded は常に検出器(manifest の依存キー)から導出し、リクエストの成功 ステータスからは導出しない」という設計判断そのものが実測で裏付けられた。 リクエスト完了を待っていたら、実際より遅く成功を報告していた。
サンドボックス 2038 tests / 0 failed(進捗状態機械のテーブルテスト19件を含む)。