# UI差分まとめ 第3章 — 8件の「不具合 / 仕様」振り分け調査

**作成: 2026-09-16 / ブランチ: `develop`（`2aaf606` 時点） / 調査のみ。コードは1行も変更していない**

---

## 0. この文書の位置づけ

`docs/decisions.md` の **D-142 項8 の J-6**（`docs/decisions.md:11232` 付近）
「`UI差分まとめ` 第3章8件が『仕様』か『不具合』か」に答えるための材料です。

- 対象: `docs/UI差分まとめ_20260915.md:206-222` の8件
- ★本文書は決定ではありません★。決めるのはユーザーで、決めた内容は `docs/decisions.md` に D-143 として残してください
- ★実装は Cursor 側★。§11 に指示書AO の段階分け案を置きました
- ★根拠はすべて実測★（`file:line` / grep コマンド / `git blame`）。推測の箇所は「推測」と明記しました

---

## 1. 結論 — 3分類の一覧

| # | 内容 | 判定 | 一言 |
|---|---|---|---|
| 1 | 「未対応」の対訳キー衝突 | ★不具合★ | 2026-09-09 に別画面のために足したキーが、7日前から使われていた同じ日本語を巻き込んだ。記録は「登録済みであることを確認した」だけ |
| 2 | ダッシュボードの「判定 ?」ボタンが死んでいる | ★不具合★ | D-053 に真正面から反する。`onToggleGradeInfo={() => {}}` を渡しているだけで、直すのは2行 |
| 3 | ダッシュボードの清掃ログ表が4列 | ★不具合★ | `docs/spec.md:32` が「機種・シリアル列を省略」＝8列と書いている。★落ちている4列のデータはAPIに全部入っている★ |
| 4 | サイドバーの未対応件数バッジが無い | ★判断が要る★ | モックにはあるが `docs/spec.md:140` は要求していない。件数は取れるが、共通レイアウトに初めてデータ取得を持ち込むことになる |
| 5 | D-Secアラート「通信断」の色が赤→アンバー | ★判断が要る★ | モックの赤は「トークン期限だけを橙にする」分岐の裏返し。その種別が D-030 で消えた今、単純に戻すのが正しいとは限らない |
| 6 | コンパクト表で行展開アドバイスが無効 | ★判断が要る★ | 実装が根拠にしている「規約」は★どの資料にも存在しない★（grep 0件）。一方 `docs/spec.md` の F-01 にも行展開は載っていない。資料同士が食い違う |
| 7 | D-Secアラートの期間フィルタが無い | ★判断が要る★ | モックの日付欄は★飾り★（`onChange` なし）。足すには先に `d-watch-api.yaml` を直す必要がある（新規パラメータ2つ） |
| 8 | アラート画面のバッテリー残量行 | ★意図した仕様★ | ★記録あり★。D-105 項5 が「画面の残量表示の経路を残す」と明記。第3章の「記録なし」は誤り |

**内訳: 不具合 3件 / 意図した仕様 1件 / 判断が要る 4件**

---

## 2. #1 —「未対応」の対訳キーが衝突している

### 【現状】

`lib/i18n.ts` は★キーが日本語原文★の1階層の辞書です（`lib/i18n.ts:363-366` の `translate()`
は完全一致でしか引かない）。そのため★同じ日本語を別の意味で使うと必ず衝突します★。

```ts
// lib/i18n.ts:159-160
// 対応機種レジストリ（lib/config/index.ts の ROBOT_MODELS）に無い機種のバッジ（指示書N）
未対応: "Unsupported",
```

`t("未対応")` の呼び出しは★3箇所★（実測）:

| 場所 | 意味 | EN表示 | 正しい英語 |
|---|---|---|---|
| `components/features/ds-alerts/DsAlertsScreen.tsx:141` | 数値カード「未対応」＝★未処理のアラート件数★ | `Unsupported` | `Open` |
| `components/features/ds-alerts/DsAlertsScreen.tsx:289` | ステータスバッジ「未対応」＝★未処理★ | `Unsupported` | `Open` |
| `components/features/facilities/FacilitiesScreen.tsx:180` | 機種バッジ「未対応」＝★サポート外の機種★ | `Unsupported` | `Unsupported`（正しい） |

**実害**: EN表示で、D-Secアラートの「未処理の警報が3件」が「非対応が3件」に化けます。
★状態の意味が逆どころか別カテゴリになる★ので、英語で運用する担当者は件数の意味を取り違えます。

### 【モック】

`d-watch-mock.jsx` は自前の辞書（`:129-147`）を持ちます。★モック側に `未対応` の対訳エントリはありません★
（`grep -n '"未対応"' d-watch-mock.jsx` → 辞書行にヒットなし。`:189` / `:901` の状態文字列のみ）。
つまり★モックでは EN でも「未対応」と日本語のまま出ており、誤訳は実装側で新たに生まれた★ものです。

### 【記録の有無】 — ★衝突を認めた記録は無い★

```
$ grep -n "Unsupported" docs/decisions.md
11216:例: ★「未対応」の対訳キー衝突で英語表示が `Unsupported`（非対応）になる★ /
```

唯一のヒットは D-142（2026-09-16）が★本件を「これから振り分ける宿題」として引用している箇所★で、
決定ではありません。

代わりに、衝突が★見落とされた瞬間★の記録があります（D-087 = 指示書N の検証節）:

```
docs/decisions.md:3084
  および`t("未対応")`が`lib/i18n.ts`に登録済みであることをコードレビューで確認したのみ
```

`git blame` で時系列が確定します:

| コミット | 日付 | 内容 |
|---|---|---|
| `d59fecb` | 2026-09-02 | `DsAlertsScreen.tsx:141` / `:289` が `t("未対応")` を使い始める（当時は辞書に無く EN でも和文＝実害なし） |
| `7a68a4d` | 2026-09-09 | 指示書N が `lib/i18n.ts:160` に `未対応: "Unsupported"` を追加 → ★7日前からあった別画面を巻き込んだ★ |

D-087 の検証文は「登録済みであることを確認した」＝★自分が足したキーを確認しただけ★で、
★他画面が同じキーを使っていないかは見ていません★。

### 【仕様書】

`docs/spec.md` / UI仕様書に対訳の規定はありません。`d-watch-api.yaml` にも該当なし。

### 【判定】 ★不具合★

- 意図した記録が無い（上記のとおり、見落としの記録しか無い）
- 実害がある（EN表示で状態の意味が変わる）
- `CLAUDE.md` §9.6「JP/EN切替の器を壊さない」に反する

### 【直す場合の影響範囲】

★キーを日本語原文にしたまま2つの意味を区別することは、いまの `translate()` では不可能★です。
どちらかの呼び出し側を変える必要があります。推奨は★D-Secアラート側の文言を変えない方針★
（モックの文言は「未対応」で、`CLAUDE.md` §5 でモックが文言の正）なので、
★機種バッジ側のキーを変える★のが副作用が小さいです。

