# 改善計画書

## 概要

match_12 プロジェクト（Laravel 12）のコード品質・パフォーマンス・セキュリティを分析し、改善すべき課題を洗い出した。

---

## 0. 2026-05 セキュリティ修正（対応済み）

以下の項目はコードレビューで検出し、修正済み:

| 重要度 | 内容 | 対応 |
|--------|------|------|
| Critical | `hyperliquid-bot.js` トレード履歴・autofixログの innerHTML XSS | `escapeHtml()` で全動的値をエスケープ |
| High | `civitai.js` トリガーワード onclick XSS | `data-copy-text` 属性 + イベント委譲に変更 |
| High | `civitai.js` model.description innerHTML XSS | `sanitizeHtml()` で script/iframe/on*/javascript:/data: URI 除去 |
| High | `hl_bot.py` / `hl_pair_bot.py` Discord エラー通知の完全無効化 | 10分レート制限付きで再有効化 |
| High | `HyperliquidBotController` SSRF リスク | `botRemoteUrl()` で http/https スキーマのみ許可 |
| High | 内部API経由の再帰プロキシループ | `isInternalApiRequest()` で内部APIルートからのプロキシをスキップ |
| High | `bootstrap/app.php` ConnectionException 一律抑制 | Shopping/PriceCompare/Comic 関連のみに限定 |
| Medium | `CivitaiService` ダウンロード URL 未検証 | `civitai.com` / `civitai.red` ホストのみ許可（サブドメイン偽装対策済み） |
| Medium | `CivitaiService` timeout(0) 無期限ハング | timeout(1800) に変更 |
| Medium | `proxyGet()` 例外の握りつぶし | デバッグログを追加 |
| Medium | `civitai.js` resumeActiveDownloads クロージャバグ | `var` → `let` に変更 |
| Medium | `hl_bot.py` pnl==0 が loss_count に加算 | `elif pnl < 0` に修正（ゼロはカウント外） |
| Medium | `civitai.js` `sanitizeHtml()` 重複定義 | デッドコードの1つ目を削除 |
| Medium | `hyperliquid-bot.js` 未使用 `escapeHtmlBot()` | 削除 |
| Medium | シェアトークン検証が非タイミングセーフ | `hash_equals()` に統一 + `verifyShareToken()` にリファクタ |
| Low | `proxyGet` の `Log` が完全修飾名 | import 済みの `Log` ファサードを使用 |
| Low | `HyperliquidSigningService` の `ltrim('0x')` が `'0'`+`'x'` を個別除去 | `str_starts_with()` + `substr()` に修正 |
| Low | `civitai.js` `sanitizeHtml()` に `data:` URI 未対処 | `data:` で始まる属性値も除去対象に追加 |
| Medium | `affiliate_link()` / `setLink()` もしもURL の `url=` パラメータ未エンコード | PHP: `urlencode()`、JS: `encodeURIComponent()` を追加 |
| Low | `config/services.php` 環境変数名 typo（`AFIILIATE` → `AFFILIATE`） | 正しいスペルに修正 |
| Low | `.env.example` に新規環境変数が未登録 | `MERCARI_AFFILIATE_ID` / `MOSHIMO_*` / `DISCORD_HEALTH_CHECK_WEBHOOK_URL` を追加 |
| Low | `affiliate_link()` mercari の `afid` パラメータ未エンコード | `urlencode($aid)` / `encodeURIComponent(aid)` を追加 |

---

## 1. セキュリティ（緊急度: 高）

### 1-1. SQLインジェクションリスク

| ファイル | 行 | 問題 |
|---------|-----|------|
| `app/Http/Controllers/Comic/ComicController.php` | 386 | `orderByRaw("FIELD(id, {$ids_str}")` — 文字列を直接埋め込み |
| `app/Http/Controllers/App/FrimaPrize/Item/ItemsController.php` | 123 | `orderByRaw(DB::raw("FIELD(id, {$ids}) ASC"))` — 同上 |

**対策:** パラメータバインディングを使用する、または `orderByRaw("FIELD(id, " . implode(',', array_fill(0, count($ids), '?')) . ")", $ids)` のようにプレースホルダを使う。

### 1-2. XSSリスク（未エスケープHTML出力）

| ファイル | 内容 |
|---------|------|
| `resources/views/content/user_posts/public/show.blade.php` | `{!! MatomeFormatter::format($post->body) !!}` — ユーザー投稿をそのまま出力 |
| `resources/views/core/docs/show.blade.php` | `{!! $html !!}` — 生HTML出力 |
| `resources/views/real_estate/estate/view.blade.php` | `{!! $product->description !!}` — スクレイピングデータをそのまま出力 |

**対策:** `MatomeFormatter` 内でHTMLPurifierなどのサニタイザーを通す。外部データは必ずエスケープしてから出力する。

### 1-3. Webhook認証の欠如

| エンドポイント | 問題 |
|---------------|------|
| `POST /api/qa/chatwork-webhook` | 署名検証なし |
| `POST /api/qa/github-webhook` | HMAC-SHA256検証なし |
| `GET /api/price-compare/mercari-pending` | 認証なし |

**対策:** Chatworkトークン検証、GitHub Webhook署名検証を実装。Mercariエンドポイントにも認証を追加。

### 1-4. 認可チェックの不足

- 管理者ルート (`/admin/*`) が `auth` ミドルウェアのみで保護されており、ロール/権限チェックがない
- Policyクラス、Gateが未定義

**対策:** Laravel Policyまたは権限パッケージ（spatie/laravel-permission等）を導入し、管理者と一般ユーザーを分離する。

---

## 2. パフォーマンス（緊急度: 中〜高）

### 2-1. データベースインデックスの不足

#### `suumo_properties` テーブル（影響大）

| カラム | 用途 | 状態 |
|--------|------|------|
| `price_man` | WHERE / ORDER BY | インデックスなし |
| `land_area_m2` | WHERE / ORDER BY | インデックスなし |
| `building_area_m2` | WHERE / ORDER BY | インデックスなし |
| `building_year` | WHERE（CAST使用） | インデックスなし |
| `ai_rating` | WHERE | インデックスなし |
| `created_at` | ORDER BY | インデックスなし |

#### `comic_comments` テーブル

