# 指示書AJ — 要レスキューの見せ方を直し、サイドバーのスクロールを独立させる

**作成: 2026-09-15 / ブランチ: `develop` / 前提: 指示書AI 完了（D-135 / D-136）**

---

## ★Cursor への指示文（ここから下をそのまま貼ってください）★

> ```
> D-Watch の実装をお願いします。ブランチは develop です。
>
> ■ 最初に読むもの（この順で、全部）
>   1. CLAUDE.md（全文。特に §0-3 フォント / §5 モックが正 / §7 禁止事項 / §9 実装規約）
>   2. docs/handoff/指示書AJ_要レスキューの見せ方とサイドバーのスクロール.md（全文）
>   3. docs/handoff/指示書AI_要レスキュー店舗と詳細ログの期間上限.md の §6-5
>      （今回直すのは、ここで私が指定を誤ったところです）
>
> ■ やること
>   指示書AJ の 段階1 から 段階4 までを、★番号順に★実行してください。
>   前回、段階の順序が前後しました。今回は番号順でお願いします
>   （段階2 はサイドバーの見た目に関わるので、段階1 と混ざると切り分けができません）。
>
> ■ 段階ごとに必ずやること
>   1. npx tsc --noEmit    → 0 であること
>   2. npm run lint        → 0 であること
>   3. npm test            → 全パス
>   4. コミットする（★段階ごとに1コミット★。まとめない）
>
> ■ コミットの決まり
>   ・git add -A は使わないでください。必ずファイルパスを明示してください
>   ・コミットメッセージは日本語。「なぜそうしたか」を1〜2行入れてください
>   ・push はしないでください
>
> ■ 絶対に触らないファイル
>   README.md / docs/code-map.md /
>   docs/handoff/管理画面_設計検討_20260910.md / .claude/worktrees/** /
>   d-watch-mock.jsx / lib/dashboard/aggregate.ts / lib/judge/advice.ts / lib/db/prisma.ts
>
> ■ 絶対にやらないこと
>   ・閾値・件数のハードコード — 必ず lib/config/index.ts に置いてください
>   ・新しい CSS に font-family を書くこと
>     （日本語フォントが落ちて漢字が中華字形になります）
>   ・判定ロジック（lib/judge/rescue.ts）を変えること
>     ★今回は「判定」ではなく「見せ方」だけを直します★
>   ・仕様が不明なところを推測で実装すること
>
> ■ 動作確認
>   ★テストDBのデータは 2026-09-13 で終わっています★。
>   /api/dashboard?date=2026-09-13 と ?date=2026-09-12 で確かめてください。
>   期待される結果は指示書AJ の §6 に書いてあります。
>   ★段階2（サイドバー）は画面を見ないと確かめられません★。
>   §6-3 に、目視以外の確かめ方（getComputedStyle / scrollTop）を書いてあります。
>
> ■ 終わったら
>   ・段階ごとのコミットハッシュ
>   ・tsc / lint / test の結果（テスト本数も）
>   ・★§6 の動作確認を実際に行った結果★（前回はここが素通りになりました）
>   ・指示書どおりにできなかったところと、その理由
>   ・判断に迷って自分で決めたところ（あれば全部）
> ```

---

## 0. なぜこの指示書があるか

★**指示書AI の実装は合格でした。**★ 3本の査読が独立に検算し、★実装の誤りは1件も出ていません★。

★**直すのは、私（監督）が指示書AI §6-5 で指定を誤った1箇所です。**★

> §6-5: 「並び＝連続問題日数の降順」「件数＝上限を設ける。詳細ログに揃えて5件」

★この2つの組み合わせで、急落だけで該当する施設が構造的に一覧から落ちていました。★

★加えて、ユーザーから新しい要望が1件★来ています（段階2）。

★★実装者に落ち度はありません。指示書AI §6-5 のとおりに作られています。★★

---

## 1. ★実データで何が起きているか（実測）★

テストDB（`133.125.238.144:13306 / clean_watch`）で確認した事実です。

### 1-1. 上限で切られている