| 触るファイル | 変更 |
|---|---|
| `lib/i18n.ts:159-160` | `未対応` を削除し、`"未対応（機種）": "Unsupported"` 等の★一意なキー★に置き換え。さらに `未対応: "Open"` を D-Secアラート用に登録 |
| `components/features/facilities/FacilitiesScreen.tsx:180` | `t("未対応")` → `t("未対応（機種）")`。★`Pill` に渡すのは `t()` の戻り値なので、日本語表示が「未対応（機種）」に変わってしまう★ → ★方式A（`t("...").replace()`）ではなく、表示用の日本語を別に持つ必要がある★（§10 の質問Q1） |
| `components/features/ds-alerts/DsAlertsScreen.tsx:141,289` | 変更不要（キーはそのまま、対訳が `Open` になる） |

- **既存テストへの影響**: `lib/i18n.ts` を直接検証するテストは★0件★
  （`grep -l "i18n\|translate" **/*.test.ts` → `lib/prechecks/__tests__/label.test.ts` と
  `lib/db/__tests__/report-mapping.test.ts` のみで、どちらも `未対応` を扱わない）。
  `lib/facilities/__tests__/query.test.ts:677-694` は `isSupportedModel()` の判定だけを見ており★文言に依存しない★
- **i18n 両言語**: JA は現状維持が必須（モック準拠）。EN は2語に分かれる
- **ダーク/ライト**: 影響なし（色は `c.wn` / `THEME_TOKENS` 由来で文言と独立）

---

## 3. #2 — ダッシュボードの「判定 ?」ボタンが押しても何も起きない

### 【現状】

ボタンは★`compact` で隠されていません★（`CleanLogTable.tsx:110-120`）:

```tsx
<th className={styles.th} style={{ textAlign: "center" }}>
  {t("判定")}{" "}
  <button type="button" className={styles.helpBtn} onClick={onToggleGradeInfo} aria-label="判定基準">
    ?
  </button>
</th>
```

一方ダッシュボードは★空の関数と `false` を渡しています★（`DashboardScreen.tsx:152-162`）:

```tsx
<CleanLogTable
  rows={logs}
  compact
  ...
  showGradeInfo={false}
  onToggleGradeInfo={() => {}}
  onToggleRow={() => {}}
  onOpenAreas={() => {}}
/>
```

凡例本体は `CleanLogTable.tsx:123-152` にあり `showGradeInfo` でしか開きません。
★つまり「押しても何も起きない」のは仕様上の制約ではなく、状態を持たせていないだけ★です。

### 【モック】

`d-watch-mock.jsx:301` の `?` は★トップレベルの `showGradeInfo`（`:171`）★を切り替えます。
`LogTable` は `compact` の有無で分岐しないので、★ダッシュボード（`:508`）でも詳細ログ（`:573`）でも同じように開きます★。

### 【記録の有無】 — ★無い★

```
$ grep -n "showGradeInfo\|凡例" docs/decisions.md
10864:- 画面の凡例（`CleanLogTable.tsx` / `SystemScreen.tsx`）が「◎90%超」「○70%超」のままだった
```

唯一のヒットは D-139 項8（文言を「超」→「以上」に直した話）で、★ボタンの有効/無効には触れていません★。
`docs/spec.md` にも記述なし。

### 【D-053 との整合 — 質問に対する回答】

D-053（`docs/decisions.md:333-337`）の本文:

> - **決定**: グループ・会社の絞り込み `<select>` は、マスタが揃うまで画面から削除する
> - **理由**: 固定の選択肢だけがあって何も起きないUIは、不具合と区別できないため

D-053 が「消す」を選んだのは★機能させるためのデータ（マスタ）が存在しなかったから★です。
本件は★データも凡例本体も既にあり、必要なのは `useState` 1つ★なので、前提が違います。

同じ趣旨がもう1箇所、`lib/i18n.ts:320-321` に明文化されています:

> ★★`disabled` だけにして理由を出さないことはしない★★ —
> 押せないボタンは、理由が書いていないと不具合と区別がつかない（D-053 と同じ理由）

**したがって D-053 と整合するのは★「機能させる」★です。**
「消す」も D-053 の文言だけ見れば整合しますが、`CLAUDE.md` §5（モックが画面レイアウト・
文言・遷移の正）に反します。モックには `?` があり、押すと開きます。

### 【判定】 ★不具合★（直し方は「機能させる」）

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `components/features/dashboard/DashboardScreen.tsx` | `const [showGradeInfo, setShowGradeInfo] = useState(false)` を足し、`:158-159` の `false` / `() => {}` を差し替える（★実質2行★） |
| `components/features/detail-log/CleanLogTable.tsx` | 変更不要 |

- **既存テストへの影響**: なし（画面のテストは存在しない）
- **★i18n の落とし穴★**: 凡例の文言は★`t()` を通していません★
  （`CleanLogTable.tsx:126` `判定基準（タスク完了率）:` / `:142` `（閾値はシステム設定で変更可能）`）。
  ★開けるようにすると、EN表示で和文の塊が新たに1つ増えます★。
  同じ凡例が詳細ログでも開くので★これは既存の抜けであって本件が作る問題ではありません★が、
  直すなら同じコミットで対訳を足すのが自然です（辞書に足すのは2キー）
- **ダーク/ライト**: 凡例は `CleanLogTable.module.css` の `.legend*` を使い、色は CSS 変数。追加作業なし

---

## 4. #3 — ダッシュボードの清掃ログ表が4列

### 【現状】

`CleanLogTable.tsx:74-106` が `!compact &&` で★6列を落としています★:

| 列 | compact |
|---|---|
| 施設名 | 出す |
| 機種 | ★落とす★ |
| シリアル | ★落とす★ |
| 日付 | ★落とす★ |
| 予定 | 出す |
| 1h前ST | ★落とす★ |
| 30分前ST | ★落とす★ |
| 出発 | ★落とす★ |
| 完了率 | 出す |
| 判定 | 出す |

`CleanLogTable.tsx:24` の docstring も「4列表示にする（施設名/予定時刻/完了率/判定のみ）」と
自認しています。

### 【データはあるのか — ★実測した★】

★あります。表示していないだけです。★

ダッシュボードは★詳細ログとまったく同じ API・同じ型★を使っています:

- `DashboardScreen.tsx:38-46` — `apiFetch<ListResponse<CleanLogItem>>("/api/clean-logs?result=problem&date_from=…&per_page=5")`
- 型は `lib/types/index.ts:202` の `CleanLogItem`。落ちている列に対応するフィールドが★全部入っています★:

| 落ちている列 | `CleanLogItem` のフィールド | 定義位置 |
|---|---|---|
| 日付 | `scheduled_at`（ISO8601 +09:00） | `lib/types/index.ts:209` |
| 1h前ST | `status_1h` | `lib/types/index.ts:216` |
| 30分前ST | `status_30m` | `lib/types/index.ts:217` |
| 出発 | `departed` | `lib/types/index.ts:223` |
| （機種） | `model_name` | `lib/types/index.ts:206` |
| （シリアル） | `serial_number` | `lib/types/index.ts:207` |

`app/api/dashboard/route.ts` は関係ありません（コンパクト版ログは `GET /dashboard` に含まれない
契約です。`d-watch-api.yaml:219` / `docs/spec.md:36`）。★APIを1本も変えずに列を戻せます。★

### 【モック】

`d-watch-mock.jsx:285-303` の `LogTable` は★`compact` で `機種`（`:290`）と `シリアル`（`:291`）の
2列だけ★を落とします。`:508` がダッシュボードで `compact={true}`。→ ★8列★。

### 【仕様書】 ★ここが決定的★

```
docs/spec.md:32
- 清掃詳細ログ（コンパクト版。機種・シリアル列を省略）
```

`CLAUDE.md` §5 で `docs/spec.md` は★機能一覧の正★です。モックと spec.md が★一致して8列★と
言っており、実装だけが4列です。

### 【記録の有無】 — ★無い★

```
$ grep -n "コンパクト版" docs/decisions.md docs/spec.md d-watch-api.yaml
docs/decisions.md:10191  （D-137。「コンパクト版ログを二重に作るな」という API 契約の話）
docs/spec.md:32          （8列＝機種・シリアルのみ省略）
docs/spec.md:36          （API再利用の話）
d-watch-api.yaml:219     （API契約の話）
d-watch-api.yaml:313     （D-137 が上に抵触しない旨）
```

★列数を減らした決定は1件もありません。★
`git blame` では `47f2df4`（2026-08-30「F-01 ダッシュボード画面を実装」）の初回実装から4列で、
docstring の理由（「ダッシュボードではアドバイスを一切出さない規約のため」）は★#6 と同じ
出所不明の「規約」★です（§7 参照）。

### 【判定】 ★不具合★

モックと `docs/spec.md` が一致し、記録が無く、データは揃っている。3条件そろっています。

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `components/features/detail-log/CleanLogTable.tsx` | `!compact &&` を★日付・1h前ST・30分前ST・出発の4列から外す★（機種・シリアルは落としたまま）。`colSpan={compact ? 4 : 10}`（`:156` / `:205`）を★`compact ? 8 : 10` に直す★ — ★これを忘れると空表示の行が詰まる★ |

- **レイアウト**: `CleanLogTable.module.css:1-5` が `.table { min-width: 1000px }`、
  `DashboardScreen.module.css:75-77` が `.tableWrap { overflow-x: auto }`。
  ★横スクロールで収まるので CSS 変更は不要★（モックも `minWidth: compact ? 700 : 1000` で同じ考え方）
- **既存テストへの影響**: なし（画面のテストは無い）
- **i18n 両言語**: 追加する4列のうち `日付`（`lib/i18n.ts:27`）・`予定`（`:28`）・`出発`（`:29`）は
  ★対訳済み★。`1h前ST` / `30分前ST` は★モックも実装も `t()` を通していない生文字列★
  （`CleanLogTable.tsx:94` / `:99`）＝ EN でも和文。★詳細ログでも同じなので本件では変えない★
- **★ダーク/ライトと D-077 の副作用★**: `1h前ST` / `30分前ST` は `Pill` + `statusColor()`。
  D-077（生値表示）により実DBでは英語識別子が入り、`lib/theme-status.ts:26-30` の仕様どおり
  ★全部グレーにフォールバック★します。★ダッシュボードにグレーのPillが2列並ぶ★のは
  「意図した挙動」（`CLAUDE.md` §4.8）ですが、見え方が変わるので §10 の質問Q3に出しました

---

## 5. #4 — サイドバーの未対応件数バッジが丸ごと無い

### 【現状】

`components/layout/AppShell.tsx` に★バッジの受け口自体がありません★:

- メニュー定義 `:8-34` は `{ href, id, label }` の3キーのみ（`badge` に相当するものが無い）
- `NavItem`（`:36-53`）は `href` / `label` / `active` だけを受け取る
- `AppShell` は★1本もデータ取得をしていません★（`useTheme()` と `usePathname()` のみ）

### 【モック】

```
d-watch-mock.jsx:188  const unresPre = PRECHK.filter(function (a) { return !a.ok; }).length;
d-watch-mock.jsx:189  const unresDsa = dsaState.filter(function (a) { return a.st === "未対応" || a.st === "対応中"; }).length;
d-watch-mock.jsx:372  { id: "alert", label: t("🔔 アラート"), badge: unresPre },
d-watch-mock.jsx:378  { id: "dsalert", label: t("⚠ D-Secアラート"), badge: unresDsa },
d-watch-mock.jsx:391  {props.badge > 0 && <span style={{ ... background: c.ng, ... }}>{props.badge}</span>}
```

赤いバッジが2箇所（アラート／D-Secアラート）。0件のときは出しません。

### 【件数は取れるのか — ★取れる★】

| バッジ | 取得元 | 根拠 |
|---|---|---|
| アラート | `GET /prechecks` の `summary.unresolved`（未解消＋対応中） | `d-watch-api.yaml:1754-1757`、D-054（`docs/decisions.md:339`） |
| D-Secアラート | `GET /ds-alerts` の `summary.pending + summary.in_progress` | `app/api/ds-alerts/route.ts:69`、`DsAlertsScreen.tsx:141-142` |

★モックの `unresDsa`（未対応+対応中）とちょうど同じ定義★です。値の意味合わせは不要。

### 【記録の有無】 — ★無い★

```
$ grep -n "未対応件数\|件数バッジ" docs/decisions.md
（0件）
$ grep -n "サイドバー" docs/decisions.md
10367, 10374, 10488, 10506, 10519, 10522, 10566, 10591   ← すべて D-137 の「スクロール」の話
```

### 【仕様書】

```
docs/spec.md:140
- [ ] 共通レイアウト（サイドバー10画面ナビ、ダーク/ライト、JP/EN切替の器）
```

★バッジは要求されていません★。モックにはあるが spec.md には無い、という状態です。

### 【判定】 ★判断が要る★

- 「モックが正」（`CLAUDE.md` §5）に従えば足すべき
- `docs/spec.md` は要求していない
- ★足すと共通レイアウトに初めてデータ取得が入る★ — これは見た目の差分ではなく★設計上の新要素★です

★実装コストの実態★（これがユーザー判断の材料）:

1. `AppShell` は `app/(dashboard)/layout.tsx` 配下の★全10画面で常に描画される★
2. バッジを出すには★全画面で2本の API を叩く★ことになる（`/prechecks` と `/ds-alerts`）
3. ★件数だけ返す軽いエンドポイントは `d-watch-api.yaml` に存在しない★ →
   既存2本を `per_page=1` で叩いて `summary` だけ使う（`items` は捨てる）か、
   契約に `GET /badges` のような1本を足すか
4. ★更新のタイミングが未定義★ — 画面遷移のたびに取り直すのか、一定間隔で更新するのか。
   モックはローカル state なので参考にならない
5. ★D-142 の「対応状況の更新（PATCH）は更新用アカウント未発行のため未実装」★との関係:
   件数は★誰も操作できないので減りません★。「未対応 27」が固定表示され続けます

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `components/layout/AppShell.tsx` | メニュー定義に `badge` を足し、`NavItem` に受け口を足し、`useEffect` で2本フェッチ |
| `components/layout/AppShell.module.css` | `.navBadge` を追加（モック `:391` 相当。`background: var(--ng)`） |
| `d-watch-api.yaml` | ★1本足す案を採る場合のみ★（`CLAUDE.md` §6-1: 先にYAMLを直す） |
| `lib/i18n.ts` | 不要（数字だけ） |

- **既存テストへの影響**: なし
- **ダーク/ライト**: `var(--ng)` を使えば両対応（`lib/theme.ts:16` dark `#ef4444` / `:35` light `#dc2626`）

---

## 6. #5 — D-Secアラート「通信断」の色が赤→アンバー

### 【現状】

```ts
// components/features/ds-alerts/DsAlertsScreen.tsx:36-38
function typeColor(c: ThemeTokens, type: DsAlertType): string {
  return type === "disconnected" ? c.wn : c.ng;
}
```

`c.wn` はアンバー（`lib/theme.ts:14` dark `#f59e0b` / `:33` light `#d97706`）。
この色は★Pill（`:264`）とカード左端の帯（`:259` `borderLeftColor`）の2箇所★で使われます。

### 【モック】

```js
// d-watch-mock.jsx:946
var tpCol = a.type === "トークン期限" ? c.wn : c.ng;
```

★モックでアンバーだったのは「トークン期限」だけ★で、「通信断」と「セキュリティ無効」は
どちらも `c.ng`（赤）でした。

つまり実装は、★D-030 で消えた「トークン期限」の色を、残った「通信断」に付け替えた★形です。
意図的な付け替えなのか、条件式を機械的に書き換えた結果なのかは★コミットからは読み取れません★
（`d59fecb` 2026-09-02「feat: F-07 D-Secアラート一覧を実装 (D-050)」の初回実装から現在の形）。

### 【記録の有無】 — ★無い★

```
$ grep -n "バッジの色" docs/decisions.md
146:  （アドバイスの行バッジの色。無関係）
237:  （判定バッジの色分け。無関係）
$ grep -n "通信断" docs/decisions.md
351, 497, 498, 505, 1138, 1168, 1170, 1778, 1795, 1925, 9720, 9721, 9875
  → すべて「2状態化」「判定ロジック」「ソート順」の話。★色に触れた行は1つも無い★
```

### 【★この色が効いてくる事情★】

`lib/db/index.ts:1533` の `dsAlerts()` は★`alert_type` に常に `"disconnected"` を入れます★
（`:1520-1531` の docstring: `security_off` に対応するカラムが DB に無い。D-090 項3-9）。

★帰結: 実DB接続時、この画面のカードは★★全部アンバー★★になり、赤は1件も出ません。★
「セキュリティ無効（＝赤＝重大）」という対比が画面から消えているため、
★色で重要度を判断する運用が成立していません★。

### 【判定】 ★判断が要る★

- 記録が無い＝★不具合の条件の1つは満たす★
- しかし「モックの赤に戻す」ことが正しいとは限らない:
  - モックの赤は「トークン期限だけを橙にする」ための消極的な色分けで、
    ★「通信断は重大」という積極的な意味づけの記録はどこにも無い★
  - 一方 `docs/decisions.md:497-498`（D-065）は★「異常＝通信断は同じもの」★と確定しており、
    D-Secログ画面では★異常＝`ng`（赤）★で描かれています（`DsLogScreen.tsx:308` の `tone="ng"`）。
    ★同じ事象が2画面で違う色★になっているのは、どちらかに揃えるべき論点です

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `components/features/ds-alerts/DsAlertsScreen.tsx:36-38` | 1行（`c.wn` → `c.ng`、または `typeColor()` ごと削除して常に `c.ng`） |

- **既存テストへの影響**: なし（`lib/ds-alerts/__tests__/query.test.ts` は絞り込み・ソートのみ検証）
- **i18n**: 影響なし
- **ダーク/ライト**: `THEME_TOKENS` 経由なので両対応のまま
- ★どちらを選んでも `docs/decisions.md` に記録を残すこと★（次に突き合わせた人が同じ問いを立てるため）

---

## 7. #6 — コンパクト表で行展開アドバイスが無効

### 【現状】

```tsx
// components/features/detail-log/CleanLogTable.tsx:162
const hasAdvice = !compact && (r.grade === "△" || r.grade === "×");
```

`hasAdvice` が false なので、行の `onClick`（`:171`）も `▼` の表示（`:197-199`）も出ません。
ダッシュボード側は `onToggleRow={() => {}}` / `expandedId={null}` / `adviceById={{}}` を
渡しています（`DashboardScreen.tsx:155-161`）。

根拠として docstring（`CleanLogTable.tsx:25`）にこう書かれています:

> ダッシュボードではアドバイスを一切出さない規約のため、compact 時は行クリック・アドバイス展開も無効化する。

### 【★この「規約」は存在しない★】

```
$ grep -n "アドバイスを一切\|ダッシュボードではアドバイス" docs/decisions.md docs/spec.md docs/handoff.md docs/変更点まとめ_20260914.md
（0件）
$ grep -n "行展開" docs/decisions.md
7973:（★ダーク/ライトの見た目・JP/EN の切替・CSVの中身・行展開・備考編集★）
   → D-120 の「目視確認が要る項目」の列挙。方針ではない
```

`git blame` によれば docstring は `47f2df4`（2026-08-30、F-01 初回実装）で書かれたもので、
★実装者の自己申告であり、どの資料にも裏付けがありません★。

### 【モック】

`d-watch-mock.jsx:311`（`LogTable` 内）:

```js
var hasAdvice = r.g === "△" || r.g === "×";
```

★`compact` で分岐していません★。展開行の `colSpan` にだけ `compact ? 8 : 10` が入っており
（`:331`）、★compact でも展開する前提で書かれています★。

### 【仕様書】