- `comic_id`, `ip`, `(comic_id, created_at)` の複合インデックスが全て欠如

#### `user_posts` テーブル

- `user_id`, `user_post_category_id` のインデックスが欠如

**対策:** マイグレーションを追加してインデックスを作成する。

### 2-2. N+1クエリ問題

| ファイル | 箇所 | 問題 |
|---------|------|------|
| `ComicController.php` | 161行 | ループ内で `$comic->comicSites` にアクセス |
| `ErrorLogController.php` | 64行 | `$errorLog->load('user')` — 取得後にリレーション読み込み |
| `SuumoPropertyController.php` | 93, 127行 | `favoriteSuumoProperties()` を複数回呼び出し |

**対策:** `with()` によるEager Loadingを徹底する。Laravel Debugbarでクエリ数を監視する。

### 2-3. 大量データ処理の非効率性

| ファイル | 行 | 問題 |
|---------|-----|------|
| `DataPortController.php` | 180-186 | `DB::table($table)->get()->toArray()` — テーブル全件をメモリに読み込み |
| `DataPortController.php` | 151-153 | テーブルごとに `count()` を個別実行（ループ内でN回のDBクエリ） |
| `DataPortController.php` | 262-270 | upsertモードで1行ずつ処理（バッチ処理すべき） |
| `DataPortController.php` | 209 | `file_get_contents()` でファイル全体をメモリに展開 |

**対策:**
- `->get()` を `->chunk()` または `->lazy()` に変更
- テーブルカウントは `INFORMATION_SCHEMA` から一括取得
- upsertは `upsert()` メソッドでバッチ処理
- 大きなファイルはストリーム処理

### 2-4. キャッシュ・キュー・セッションがすべてデータベース

```
QUEUE_CONNECTION=database
CACHE_STORE=database
SESSION_DRIVER=database
```

**対策:** 本番環境ではRedisに切り替える。DB負荷を大幅に軽減できる。

### 2-5. 同期処理すべきでない重い処理

| ファイル | 行 | 問題 |
|---------|-----|------|
| `ErrorLogController.php` | 183-187 | `bulkAnalyze()` — AI分析をリクエスト内でループ実行 |
| `ComicController.php` | 146 | `ComicView::create()` — リクエスト内で同期的にログ作成 |

**対策:** Jobにディスパッチしてバックグラウンドで処理する。

---

## 3. コード品質（緊急度: 中）

### 3-1. バリデーション不足

| ファイル | 問題 |
|---------|------|
| `FrimaPrize/Item/ItemsController.php` | `$request->...` を検証なしで使用（52, 60, 117, 120行） |
| `AccessLogController.php` | フィルタリング入力の検証なし |

**対策:** `$request->validate()` または FormRequest を使用する。

### 3-2. エラーハンドリング不足

| ファイル | 問題 |
|---------|------|
| `DataPortController.php:209` | `file_get_contents()` が try-catch なし |
| `ZundamonVoiceController.php:159` | ZIP作成失敗時のロールバックなし |
| `SuumoPropertyController.php:179-191` | スクレイピング・駅保存のエラーハンドリング不足 |

### 3-3. APIレート制限の不足

- `/site-chat` — レート制限なし（AI APIコスト増大リスク）
- ショッピング検索エンドポイント — レート制限なし
- コミックAPIエンドポイント — レート制限なし

**対策:** `throttle` ミドルウェアを追加する。特にAI API呼び出しが絡むルートは必須。

---

## 4. テスト（緊急度: 中）

### 現状

テストファイルは15個のみ。70以上のコントローラーに対してカバレッジが大幅に不足。

### 不足しているテスト

| 対象 | 必要なテスト |
|------|-------------|
| 認証・認可 | ログイン、権限チェック、管理者ページへのアクセス制御 |
| APIエンドポイント | Webhook処理、Mercari API |
| セキュリティ | CSRF、XSS防止、SQLインジェクション防止 |
| 金融機能 | 家計簿、クレジットカード明細パース、仮想通貨取引 |
| 不動産機能 | SUUMOクロール、住宅ローン計算 |
| データポート | インポート/エクスポートの正常系・異常系 |

---

## 5. フロントエンド（緊急度: 低〜中）

### 5-1. Viteエントリーポイントが多すぎる（130以上）

- 同一ドメインのCSSファイルを統合可能（例: comic関連の6ファイルを1ファイルに）
- コード分割（code splitting）の設定が未導入

### 5-2. jQueryの使用

- モダンなバニラJSまたはAlpine.jsへの段階的な移行を検討

### 5-3. innerHTML の直接使用

- `resources/js/app/youtube-pdca-show.js` で `innerHTML` を直接操作 — XSSリスクあり
- `textContent` または DOMPurify の使用を推奨

---

## 6. インフラ・設定（緊急度: 中）

### 6-1. 本番環境設定

| 項目 | 現状 | 推奨 |
|------|------|------|
| `APP_DEBUG` | `true` | `false`（本番） |
| `LOG_LEVEL` | `debug` | `warning` 以上 |
| `SESSION_ENCRYPT` | `false` | `true` |

### 6-2. Vite開発設定

- `cors: { origin: '*' }` — 本番では制限すべき
- ngrokのURLがハードコードされている — 環境変数化すべき

---

## 優先度別アクションプラン

### Phase 1: 緊急対応 ✅ 完了（2026-03-30）

1. ✅ SQLインジェクション修正（ComicController, ItemsController — プレースホルダ化）
2. ✅ 認可チェック導入（AdminOnlyミドルウェア作成、adminルートに適用）
3. ✅ Webhook署名検証（Chatwork/GitHub既に実装済み確認、Mercari APIにVerifyInternalApiTokenミドルウェア追加）
4. ✅ 本番環境設定の修正（deploy.ymlにsed適用ステップ追加: APP_DEBUG=false, LOG_LEVEL=warning, SESSION_ENCRYPT=true）

### Phase 2: パフォーマンス改善 ✅ 完了（2026-03-30）