| 当該日 | 3条件に当たる施設 | APIが返す件数 | ★消えた施設★ |
|---|---|---|---|
| 2026-09-13 | ★7件★ | 5件 | ★施設1（46.0%急落）/ 施設10（46.5%急落）★ |
| 2026-09-12 | ★7件★ | 5件 | ★施設8（91%急落）/ 施設10（28%急落）★ |

★消えた4件は、すべて `completion_drop` 単独★でした。

```
急落 = 「昨日まで正常 → 今日落ちた」
     → consecutive_problem_days は 1〜2 にしかならない
     → 連続日数の降順で並べると、必ず L3（3以上）の後ろ
     → L3 が5施設ある日は、急落が1件も出ない
```

★★ユーザーがわざわざ新設を指示した条件が、実データでほぼ機能していません。★★

### 1-2. 件数の表示が、切ったあとの数になっている

`components/features/dashboard/RescueRequiredCard.tsx:85`

```tsx
{t("{n}件").replace("{n}", String(items.length))}
```

`items` は切ったあとの配列です。★7件該当していても「5件」と出ます。★
★運用担当は5件を全件として読みます。★ ★例外もテスト失敗も出ません。★

---

## 2. ★ユーザーが決めたこと（2026-09-15。原文）★

### 2-1. 件数

> ①上限は設けずに、表示は5件、もっと表示のようなのもので全件

★**確定:**★

| 層 | どうするか |
|---|---|
| ★API★ | ★**上限を設けない**★。該当する施設を**全部**返す |
| ★画面★ | ★**最初は5件**★。「もっと表示」で★全件★を開く |

★★API 側の上限（`RESCUE_LIST_LIMIT`）は撤廃します。★★
★これで「切ったのに気づけない」問題が根から消えます★ — ★切らないからです。★

★件数が青天井にならないか★: なりません。★要レスキューは施設ごとに最大1行★なので、
★施設数（P1 の想定で200件程度）が上限★です。★ページ送りは要りません。★

### 2-2. 評価日の古さ

> ②これも上限無し

★**確定: 評価日が何日前であっても出す。足切りをしない。**★

★背景★: 「当該日以前で最も新しいスケジュール存在日」で判定するため（指示書AI §1-5）、
★清掃予定が止まった施設は、遡り幅いっぱい（既定217カレンダー日 ≒ 7か月）出続けます★。

実測（今日 2026-09-15、日付なしで `/api/dashboard`）:

```
summary          success 0 / failed 0 / not_executed 0 / success_rate null
rescue_required  5件（evaluated_on は 2026-09-12 と 2026-09-13）
```

★★ユーザーはこの挙動を承知のうえで「上限無し」と決めました。★★
★**足切りの実装はしません。**★

★★判断の根拠（記録に残すこと）★★: ★困っている店舗が、時間が経ったという理由だけで
一覧から消えるほうが危ない★。★カードには既に「判定日」が出ている★ので
（`RescueRequiredCard.tsx:116`）、★いつの状態かは読み手が判断できます★。

---

## 3. ★触ってはいけないもの★

| 対象 | 理由 |
|---|---|
| `README.md` / `docs/code-map.md` / `docs/handoff/管理画面_設計検討_20260910.md` / `.claude/worktrees/**` | ★別作業★ |
| `d-watch-mock.jsx` | ★モックは原型として保存する★（段階2 で外れるが、書き換えない。§5） |
| `lib/dashboard/aggregate.ts` | ★数値カードを変えない★ |
| `lib/judge/advice.ts` | R1〜R4。要レスキューとは別物 |
| `lib/db/prisma.ts` | ★未コミットの変更が乗っている★ |
| ★`lib/judge/rescue.ts` の判定ロジック★ | ★★今回は「見せ方」だけを直します★★。3条件の判定は査読で合格しています |

★★禁止★★: `git add -A` / 生SQL / 閾値・件数のハードコード / スキーマ変更 /
★新しいCSSへの `font-family`★ / 推測での実装

---

## 4. 段階1 — 上限を撤廃し、画面で「もっと表示」する

### 4-1. 設定値

`lib/config/index.ts:81`

```ts
export const RESCUE_LIST_LIMIT = 5 as const;
```