```
docs/spec.md:29-36   F-01 ダッシュボード
  - 清掃詳細ログ（コンパクト版。機種・シリアル列を省略）   ← 行展開の記述なし
docs/spec.md:43-52   F-02 清掃詳細ログ
  - **行展開アドバイス（Phase A）**: △×行クリックで R1〜R4 の推定原因とアクションを表示
```

★行展開は F-02 の機能として書かれており、F-01 の箇条書きには出てきません。★
ただしこれは「F-01 では禁止」と書いてあるわけではなく、★ブロックの列挙に含まれていない★だけです。

### 【判定】 ★判断が要る★

- ★モック（レイアウト・遷移の正）は「展開できる」★
- ★`docs/spec.md`（機能一覧の正）の F-01 には載っていない★
- 実装が挙げた根拠（「規約」）は★存在しない★

資料が正面から食い違うので、`CLAUDE.md` §5 の最後の指示「それでも解決しない場合は
★実装を止めて確認を求める★」に該当します。

★運用上の意味★: ダッシュボードは「昨夜の結果を10分で把握」する画面（`docs/spec.md:12`）で、
表示されるのは★当日の △× 上位5件のみ★（`DashboardScreen.tsx:38-43` の `result=problem` /
`per_page=5`）。★問題行しか出ない表で理由が見られない★のは導線として不自然、というのが
「直す」側の論拠です。「直さない」側の論拠は「ダッシュボードは要約に徹し、
理由は『全項目 →』で F-02 に飛ぶ」という切り分け（`DashboardScreen.tsx:36-37` のコメント）。

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `components/features/detail-log/CleanLogTable.tsx:162` | `!compact &&` を外す |
| `components/features/dashboard/DashboardScreen.tsx` | `expandedId` / `adviceById` / `adviceLoadingId` の state と、`GET /api/clean-logs/{id}/advice` の取得を足す（★`DetailLogScreen.tsx` の実装をそのまま移植できる★） |

- ★`colSpan` を `compact ? 4 : 10` から直すこと★（`:205`）。#3 を先に直すなら `compact ? 8 : 10`
- **既存テストへの影響**: なし。`app/api/clean-logs/[id]/__tests__/route.test.ts` は既にあり、
  ★APIは変更不要★
- **i18n**: 展開部の見出し（`CleanLogTable.tsx:37-51` の「🔴 レベル3 — DFA介入を検討」等）は
  ★`t()` を通していない★ため EN で和文。詳細ログでも同じ既存の抜け
- **★アドバイス0件時の分岐★**: `:210-214` に「該当するアドバイスはありません」があり、
  ダッシュボードでもこの経路が出ます

---

## 8. #7 — D-Secアラートの期間フィルタが無い

### 【現状】

`DsAlertsScreen.tsx:86-97` が組み立てるクエリは★日付を含みません★:

```
type / status / group_id・customer_id（分類） / per_page / page
```

サーバ側 `lib/ds-alerts/query.ts:46-82` の `parseDsAlertQuery()` も `date_from` / `date_to` を
★読みません★（`TYPE_FILTERS` / `STATUS_FILTERS` / `parseMasterIdFilters` / `page` / `per_page` のみ）。

### 【モック】

`d-watch-mock.jsx:916-921` に日付入力が2つあります。ただし★飾りです★:

```jsx
<input type="date" defaultValue="2026-03-20" ... />   // :918 — onChange なし
<span>〜</span>
<input type="date" defaultValue="2026-03-27" ... />   // :920 — onChange なし
```

★絞り込みロジック（`:937-945`）は日付を一切参照していません。★
第3章の「期間の絞り込みが無い」は正しい指摘ですが、★モック側も動いてはいなかった★点は
記録しておく価値があります（`docs/UI差分まとめ_20260915.md:138` は「あり」としか書いていません）。

### 【記録の有無】 — ★無い★

```
$ grep -n "D-Secアラート.*期間\|ds-alerts.*date\|期間の絞り込み\|期間フィルタ" docs/decisions.md
（0件）
```

### 【API契約】 ★足りない★

`d-watch-api.yaml:1131-1149`（`/ds-alerts` の parameters）:

```
GroupId / CustomerId / type / status / Page / PerPage
```

★`date_from` / `date_to` がありません。★
`CLAUDE.md` §6-1「API契約を変えたくなったら、先に `d-watch-api.yaml` を直す」に従い、
★実装より先に YAML を直す必要があります★（＝ 1行の修正では済まない）。

比較: `GET /prechecks` は `date_from` / `date_to` を持ち、フィルタの前例もあります
（`lib/prechecks/query.ts:65-69` の検証、`:119-127` の `filterPrechecksByDate()`）。
★同じ形をそのまま写せます。★

### 【実装方式】 — ★SQLに降ろさなくてよい★

`docs/decisions.md:9550-9560`（D-132 項7）が★実測で結論を出しています★:

> ★結論: `/facilities` `/schedules` `/ds-devices` `/ds-alerts` は降ろす価値がない。★
> `/ds-alerts` | ★20行★

`app/api/ds-alerts/route.ts:64-74` と同じくメモリ内で絞る形で足せます。
（`lib/db/index.ts:1533` の `dsAlerts()` は毎回全件読みですが、★D-132 で「そのままでよい」と
判断済み★なので本件の論点ではありません）

### 【判定】 ★判断が要る★

- 記録は無い
- が、モックの当該UIは★動いていなかった飾り★であり、「モック準拠で戻す」という単純な話ではない
- API契約の変更を伴う＝★新規の作業★であって「戻す」ではない
- ★実害の程度が論点★: 並び順は `detected_at` 降順固定（`lib/ds-alerts/query.ts:110-117`）＋
  ページ送りがあるので、直近のものは1ページ目に出ます。一方で★対応状況の更新（PATCH）が
  未実装（更新用アカウント未発行）★なので、★`status=open` の既定表示に古いアラートが
  永遠に溜まり続けます★ — ここが「期間で絞りたい」の実需です

### 【直す場合の影響範囲】

| 触るファイル | 変更 |
|---|---|
| `d-watch-api.yaml`（`:1131` 付近） | `date_from` / `date_to` を parameters に追加（`/prechecks` の定義をコピー） |
| `lib/ds-alerts/query.ts` | `DsAlertQuery` に `dateFrom` / `dateTo`、検証（422）、`filterDsAlertsByDate()` を追加 |
| `app/api/ds-alerts/route.ts:70-73` | 日付フィルタを type/status と同じ層に差し込む。★`summary` より後（分類より後）★に置くこと — ★summary の母集団を変えるかどうかが設計判断★（§10 の質問Q5） |
| `components/features/ds-alerts/DsAlertsScreen.tsx` | 日付入力2つ。★既定値は空＝全期間★（`AlertsScreen` と揃える。`docs/UI差分まとめ_20260915.md:87`）。★変更時に `setPage(1)`★（D-120 の規則） |
| `lib/ds-alerts/__tests__/query.test.ts` | ★テスト追加が要る★（`filterPrechecksByDate` のテストが手本） |
| `lib/i18n.ts` | `開始日` / `終了日` は★既存★（`:347-348`）。追加不要 |