5. ✅ データベースインデックス追加（マイグレーション作成: suumo_properties, comic_comments, user_posts）
6. ✅ N+1クエリ修正（ComicController Eager Loading、SuumoPropertyController重複クエリ統合）
7. ✅ DataPortController改善（INFORMATION_SCHEMA一括カウント、chunkエクスポート、upsertバッチ化）
8. ✅ 重い同期処理のJob化（AnalyzeErrorLogJob作成、bulkAnalyzeをキューディスパッチに変更）
9. ✅ Redis導入（deploy.ymlでredis-cli ping検出時にCACHE/QUEUE/SESSIONを自動切替）

### Phase 3: コード品質向上 ✅ 完了（2026-03-30）

10. ✅ バリデーション追加（ItemsController, AccessLogController）
11. ✅ エラーハンドリング強化（ZundamonVoice ZIP作成、SuumoProperty スクレイピング+駅保存トランザクション化）
12. ✅ レート制限追加（site-chat, price-compare/search, comic API, YouTube AI, WebScraper, StockYutai, SuumoChat）
13. ✅ XSSリスク対応（estate/view.blade.php strip_tags、youtube-pdca-show.js escapeHtml）

### Phase 4: テスト・保守性 ✅ 完了（2026-03-30）

14. ✅ 認証・認可テスト追加（AuthorizationTest: ログイン/権限/AdminOnly/内部API認証 10テスト）
15. ✅ 金融・不動産機能テスト追加（HousingLoanTest: 住宅ローン/おすすめ/SUUMO/土地価格 9テスト）
16. ✅ APIエンドポイントテスト追加（DataPortTest: エクスポート/インポート/プレビュー/エラーログ 11テスト、SecurityTest: XSS/SQLi/レート制限 6テスト）
17. ✅ Viteエントリーポイント統合（comic CSS 6→1バンドル、train route CSS 4→1バンドル、計9エントリーポイント削減）

---

## Phase 1〜4 再検証結果（2026-04-15）

実コードで以下を確認した：

| 項目 | 検証内容 | 結果 |
|------|---------|------|
| SQLi対策 | `orderByRaw.*FIELD` 全箇所がプレースホルダ＋バインディング化 | ✅ 維持 |
| AdminOnly | `app/Http/Middleware/Admin/AdminOnly.php` で `role==='admin'` チェック、`/admin/*` 配下に適用 | ✅ 維持 |
| インデックス | `2026_03_30_000001_add_performance_indexes.php` 適用済み（suumo/comic_comments/user_posts） | ✅ 維持 |
| Job化 | `app/Jobs/Admin/AnalyzeErrorLogJob.php` 作成、`ErrorLogController::bulkAnalyze` から dispatch | ✅ 維持 |
| レート制限 | `routes/web.php` で `throttle:` 23箇所適用 | ✅ 維持 |
| XSS対策 | `estate/view.blade.php` は `strip_tags` 経由（許可タグのみ） | ✅ 維持 |
| FormRequest | `ItemsController::disp_items_json` で `$request->validate()` 実装 | ✅ 維持 |
| テスト | Feature テスト 34 ファイル（旧15 → 倍増以上） | ✅ 維持 |

---

## Phase 5: 新規課題（2026-04-15 追加）

Phase 1〜4 完了後に追加された機能・残課題で、新たに対応が必要な項目。

### 5-1. モバイルアプリAPI（React Native / Expo）の強化

- 2026-04 に iPhone アプリ（`mobile/`、Expo / RN 0.76.9）と `routes/api.php` の `mobile/*` エンドポイントを追加
- `MobileApiAuth` ミドルウェア＋`MobileApiAuthTest` で基本認証は実装済み
- **未対応:**
  - ゲストトークンの有効期限・ローテーション戦略の明文化
  - 全モバイルエンドポイントへの `throttle` 追加（`auth/login` `price-compare/search` のみ設定済み）
  - レスポンスでの個人情報マスキング監査
  - モバイル端末固有 ID（device_id）と user_id の紐付け監査ログ

### 5-2. Pythonスクレイパー Docker コンテナのセキュリティ

- `docker-compose.yml` に `scraper` サービス（x11vnc + Selenium + Python）を追加
- Laravel 側 `INTERNAL_API_TOKEN` で POST 認証する設計 ✅
- **未対応:**
  - x11vnc のパスワード設定とポート公開範囲（127.0.0.1 限定にすべき）
  - スクレイピング対象サイトの robots.txt / 利用規約遵守チェック
  - スクレイパーコンテナのリソース上限（メモリ/CPU）設定
  - `INTERNAL_API_TOKEN` のローテーション手順

### 5-3. innerHTML / 生HTML出力の広範使用

- `resources/js` 配下で `innerHTML` 使用が **594 箇所 / 77 ファイル**
- ユーザー入力・スクレイピングデータを混入させる箇所がないか棚卸し未完
- **未対応:**
  - 高リスクファイルの優先リスト化（finance/kakeibo-index.js: 46回, shopping/price-compare.js: 39回 等）
  - DOMPurify 導入 or `textContent` 置換のガイドライン策定
  - 新規 JS で `innerHTML` を使う場合の lint ルール（eslint-plugin-no-unsanitized 等）

### 5-4. Blade `{!! !!}` の残り箇所監査

22 ファイルで `{!! !!}` を使用。サニタイザ未経由の可能性があるもの：

| ファイル | 内容 |
|---------|------|
| `content/user_posts/public/show.blade.php:38` | `MatomeFormatter::format($post->body)` — フォーマッタ内部のサニタイズ責務を再確認 |
| `core/docs/show.blade.php` | 生 HTML 出力 — Markdown レンダラ経由か未確認 |
| `comic/view.blade.php` / `entertainment/horse_racing/*.blade.php` 等 | ランキング/コメント類の混入有無を確認 |

**対策:** 各箇所で「データ源が信頼できるか」「サニタイザを通しているか」をチェックリスト化。

### 5-5. jQuery 段階的廃止（Phase 4 から継続）

- `$(` を含む JS が 77 ファイル
- **方針案:**
  - 新規 JS は素の DOM API / Alpine.js を必須化
  - 既存ファイルはドメイン単位（finance, comic, entertainment）で四半期ごとに置換
  - `jquery` import を ESLint で警告（新規ファイルのみ error）

### 5-6. Policy / Gate 未導入