★**この定数は「APIが返す上限」ではなくなります。**★
★**画面の初期表示件数**に役割を変え、名前もそれに合わせること★（例: `RESCUE_INITIAL_VISIBLE`）。

★★名前を変えずに意味だけ変えないこと★★ — ★次に読む人が「APIの上限」だと思い込みます。★

docstring に書くこと:

```
★これは API が返す件数の上限ではない★（上限は設けない。ユーザー指示 2026-09-15）。
★画面で最初に見せる件数であり、「もっと表示」で全件が開く★。
★API 側で切らない理由★: 切ると「切られたこと」に運用担当が気づけないため
（指示書AJ §1-2。実データで7件中2件が黙って消えていた）。
★件数が青天井にならない理由★: 要レスキューは施設ごとに最大1行なので、
施設数が自然な上限になる。
```

### 4-2. データ層 — ★上限を外す★

`lib/db/rescue-mapping.ts:156-161`

- ★`.slice(0, limit)` を外す★
- ★`buildRescueRequired()` の `limit` 引数を外す★（★呼び出し側から渡さない★）
- ★`sort` は残す★（§4-3 で並び順を変える）

★総数を別キーで返す必要はありません★ — ★配列の長さがそのまま総数★になります。
★`rescue_required_total` のようなキーを足さないこと。★

### 4-3. ★並び順に「理由の数」を入れる★

★現在★: `consecutive_problem_days` の降順 → `facility_id` の昇順
★変更後★:

```
1) reasons.length の降順          ← ★複数の条件に当たる施設ほど重い★
2) consecutive_problem_days の降順
3) facility_id の昇順             ← ★安定した順序にするため★
```

★なぜ理由の数を最優先にするか★を docstring に書くこと:

```
★連続日数だけで並べると、急落（連続日数が浅いのが当たり前）が下に沈む★
（指示書AJ §1-1）。理由の数を先に見ることで、
「L3 かつ急落」の施設が「L3 だけ」の施設より上に来る。
★★これでも「急落だけ」の施設は下のほうに来る★★ —
そこは上限を撤廃し、画面で全件を開けるようにしたことで補っている。
```

★★「急落だけ」の施設が上位に来るわけではありません。正直に書くこと。★★

### 4-4. 画面 — ★初期5件、「もっと表示」で全件★

`components/features/dashboard/RescueRequiredCard.tsx`

```
要レスキュー店舗  7件           ← ★受け取った配列の長さ（＝総数）★
（… 5件ぶんの行 …）
もっと表示（あと2件）           ← ★押すと全件が開く★
```

- ★件数の表示は `items.length`（＝総数）のまま★でよい。★上限を外したので、これが正しい数になります★
- ★初期表示は先頭 `RESCUE_INITIAL_VISIBLE` 件★
- ★`items.length > RESCUE_INITIAL_VISIBLE` のときだけ「もっと表示」を出す★
- ★開いたあとは「閉じる」に切り替える★（★開きっぱなしで戻せないのは不便★）
- ★状態は画面のローカル state でよい★。★URL に持たせない★
  （★D-131 申し送り⑤「ページ番号を URL に持たせる件」と混ざらないようにする★）
- ★文言は `t()` を通すこと★（JP/EN の器。§9.6）。★数値は画面側で差し込む★（D-111）
- ★`lib/i18n.ts` に新しい語を足すこと★（「もっと表示」「閉じる」など）

★★0件のときカードごと消さない★★ — 指示書AI の実装者判断（D-135）を維持すること。
★「確認した結果0件だった」と「表示が出ていない／壊れている」を区別できる必要があります。★

### 4-5. 期待値表

★データ層（上限が無いこと）★

| # | 該当施設 | APIが返す件数 |
|---|---|---|
| 1-1 | 0 | ★0★ |
| 1-2 | 7 | ★★7★★（★5ではない★） |
| 1-3 | 50 | ★50★ |

★1-2 が今回の眼目★です。★実データで確かめられます（§6）。★

★並び順★

| # | 入力 | 期待 |
|---|---|---|
| 1-4 | A(理由2・連続3) / B(理由1・連続6) | ★A が先★（理由の数が優先） |
| 1-5 | A(理由1・連続3) / B(理由1・連続6) | ★B が先★（同数なら連続日数） |
| 1-6 | A(id=9・理由1・連続3) / B(id=3・理由1・連続3) | ★B が先★（同値なら facility_id 昇順） |