- **既存テストへの影響**: `lib/ds-alerts/__tests__/query.test.ts` は既存分が★壊れません★
  （既定値が「絞らない」なので）
- **ダーク/ライト**: 日付入力の CSS は `AlertsScreen.module.css` の `.dateGroup` を写す

---

## 9. #8 — アラート画面のバッテリー残量行

### 【現状】

```tsx
// components/features/alerts/AlertsScreen.tsx:285-290
{item.battery_level !== null && (
  <div className={styles.batteryLine}>
    {t("残量")} {item.battery_level}%
  </div>
)}
```

★`null` ガードがあるので、実DBでは1件も描画されません★（DOMにも出ません）。
`USE_FIXTURES=true` のときだけ表示されます。

### 【モック】

★モックにこの行はありません★（`d-watch-mock.jsx` の PRECHK カードに残量の表示なし）。
第3章の分類どおり「モックに無いが追加した」項目です。

### 【記録の有無】 — ★★ある★★（第3章・第4章の「記録なし」は誤り）

★記録は2件、どちらも明示的です。★

**(1) D-105 項5（`docs/decisions.md:5596-5604`）** — 「なぜ `null` にしたか」と★「なぜ画面の行は残すか」★:

```
docs/decisions.md:5596  #### 5. ★★`battery_level` は常に `null`（D-090 項8 の解決）★★
docs/decisions.md:5597  - ★★実DB経由では全件 `null`★★（実測。27件すべて `null`）
docs/decisions.md:5599  - ★理由★: `robots.battery` は現在値のみで履歴が無いため…
docs/decisions.md:5602  - ★fixtures には値が入ったまま★（画面の残量表示の経路を残すため）。
docs/decisions.md:5603    ★`USE_FIXTURES` の true / false で差が出るのは**想定内**★
```

**(2) D-114（`docs/decisions.md:7138`）** — TeamWorks 第8回の回答で★恒久化★:

```
docs/decisions.md:7138  - ★A9-1: バッテリー残量の履歴は残さない★ → ★★`battery_level` は恒久的に `null` で確定★★
```

### 【「行ごと消す」か「空欄のまま残す」か — ★決定の文面から読み取れる答え★】

★★残す★★です。根拠は D-105 項5 の一文:

> ★fixtures には値が入ったまま★（★**画面の残量表示の経路を残すため**★）

★「経路を残す」と明示的に書かれている★ので、行を消すことは決定の意図に反します。
補強材料:

- `CLAUDE.md` §9.5 — ★「fixtures はDB接続後も削除しない（テスト・デモ用）」★
- D-105 項5 — ★「`USE_FIXTURES` の true / false で差が出るのは**想定内**」★
- D-105 項5 末尾 — ★「事前チェック時点の残量を取るには TeamWorks 側のスキーマ変更が要る」★＝
  ★将来復活しうる★。消すと、そのときに画面を書き直すことになる
- `d-watch-api.yaml` の `PrecheckItem` にも `battery_level` を★意図的に足してある★（D-105 項5）

### 【判定】 ★意図した仕様★

★ただし `docs/UI差分まとめ_20260915.md:89` / `:244` の「★記録なし★」は事実に反します。★
この2行の訂正が必要です（本文書に基づき「D-105 項5 / D-114」と書き換える）。

### 【影響範囲】

★コード変更は不要★。文書のみ:

| 触るファイル | 変更 |
|---|---|
| `docs/UI差分まとめ_20260915.md:89` | 根拠欄を「★記録なし★」→「D-105 項5（経路を残すと明記）／D-114（`null` で恒久確定）」 |
| `docs/UI差分まとめ_20260915.md:244` | 第4章の行を削除（記録が存在するため） |

---

## 10. ★調査中に見つかった、第3章に載っていない問題★

### 追加1 — ★英語表示の抜けは第2章の記載より広い（★実測37キー★）★

第2章（`docs/UI差分まとめ_20260915.md:196-203`）は EN の抜けを
「D-Secログ／D-Secアラート／読み込み中／ログイン画面」と書いていますが、
★`components/**` の `t()` 呼び出しを全部拾って辞書と突き合わせた★ところ、
★ダッシュボードとアラート画面にも抜けがあります★（第2章に記載なし）:

| 画面 | 辞書に無いキー | 位置 |
|---|---|---|
| ★ダッシュボード★ | `成功` / `失敗` / `未実施` / `成功率` / `予定時刻経過・実績なし` / `全項目 →` | `DashboardScreen.tsx:101,107,113,114,122,148` |
| ★アラート（F-03）★ | `未解消` / `解消済み` / `合計` / `要対応` / `対応完了` / `全アラート` / `未解消のみ` / `解消` / `対応中` / `スケジュール開始前のエラー検知と出発失敗` / `該当するアラートはありません` | `AlertsScreen.tsx:138,142,143,144,231,251,260,298,303,308` |

★ダッシュボードは「ログイン後の最初の画面」（`docs/spec.md:12`）★なので、
EN に切り替えると★最初に見る4枚の数値カードが全部和文★になります。

### 追加2 — ★#1 と同じ衝突が、次に対訳を足したときに起きるキーが1つある★

`要対応` が★意味の違う2箇所★で使われています（どちらも現在は辞書に無く和文のまま）:

| 位置 | 意味 |
|---|---|
| `components/features/alerts/AlertsScreen.tsx:142` | 未解消アラートのカードの補助文（★人が対応すべき件数★） |
| `components/features/ds-logs/DsLogScreen.tsx:308` | 異常デバイスのカードの補助文（★機器が異常★） |

★追加1 を直すときに `要対応: "Action Required"` のように素直に足すと、#1 とまったく同じ構造で
2画面を巻き込みます。★ 先に方針（§11 段階1）を決めてから足すこと。

なお `注意` は `ReportsScreen.tsx:394`（施設ステータス）と `SystemScreen.tsx:67,446`
（アドバイスのレベル1）の2系統で共用されています。今は両方 `"Caution"` で成立していますが、
★同じ構造のリスクを抱えています★。

### 追加3 — ★未使用のまま残っている危険な1文字キーが4つ★

`lib/i18n.ts:126-129`:

```ts
他: "View ",
"件を表示 →": " more →",
全: "View all ",
"施設を表示 →": " facilities →",
```

★4つとも使用箇所0件★（実測。`grep -rn 't("他")' components/ app/ lib/` 等はいずれも
`lib/i18n.ts:120` のコメント行しかヒットしない）。`lib/i18n.ts:122-123` が
★自分で警告しています★:

> ★注意★ `他` / `全` のような1文字キーは他画面の文言と衝突しやすい

★`全` は特に危険★で、誰かが `t("全")` と書いた瞬間に EN で `View all ` になります。
`lib/i18n.ts:111-112` に「使わなかった方は画面実装が固まった時点で削除してよい」とあり、
★方式A（`全{n}施設を表示 →`）が確定しているので削除条件は満たしています★。

### 追加4 — ★孤児になった対訳キー `D-Sec ログ`★

`lib/i18n.ts:36` の `"D-Sec ログ": "D-Sec Logs"` は★使用箇所0件★。
h1 が「D-Secログ」（半角スペースなし。`DsLogScreen.tsx:301`）に変わったためです。
第1章 1-6（`docs/UI差分まとめ_20260915.md:121`）が「副作用で英語表示の対訳が当たらない」と
書いているのと同じ事象ですが、★辞書側にも死んだキーが残っている★点は未記載でした。

---

## 11. ★ユーザーに聞くべきこと（実例つき）★

### Q1 — #1 の直し方: 日本語表示はどちらも「未対応」のままにするか

`translate()` はキー＝日本語原文なので、2つの意味を区別するには★片方のキーを変える★しかありません。
キーを変えると★日本語表示もそのキーの文字列になります★（`Pill text={t(...)}` に渡すため）。

| 案 | JA表示（施設マスタの機種バッジ） | JA表示（D-Secアラート） | EN | 備考 |
|---|---|---|---|---|
| ★案A★ | 「未対応」のまま | 「未対応」のまま | 機種=`Unsupported` / アラート=`Open` | ★`translate()` に「画面ID」等の第2キーを足す必要がある★（i18n の仕組みを変える） |
| 案B | ★「未対応機種」★ | 「未対応」のまま | 機種=`Unsupported model` / アラート=`Open` | ★仕組みは変えない★。JA表示が1語増える（D-087 の「色だけでなく必ず文字を出す」には反しない） |
| 案C | 「未対応」のまま | ★「未処理」★ | 機種=`Unsupported` / アラート=`Open` | ★モックの文言（「未対応」）から外れる★。`CLAUDE.md` §5 に抵触 |

★この選択をするとこうなる★:
- 案Aを選ぶと `lib/i18n.ts` の `translate()` の引数が増え、★`t()` の呼び出し約180箇所すべてが
  影響範囲の候補★になります（実際に直すのは2箇所でも、レビュー範囲が全画面になる）
- 案Bを選ぶと施設ロボットマスタの機種バッジが「未対応」→「★未対応機種★」に見た目が変わります。
  機種名の右隣に出るので「PUDU MT1 ★未対応機種★」となり、むしろ読みやすくなる可能性があります
- 案Cを選ぶとモックとの文言差分が1件増えます（第1章に追記が必要）

**★推奨は案B★**（仕組みを変えず、モックの文言から外れるのは機種バッジ側＝そもそもモックに無い要素）。

### Q2 — #2 の直し方: 「機能させる」で確定してよいか

§3 のとおり D-053 とも `CLAUDE.md` §5 とも整合するのは「機能させる」です。

★この選択をするとこうなる★: ダッシュボードで `?` を押すと表の下に凡例が開きます。
凡例は `t()` を通していないので★EN でも「判定基準（タスク完了率）: ◎ 90%以上 …」と和文★で出ます。
同じコミットで対訳を足すか（2キー）、和文のままにするかを決めてください。

### Q3 — #3 で「1h前ST / 30分前ST」の2列を戻すか

`docs/spec.md:32` は「機種・シリアル列を省略」なので★文面どおりなら戻す★のですが、
D-077（エラー種別を変換しない）の帰結として★実DBでは英語識別子がグレーのPillで並びます★。

★この選択をするとこうなる★:

| 案 | ダッシュボードの見え方 |
|---|---|
| ★全4列戻す（spec.md どおり）★ | 「日付 / 予定 / ★`Standby.` / `EmergencyStop`★ / ✓✗ / 完了率 / 判定」。★ST2列がグレー一色★（`lib/theme-status.ts:26-30` の仕様どおり） |
| ST 2列だけ落とす | 「日付 / 予定 / 出発 / 完了率 / 判定」の★6列★。spec.md から1歩外れるので★記録が要る★ |

★D-098（`docs/decisions.md:4349`）でエラーが無いときの `status_1h` は `Standby.`（原文どおり）と
確定しています★ので、正常な行は「Standby.」がずらりと並びます。

### Q4 — #4 のバッジを足すか。足すなら更新タイミングは

★この選択をするとこうなる★:
- 足す場合、★全10画面で毎回2本のAPIが余分に走ります★（`/prechecks` と `/ds-alerts`）
- ★PATCH（対応状況の更新）が未実装なので件数は誰にも減らせません★。
  「🔔 アラート ★27★」が★毎日固定で表示され続けます★ → ★かえって無視されるようになる★恐れ
- 足さない場合、モックとの差分1件が「意図した仕様」として `docs/decisions.md` に残ります

★選択肢★: (a) 今すぐ足す / (b) ★PATCH が実装できるようになってから足す★（そのとき D-143 に条件付きで記録） / (c) 足さない

### Q5 — #7 を足すか。足すなら日付はサマリにも効かせるか

D-054 と指示書AK の設計では、★type / status は「見え方」なので summary に効かせない★、
★分類（group/customer）は「母集団」なので summary に効かせる★、という区別があります
（`app/api/ds-alerts/route.ts:58-69`）。★期間はどちらなのかが未定義★です。

★この選択をするとこうなる★:

| 案 | 「2026-09-01〜09-10」を指定したとき |
|---|---|
| ★母集団扱い（分類と同じ）★ | 数値カードが★その期間の未対応/対応中/対応済み★になる。一覧と数字が一致する |
| 見え方扱い（type/status と同じ） | 数値カードは★全期間のまま★。一覧は10日分だけ。★「未対応 27」と書いてあるのに3件しか出ない★ |

★母集団扱いを推奨★（「期間を選ぶ」は明らかに対象を選ぶ操作なので、見え方扱いは誤読を招く）。

### Q6 — #5 の色をどちらにするか

★この選択をするとこうなる★:
- ★赤に戻す★: D-Secアラート画面のカードが★全部赤★になります（実DBでは `disconnected` しか
  出ないため）。D-Secログの「異常＝赤」と揃います
- ★アンバーのまま★: 画面が★全部アンバー★のままです。「重大」に相当する赤が1色も出ません
- いずれにせよ★`docs/decisions.md` に理由を残すこと★

### Q7 — #6 をどちらに寄せるか

★この選択をするとこうなる★:
- ★展開できるようにする（モック準拠）★: ダッシュボードの5行が展開でき、
  ★そのたびに `GET /api/clean-logs/{id}/advice` が1本走ります★。エリア別モーダルも開けるようになります