- `AdminOnly` ミドルウェアによる role チェックのみで、`app/Policies/` ディレクトリ自体が存在しない
- 「自分の投稿のみ編集可」「お気に入りは本人のみ操作可」などのリソースレベル認可がコントローラ内のIF文に散在
- **対策:** `UserPostPolicy`, `SuumoPropertyFavoritePolicy` 等を作成し `$this->authorize()` に統一

### 5-7. 新規追加機能のテスト不足

2026-04 までに追加された以下機能のテストカバレッジが低い：

| 機能 | 必要なテスト |
|------|-------------|
| Amazon Associates `import-json` API | 異常系（不正トークン、バリデーション）追加検討 |
| ボートレース AI 予測ジョブ群 | ジョブ実行・失敗時リトライ |
| ずんだもん会話デーモン（Python） | 起動/停止、API疎通 |
| Pixiv / 裏サンデー エピソード取得 | スクレイピングのスナップショットテスト |

---

---

## Phase 6: 2026-05 ブランチレビュー課題（新規）

2026-05 ブランチ（Auto Video Edit, LIFF Price Compare, Hyperliquid Bot 改善）のコードレビューで検出された課題。

### 6-1. Auto Video Edit — 認可・アップロードセキュリティ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Critical | `authorizeOwn()` が `user_id = NULL` のジョブに全ユーザーアクセスを許可 | 未対応 |
| Critical | チャンクアップロード（`chunk()`, `abortUpload()`）に所有権チェックなし — 別ユーザーの upload_id を操作可能 | 未対応 |
| High | `assembleFromChunks` の拡張子が `normalizeExtension()` を経由せずパストラバーサルリスク | 未対応 |
| High | チャンクアップロードにレート制限なし — ディスク枯渇攻撃が可能 | 未対応 |
| High | `total_chunks` バリデーション max:100000 と DB 型 unsignedSmallInteger(max:65535) の不一致 | 未対応 |
| High | ダウンロードファイル名 `original_name` の特殊文字によるヘッダインジェクションリスク | 未対応 |
| Medium | `checkMissingModules()` がページロード毎に Python プロセスを3つ起動 — キャッシュすべき | 未対応 |
| Medium | テストスキーマに `upload_id`, `total_chunks` カラムが欠如 | 未対応 |
| Medium | 孤立チャンクアップロードディレクトリの自動クリーンアップなし | 未対応 |
| Low | チャンクアップロードフローのテストカバレッジがゼロ | 未対応 |

### 6-2. LIFF Price Compare — バリデーション・プライバシー

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `PayPayFrimaService::searchViaProxy()` のレスポンスが `normalizeItem()` を経由せず未検証で返却 | 未対応 |
| High | `PriceCompareController::search()` のキャッシュ LIKE 照合で `%` `_` 未エスケープ — 意図しないキャッシュヒット＋SQL LIKE インジェクション | 未対応 |
| Medium | `X-Guest-Token` ヘッダの形式バリデーションなし（48文字hex等のチェック） | 未対応 |
| Medium | `ip_address` カラム追加に伴うプライバシー（GDPR等）への配慮・データ保持ポリシー未明文化 | 未対応 |
| Medium | `PayPayFrimaService` プロキシモードのテストカバレッジがゼロ | 未対応 |
| Medium | `price-compare-common.js` の `setupFavHandler` で `getCsrfToken()` が未定義 — お気に入りトグルが壊れている可能性 | 未対応 |
| Low | LIFF ページでアフィリエイトリンク変換（`setLink()`）未適用 — 収益機会の損失 | 未対応 |
| Low | LIFF SDK バージョン未固定（`edge/2` で自動更新）— LINE 側変更で突然壊れるリスク | 未対応 |
| Low | LIFF ページに CSP ヘッダー未設定 | 未対応 |

### 6-3. Hyperliquid Bot — トレーディング安全性

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Critical | ペアボット: 片足注文失敗時にヘッジなしポジションが放置される（ロールバック/クリーンアップなし） | 未対応 |
| Critical | Watchdog が Bot 停止直後に再起動する TOCTOU 競合（status.json の "stopped" を確認すべき） | 未対応 |
| Critical | `discord_error_notify(e, ...)` で Exception オブジェクトの `[:2000]` スライスが TypeError — エラー通知が全て沈黙 | 未対応 |
| High | `BotWatchdogCommand` の `sudo pip install` が `default => $module` で未知のモジュール名を実行 — ホワイトリスト化すべき | 未対応 |
| High | ステータス/設定 JSON ファイルにファイルロックなし — 部分書き込み中の読み取りで JSON 破損 | 未対応 |
| High | Discord Webhook URL が `hl_bot_status.json` に平文記録 | 未対応 |
| High | ペアボットに発注前マージンチェックなし | 未対応 |
| High | PID 値を `exec()` に直接展開 — `is_numeric()` は `0x1A` 等も通すため、`posix_kill()` か `escapeshellarg()` を使うべき | 未対応 |
| High | 秘密鍵が `nohup env HYPERLIQUID_PRIVATE_KEY=...` でプロセス引数に露出 — `/proc/<pid>/environ` や `ps` で読み取り可能 | 未対応 |
| High | `hl_pair_bot.py` で FAILED/ERROR 時も手数料が加算される — `hl_bot.py` は約定時のみ加算しており不整合 | 未対応 |
| Medium | `_round_price()` がサブドル銘柄で精度不足 | 未対応 |
| Medium | `bot_containers.blade.php` の ~220行インラインスクリプト（CLAUDE.md のCSS/JS分離規約違反） | 未対応 |
| Medium | `position_size_usd` 最低値 $1 vs Hyperliquid 実際の最低額 $10 の不一致 | 未対応 |
| Medium | ボットログファイルのローテーション/サイズ制限なし | 未対応 |
| Medium | `bot.blade.php` のローソク足間隔ドロップダウンに `3m` が欠落 — バリデーションでは許可済み | 未対応 |
| Medium | EMA10 戦略の状態（`ema10_state`, `ema10_pending`, `ema10_active_tp/sl/side`）が `_save_runtime_state()` に未保存 — Bot 再起動時に TP/SL が失われる | 未対応 |
| Medium | `hl_pair_bot.py` に一過性ネットワークエラーハンドリングなし — 単発接続エラーで即 `error` ステータス | 未対応 |
| Medium | `hl_bot.py` と `hl_pair_bot.py` の大量コード重複 — 共通モジュール `hl_common.py` に切り出すべき | 未対応 |
| Medium | `bot_presets.blade.php` の `$strategy_labels` に `ema10` が欠落 — 生値で表示される | 未対応 |
| Medium | Bot 起動の二重起動防止に排他制御なし — 同時リクエストで2プロセス起動の可能性 | 未対応 |
| Low | RSI 計算が Cutler 方式（Wilder 方式ではない）— TradingView と値が異なる | 未対応 |
| Low | テイカー手数料率 0.035% がハードコード | 未対応 |
| Low | `HyperliquidService` が常にメインネット URL を使用（テストネット未対応） | 未対応 |