★画面★

| # | 該当件数 | 初期表示 | 「もっと表示」 |
|---|---|---|---|
| 1-7 | 0 | 0行 | ★出さない★（カードは残す） |
| 1-8 | 3 | 3行 | ★出さない★ |
| 1-9 | ★ちょうど5★ | ★5行★ | ★★出さない★★ |
| 1-10 | ★6★ | ★5行★ | ★★出す（あと1件）★★ |
| 1-11 | 6 → 押したあと | ★6行★ | ★「閉じる」に変わる★ |

★1-9 と 1-10 の両方をテストに入れること★（`>` と `>=` の取り違えが通らないように）。

★★画面のテストは `vitest.config.ts` の `include` が `lib/**` と `app/**` なので走りません★★（D-120 項2）。
★「何件表示するか」を決める部分は `lib/` 側の純粋関数に切り出せば、テストできます。★
★切り出すかどうかは実装者判断★ですが、★切り出さないならその旨を記録に残すこと★。

---

## 5. 段階2 — サイドバーのスクロールを本文と独立させる

### 5-1. ユーザー指示（原文）

> サイドパネルはメインパネルとスクロールは独立させてください

★ユーザー確定（2026-09-15）: **案A（シェルを画面高に固定し、左右それぞれを独立させる）**★

### 5-2. ★今どうなっているか（実測）★

```
.shell  { min-height: 100vh }   ← 高さが内容で決まる
.main   { overflow: auto }      ← ★書いてあるが効いていない★
```

`.shell` が `min-height` なので flex 子の `.main` が内容分まで伸び、
`scrollHeight === clientHeight` になってスクロールコンテナになりません。

実測（`components/layout/AppShell.module.css` の宣言を実ページ上で再現して測定）:

| 要素 | clientHeight | scrollHeight | スクロールするか |
|---|---|---|---|
| `html` | 1268 | 3088 | ★する★ |
| `.sidebar` | 3088 | 3088 | しない（`position: static`） |
| `.main` | 3088 | 3088 | ★しない★ |

★下にスクロールすると、サイドバーは色のついた空の柱になります。★
★メニュー・テーマ切替ボタン・フッター「DFA運用担当」が全部画面外へ流れます。★

### 5-3. 変更

`components/layout/AppShell.module.css` のみ。★JSX の構造変更は不要★です
（`aside` と `main` は既に兄弟です）。

```css
.shell {
  display: flex;
  height: 100vh;    /* ★min-height から height へ★ */
  height: 100dvh;   /* ★dvh 対応ブラウザではこちらが勝つ（モバイルのURLバー分）★ */
  ...
}

.sidebar {
  ...
  overflow-y: auto;   /* ★1行追加★ */
}

/* .main の overflow: auto はそのまま。これで初めて効く */
```

★`height: 100vh` を先に、`height: 100dvh` を後に書くこと★（2段指定）。
★`100dvh` を知らないブラウザは後者を無視して前者が残ります。★

### 5-4. ★サイドバー自体のスクロールが要る理由★

★これは将来の話ではなく、もうすぐ起きます。★

```
今のメニューの高さ       約591px
点検記録を戻すと         約628px
総清掃面積の画面を足すと  約665〜699px
```

★ノートPCのブラウザ内寸は600〜700px★です。★`overflow-y: auto` が無いと、
下のメニューに手が届かなくなります。★

### 5-5. ★★印刷の退避を必ず入れること★★

★`height: 100vh` にすると、ブラウザの「印刷」で1画面分しか出ない可能性があります。★

```css
@media print {
  .shell { height: auto; }
  .main  { overflow: visible; }
}
```

★これを入れ忘れると、印刷したときに初めて気づきます。★
★★画面では絶対に分かりません。★★

### 5-6. ★画面遷移で本文が先頭に戻るか、必ず確かめること★