- ★展開させない（現状維持）★: `CleanLogTable.tsx:25` の docstring から★「規約のため」を削除★し、
  「D-143 で確定」と書き換えてください（★存在しない根拠を引用したままにしない★）

---

## 12. ★指示書AO に載せるべき段階分け案★

`docs/handoff/指示書AN_総清掃面積の画面を作る.md` の書式に合わせ、
★段階ごとに1コミット★、★番号順に実行★、各段階で `npx tsc --noEmit` / `npm run lint` / `npm test` を通す前提です。

### 前提: ★着手前にユーザー判断が要る★

★段階1・3・5・6・7 は Q1〜Q7 の回答が無いと着手できません★（`CLAUDE.md` §0-1「仕様が不明なら止まる」）。
★段階0 と段階2 だけは判断不要で先に進められます★。

| 段階 | 内容 | 前提となる判断 | コミット単位の理由 |
|---|---|---|---|
| ★段階0★ | ★文書の訂正のみ★。`docs/UI差分まとめ_20260915.md:89` / `:244` の「記録なし」を「D-105 項5 / D-114」に直す（#8） | ★不要★ | ★コード0行★。混ぜると「文書だけ直したコミット」が追えなくなる |
| ★段階1★ | ★#1 対訳キー衝突の解消★（`lib/i18n.ts` + `FacilitiesScreen.tsx` 1行） | ★Q1★ | ★実害のある不具合を単独で追えるようにする★。revert したくなったときに他と混ざらない |
| ★段階2★ | ★#2 死んだボタンを機能させる★（`DashboardScreen.tsx` に `useState` 1つ） | ★Q2（推奨で確定なら不要）★ | 2行。★D-053 違反の解消という単一の理由★ |
| ★段階3★ | ★#3 コンパクト表の列を戻す★（`CleanLogTable.tsx` の `!compact` と `colSpan`） | ★Q3★ | ★`colSpan` の直し漏れが起きやすい★ので、他と混ぜず単独で目視確認する |
| ★段階4★ | ★追加1・追加2 の EN 抜けを埋める★（ダッシュボード6キー・アラート11キー。★`要対応` は段階1 の方針に従う★） | ★Q1（`要対応` の扱いが同型）★ | ★辞書だけの変更★。段階1 の方式が決まっていないと同じ地雷を踏む |
| ★段階5★ | ★#5 「通信断」の色★（1行）＋ `docs/decisions.md` への記録 | ★Q6★ | ★1行だが決定の記録が本体★。混ぜると記録が埋もれる |
| ★段階6★ | ★#6 行展開★（実装する場合のみ。しない場合は★docstring の訂正だけ★） | ★Q7★ | ★段階3 の `colSpan` に依存する★ので必ず後 |
| ★段階7★ | ★#7 期間フィルタ★。★7-1 YAML → 7-2 `query.ts` + テスト → 7-3 ルート → 7-4 画面★の4コミットに割る | ★Q5★ | ★`CLAUDE.md` §6-1（YAMLが先）★。テストを実装より先に置く（§6-2） |
| ★段階8★ | ★#4 サイドバーのバッジ★（足す場合のみ） | ★Q4★ | ★共通レイアウトに初めてフェッチを入れる★ので、他と混ぜると全画面の回帰が切り分けられない |
| ★段階9★ | ★追加3・追加4 の死んだ辞書キー4+1件を削除★ | ★不要★ | 掃除。★段階4 の後★（足す作業と消す作業を同じコミットに入れない） |
| ★段階10★ | ★`docs/decisions.md` に D-143 として8件の振り分けを記録★＋ `docs/UI差分まとめ_20260915.md` 第3章・第4章の更新 | — | ★記録が最後★（実際にやったことを書くため） |

### ★段階分けの原則（この指示書で守ってほしいこと）★

1. ★判断不要の段階（0・2・9）と判断待ちの段階を混ぜない★ — 回答待ちで全部止まるのを避ける
2. ★#3 → #6 の順序は固定★（`colSpan` の依存）
3. ★#7 は YAML から★（`CLAUDE.md` §6-1）
4. ★色・文言の変更は必ず `docs/decisions.md` への記録とセット★ — 記録が無いから今回の調査が発生した
5. ★`git add -A` を使わない★（`CLAUDE.md` §7）

### ★指示書AO で「絶対に触らない」と書くべきファイル★

`d-watch-mock.jsx`（資料。`docs/UI差分まとめ_20260915.md:262`）/ `lib/judge/**` /
`prisma/**` / `docs/handoff/TeamWorks確認事項_第9回_20260915.md` /
`docs/handoff/セキュリティ申し送り_20260916.md` / `docs/handoff/pdf/**` /
`README.md` / `docs/code-map.md`

---

## 13. 使った検証コマンド（再現用）

```bash
# 決定の位置（★番号順に並んでいないので必ずこれで取る★。最新は D-142）
grep -n "^### D-" docs/decisions.md

# #1
grep -rn "未対応" components/ lib/ app/ --include=*.tsx --include=*.ts
grep -n "Unsupported" docs/decisions.md            # → 11216（D-142 の引用のみ）
git blame -L 158,161 --date=short lib/i18n.ts
git blame -L 141,141 --date=short components/features/ds-alerts/DsAlertsScreen.tsx

# #2
grep -n "showGradeInfo\|凡例" docs/decisions.md    # → 10864 のみ（文言の話）

# #3
grep -n "コンパクト版" docs/decisions.md docs/spec.md d-watch-api.yaml
sed -n '202,260p' lib/types/index.ts               # CleanLogItem に全フィールドがある

# #4
grep -n "未対応件数\|件数バッジ" docs/decisions.md  # → 0件
grep -n "サイドバー" docs/decisions.md              # → すべて D-137（スクロール）

# #5
grep -n "バッジの色" docs/decisions.md              # → 146 / 237（どちらも別物）
sed -n '946,947p' d-watch-mock.jsx

# #6
grep -n "アドバイスを一切\|ダッシュボードではアドバイス" docs/decisions.md docs/spec.md docs/handoff.md docs/変更点まとめ_20260914.md   # → 0件
grep -n "行展開" docs/decisions.md                  # → 7973 のみ（目視項目の列挙）

# #7
grep -n "D-Secアラート.*期間\|ds-alerts.*date\|期間フィルタ" docs/decisions.md   # → 0件
sed -n '1131,1149p' d-watch-api.yaml                # parameters に日付が無い

# #8
grep -n "battery_level" docs/decisions.md           # → D-105 項5（5596-5604）/ D-114（7138）

# 追加1（EN の抜け）— t() のキーを全部拾って辞書と突き合わせる
grep -rno 't("[^"]*")' components/ --include=*.tsx
```