### 6-4. デプロイ・インフラ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `deploy-nas.yml` のアプリリビルド後 `sleep 30` が固定値 — ポーリングループに変更すべき | 未対応 |
| Medium | `SiteHealthCheckCommand` のメルカリ Docker 再起動にクールダウンなし — 再起動ループのリスク | 未対応 |
| Medium | `docker-compose.yml` の Docker ソケットマウント — Webアプリ脆弱性時にホスト root 権限と同等のリスク。Docker Socket Proxy の導入を推奨 | 未対応 |
| Medium | `docker-compose.yml` の MySQL パスワードデフォルト値が `secret` / `rootsecret` — `.env` 未設定時に弱いパスワードで起動 | 未対応 |
| Medium | `config/services.php` で `env()` 内に `env()` をネスト（例: `env('GEMINI_API_KEY', env('GOOGLE_CLOUD_API_KEY'))`）— `config:cache` 後にフォールバックが動作しない | 未対応 |
| Medium | `deploy-nas.yml` で `docker-compose` (V1) と `docker compose` (V2) が混在 | 未対応 |
| Low | `vite.config.js` の ngrok URL がハードコードのまま（5-2 から継続） | 未対応 |
| Low | `.claude/worktrees/` がコミットに含まれている（開発アーティファクト） | 未対応 |
| Low | 直近コミット「メール送信処理対応」の内容が実際の変更（CivitAI お気に入り機能追加）と不一致 | 未対応 |

### 6-5. CivitAI お気に入り — セキュリティ・品質

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `sanitizeHtml()` が `<style>`, `<svg>`, `<math>` タグを未処理 — CSS injection や SVG `<foreignObject>` 経由のバイパスが可能。DOMPurify 導入を推奨 | 未対応 |
| High | `thumbnail_url` が `string|max:1024` のみで URL 形式バリデーションなし — `javascript:` URL やデータ URI を保存可能 | 未対応 |
| Medium | `model.type` が未エスケープで `innerHTML` 内の CSS class 名に使用 — CivitAI API が想定外の値を返した場合に HTML injection の余地 | 未対応 |
| Medium | `CivitaiModelFavorite` の `$fillable` に `user_id` が含まれる — mass assignment リスク | 未対応 |
| Medium | `favorites()` にページネーションなし — 大量お気に入り時にメモリ・レスポンスサイズ問題 | 未対応 |
| Medium | `search()` / `show()` の catch で `$e->getMessage()` をそのままクライアントに返却 — 内部情報（ファイルパス・接続先URL等）漏洩リスク | 未対応 |
| Low | `civitai_model_favorites` テーブルに `user_id` の外部キー制約なし — ユーザー削除時に孤立レコード | 未対応 |
| Low | `search()` の `type` / `sort` バリデーションに許可値制限なし — 任意文字列が CivitAI API に渡される | 未対応 |

### 6-6. Stable Diffusion — コーディング規約違反

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `stable_diffusion/index.blade.php` に ~90行のインライン CSS + ~370行のインライン JS — CLAUDE.md の「約5行以下のみインライン可」規約に違反。`resources/css/tool/stable-diffusion.css` と `resources/js/tool/stable-diffusion.js` に分離すべき | 未対応 |
| Low | `id="error-area"` / `id="error-msg"` がページ内で重複 — `getElementById` が意図しない要素を参照する可能性 | 未対応 |

---

## Phase 7: 2026-05-16 ブランチレビュー課題（新規）

#523 / #524 のコードレビューで検出された課題。

### 7-1. IpatPurchaseService — syncBetStatuses のサーバー委譲リファクタ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `Process` import が残存（syncBetStatuses ではもう使用していないが、他メソッドで使用のため削除不可。ただし今後の整理候補） | 情報のみ |
| Medium | `check-votes` エンドポイントの `progress["running"]` グローバルフラグが購入処理と共有 — 購入中に投票照会ができない排他制御の設計上の制約 | 未対応 |
| Low | `ipat_server.py` の `check-votes` が同期処理なのに `progress` 状態を書き換え — 別リクエストの `/progress` SSE に不正な状態を配信する可能性 | 未対応 |
| Low | `ipat_local_server.py` の `check-votes` は `stdin` 経由、`ipat_server.py` はコマンドライン引数経由 — 入力方式が不統一 | 未対応 |

### 7-2. HorseRacingService — getSummary の拡張

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | `getWeekRange()` を2回呼び出し（offset=0 と offset=-1）— 効率上の問題はないが `$weekEnd` 未使用のため `$this->getWeekRange(-1)['start']` で十分。現状で問題なし | 情報のみ |
| Low | `selectRaw` のバインディング数が10個に増加 — 可読性維持のためクエリを分割するか定数化を検討 | 未対応 |

### 7-3. purchase-monitor.blade.php — オッズ表示ロジック

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | オッズ取得ロジックが2箇所に重複（購入済みセクション・購入待ちセクション）— Blade パーシャルまたは `@php` ヘルパーに切り出すべき | 未対応 |
| Low | `$oddsMap->get((string) $selNum) ?? $oddsMap->get((int) $selNum)` — odds_data のキーが文字列か整数か不定のため防御的に書いているが、データ源で正規化するのが理想 | 未対応 |
| Low | sidebar の `total_profit` 表示追加だが `getSummary()` は元々 `total_profit` を返しているため動作OK。ただしテストでの検証が未確認 | 未対応 |