Next.js は遷移時に `document.documentElement.scrollTop = 0` を試し、
ダメなら `scrollIntoView()` に落ちます。
★`.shell` を `height: 100vh` にすると前者が効かなくなり、後者頼みになります。★

★実機で確かめること★（§6-3 の (5)）。★動かなければ報告してください。★
★勝手に `scrollTo` を画面に足さないこと★ — ★アプリコードに `scrollTo` / `scrollIntoView` /
`scrollY` は現在1件もありません★。1つ足すと、全画面の遷移の挙動を1箇所で背負うことになります。

### 5-7. ★スマートフォン幅は今回スコープ外★

★実測: 375px 幅でサイドバーは 220px のままで、本文は 155px に潰れます。★
★横スクロールは出ません。★

★★今回の変更は、これを改善も悪化もさせません。★★
★直したくなっても、今回は触らないこと★ — ユーザー指示はスクロールのみで、
★レイアウトを変えるとモックからさらに外れるため、別の判断が要ります★。
★申し送りに書くこと。★

### 5-8. ★モックから意図的に外れることの記録★

`d-watch-mock.jsx:426` `minHeight: "100vh"` / `:429` サイドバー（`position` 指定なし）/
`:468` `overflow: "auto"`。

★★モックにも同じ `overflow: "auto"` が、同じ理由で効かないまま置かれています。★★
★実装はモックの 1:1 移植で、外れていません。★ ★今回が「外れる」最初の変更です。★

`CLAUDE.md` §5 は「モックが画面レイアウト・文言・遷移の正」と定めています。★前例が2件★:

| 決定 | 何をしたか |
|---|---|
| ★D-120★ | モックに無いページ送りUIを新規に作った。「§5 の例外」と明記し、★ユーザー原文を転記★ |
| ★D-121★ | モックと違う色にした。同上＋★コード側にも理由コメントを残した★ |

★**同じ作法を踏襲すること:**★

1. ★`d-watch-mock.jsx` は1文字も書き換えない★
2. `docs/decisions.md` に ★「`CLAUDE.md` §5 の例外。ユーザーの明示指示（2026-09-15）に基づく」★
   と記録し、★指示の原文を引用する★
3. ★`AppShell.module.css` の該当箇所の直上に、理由コメントを残す★
   — ★★書かないと、次にモックと突き合わせた人が「モックと違う」と判断して戻します★★

---

## 6. ★動作確認（前回ここが素通りになりました）★

★★前回の実装では、実データでの確認が行われませんでした。★★
★記録に「本作業では実施していない」と正直に書かれていたので分かりましたが、
その結果、上限で2件消えている問題は査読まで見つかりませんでした。★

★今回は必ず行い、結果を報告してください。★

### 6-1. 前提

`.env.local` は既にテストDB（`133.125.238.144:13306 / clean_watch`）を向き、`USE_FIXTURES=false` です。
★★テストDBのデータは 2026-09-13 で終わっています。今日の日付では数値カードが全部0になります。★★

### 6-2. 確かめること

```
GET /api/dashboard?date=2026-09-13
```

| # | 期待 |
|---|---|
| ★6-1★ | ★★`rescue_required` が 7件 返ること★★（★前回は5件だった★） |
| ★6-2★ | ★★施設1 と 施設10 が含まれること★★（★どちらも急落46%。前回は消えていた★） |
| ★6-3★ | ★施設7 が含まれ、`evaluated_on` が `2026-09-12` であること★ |
| 6-4 | ★並びの先頭が施設9★（理由2つ・連続6日） |
| 6-5 | ★数値カードが `success 8 / failed 9 / not_executed 1` のままであること★ |

```
GET /api/dashboard?date=2026-09-12
```

| # | 期待 |
|---|---|
| 6-6 | ★`rescue_required` が 7件★ |
| 6-7 | ★施設8 が含まれること★（★91%急落。前回は消えていた★） |
| 6-8 | 施設6 の `reasons` に `not_executed_streak` と `escalation_l3` が両方入る |

```
GET /api/dashboard        （日付なし＝今日 2026-09-15）
```

| # | 期待 |
|---|---|
| ★6-9★ | ★★数値カードは全部0のまま、`rescue_required` は件数が返ること★★ |

★6-9 はユーザーが承知のうえで決めた挙動★です（§2-2）。
★★「0件になるべきでは」と考えて足切りを入れないこと。★★

### 6-3. 段階2（サイドバー）の確かめ方

★★画面のログインにはアクセストークンが要ります。★★
★ログインできる場合は、縦に長い画面（`/detail-log` で期間を広げる）で確かめてください。★

ブラウザのコンソールで:

```js
// (1) スクロールコンテナがどれか
const info = e => { const c = getComputedStyle(e); return {
  overflowY: c.overflowY, position: c.position, height: c.height,
  clientH: e.clientHeight, scrollH: e.scrollHeight,
  scrollable: e.scrollHeight > e.clientHeight + 1 }; };
({ html: info(document.documentElement),
   sidebar: info(document.querySelector('aside')),
   main: info(document.querySelector('main')) })
```

★合格条件★: `main.scrollable === true` ★かつ★ `html.scrollable === false`

```js
// (2) 独立していることの証明
const m = document.querySelector('main'), a = document.querySelector('aside');
m.scrollTop = 500;
({ mainTop: m.scrollTop, docTop: document.documentElement.scrollTop,
   brandVisible: a.querySelector('div').getBoundingClientRect().top >= 0 })
```

★合格条件★: `mainTop === 500` ★かつ★ `docTop === 0` ★かつ★ `brandVisible === true`
（＝★本文を動かしてもロゴが画面内に残っている★）

```js
// (3) メニューが溢れたときサイドバー内だけが動く
//     先にブラウザの内寸を 1280×600 程度にすること
const a = document.querySelector('aside');
a.scrollTop = 9999;
({ asideScrollable: a.scrollHeight > a.clientHeight + 1, asideTop: a.scrollTop,
   mainTop: document.querySelector('main').scrollTop })
```

★合格条件★: `asideTop > 0` ★かつ★ `mainTop` が変化しない

```js
// (4) テーマ切替が壊れていない（🌙 を押してから）
({ theme: document.documentElement.dataset.theme,
   asideBg: getComputedStyle(document.querySelector('aside')).backgroundColor })
```

★合格条件★: ダーク `rgb(26,35,50)` ⇄ ライト `rgb(255,255,255)` で切り替わる

★(5) 画面遷移★: 本文を下までスクロール → サイドバーのリンクで別画面へ →
★`document.querySelector('main').scrollTop === 0` になるか★

★(6) スマホ幅★: 375px にして ★横スクロールが出ていないこと★
（`document.documentElement.scrollWidth === clientWidth`）

★(7) 「もっと表示」★: 要レスキューが6件以上ある日で、★押すと全件出て、「閉じる」に変わるか★

★★ログインできない場合は、そう報告してください。★★ ★推測で「動いているはず」と書かないこと。★

---

## 7. 段階3 — 指示書AI §12 の期待値表を直す

★私が書いた期待値が間違っていました。★ ★直さないと、次に読む人が「実装が壊れている」と誤判定します。★

`docs/handoff/指示書AI_要レスキュー店舗と詳細ログの期間上限.md` の §12:

| 現在の記述 | 正しい値 |
|---|---|
| 「`?date=2026-09-13` → R-2 が4件」 | ★★5件★★（★施設7 を数え漏らしていた★。09-13 に予定が無いが 09-12 評価で出る） |
| 「R-3 が4件」 | ★4件で正しい★。★ただし当時は上限5件のため、APIには2件しか出ていなかった★ |

★★訂正であることが分かるように書くこと。★★ ★元の数字を消して上書きしないこと★ —
★「4件と書いていたが誤り。正しくは5件」という形にする★。
★次に読む人が、この指示書を信じて数を合わせにいく可能性があります。★

★あわせて §6-5（並びと件数の指定）にも、★★指示書AJ で撤回した旨★★を1行足すこと。★

---

## 8. 段階4 — 記録

### 8-1. `docs/decisions.md`

★★採番の前に必ず実測すること★★:

```bash
grep -nE "^### D-(0|1)[0-9][0-9]" docs/decisions.md | tail -3
```

★`docs/decisions.md` は番号順に並んでいません。★ 末尾を見て最大値を判断しないこと。