### 7-4. ipat_server.py / ipat_local_server.py — check-votes の堅牢性

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `ipat_server.py` の `check-votes` で `progress["running"] = True` 設定後にスクリプト実行が例外 → `finally` で `running = False` にはなるが、`broadcast_progress` が呼ばれない（`error` 状態のままSSE未通知） | 未対応 |
| Medium | `ipat_local_server.py` の `check-votes` にはタイムアウト通知用の `state["running"]` 更新がない — 他リクエストが並行して受け付けられてしまう | 未対応 |
| Low | `ipat_server.py` の `check-votes` で `subprocess.TimeoutExpired` キャッチ時に `proc` 変数が未定義（`subprocess.run` が例外を投げるため戻り値なし）— `proc.kill()` 等の後処理ができない | 未対応 |

---

## Phase 8: 2026-05-18 ブランチレビュー課題（新規）

Stable Diffusion LoRA/お気に入り拡張、Hyperliquid Bot トレード DB 永続化、CivitAI ダウンロードタイムアウト延長、job-progress-widget 改善、api.php リファクタのコードレビューで検出された課題。

### 8-1. Stable Diffusion — LoRA パネル・お気に入り・img2img 拡張

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `stable_diffusion/index.blade.php` にインライン CSS 165行 + インライン JS 1502行（計2359行）— CLAUDE.md の「約5行以下のみインライン可」規約に大幅違反。Phase 6-6 で指摘済みだが改善されず、今回の変更でさらに増加 | 未対応 |
| High | `loraPreview()` の `response()->file($path)` で配信するファイルの Content-Type が `realpath` 結果の拡張子から自動推定 — `.preview.php` 等が LoRA ディレクトリに存在した場合にソースコード露出リスク。配信時に画像 MIME タイプ（`image/png`, `image/jpeg`, `image/webp`）を明示的に検証・制限すべき | 未対応 |
| Medium | `loraPreview()` の `showThumbPreview()` で `innerHTML = '<img src="' + src + '">'` — `src` は LoRA プレビューURLから取得しているが、将来の変更でユーザー入力が混入した場合に XSS リスク。`document.createElement('img')` を使うべき | 未対応 |
| Medium | LoRA 一覧 `listLoras()` がリクエストの度にディレクトリを再帰走査 — LoRA ファイルが数百個になるとレスポンスが遅延。数分間のキャッシュを導入すべき | 未対応 |
| Medium | `destroyAll()` にレート制限なし — 連打や自動化ツールで全画像が即座に削除される。確認ダイアログはJS側にあるがAPIとしては無防備 | 未対応 |
| Medium | `toggleFavorite()` / `destroyAll()` / `destroy()` に認可チェックなし — 現状シングルユーザーだが、マルチユーザー時に他人の画像を操作可能 | 未対応 |
| Medium | 画像生成ルート（`generate`, `img2img`）にレート制限なし — SD WebUI への過負荷リスク | 未対応 |
| Low | `buildHistoryItem()` で `onclick="showDetail(this)"` 等のインラインイベントハンドラを使用 — イベント委譲パターンに統一すべき | 未対応 |
| Low | `img2img` の `source_image_id` で他ユーザーの画像IDも指定可能 — マルチユーザー時の認可考慮 | 未対応 |
| Low | `lora-detail-modal` の CivitAI 画像サンプル表示で `onerror="this.style.display='none'"` — インラインイベントハンドラ | 未対応 |
| Low | 構図テンプレート（`composition_templates.blade.php`）のタグ一覧がハードコード — 設定ファイルや定数クラスに外出しする方が保守しやすい | 未対応 |

### 8-2. Hyperliquid Bot — トレード DB 永続化

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `ingestTrade()` エンドポイントに `VerifyInternalApiToken` ミドルウェアは適用済みだが、`side` / `status` のバリデーションに許可値制限なし — 任意文字列が DB に入る。`in:OK,FAILED,ERROR` 等で制限すべき | 未対応 |
| Medium | `HyperliquidBotTrade` モデルの `$fillable` に全カラムが入っている — `ingestTrade()` は `$validated` からのみ `create()` しているため実害は低いが、他の利用箇所で mass assignment リスク | 未対応 |
| Medium | `post_trade_to_laravel()` の通信失敗をログのみで握りつぶしている — 設計上の意図（取引フローを止めない）は正しいが、連続失敗時に Discord 通知を送るべき | 未対応 |
| Medium | `hyperliquid_bot_trades` テーブルへの INSERT 頻度に上限なし — Bot が高頻度取引した場合にテーブル肥大化。定期的なパーティション or アーカイブ戦略を検討 | 未対応 |
| Low | `hl_bot.py` の `post_trade_to_laravel()` が `datetime.now().isoformat()` でタイムゾーン情報なし — UTC か JST か不明確。`datetime.now(timezone.utc).isoformat()` にすべき | 未対応 |
| Low | `ingestTrade()` のテストカバレッジがゼロ | 未対応 |

### 8-3. Hyperliquid Bot — UI 改善（ポジションカード）

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | `renderPositionCard()` で `document.getElementById()` を多用（10箇所以上）— DOM参照のキャッシュ化を検討 | 未対応 |
| Low | ポジションカードの `pos-notional` に表示する想定額が `size * entry` で算出されているが、レバレッジが考慮されていない | 情報のみ |

### 8-4. BotWatchdogCommand — Discord 通知の環境情報

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | `gethostname()` がコンテナ内ではランダムなコンテナIDを返す — 意味のある名前にするには `HOSTNAME` 環境変数を Docker Compose で設定する必要がある。ドキュメントに記載すべき | 未対応 |

### 8-5. CivitAI — ダウンロードタイムアウト延長

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `CivitaiDownloadJob::$timeout` を 1800→7200（2時間）に延長 — キューワーカーの `--timeout` がこれ以下だとジョブが強制終了される。`docs/Tool/civitai.md` のタイムアウト記述が 30 分のままで更新が必要 | 未対応 |
| Low | VirtualBox 共有フォルダ越しの `rename` EXDEV フォールバック（`copy + unlink`）— 数GBのファイルを `copy()` するとメモリとディスクI/Oが2倍。`stream_copy_to_stream()` の方が安全 | 未対応 |