書くこと:

- ★API 側の上限を撤廃した理由★（★切ったことに気づけないのが問題だった。実データで7件中2件が黙って消えていた★）
- ★件数が青天井にならない理由★（施設ごとに最大1行）
- ★並び順に「理由の数」を入れた理由★と、★★それでも「急落だけ」の施設は下に来ること★★
- ★画面で初期5件＋「もっと表示」にしたこと★
- ★★評価日の古さに上限を設けないと決めたこと★★ — ★ユーザー判断（2026-09-15「これも上限無し」）。
  原文を転記する★。★理由（困っている店舗が時間経過だけで消えるほうが危ない／カードに判定日が出ている）も書く★
- ★サイドバーのスクロールを独立させたこと。`CLAUDE.md` §5 の例外であること。★ユーザー原文を転記★
- ★印刷の退避を入れた理由★
- ★★指示書AI §6-5 と §12 が誤っていたこと★★（★監督の誤りとして残す★）

### 8-2. `docs/handoff.md` に追記

- ★スマートフォン幅（375px で本文が155px）は未対応のまま★
- ★「急落だけ」の施設が下に来る構造は残っていること★ —
  ★施設数が増えて一覧が長くなったら、並び順を見直す余地がある★
- ★評価日が古い施設が出続けること★ — ★ユーザー判断で上限を設けていない。
  実運用で「古い行が邪魔」という声が出たら再検討する★
- ★画面遷移時のスクロール先頭復帰が Next の `scrollIntoView` 経路に依存するようになったこと★

---

## 9. ★実装者へ — 特に踏みやすい落とし穴★

| # | 落とし穴 | どうなるか |
|---|---|---|
| ★1★ | ★`RESCUE_LIST_LIMIT` の名前を変えずに意味だけ変える★ | 次の人が「APIの上限」だと思い込む |
| ★2★ | ★API 側にも上限を残す★ | ★今回直したかったことが直らない★ |
| ★3★ | ★評価日の足切りを「親切のつもりで」入れる★ | ★ユーザーが上限無しと決めている★。入れると古い問題店舗が消える |
| ★4★ | ★「もっと表示」の状態を URL に持たせる★ | 別課題（D-131 申し送り⑤）と混ざる |
| ★5★ | ★開いたあと閉じられない★ | 一度押すと戻せない |
| ★6★ | ★`height: 100vh` だけ書いて `100dvh` を書かない★ | モバイルでURLバーの分だけ画面外に出る |
| ★7★ | ★`@media print` を忘れる★ | ★印刷で1画面分しか出ない。画面では絶対に気づけない★ |
| ★8★ | ★サイドバーに `overflow-y: auto` を入れ忘れる★ | メニューが増えた時点で下に手が届かなくなる |
| ★9★ | ★`lib/judge/rescue.ts` の判定を触る★ | ★査読で合格した判定を壊す。今回は見せ方だけ★ |
| ★10★ | ★新しいCSSに `font-family` を書く★ | ★漢字が中華字形になる★ |
| ★11★ | ★段階2 を段階1 と同じコミットにする★ | 壊れたときに切り分けられない |

---

## 10. やらないこと（★この指示書の範囲外★）

| 項目 | なぜ |
|---|---|
| ★評価日の足切り★ | ★ユーザーが「上限無し」と決めた★（§2-2） |
| ★要レスキューのページ送り★ | ★施設ごとに最大1行なので要らない★ |
| ★スマートフォン幅のレイアウト★ | ユーザー指示はスクロールのみ。★モックからさらに外れるので別の判断が要る★ |
| ★「急落だけ」の施設を上位に出す仕組み★ | ★上限撤廃と「もっと表示」で足りるかを、まず実運用で見る★ |
| ★分類（ホールディングス/屋号/店舗）の復活★ | TeamWorks 確認待ち |
| ★総清掃面積の新画面★ | 分類が先 |
| ★`LIMIT` の SQL 押し下げ / `ORDER BY` の向き揃え★ | 別課題（D-136 の申し送り） |
| ★出発失敗を未実施と別に判定する★ | ★データがDBに無い★（第9回 11章で照会中） |