### 8-6. job-progress-widget — UX 改善

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | エラートースト（`showToast(msg, true)`）が自動で消えず手動閉じのみ — 長時間放置するとトーストが画面に蓄積。一定時間後にフェードアウトする選択肢も検討 | 未対応 |
| Low | 404 を40回リトライ（約60秒）してからエラー表示 — キューワーカーが起動していない場合にユーザーが1分間待たされる。「キューワーカー待ち...」表示は改善だが、設定でリトライ上限を変更可能にすべき | 未対応 |

### 8-7. api.php — コードスタイルリファクタ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | `api.php` の import 文リファクタ（FQCN → `use` 文）は良い改善。ただし `QaController` のインポートコメントに「認証不要」と記載があるが、Phase 1 で指摘済みの署名検証未実装が依然として未対応 | 情報のみ |

### 8-8. PriceCompareHistoryController — title 切り詰め

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Low | `mb_substr($data['title'], 0, 255)` はバイト数ではなく文字数で切り詰めている — VARCHAR(255) は文字セットによりバイト制限が異なる（utf8mb4 では1文字最大4バイト）。MySQL 8.0 の VARCHAR(255) は255**文字**なので mb_substr で正しい。問題なし | 対応済み |

---

## Phase 9: 2026-05-20 ブランチレビュー課題（新規）

競艇自動購入 Python 一式、IoT 人感センサー精度改善、Hyperliquid Bot トレード DB 永続化・ライブ設定変更、Stable Diffusion LoRA 削除・構図テンプレート・プロンプト翻訳拡張、api.php リファクタ（FQCN→use文）のコードレビューで検出された課題。

### 9-1. 競艇 Teleboat 自動購入 — セキュリティ・堅牢性

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Critical | `auto_purchase.py` が PHP コードを動的に文字列生成→一時ファイル→ `php artisan` 実行 — PHPコードインジェクションのリスク。Artisan コマンド経由の DB 操作に切り替えるべき | 未対応 |
| Critical | `teleboat_local_server.py` が `0.0.0.0` でバインド＋認証なし＋CORS `*` — Teleboat 認証情報がネットワーク上に露出。`127.0.0.1` 限定 + トークン認証を追加すべき | 未対応 |
| High | `auto_purchase.py` / `auto_check_votes.py` が認証情報（PIN、P-ARS）をコマンドライン引数でサブプロセスに渡す — `/proc/{pid}/cmdline` で閲覧可能。環境変数ファイル経由に統一すべき | 未対応 |
| High | `auto_purchase.py` / `auto_check_votes.py` でユーザーID=2 がハードコード — 複数ユーザーに非対応。環境変数またはコマンドライン引数で取得すべき | 未対応 |
| Medium | `BoatTeleboatPurchaseService` の一時ファイル（`tempnam`）にパーミッション設定なし — `chmod 0600` を追加すべき | 未対応 |
| Medium | `reconcileBets` で Teleboat 照会結果にマッチしない DB ベットを自動的に `error` に変更 — 照会画面の表示制限等で正常購入ベットが誤ってエラーになるリスク | 未対応 |
| Medium | Python スクリプト全体に TODO コメント（「実Teleboat画面を確認して実装」）が大量残存 — コミットメッセージは「完成」だが枠実装の状態 | 未対応 |
| Medium | `destroyBet` が `purchased`/`won`/`lost` ステータスのベットも物理削除可能 — 収支データの整合性が崩れる。ステータスチェックを追加すべき | 未対応 |
| Low | `adoptStrategy` の許可リストに `sanrentan_combined_ev` が含まれていない — バックテストで採用可能な戦略が実際には採用できないバグ | 未対応 |
| Low | `auto_check_votes.py` の `__import__("datetime")` インライン呼出し — 既にインポート済み | 未対応 |
| Low | `auto_purchase.py` / `auto_check_votes.py` で `load_env()` / `notify_discord()` が重複定義 — `teleboat_common.py` に統合すべき | 未対応 |

### 9-2. 競艇 — パフォーマンス・アーキテクチャ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `BoatRacer` のアクセサ4つ（勝率・複勝率・2着率・3着率）が各々DBクエリを発行 — リスト表示で N×4 問題。キャッシュまたはDB非正規化が必要 | 未対応 |
| Medium | `BoatRacingService::runBacktest` が全レースを `$query->get()` で一括取得 — 長期間で10万件超のメモリ不足リスク。`chunk()` 処理を検討 | 未対応 |
| Medium | `BoatRacingController` が1682行・約50メソッド — Backtest/Purchase/Schedule への分割を検討 | 情報のみ |
| Medium | 戦略ラベル定義が Controller 内5箇所で重複 — 定数クラスまたは `Consts/` に集約すべき | 未対応 |
| Medium | `backtest.blade.php` にインライン JS 約600行 — CLAUDE.md 規約違反。専用 JS ファイルに分離すべき | 未対応 |
| Low | `BoatRacingService` の `racerWinRates` 集計クエリが `applyStrategyToRaces` / `runBacktest` で重複 — 共通メソッドに抽出すべき | 未対応 |
| Low | `purchaseMonitor` での noVNC 可用性チェックが同期 `curl` — キャッシュ結果を使うか非同期にすべき | 未対応 |

### 9-3. 競艇 — テスト不足

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `BoatTeleboatPurchaseService` のテストがゼロ — `reconcileBets` の複雑なマッチングロジックが未検証 | 未対応 |
| Medium | スクレイピングパーサー（`parseRaceCardPage` / `parseResultPage` / `parseOddsPage`）のテストが不足 — HTML構造変更で壊れやすい箇所 | 未対応 |
| Low | Python 側テストが一切存在しない — パース処理は正規表現ベースでテスト必須 | 未対応 |

### 9-4. IoT 人感センサー — 品質・テスト

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `smart-home/index.blade.php` にインライン JS 約360行 — CLAUDE.md 規約違反。`resources/js/iot/smart-home.js` に分離すべき | 未対応 |
| Medium | `SmartHomeController::control()` の `type` パラメータにバリデーションルール（`in:aircon,tv,light`）なし | 未対応 |
| Medium | `devices` / `appliances` エンドポイントに `throttle` なし — Nature Remo API レート制限（30回/5分）に抵触するリスク | 未対応 |
| Low | `mo.val` のカウンタラップアラウンド（オーバーフロー→0リセット）時に検知漏れ — `$current_val !== $state->last_val` で判定するか対策を検討 | 未対応 |
| Low | テストに val 減少（カウンタリセット）、複数デバイス同時処理、タイムゾーン境界ケースが不足 | 未対応 |

### 9-5. Stable Diffusion — インライン規約違反・セキュリティ

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `stable_diffusion/index.blade.php` にインライン CSS 165行 + インライン JS 1618行（計2476行）— Phase 6-6、Phase 8-1 で繰り返し指摘済みだが改善されず、今回さらに LoRA 削除・プロンプト翻訳等で増加。CLAUDE.md 規約に大幅違反 | 未対応 |
| Medium | `loraPreview()` の `response()->file($path)` で Content-Type が拡張子から自動推定 — Phase 8-1 から継続。画像 MIME タイプの明示的検証が必要 | 未対応 |
| Medium | `destroyAll()` / 画像生成ルートにレート制限なし — Phase 8-1 から継続 | 未対応 |
| Low | `loraDestroy()` の `$e->getMessage()` をそのままクライアントに返却 — 内部情報漏洩リスク | 未対応 |

### 9-6. Hyperliquid Bot — Python バグ・堅牢性

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| Medium | `discord_error_notify(e, ...)` で例外オブジェクトを文字列として渡す箇所（hl_bot.py L1109, L1367）— `str(e)` で明示的に変換すべき。Phase 6-3 から継続 | 未対応 |
| Medium | メインループの `except` ブロックで `coin` 変数が未定義の可能性（`load_config()` 例外時）— ループ外にデフォルト値を設定すべき | 未対応 |
| Low | EMA10 戦略の状態が `_save_runtime_state()` に未保存 — Phase 8-2 から継続 | 未対応 |

### 9-7. ルーティング・その他

| 重要度 | 内容 | 対応状況 |
|--------|------|----------|
| High | `_check_sanrentan_coverage.php` がプロジェクトルートにコミット済み — デバッグ用スクリプトで認証なし DB アクセスが可能。削除すべき | 未対応 |
| Medium | `DataPortService::importSql()` の `SOURCE {$filePath}` で `$filePath` がエスケープなし — 内部生成パスだがバリデーション追加を推奨 | 未対応 |
| Medium | QA Webhooks（Chatwork/GitHub）の署名検証がシークレット未設定時にスキップ — 未設定時は 403 を返すべき | 未対応 |
| Medium | `suumo_property/auto_crawl.blade.php` で Discord Webhook URL が HTML に平文埋め込み — マスク表示にすべき | 未対応 |
| Medium | `PriceCompareHistoryController::popularPage` の `resolveUncategorizedViewHistory()` が GET リクエストで最大50件の UPDATE を発行 — バッチ処理に移すべき | 未対応 |
| Low | `suumo_property/auto_crawl.blade.php` にインライン CSS 約170行 — CLAUDE.md 規約違反 | 未対応 |
| Low | CDN 読み込み（Chart.js 等）に SRI ハッシュ（`integrity` 属性）なし — CDN 改ざん対策を推奨 | 未対応 |

---

## 優先度推奨（Phase 5 + Phase 6 + Phase 7 + Phase 8 + Phase 9）

1. **最優先:** 6-1（Auto Video Edit 認可バイパス）, 6-3 上位3件（ペアボット片足放置・Watchdog 競合・Discord通知沈黙）, 9-1 上位2件（auto_purchase.py の動的 PHP 生成廃止・teleboat_local_server.py のバインドアドレス＋認証）
2. **高:** 6-2（LIKE インジェクション・プロキシレスポンス未検証）, 6-3（PID インジェクション・秘密鍵露出・ペアボット手数料バグ）, 6-5（sanitizeHtml 不備・thumbnail_url バリデーション）, 5-1（モバイル API throttle）, 5-2（x11vnc バインドアドレス）, 8-1（loraPreview Content-Type 未検証）, 8-2（ingestTrade バリデーション不足）, 9-1（認証情報のコマンドライン渡し・ハードコード user_id）, 9-2（BoatRacer N×4 問題）, 9-5（SD index.blade.php インライン JS/CSS 2476行 — 3回目の指摘）, 9-7（_check_sanrentan_coverage.php 削除）
3. **中:** 6-1 残り（レート制限・チャンク型不一致）, 6-3（3m 欠落・EMA10 状態未保存・排他制御）, 6-4（Docker ソケット・MySQL パスワード・env ネスト）, 6-5（model.type エスケープ・mass assignment）, 6-6（インライン CSS/JS 分離）, 5-3（innerHTML 棚卸し）, 5-4（Blade `{!! !!}` 監査）, 7-1（check-votes 排他制御）, 7-3（Blade オッズロジック重複）, 8-1（LoRA キャッシュ・destroyAll レート制限・認可チェック・画像生成 throttle）, 8-2（mass assignment・通信失敗通知・テーブル肥大化対策）, 8-5（キューワーカー timeout 整合）, 9-1（一時ファイルパーミッション・reconcileBets 誤判定・destroyBet ステータスチェック）, 9-2（runBacktest メモリ・戦略ラベル重複・backtest.blade.php インラインJS）, 9-3（テスト不足3件）, 9-4（smart-home インラインJS・control バリデーション・throttle）, 9-6（discord_error_notify・coin未定義）, 9-7（DataPortService SOURCE エスケープ・QA Webhook 条件付き認証・Webhook URL 平文・GET で UPDATE）
4. **低〜中:** 5-5（jQuery 廃止）, 5-6（Policy 導入）, 5-7（新機能テスト）, 6-3 下位（RSI方式・手数料ハードコード・コード重複）, 7-2（selectRaw 可読性）, 7-4（SSE 通知漏れ）, 8-3（DOM参照キャッシュ）, 8-4（hostname ドキュメント）, 8-5（rename EXDEV フォールバック改善）, 8-6（エラートースト UX）, 9-1（adoptStrategy バグ・重複コード・inline import）, 9-4（カウンタラップアラウンド・テスト追加）, 9-5（loraDestroy エラーメッセージ漏洩）, 9-7（CDN SRI・インラインCSS）
