# 指示書AZ — 指示書AX の実装をコミットし、レビューの指摘（契約・コメント・テストの穴・見た目・資料）を直す

**日付**: 2026-10-19 / **担当**: Cursor（指示書AX を実装した担当がそのまま続ける）/ **基点**: develop `88ed0c2` ＋ 作業ツリーにある ★未コミットの指示書AX の実装★
**前提**: 指示書AX（`docs/handoff/指示書AX_D-Secアラートをrobot_error_reportsから読む_20261019.md`）／D-180（`docs/decisions.md:13037` 以降。作業ツリーで追記済み・未コミット）／
D-091 項3（`docs/decisions.md:3510-3551`）／第11回 P-8・P-10（D-158）／`CLAUDE.md` §0・§3・§4.7・§6・§7・§9.4

★**行番号はすべて 2026-10-19 に、develop `88ed0c2` の上に AX の未コミットの変更が載った作業ツリーで確かめたもの**★。
段階0 のコミットでは行番号は変わらない。段階1 以降で同じファイルを直すと後ろの行はずれるので、★文（引用した文言）で探し直すこと★。

★**本書は「書いてあることを全部やる」前提で、直す場所を1つずつ挙げてある**★。「ほかにも同じ記述があれば直す」とは書かない — ★見つけたら§2 のルールで直し、作業報告に書く★。

---

## 0. 何をするか

| # | やること | 重さ | 段階 |
|---|---|---|---|
| 0 | ★作業ツリーにある AX の実装をコミットする★（段階7 の CSS 4本で1つ・残り全部で1つ）。★push しない★ | — | 段階0 |
| 1 | `d-watch-api.yaml` の `/errors`・`/errors/{error_id}/status`・`ErrorReportItem`・`/ds-alerts` に、★AX で変わった挙動（U8・シリアル `---`・D3）を書く★ | 中 | 段階1 |
| 2 | 古い挙動を書いたままの docstring・コメントを直す（`lib/db/index.ts` ほか） | 軽微 | 段階2 |
| 3 | ★テストの穴を埋める★（V8 が罠7 の後退で落ちない／ダッシュボードのバナーの検査が空同士で中身が無い） | 軽微 | 段階3 |
| 4 | D-Sec 画面の CSS（編集中のカーソル・バッジの幅・解消日時の寄せ・見出しの下の余白） | 軽微 | 段階4 |
| 5 | `DsLogScreen.module.css:83` の余分な半角空白 | 軽微 | 段階4 |
| 6 | `docs/fixtures.md` の件数・既定の並び・「D-Sec にも出る」の書き方 | 軽微 | 段階5 |
| 7 | 監督の資料（`CLAUDE.md`・`docs/code-map.md`・`docs/spec.md`・D-091 項3）を AX に追従させる（★監督の依頼で本書に含める★） | 軽微 | 段階6 |
| 8 | ★D-180 の「実装の記録」にコミット・テスト件数・画面確認の結果・指示書と違う判断を書く★（最後） | 軽微 | 段階8 |

★**変えないもの**★: AX の仕様（U1〜U8・D1〜D15・表1〜表5）／ルート・データ層・画面の ★ロジック★（本書で直すのはコメント・契約・テスト・CSS・資料だけ）／
`lib/db/robot-error-write.ts`／`prisma/schema.prisma`／施設名・分類の解決（罠7）／`/alerts`（範囲外）／
★AW の表1 E8 のシリアル `'0'`（`app/api/errors/__tests__/route.test.ts:275`・`app/api/errors/[error_id]/status/__tests__/route.test.ts:199-200` `:263-265`）★ — ★テストの中の行なので変えない★（指示書AX §12-2-4）。

---

## 1. 背景

- 指示書AX は Cursor で実装済み（★未コミット★。作業ツリーの39ファイルの変更＋7つの新規ファイル。`docs/decisions.md` の D-180 の追記を含む）。
- ★実装担当の申告★: `tsc` 0件・`lint` 0件・`vitest` 130ファイル / 3077件 全件通過。
- ★監督の画面確認（2026-10-19。fixtures・`:3100`。当方の fixtures 由来）★ — すべて合格:
  - D-Sec アラート: 数値カード 未解消3・対応中2・解消2、既定5行
  - 編集モードで保存 → `PATCH /api/errors/FX-ERR-12/status` 200 → `/errors` に反映
  - `FX-ERR-18`・`19` は `/errors` にも `/ds-alerts` にも出ない。その PATCH は404
  - `GET /api/ds-alerts?status=done` は422
  - 清掃詳細ログ: 1440px・50行で `tableWrap` の `scrollWidth == clientWidth`（1139）。JP / EN とも
- ★監督のコードレビュー（2026-10-19）で、下の指摘が出た★（仕様の誤りは無い。契約・コメント・テスト・見た目・資料の漏れ）。§0 の #1〜#8。

---

## 2. ★共通ルール（本書だけでなく、今後のすべての指示書に当てはまる）★

| # | ルール | 本書で起きたこと |
|---|---|---|
| G1 | ★API の挙動が変わったら、`d-watch-api.yaml` の ★影響を受けるパス・スキーマを全部★ 直す★（指示書に挙がっているものだけでなく）。読み・書き・件数（`meta.total`）・404 の条件・値の例と説明を、`grep` で関係する語を探して確かめる | AX は `/ds-alerts` は直したが、U8 で挙動が変わった `/errors`（GET）・`/errors/{error_id}/status`（PATCH の404）を直していなかった。シリアルの `"0"` も2か所残っていた |
| G2 | ★古い挙動を書いた docstring・コメントを残さない★。挙動を変えた関数だけでなく、★その関数を説明している別の場所（`DataSource` の宣言・ルートの冒頭コメント・別ファイルの説明）★も直す | `lib/db/index.ts` の `DataSource` の宣言（`:333`・`:341`）が「全行が対象」「施設では絞らない」のまま |
| G3 | ★テストは「守る挙動が壊れたら落ちる」ように書く★。空同士の比較（`[]` と `[]`）や、別の理由でも同じ結果になる比較は検査にならない。★書いたら一度わざと壊して赤になるのを確かめ、戻す★（壊した変更はコミットしない） | ダッシュボードのバナーの検査が「両方空」で、絞り込みを外しても緑のまま。V8 は「名前の解決が削除済みの施設を落とした」場合でも0件で緑のまま |
| G4 | ★決定の記録（`docs/decisions.md` の「実装の記録」）に、コミット・テスト件数の前後・画面確認の結果（出所つき。`CLAUDE.md` §6-6）・指示書と違う判断を書く★ | D-180 の「実装の記録」が1行（件数だけ。前の件数・コミット・画面確認・逸脱が無い） |

---

## 3. 落とし穴

| # | 罠 | どう避けるか |
|---|---|---|
| 3-1 | ★`git add -A`・`git add .`★ | 禁止（`CLAUDE.md` §7）。★ファイルパスを1つずつ書く★ |
| 3-2 | ★`[error_id]` を含むパスがグロブとして解釈される★ | パスを引用符で囲む。★段階0 のステージの後に `git diff --cached --name-status` で、狙ったファイルが全部・それだけ入っていることを目で確かめる★。入らなければ `git add -- ":(literal)app/api/errors/[error_id]/status/__tests__/route.test.ts"` の形にする |
| 3-3 | ★削除したファイル（`lib/fixtures/ds-alerts.ts`）をステージし忘れる★ | `git add -- lib/fixtures/ds-alerts.ts`（削除もこれでステージされる）。確認で `D` が出ること |
| 3-4 | ★他のセッションの変更を巻き込む★ | ★段階0 の前と各コミットの前に `git status --short` を見る★。本書の §9 に無いファイル（`CLAUDE.md`・`docs/decisions.md` の D-180 以外の差分・`docs/handoff/` の他の文書）に変更があれば、★それは他のセッションのもの★。触らない・含めない。★`CLAUDE.md` と `docs/decisions.md` は段階6・8 で直すので、直す前に `git diff -- CLAUDE.md docs/decisions.md` が空（または D-180 の追記だけ）であることを確かめ、他人の差分があれば止まって報告★ |
| 3-5 | ★ロジックまで直してしまう★ | 本書はコメント・契約・テスト・CSS・資料だけ。★`.ts` / `.tsx` の実行される行は、段階3 のテストファイル以外では変えない★（§8 の「記録だけ」も直さない） |
| 3-6 | ★テストを直して緑にする（実装に合わせて期待値を書き換える）★ | 期待値表（AX §3）は正。★本書で足すのは検査の追加だけ★。既存の期待値を変えない |
| 3-7 | ★push する★ | ★監督のレビューが終わるまで push しない★（§10） |

---

## 段階0 — 作業ツリーにある AX の実装をコミットする（直す前に）

1. ★`develop` の本体で作業する★（`.claude/worktrees/` の中ではない）。`git log --oneline -1` が `88ed0c2`（またはその後の docs だけのコミット）であること。
2. `git status --short` を控える。★2026-10-19 時点では AX の45行（変更38・削除1・未追跡6行）★と、★本書（`docs/handoff/指示書AZ_…_20261019.md`）の未追跡1行★。これと違えば、違う行が誰のものかを確かめてから進む（3-4）。
   ★本書は AX のコミットに含めない★（監督がコミットする。まだコミットされていなければ、そのまま未追跡で残しておく）。
3. `npx tsc --noEmit -p .` → `npm run lint` → `npm test` を走らせ、★テストのファイル数と件数を控える★（AX 後の件数。申告では 130ファイル / 3077件）。通らなければコミットせずに報告。

### 0-a. 段階7（別件）の CSS — 4ファイルで1コミット

```
git add -- components/features/detail-log/CleanLogTable.module.css \
  components/features/clean-area/CleanAreaScreen.module.css \
  components/features/facilities/FacilitiesScreen.module.css \
  components/features/ds-logs/DsLogScreen.module.css
git diff --cached --name-status   # この4行だけであること
```

メッセージの例: `style: 清掃詳細ログの施設名の列を 126px → 110px にし、画面幅 1440px で縦スクロールバーが出たときの 11px の横スクロールを消す(指示書AX 段階7・D-180 項10)`
（★`DsLogScreen.module.css:83` の空白は段階4 で別に直す★。ここでは今の内容のままコミットする）

### 0-b. 残りの AX — 1コミット（★1つも漏らさない★）

```
git add -- \
  app/api/__tests__/master-filter-dashboard-reports.test.ts \
  app/api/__tests__/master-filter.test.ts \
  app/api/dashboard/__tests__/route.test.ts \
  app/api/dashboard/route.ts \
  app/api/ds-alerts/route.ts \
  app/api/ds-alerts/__tests__/route.fixtures.test.ts \
  app/api/ds-alerts/__tests__/route.test.ts \
  "app/api/errors/[error_id]/status/__tests__/route.test.ts" \
  app/api/errors/__tests__/route.fixtures.test.ts \
  app/api/errors/__tests__/route.test.ts \
  components/features/ds-alerts/DsAlertsScreen.module.css \
  components/features/ds-alerts/DsAlertsScreen.tsx \
  d-watch-api.yaml \
  docs/decisions.md \
  docs/fixtures.md \
  lib/config/index.ts \
  lib/dashboard/__tests__/aggregate.test.ts \
  lib/dashboard/aggregate.ts \
  lib/db/__tests__/ds-alert-mapping.test.ts \
  lib/db/__tests__/ds-status.test.ts \
  lib/db/__tests__/error-report-mapping.test.ts \
  lib/db/__tests__/error-report-visibility.test.ts \
  lib/db/__tests__/fixture-error-reports.test.ts \
  lib/db/__tests__/robot-error-select.test.ts \
  lib/db/ds-alert-mapping.ts \
  lib/db/ds-status.ts \
  lib/db/error-report-mapping.ts \
  lib/db/index.ts \
  lib/db/precheck-mapping.ts \
  lib/db/robot-error-select.ts \
  lib/ds-alerts/__tests__/edit.test.ts \
  lib/ds-alerts/__tests__/query.test.ts \
  lib/ds-alerts/edit.ts \
  lib/ds-alerts/query.ts \
  lib/error-reports/__tests__/query.test.ts \
  lib/error-reports/query.ts \
  lib/fixtures/ds-alerts.ts \
  lib/fixtures/error-reports.ts \
  lib/fixtures/index.ts \
  lib/i18n.ts \
  lib/types/index.ts \
  scripts/seed-local-db.ts
git diff --cached --name-status   # 42行（M 34・D 1・A 7）であること
git status --short                # 何も残っていないこと（他のセッションの変更を除く）
```

- ★`docs/decisions.md` の差分は D-180 の追記（`:13035-13061` の27行）だけ★であることを `git diff --cached -- docs/decisions.md` で確かめる。D-179 以前の行が変わっていたら止まって報告
- ★`lib/db/precheck-mapping.ts` はコメントだけの変更（`:28-33`）★。AX §9 では「中身を触らない」だったが、D8 で `DsAlertStatus` を消したので古い説明を直したもの（段階8 の記録に逸脱として書く）

メッセージの例（本文に何を・なぜを書く）:
```
feat: D-Sec アラートを robot_error_reports(D-S_CONTROL_FAILURE)から読み、D-Sec 画面に編集モードを付ける(指示書AX・D-180)

- 取得元を control_error_histories から robot_error_reports に切り替え(第11回 P-10=A)。SECURITY_ON・NOT_STARTED は出さない(U1・U2)
- DsAlert の契約: id は string・resolution_status はエラー一覧と同じ語彙・memo→note・status=done は422(D8〜D10)
- 書き込みは PATCH /errors/{error_id}/status の1本。YAML の PATCH /ds-alerts/{id}/status を削除(D6・D7)
- 削除済みの施設・清掃エリアの行をエラー一覧と D-Sec の両方から外し、その PATCH は404(U8)
- fixtures を作り直し(FX-ERR-12〜19)、ローカルのシードを追従
```

### 0-c. AX 前のテスト件数（段階8 の記録に使う）

★AX 前の件数は 125ファイル / 2,963件★（監督の実測 2026-10-16。D-178 のコミット `f07f7bf` 時点。その後 AX までのコミットは資料だけなので件数は同じ）。★測り直さない★（`git switch` で作業ツリーを動かさないこと）。

---

## 段階1 — 契約（`d-watch-api.yaml`）に AX の挙動を書く（指摘1・G1）

★文言は下のとおりにする（意味を変えなければ言い回しは整えてよい）★。YAML のブロック文字列（`description: |`）の字下げを崩さない。

| # | 場所（今の行） | 今 | 直す |
|---|---|---|---|
| 1-1 | `/errors` GET の `description`（`:778-779`） | `**対象は robot_error_reports の全行**(事前チェック・本清掃・予定なし・制御盤・セキュリティ・清掃開始失敗を問わない。robot_id が NULL の行も含む)。` | `**対象は robot_error_reports の行**(事前チェック・本清掃・予定なし・制御盤・セキュリティ・清掃開始失敗を問わない。robot_id が NULL の行も含む)。` の次の行に ★`**ただし、行の施設(facilities)か清掃エリア(sections)が削除済み(deleted_at が NULL でない。日時の値によらない)の行は返さず、meta.total にも数えない**(D-180 項11)。`★ と ★`施設名・分類(facility_name / group_id / customer_id)の解決は削除済みの施設も対象にする(D-180 項11・罠7)ので、削除済みの施設の名前で絞ると0件(200)になる。`★ |
| 1-2 | 同（`:780`） | `既定は対応状況が未解消・対応中の行だけ。include_resolved=true で解消も含める。` | 末尾に ★`status が 0/1/2 以外の行は、どちらでも出さない(例外にもしない。指示書AW 表2 F12)。`★ を足す（AW から書かれていなかった挙動。G1 のついで。監督判断） |
| 1-3 | 同（`:786`） | `制御盤のエラーは serial_number が制御盤のシリアル、セキュリティのエラーと清掃開始失敗は "0" になる(D-158)。` | ★`制御盤のエラーは serial_number が制御盤のシリアル。セキュリティのエラー(SECURITY_ON)と清掃開始失敗(NOT_STARTED)は、第11回 P-8 の回答では "0" だが、ステージングの実データでは "---"(2026-10-19 監督の SELECT・先方投入。D-158 / D-180)。どちらの値でも区分は error_type で見分ける(serial_number の値で見分けない)。`★ |
| 1-4 | `/errors/{error_id}/status` PATCH の `description`（`:834`） | `**robot_error_reports に error_id の行があれば書ける(事前チェックかどうかを問わない)。無ければ404**。` | ★`**robot_error_reports に error_id の行があり、その行の施設・清掃エリアが削除済みでなければ書ける(事前チェックかどうかを問わない)。行が無い、または削除済みの施設・清掃エリアの行(GET /errors に出ない行)なら404**(D-180 項11)。`★ |
| 1-5 | 同 `responses."404".description`（`:885`） | `robot_error_reports に error_id の行が無い(大文字小文字だけ違う id も含む)` | ★`robot_error_reports に error_id の行が無い(大文字小文字だけ違う id も含む)、またはその行の施設・清掃エリアが削除済み(D-180 項11)`★ |
| 1-6 | `ErrorReportItem.serial_number.description`（`:2201`） | `DB の値のまま。制御盤のエラーは制御盤のシリアル、セキュリティ・清掃開始失敗は "0"(D-158)` | ★`DB の値のまま。制御盤のエラーは制御盤のシリアル。セキュリティ・清掃開始失敗は P-8 の回答では "0"、ステージングの実データでは "---"(D-158 / D-180)。区分は error_type で見分ける`★ |
| 1-7 | `/ds-alerts` GET の `description`（`:1464` の次） | （D3 が書かれていない） | ★`robot_error_reports.status が 0/1/2 以外の行は出さない(summary にも数えない。例外にもしない — 1行の想定外の値でダッシュボードを落とさないため。D-180 項5)。`★ を1行足す |

★確かめること（G1）★:
- `grep -n '"0"' d-watch-api.yaml` — シリアルの説明として `"0"` を単独で言っている行が残っていないこと（1-3・1-6 の「P-8 の回答では "0"」は残ってよい）
- `grep -n "全行" d-watch-api.yaml` — `/errors` の対象を「全行」と言い切る行が残っていないこと
- `grep -n "deleted_at\|削除済み" d-watch-api.yaml` — `/errors`・`/errors/{error_id}/status`・`/ds-alerts` の3か所に U8 があること
- ★YAML として読めること★: `npx js-yaml d-watch-api.yaml > /dev/null`（PowerShell なら `> $null`）がエラーを出さないこと

コミット（YAML だけで1つ）: `docs: エラー一覧の契約に、削除済みの施設・清掃エリアの行を出さない・PATCH は404・シリアルは実データで --- を書く(指示書AZ・D-180)`

---

## 段階2 — 古い docstring・コメントを直す（指摘2・G2）

★コメントだけ。実行される行は変えない（3-5）★。

| # | 場所（今の行） | 今 | 直す |
|---|---|---|---|
| 2-1 | `lib/db/index.ts:333`（`DataSource.errorReports()`） | `★\`robot_error_reports\` の全行★が対象（事前チェック・本清掃・予定なし・\`robot_id\` NULL を問わない）。` | `\`robot_error_reports\` の行が対象（事前チェック・本清掃・予定なし・\`robot_id\` NULL を問わない）。★ただし削除済みの施設・清掃エリアの行は外す（\`isVisibleErrorRow()\`。指示書AX U8・D-180 項11）★` |
| 2-2 | `lib/db/index.ts:334` | `キーだけを SQL で \`status IN\`・\`facility_id IN\`・期間で絞って読み、` | `キーだけを SQL で \`status IN\`・\`facility_id IN\`・期間・★施設と清掃エリアの可視性（\`ERROR_ROW_VISIBLE_WHERE\`。写し）★で絞って読み、` |
| 2-3 | `lib/db/index.ts:335`（同じ docstring の続き） | `\`filterSortErrorReportKeys()\` で絞り込み・並べ替え` | `\`filterSortErrorReportKeys()\` で絞り込み（★見えない行（\`visible: false\`）を外すのもここ。正★）・並べ替え` |
| 2-4 | `lib/db/index.ts:339-341`（`DataSource.errorReportById()`） | `★\`error_id === id\` の行があれば返す（事前チェックかどうかを問わない）★。…★期間・施設・状態では絞らない★` | `★\`error_id === id\` の行があり、見える行（\`isVisibleErrorRow()\`。削除済みの施設・清掃エリアでない。指示書AX U8）なら返す（事前チェックかどうかを問わない）★。…★期間・状態・施設の絞り込み条件では絞らない★（★可視性だけは見る★）。★見えない行は null → \`PATCH /errors/{error_id}/status\` は404★` |
| 2-5 | `lib/db/index.ts:1750`（Prisma 版 `errorReports()` の docstring） | `1段目 = キーだけを SQL で \`status IN\`・\`facility_id IN\`・期間に絞って全件読み、` | `1段目 = キーだけを SQL で \`status IN\`・\`facility_id IN\`・期間・可視性（\`ERROR_ROW_VISIBLE_WHERE\`）に絞って全件読み、` |
| 2-6 | `lib/db/index.ts:1758`（同 1段目のコメント） | `// 1段目: キーだけ（★SQL で status / 施設 / 期間を絞る。並べ替え・ページ分けはしない★）。` | `// 1段目: キーだけ（★SQL で status / 施設 / 期間 / 可視性（U8）を絞る。並べ替え・ページ分けはしない★）。` |
| 2-7 | `lib/db/error-report-mapping.ts:9`（冒頭の docstring） | `（\`robot_error_reports\` の全行。D-160 項1）` | `（\`robot_error_reports\` の行。D-160 項1。★削除済みの施設・清掃エリアの行は除く — \`isVisibleErrorRow()\`。指示書AX U8★）` |
| 2-8 | `app/api/errors/route.ts:7`（冒頭コメント） | `★対象は \`robot_error_reports\` の全行★（事前チェック・本清掃・予定なし・制御盤・セキュリティ・清掃開始失敗を問わない）。` | `★対象は \`robot_error_reports\` の行★（事前チェック・本清掃・予定なし・制御盤・セキュリティ・清掃開始失敗を問わない）。★削除済みの施設・清掃エリアの行はデータ層が外す（指示書AX U8。このルートは何もしない）★。` |
| 2-9 | `app/api/errors/[error_id]/status/route.ts:6-7`（冒頭コメント） | `違いは ★\`robot_error_reports\` に \`error_id\` の行があれば書ける（事前チェックかどうかを問わない）★ことだけ` | `違いは ★\`robot_error_reports\` に \`error_id\` の行があれば書ける（事前チェックかどうかを問わない）★ことだけ。★ただし削除済みの施設・清掃エリアの行は \`db.errorReportById()\` が null を返すので404（指示書AX U8。このルートのコードは変えていない）★` |

- ★2-8・2-9 は `app/api/errors/**` だが、本書では ★コメントだけ★ 直してよい（AX §9 の「ルートを触らない」はロジックの話。監督判断 2026-10-19）
- ★直したら `grep -rn "全行" lib/db/index.ts lib/db/error-report-mapping.ts app/api/errors` で、`robot_error_reports` について「全行」と言い切る行が残っていないこと★（`lib/types/index.ts` の `clean_task_reports` の「予定外を含む全行」は別の話なので対象外）

コミット（コメントだけで1つ）: `docs: エラー一覧のデータ層・ルートのコメントに、削除済みの施設・清掃エリアの行を外すこと(U8)を書く(指示書AZ)`

---

## 段階3 — テストの穴を埋める（指摘3・G3）

★既存の期待値は変えない。検査を足すだけ（3-6）★。★各項目で「わざと壊して赤 → 戻して緑」を1回やる★（壊した変更はコミットしない。やったことを作業報告に書く）。

### 3a. ★V8 が「名前の解決が削除済みの施設を落とした」場合でも緑になる★ — `app/api/errors/__tests__/route.test.ts:601-605`

いまの V8 は「0件・`meta.total` 0」だけを見ている。★0件になる理由は2つありうる★: (1) 名前の解決で施設3が解決され、可視性で外れた（正しい）／(2) 名前の解決が施設3を落として `facility_id IN []` になった（罠7 の後退）。いまのテストは両方で緑。

直し方: `expect(body.meta.total).toBe(0);` の後に、★1段目の `where` に施設3が渡っていること★を足す。

```ts
// ★0件の理由が「可視性で外れた」ことを確かめる★ — 名前の解決が削除済みの施設を落とす後退（罠7）だと
//   `facility_id: { in: [] }` になり、上の2行だけでは緑のまま
expect(errorCalls[0].where).toMatchObject({ facility_id: { in: [BigInt(3)] } });
```

- ★このテストでは `db.facilityNameIndex()` が `vi.spyOn` で差し替えてある★（`:319-321`）ので、`lib/db/facility-name-source.ts` 自体の後退はここでは見えない（それは `lib/db/__tests__/facility-name-source.test.ts` の担当）。★ここで守るのは「ルート〜解決〜データ層で、削除済みの施設の ID が落ちないこと」★
- ★壊して確かめる★: V8 の中で一時的に `vi.spyOn(dataSource, "facilityNameIndex")` を「id 3 を除いた索引」を返すように差し替える → 足した1行で赤になること → 戻す

### 3b. ★ダッシュボードのセキュリティバナーの検査が「空と空」★ — `app/api/__tests__/master-filter-dashboard-reports.test.ts:173-177`

いまは `all.security_banner` も `scoped.security_banner` も `[]` を比べているだけで、★ルートの絞り込み（`dsAlertsOfScope` `app/api/dashboard/route.ts:195` → `:212`）を外しても緑のまま★。
（`expect(allowed.size).toBeGreaterThan(0)` はバナーの検査ではない）

★`db.dsAlerts()` を差し替えて、分類の中と外に1件ずつ `security_off` を置き、絞り込みが効くことを確かめる★。
★このファイル（fixtures 経路）で行う★ — `db.dsAlerts()` はデータ層の境目なので経路に依存しない。Prisma 経路（`app/api/dashboard/__tests__/route.test.ts`）で分類を試すと、モックした `@/lib/db/prisma` の動的 import の罠を踏む（指示書AX 4-4-1・指示書AW §13-4 #2）。

1. import を足す: `import { db } from "@/lib/db";`・既存の `import type { … } from "@/lib/types";`（`:14-20`）に `DsAlert` を足す（施設の型は `(typeof facilities)[number]` で取るので `Facility` は要らない）
2. この `describe`（`:118` 付近 `GET /dashboard の分類絞り込み`）の `afterEach`（`:129`）に ★`vi.restoreAllMocks();`★ を足す（差し替えを他のテストに漏らさない）
3. `:173-177` を次に置き換える（コメントも直す）:

```ts
// ★fixtures にも DB にも `security_off` は無い（D-180。バナーは実データでは常に空）★。
//   ★それでもルートの絞り込み（`dsAlertsOfScope`）を守るため、`db.dsAlerts()` を差し替えて
//   分類の中と外に1件ずつ置く★（空と空を比べても絞り込みの検査にならない — 指示書AZ G3）
const inside = facilities.find((f) => allowed.has(f.id))!;
const outside = facilities.find((f) => !allowed.has(f.id))!;
const securityOff = (id: string, f: (typeof facilities)[number]): DsAlert => ({
  id,
  alert_type: "security_off",
  device_serial: "DS-TEST",
  facility_id: f.id,
  facility_name: f.facility_name,
  section_name: "1F売り場",
  detected_at: `${todayJst()}T03:10:00+09:00`,
  resolution_status: "unresolved",
  responded_at: null,
  resolved_at: null,
  note: null,
});
vi.spyOn(db, "dsAlerts").mockResolvedValue([securityOff("T-1", inside), securityOff("T-2", outside)]);
const allB = await dashboard("");
const scopedB = await dashboard("customer_id=1");
expect(allB.security_banner.map((b) => b.facility_name).sort()).toEqual(
  [inside.facility_name, outside.facility_name].sort()
);
expect(scopedB.security_banner.map((b) => b.facility_name)).toEqual([inside.facility_name]);
```

- ★`all` / `scoped` は差し替えの前に取っているので、差し替え後に取り直す（`allB` / `scopedB`）★。差し替えをテストの先頭に置いて `all` / `scoped` をそのまま使ってもよい（その場合 `schedule_progress` の検査が影響を受けないことを確かめる — `dsAlerts()` は予定に関係しない）
- ★`inside` / `outside` が見つかることが前提★（`allowed` は `allowedFacilityIds(null, 1)`。屋号1とそれ以外の施設が fixtures にあることは同じファイルの「`customer_id=1`」のテストが保証している）
- ★施設名が fixtures で重複していないこと★を `facility_name` で突き合わせる前提にしている。重複していたら `section_name` か `since` も合わせて比べる
- ★壊して確かめる★: `app/api/dashboard/route.ts:212` を一時的に `computeSecurityBanner(dsAlerts)` にする → `scopedB` の検査で赤になること → 戻す

### 3c. （任意。時間があれば）

1. ★`app/api/ds-alerts/__tests__/route.test.ts`★ — いまのスタブは ★`where` を無視して全行返す形だけ★（`:83`）。AX 表5 の注意書きは「`where` を評価する形と無視する形の両方」。★`where` の `error_type.in`・`status.in`・`facility.deleted_at`・`section.deleted_at` を評価する形★を1つ足し、表5 V4〜V7 と表1 R1〜R4・R11〜R13 が同じ結果になることを確かめる（知らないキーは例外にする — `app/api/errors/__tests__/route.test.ts:109-145` の `matchErrorWhere()` と同じ作法。★`error_type` の比較は SQL の ci・PAD SPACE を真似なくてよい（完全一致でよい）★）
2. ★`app/api/errors/__tests__/route.test.ts`★ の表5 に、★D-Sec の行（`D-S_CONTROL_FAILURE`・`robot_id` NULL）で削除済みのもの（V5〜V7）★を足し、エラー一覧に出ないこと（既定・`include_resolved=true`・`meta.total`）を確かめる。`guardNullRobotId()` は既にスタブに入っている（`:171`）
3. ★`lib/db/__tests__/fixture-error-reports.test.ts`★ に、既定（未解消・対応中）の ★並び★ を足す（いまは件数だけ。`:132-138`）。期待値は段階5 の 5-2 の並び（★表の時刻から手で導いたもの★）

コミット（テストだけで1つ）: `test: エラー一覧の V8 で削除済みの施設の ID が where に渡ることと、ダッシュボードのバナーが分類で絞られることを確かめる(指示書AZ G3)`

---

## 段階4 — 画面の CSS（指摘4・5）

★`components/features/ds-alerts/DsAlertsScreen.module.css` と `components/features/ds-logs/DsLogScreen.module.css` だけ★。`.tsx` は変えない。
★色は既存の CSS 変数だけ・`font-family` を宣言しない★（ファイル冒頭の注意書き `:1-7`）。

| # | 症状 | 原因（今の行） | 直し方 |
|---|---|---|---|
| 4a | ★編集中、状態の絞り込みボタン（`FilterButton`）とページ送りにマウスを載せると指のカーソル（pointer）が出る★（押せないのに押せそうに見える） | `.toolbar:disabled .select, .toolbar:disabled .statusButtons { cursor: not-allowed }`（`:130-135`）は ★入れ物★ に付いているだけで、中のボタンは `FilterButton.module.css:5` の `cursor: pointer` が勝つ。ページ送り（`.pagerFieldset:disabled` `:160-162`）はカーソルの指定が無い | ★アラート画面（`components/features/alerts/AlertsScreen.module.css:54-57`）と同じ形★: `.toolbar:disabled *, .pagerFieldset:disabled * { cursor: not-allowed; }` を足す。既存の `:130-135` は `opacity` のために残してよい（`cursor` の行は消してよい）。コメント「編集中は中の部品すべてを押せない見た目にする（`AlertsScreen.module.css` と同じ）」 |
| 4b | ★通常モードの対応状況のバッジの幅が JP⇔EN で変わる★（「未解消」⇔ "Unresolved"）。右寄せの列（`.statusColumn` `:243-248` の `align-items: flex-end`）なので、★バッジの左端が動く★ | `.statusBadge`（`:308-315`）に幅の指定が無い | `.statusBadge` に ★`box-sizing: border-box; min-width: 110px; text-align: center;`★ を足す。110px の根拠をコメントに書く（「12px・太字の "In progress" ≒75px ＋ 左右の padding 28px ≒103px。JP/EN・3状態で同じ幅になる」）。★画面で3状態 × JP/EN の幅が全部同じことを確かめる★（違えば最も広いものに合わせて値を上げ、コメントの数字も直す） |
| 4c | ★編集モードで、解消のカードの解消日時が左に寄る★（通常モードでは右寄せ） | `.statusColumnEditing { align-items: stretch }`（`:254-258`）で `.statusTime` が列いっぱいに伸び、文字が左から始まる | ★`.statusColumnEditing .statusTime { text-align: right; }`★ を足す（`.statusTime` の定義 `:318-322` の後） |
| 4d | ★見出し（副題）の下の余白が 20px → 16px に減った★（AX 前より数値カードが4px 上に詰まった） | AX 前は `.header { margin-bottom: 4px }` ＋ `.subtitle { margin-bottom: 16px }` ＝ 20px（`git show 64c4079:components/features/ds-alerts/DsAlertsScreen.module.css` の `:5-19`）。AX で `.subtitle` の余白を消し、`.header { margin-bottom: 16px }`（`:16`）にした | ★`.header` の `margin-bottom` を `20px` にする★。コメント「AX 前の見た目（.header 4px ＋ .subtitle 16px）に合わせる」。★`.title` の `margin: 0 0 4px`（`:24`）は変えない★ |
| 5 | `DsLogScreen.module.css:83` の「約1139px） なので」に余分な半角空白 | 段階7 の書き足し | `約1150px（縦スクロールバーが出ると約1139px）なので` にする（全角括弧の後の半角空白を消す。他は変えない） |

- ★エラー一覧（`ErrorsScreen.module.css`）・アラート（`AlertsScreen.module.css`）は変えない★（写すだけ）
- ★画面での確認は段階7 の 7-5★

コミット（CSS だけで1つ）: `style: D-Sec 画面の編集中のカーソル・バッジの幅・解消日時の寄せ・見出しの下の余白を直す(指示書AZ)`

---

## 段階5 — `docs/fixtures.md`（指摘6）

| # | 場所（今の行） | 今 | 直す |
|---|---|---|---|
| 5-1 | §6（`:295`） | `対象は \`error_type\` が \`D-S_CONTROL_FAILURE\` の行だけ（7行: \`FX-ERR-10\`・\`12\`〜\`17\`）。` | ★`対象は \`error_type\` が \`D-S_CONTROL_FAILURE\` の行だけ（★8行のうち出るのは7行★: \`FX-ERR-10\`・\`12\`〜\`17\`。★\`FX-ERR-19\` は清掃エリアが削除済みなので出ない — U8・表5 V6★）。`★ |
| 5-2 | §13（`:552-557` の「解消済みも表示」の並びの後） | （既定の並びが無い） | ★既定（未解消・対応中）の並びを1段落足す★: `★既定（未解消・対応中）の並び★ — 上の並びから \`FX-ERR-03\`・\`14\`・\`15\`（解消）を除いたもの（14行）: \`FX-ERR-07\` → \`12\` → \`16\` → \`17\` → \`05\` → \`11\` → \`01\` → \`13\` → \`08\` → \`09\` → \`10\` → \`02\` → \`04\` → \`06\`。` ★テストで固定していなければ「（件数はテストで固定。並びは手で導いたもの）」と書く（段階3c-3 を足したら「並びもテストで固定」）★ |
| 5-3 | §13 の表（`:541`〜`:550`）の右端の列 | 「D-Sec にも出る」が `FX-ERR-12`（`:543`）と `16`（`:547`）にだけある | ★D-Sec に出る行すべてに揃える★: `10`（`:541`）→ `制御盤のエラー（D-158 P-8 a）・指示書AX R1（D-Sec にも出る）`／`13`（`:544`）→ `指示書AX R2（D-Sec にも出る）`／`14`（`:545`）・`15`（`:546`）→ `指示書AX R3（★既定では出ない★。D-Sec は「全件」「解消」で出る）`／`17`（`:548`）→ `指示書AX R12（D-Sec にも出る）`。`12`・`16` はそのまま。`19`（`:550`）の「どこにも出ない」はそのまま |

- ★件数・並びは表の時刻（`lib/fixtures/error-reports.ts`）から手で導き、テストを走らせた結果を写さない★（AX 3-4 と同じ）

コミット（資料だけで1つ。段階6 と一緒でもよい）。

---

## 段階6 — 監督の資料を AX に追従させる（指摘8。★監督の依頼で本書に含める★）

★AX §9 では「監督が直す」としていたもの。本書では実装担当が直してよい（監督判断 2026-10-19）★。
★直す前に 3-4 の確認をする（`CLAUDE.md` に他人の未コミットの差分があれば止まって報告）★。

### 6-1. `CLAUDE.md`

| # | 場所（今の行） | 今 | 直す |
|---|---|---|---|
| 6-1a | §4.7 データの取得元の表、「エラー」の行（`:278`）の後半 | `★3区分の見分けと D-Sec アラートの取得元の切り替えは次フェーズ★。` | ★`★D-Sec アラートは \`robot_error_reports\` のうち \`error_type\` が \`D-S_CONTROL_FAILURE\` の行だけ（完全一致。\`SECURITY_ON\`・\`NOT_STARTED\` は出さない）を読み、対応状況・備考はエラー一覧と同じ \`PATCH /errors/{error_id}/status\` で書く（D-180）★。★\`control_error_histories\` は読まない★。★削除済み（\`deleted_at\` が NULL でない）の施設・清掃エリアの行は、エラー一覧（\`meta.total\` も）にも D-Sec アラート（\`summary\`・ダッシュボードも）にも出さず、その PATCH は404（U8。D-180 項11）★。★施設名・分類の解決は従来どおり \`deleted_at\` で絞らない（罠7）★。★区分（ロボット／制御盤／セキュリティ／清掃開始失敗）を画面に作るのは次フェーズ★。`★ |
| 6-1b | §3 の「接続先についての注記」、`:123`（`ダッシュボードは「各清掃エリアの直近の清掃（7日以内）」…`）の次・`:124`（`接続元の制限・TLS`）の前 | （P-8 のシリアルの記述が無い。2026-10-19 grep で確認） | ★1項目足す★: `> - ★\`robot_error_reports.serial_number\` の実値★（2026-10-19 監督の SELECT・先方投入）: セキュリティ（\`SECURITY_ON\`）・清掃開始失敗（\`NOT_STARTED\`）の行は ★\`---\`★（第11回 P-8 の回答は \`0\`）。★\`serial_number\` の値や \`robot_id IS NULL\` で区分を見分けない — \`error_type\` で見分ける★（D-180 項5）。どちらに揃うかは TeamWorks に照会予定（指示書AX §12-1-2）` |

- ★`CLAUDE.md:136`（更新用アカウントは `control_error_histories` の4カラムも UPDATE 可）は変えない★（権限の説明として正しい）

### 6-2. `docs/code-map.md`

★冒頭の改訂の履歴（`:8-21` の「第4版改訂4」の後）に1項目足す★: `★**第4版改訂5: 2026-10-19**（**D-180** / 指示書AX の実装 <段階0-b のコミット> まで）★ — 指示書AX で古くなった D-Sec アラートの記述だけを直しました（取得元を \`robot_error_reports\` に・編集モード・\`PATCH /ds-alerts/{id}/status\` の削除・fixtures の \`ds-alerts.ts\` の削除・削除済みの施設・清掃エリアの行を出さない）。★直した箇所の行番号は <段階0-b のコミット> で確かめました★。それ以外は上のとおりです`

| # | 場所（今の行） | 今（要旨） | 直す（要旨） |
|---|---|---|---|
| 6-2a | `:548`（ダッシュボードのセキュリティバナー） | 取得元 `control_error_histories`・`security_statuses` に列が無いので空 | 取得元は `dsAlerts()`（`robot_error_reports` の `D-S_CONTROL_FAILURE`）。★`security_off` は DB から出ないので実データでは常に空（D-180 項7。コードは残す — U7）★。根拠の行番号は `lib/db/index.ts` の Prisma 版 `dsAlerts()`（今 `:1967-1986`）／`lib/dashboard/aggregate.ts:131-141` |
| 6-2b | `:759` | `DsAlertsScreen.tsx`（★326行。`f2b91fc`★） | ★613行★（<段階0-b のコミット>） |
| 6-2c | `:760` | `GET /api/ds-alerts`（`:103`） | `（:200）`。★書き込みは `PATCH /api/errors/{error_id}/status`（`:96`。`sendDsAlertUpdate()`）★を1行足す |
| 6-2d | `:761`（この画面の数字はどこから） | `control_error_histories`（`occurred_at` / 0 未対応・1 対応中・2 対応済…）＋ `controls.serial_number` | ★`robot_error_reports` のうち `error_type` が `D-S_CONTROL_FAILURE`（`D_SEC_ALERT_ERROR_TYPES`）・`status` 0/1/2 の行。検知時刻は `errored_at ?? created_at`・対応状況は 0 未解消・1 対応中・2 解消・備考は `comment`・シリアルは行の `serial_number`（生値）・施設と清掃エリアは行の `facility_id` / `section_id`（U3）。削除済みの施設・清掃エリアの行は出ない（U8）★。関数は `lib/db/ds-alert-mapping.ts` の `dsAlertsFromErrorRows()` |
| 6-2e | `:764` | ★読み取り専用★。… `PATCH /ds-alerts/{id}/status` の契約だけ | ★編集モードあり★（エラー一覧と同じ操作。`編集` → `保存（N件）`・`キャンセル`。D-161 / D-165）。★書き込みはエラー一覧と同じ `PATCH /errors/{error_id}/status`（`robot_error_reports` の4列）★。`PATCH /ds-alerts/{id}/status` は契約から削除（D-180 項4） |
| 6-2f | `:765` | 集約の話は TeamWorks の DDL 変更待ち | ★集約済み★（第11回 P-10 = A。D-180） |
| 6-2g | `:947`（`/dashboard` の読むテーブル） | `… \`clean_schedules\` \`control_error_histories\`` | `… \`clean_schedules\` \`robot_error_reports\`（D-Sec アラート）` |
| 6-2h | `:958`（`/ds-alerts`） | `\`control_error_histories\`` | `\`robot_error_reports\` \`facilities\` \`sections\``。★`/errors/{error_id}/status` の行の説明に「D-Sec 画面からも呼ばれる」を足す（`:951`）★ |
| 6-2i | `:963-974`（契約にあるがルートが無いもの） | 26パス・ルート23・残り3つ／`/ds-alerts/{id}/status` の行／`（d-watch-api.yaml:1610 / :1699 / :1478。f2b91fc）` | ★`/ds-alerts/{id}/status` の行を消す★。件数は ★数え直す★（2026-10-19 の作業ツリー: YAML のパス28（`grep -c "^  /" d-watch-api.yaml`）・ルート26（`app/api/**/route.ts`）・契約だけ2つ（`/inspections`・`/inspections/{id}`）。段階1 の後にもう一度数える）。括弧の行番号から `:1478` を消し、残り2つの行番号を今の YAML で引き直す |
| 6-2j | `:1748`（テーブルと画面の対応表） | `control_error_histories` → D-Sec アラート / ダッシュボード（バナー） | ★「アプリは読まない（D-180）」★に直す。`robot_error_reports` の行に「D-Sec アラート（`D-S_CONTROL_FAILURE`）」を足す |
| 6-2k | `:1792`（ダッシュボードの D-Sec `N件` とバナー） | 取得元 `control_error_histories`・`security_statuses` に列が無い・DDL 変更待ち | 取得元 `robot_error_reports`（`dsAlerts()`）。★実データでは常に0件 — `security_off` を DB から作らない（U1・D-180 項7）★。★意図した挙動（コードは残す — U7）★。「DDL 変更待ち」は消す |
| 6-2l | `:1801`（サンプルデータのとき） | ★セキュリティ無効バナーはサンプルデータでは出ます★（`lib/fixtures/ds-alerts.ts` に `security_off` の行がある） | ★サンプルデータでも出ません★（`lib/fixtures/ds-alerts.ts` は削除。D-Sec アラートは `errorReportRows` の `D-S_CONTROL_FAILURE` 行から作り、`security_off` は無い — D-180 項9）。★描画は `lib/dashboard/__tests__/aggregate.test.ts`（テスト内で作った `DsAlert`）と `app/api/__tests__/master-filter-dashboard-reports.test.ts`（`db.dsAlerts()` を差し替え。指示書AZ 段階3b）で確かめている★ |
| 6-2m | `:2011-2017`（5B-10 の表と注記） | 未対応 / 対応中 / 対応済み・`control_error_histories.status`・`resolutionStatusFromControlErrorStatus()`・`controls.deleted_at`・`occurred_at`・「まだ作っていません」・`lib/fixtures/ds-alerts.ts` | ★未解消 / 対応中 / 解消★・`robot_error_reports.status`・`resolutionStatusFromRobotErrorStatus()`（`lib/db/precheck-mapping.ts`）・★行の施設・清掃エリアの `deleted_at` が NULL（U8）★・`errored_at ?? created_at`（`detectedAtFromError()`）・★編集モードで書ける（`PATCH /errors/{error_id}/status`）★・★サンプルデータは `errorReportRows` の `D-S_CONTROL_FAILURE` 行（8行・出るのは7行）。セキュリティ無効の行は無い★。種別（札）の行は「★DB からは常に「通信断」（`alert_type: "disconnected"`。D-180 項7）★」 |
| 6-2n | `:2711`（テーブルの一覧） | `control_error_histories` → D-Sec アラート・バナー・`lib/db/index.ts:1632` | ★アプリは読まない（D-180 項8）。シードは `deleteMany` だけ★ |
| 6-2o | `:2783`（書き込み） | `control_error_histories` の4列: 権限上は可・書くコードはまだ無い | そのまま残し、★「D-Sec アラートの対応状況は `robot_error_reports` に書く（D-180）ので、今後も書く予定は無い」★を足す |
| 6-2p | `:2842`（`ds-status.ts`） | 61行・`control_error_histories.status` 0/1/2 の変換も | ★35行★。`controls.status` 0/1 の変換だけ（制御盤エラーの変換2関数は削除。D-180 項8） |
| 6-2q | `:2881`（`DataSource` の表、10 `dsAlerts()`） | `control_error_histories`・`:538` / `:1627` | `robot_error_reports`（`D-S_CONTROL_FAILURE`）・★宣言 `:375`・fixtures 版 `:692`・Prisma 版 `:1977`★ |
| 6-2r | `:2935`（fixtures の一覧） | `ds-alerts.ts` 185行 | ★行を消す★（削除済み）。`error-reports.ts` の行があれば「D-Sec アラートの元（FX-ERR-10・12〜17・19）」を足す |
| 6-2s | `:3097` | `control_error_histories`（D-Sec アラート）の4列を書くときも、この形を真似て…（未着手） | ★D-Sec アラートも `robot-error-write.ts` の同じ1本で書く（`PATCH /errors/{error_id}/status`。D-180）★。`control_error_histories` を書く予定は無い |
| 6-2t | `:3749`（用語の表、対応状態） | D-S側は `control_error_histories.status`（`:391`） | ★D-Sec アラートも `robot_error_reports.status`（エラー一覧と同じ。D-180 項6）★ |
| 6-2u | `:4231`（付録A の fixtures） | `lib/fixtures/ds-alerts.ts` | ★行を消す★ |
| 6-2v | `:4322`（付録B ダッシュボード） | `… control_error_histories …` | `… robot_error_reports …` |
| 6-2w | `:4330`（付録B D-Sec アラート） | `lib/ds-alerts/query.ts` `lib/db/ds-status.ts`／`dsAlerts()` `:1627`／`control_error_histories` `controls` `facilities` `sections`／`GET /api/ds-alerts` | `lib/ds-alerts/query.ts` ★`lib/ds-alerts/edit.ts` `lib/db/ds-alert-mapping.ts`★／`dsAlerts()` ★`:1977`★／★`robot_error_reports` `facilities` `sections`★／`GET /api/ds-alerts`・★`PATCH /api/errors/{error_id}/status`★ |

- ★`:3683`（書いてよいのは `robot_error_reports` / `control_error_histories` の4列）は変えない★（権限の説明として正しい）
- ★行番号はこの表を書いた時点のもの★。上から順に直すと後ろがずれないよう、★下（行番号の大きいほう）から直す★
- ★最後に `grep -n "control_error_histories\|ds-alerts\.ts\|PATCH /ds-alerts\|resolutionStatusFromControlErrorStatus\|DsAlertStatus" docs/code-map.md` を走らせ、残りが `:3683` と、改訂5 の説明・「アプリは読まない」等の意図した記述だけであること★

### 6-3. `docs/spec.md`

| # | 場所 | 今 | 直す |
|---|---|---|---|
| 6-3a | `:18`（画面一覧） | `セキュリティ無効・通信断の検知。対応状況を更新できる` | `制御盤の通信断（\`D-S_CONTROL_FAILURE\`）の検知。対応状況・備考を更新できる（編集モード。D-180）`。★種別の欄「セキュリティ無効」はコードに残る（U6）が DB からは出ないことを括弧で★ |
| 6-3b | `:34`（F-01 のバナー） | `D-Secアラートバナー（セキュリティ無効施設の赤警告）` | 末尾に `（★DB のデータでは出ない — D-Sec アラートに \`security_off\` を作らないため。コードは残す。D-180 項7・U7★）` |
| 6-3c | `:111` | `サマリーカウント（未対応 / 対応中 / 対応済み）` | `サマリーカウント（未解消 / 対応中 / 解消。エラー一覧と同じ文言。D-180 項7b）` |
| 6-3d | `:112` | `種別: セキュリティ無効 / 通信断` | `種別: セキュリティ無効 / 通信断（★DB からは通信断だけ。セレクトは残す — U6★）` |
| 6-3e | `:113` | `対応状況の遷移: 未対応 → 対応中 → 対応済み` | `対応状況の遷移: 未解消 → 対応中 → 解消（編集モードでまとめて保存。D-161 / D-165）` |
| 6-3f | `:114` | `API: \`GET /ds-alerts\`, \`PATCH /ds-alerts/{id}/status\`` | ★`API: \`GET /ds-alerts\`, \`PATCH /errors/{error_id}/status\`（エラー一覧と同じ書き込み。編集モード。D-180）`★ |
| 6-3g | `:201`（M3 のチェックリスト） | `D-Secアラート（F-07）: 一覧 + 対応状況PATCH` | ★`[x]` にはしない★（M3 全体の完了判定は監督が持つ）。末尾に `（2026-10-19 実装。PATCH は /errors/{error_id}/status。D-180）` を足すだけ |

### 6-4. `docs/decisions.md` の D-091 項3（★追記だけ。既存の文は変えない★）

`:3551`（`… ★3値は残る★★`）の次の行に、字下げを揃えて1項目足す:

```markdown
- ★★追記（2026-10-19。D-180）★★: ★`SECURITY_ON`（セキュリティ）は D-Sec アラートに出さない★ことでユーザー確定（指示書AX U1）。
  上の「確認が必要なこと」（バナーをどうするか）は、★バナーのコード（`computeSecurityBanner()`）は残す★ことでユーザー確定（U7）。
  ★DB のデータではバナーは常に空★（`security_off` を作らない）。廃止・転用するかは未決のまま。
  ★`disconnected` 側の3値は `robot_error_reports.status`（0/1/2）になった★（`control_error_histories` は読まない。D-180 項6・項8）
```

コミット（資料だけで1つ。段階5 と一緒でもよい）: `docs: CLAUDE.md・code-map・spec・D-091 を指示書AX(D-180)に追従させる(D-Sec アラートの取得元・編集モード・U8・シリアル ---)`

---

## 段階7 — 全体の確認

1. `npx tsc --noEmit -p .` — 0件
2. `npm run lint` — 0件（★`eslint-disable` を足していない★）
3. `npm test` — ★全件通過★。件数を控える（AX 後の件数以上。3c をやれば増える）
4. ★`USE_FIXTURES=true` で `npm run build`★（PowerShell: `$env:USE_FIXTURES='true'; npm run build`）— 成功（★本体で★。ワークツリーではない）
5. ★画面の確認★（段階4 の CSS）— ★アプリ内ブラウザ（`mcp__Claude_Browser__*`）を使う。Edge（ヘッドレス・CDP を含む）は使わない★（ユーザー指示 2026-10-16）。★ユーザーの `:3000` は止めない★。
   手順は指示書AX 段階10-1 の 1〜3（`:3100` で `next start`・テスト用のトークンはその場で生成し、★文書・コミット・報告に書かない★）。`/ds-alerts` で:
   - 状態ボタン「全件」→ `編集`。★状態ボタン・ページ送りのボタンの `getComputedStyle(el).cursor` が `not-allowed`★（4a）
   - 通常モードで、★`[class*="__statusBadge"]` の `getBoundingClientRect().width` が3状態とも同じ★ことを JP と EN の両方で（4b）
   - 編集モードで、★解消のカード（`FX-ERR-14`・`15`）の `[class*="__statusTime"]` の `getComputedStyle(el).textAlign` が `right`★（4c）
   - ★見出しの下の余白★: 見出しの入れ物（`.header`）の `getBoundingClientRect().bottom` と、数値カードの入れ物の `top` の差が ★20px★（4d）
   - ★スクリーンショットを1枚ずつ★（通常モード JP・EN、編集モード）。終わったら自分で起動した `:3100` の listen プロセスを止める
   - ★アプリ内ブラウザが使えないときは、画面の確認をせずに「監督に任せる」と作業報告に書く★（ほかの手段で代わりにしない）
6. 最後の grep（★結果を作業報告に貼る★）:
   ```
   grep -n "全行" d-watch-api.yaml lib/db/index.ts lib/db/error-report-mapping.ts app/api/errors/route.ts
   grep -n '"0"' d-watch-api.yaml
   grep -n "D-Sec アラートの取得元の切り替えは次フェーズ" CLAUDE.md
   grep -n "control_error_histories\|ds-alerts\.ts\|PATCH /ds-alerts" docs/code-map.md docs/spec.md
   ```
   - 1行目: `robot_error_reports` について「全行」と言い切る行が0件
   - 2行目: 「P-8 の回答では "0"」の形だけ
   - 3行目: 0件
   - 4行目: 段階6-2 の最後に書いた「残ってよいもの」だけ

---

## 段階8 — D-180 の「実装の記録」を書く（指摘7・G4。★最後★）

`docs/decisions.md:13059-13061`（`#### 実装の記録` とその下の1行）を、次の形に書き換える（★D-180 の本文 `:13037-13057` は変えない★）:

```markdown
#### 実装の記録

- ★2026-10-19 指示書AX（Cursor）★: 段階1〜8 を実装。
  - ★コミット★: <0-a の hash>（段階7 の CSS。別件）／<0-b の hash>（AX の残り全部）
  - ★テスト★: AX 前 125ファイル / 2,963件（監督の実測 2026-10-16・`f07f7bf` 時点） → AX 後 130ファイル / 3077件（全件通過）
  - ★画面確認★（監督。fixtures・`:3100`。2026-10-19。当方の fixtures 由来）: D-Sec の数値カード 未解消3・対応中2・解消2・既定5行／
    編集モードで保存 → `PATCH /api/errors/FX-ERR-12/status` 200 → `/errors` に反映／`FX-ERR-18`・`19` は `/errors`・`/ds-alerts` の両方に出ず PATCH は404／
    `status=done` は422／清掃詳細ログ 1440px・50行で `tableWrap` の `scrollWidth == clientWidth`（1139。JP / EN）
  - ★指示書と違う判断★: `lib/db/precheck-mapping.ts:28-33` のコメントを直した（AX §9 は「中身を触らない」。D8 で `DsAlertStatus` を消したので、「D-Sec 側は `pending` / `done`」という古い説明を消した。★コメントだけ・ロジックは変えていない★）
- ★2026-10-19 指示書AZ（AX のレビュー指摘）★: 契約（`/errors` GET・`/errors/{error_id}/status` の404・`ErrorReportItem.serial_number`・`/ds-alerts` の D3）・
  古いコメント・テストの穴（V8 の `where`・ダッシュボードのバナーの絞り込み）・D-Sec 画面の CSS・`docs/fixtures.md`・`CLAUDE.md` / `docs/code-map.md` / `docs/spec.md` / D-091 項3 を直した。
  - ★コミット★: <段階1〜6 の hash を順に>
  - ★テスト★: <段階7 で測った数>（全件通過）
  - ★画面確認★: <段階7-5 の結果と出所（誰が・どこで・いつ）。監督に任せたならそう書く>
  - ★指示書と違う判断★: <あれば。無ければ「無し」>
```

- ★この記録のコミット自体の hash は書かない★（書けない）
- ★「実測」と書く数字には出所を書く★（`CLAUDE.md` §6-6。上の画面確認は「当方の fixtures 由来」）

コミット（`docs/decisions.md` だけで1つ）: `docs: D-180 に指示書AX・AZ の実装の記録(コミット・テスト件数・画面確認・逸脱)を書く`

---

## 8. 記録だけ（★直さない★。作業報告に「確認した・直していない」と書く）

| # | 内容 | 場所 | なぜ直さないか |
|---|---|---|---|
| R1 | 保存で `PATCH` が成功しても、応答の `id` が行の `id` と違うと `dsAlertWithResolution()` が例外を投げ、★その行は「保存できませんでした」と出る★ | `components/features/ds-alerts/DsAlertsScreen.tsx:95-102` → `lib/ds-alerts/edit.ts:20` | サーバーは同じ `id` を返す（`errorReportById(id)` の `===`）ので理論上だけ。表3 S2 で決めた挙動 |
| R2 | `section_id` が存在しない清掃エリアを指す行（FK 切れ）では、`errorReportById()` が404ではなく500になりうる（`section: { select: … }` の必須リレーション） | `lib/db/index.ts:1796-1811`・`lib/db/robot-error-select.ts:94` | `robot_error_reports.section_id` に外部キーがあり、起きにくい |
| R3 | EN の訳が無い（または暫定）: 「即時対応」「進行中」「完了」「全種別」「セキュリティ無効」「通信断」・副題・0件の文言 | `lib/i18n.ts` | ★EN はあとで一括（方針）★。範囲外 |
| R4 | `/alerts`（事前チェック）で削除済みの施設・清掃エリアの行が出るか | 指示書AX §12-2-5 | 範囲外（監督が確かめる） |

---

## 9. 触ってよいもの・触ってはいけないもの

### 触ってよい

- 段階0: §段階0 に挙げた46ファイル（コミットするだけ。中身は変えない）
- `d-watch-api.yaml`（段階1 の7か所）
- `lib/db/index.ts`・`lib/db/error-report-mapping.ts`・`app/api/errors/route.ts`・`app/api/errors/[error_id]/status/route.ts`（★段階2 のコメントだけ★）
- `app/api/errors/__tests__/route.test.ts`・`app/api/__tests__/master-filter-dashboard-reports.test.ts`（段階3a・3b）／（任意）`app/api/ds-alerts/__tests__/route.test.ts`・`lib/db/__tests__/fixture-error-reports.test.ts`（段階3c）
- `components/features/ds-alerts/DsAlertsScreen.module.css`・`components/features/ds-logs/DsLogScreen.module.css`（段階4）
- `docs/fixtures.md`（段階5）
- `CLAUDE.md`（段階6-1 の2か所）・`docs/code-map.md`（段階6-2）・`docs/spec.md`（段階6-3）・`docs/decisions.md`（★段階6-4 の D-091 項3 への追記と、段階8 の D-180 の「実装の記録」だけ★）

### 触ってはいけない

- ★`docs/handoff/指示書AY_制御盤のログをD-Secログ画面から取り出す_20261019.md`・`docs/handoff/設計_制御盤ログの取り出し_20261019.md`・`docs/handoff/TeamWorks確認事項_第13回_*`・`docs/handoff/回答待ち一覧_*`・`docs/handoff/pdf/*`★（他のセッションの作業）
- 指示書AX・本書（指示書AZ）
- ★`docs/decisions.md` の D-091 項3 の既存の文・D-179 とそれ以前の本文・D-180 の本文（`:13037-13057`）★
- 段階2・3 以外の `.ts` / `.tsx`（★ロジックを変えない★）。特に `components/features/ds-alerts/DsAlertsScreen.tsx`・`lib/ds-alerts/edit.ts`・`lib/db/ds-alert-mapping.ts`・`lib/dashboard/aggregate.ts`・`app/api/dashboard/route.ts`・`app/api/ds-alerts/route.ts`
- `components/features/errors/**`・`components/features/alerts/**`・`components/ui/**`
- ★`prisma/schema.prisma`・`lib/generated/prisma/**`・`lib/db/robot-error-write.ts`・`lib/db/local-guard.ts`★
- ★施設名・分類の解決（`lib/facilities/resolve-by-name.ts` / `resolve-by-master.ts` / `lib/db/facility-name-source.ts` / `facility-group-source.ts`）★
- `d-watch-mock.jsx`・`docs/handoff.md`
- ★AW の表1 E8 のシリアル `'0'` のテスト行★（§0 の「変えないもの」）
- ★認証情報（パスワード・接続文字列・DB のユーザー名・生成したトークン）を文書・コード・テスト・コミット・作業報告に書くこと★
- ★`git add -A` / `git add .`・push★

---

## 10. コミットの計画

| 順 | 中身 | 段階 |
|---|---|---|
| 1 | 段階7（別件）の CSS 4本 | 0-a |
| 2 | AX の残り全部（42ファイル） | 0-b |
| 3 | `d-watch-api.yaml` | 1 |
| 4 | コメント（`lib/db/index.ts` ほか4本） | 2 |
| 5 | テスト（3a・3b。3c をやればここに含めるか別のコミット） | 3 |
| 6 | CSS（`DsAlertsScreen.module.css`・`DsLogScreen.module.css`） | 4 |
| 7 | 資料（`docs/fixtures.md`・`CLAUDE.md`・`docs/code-map.md`・`docs/spec.md`・D-091 項3）。2つに分けてもよい | 5・6 |
| 8 | D-180 の「実装の記録」 | 8 |

- ★`git add` はファイルパスを明示する★。各コミットの前に `git diff --cached --name-status` で中身を確かめる
- メッセージには ★何を変えたか★ と ★なぜ（指示書AZ・どの指摘か）★ を書く
- ★push しない★。★監督がコミットを見てから、監督の指示で develop に push する★。PR の作成とマージは daichi のレビューの後（D-154）

---

## 11. 期待される結果

- 作業ツリーが空（他のセッションの変更を除く）で、develop にコミット 7〜9個が積まれている（未 push）
- `d-watch-api.yaml` を読めば、エラー一覧が削除済みの施設・清掃エリアの行を返さず `meta.total` にも数えないこと、その PATCH が404になること、シリアルが実データで `---` であること、D-Sec が `status` 3以上を出さないことが分かる
- `lib/db/index.ts` の `DataSource` の宣言を読んで、`errorReports()` / `errorReportById()` が可視性で絞ることが分かる
- ★V8 は名前の解決が施設3を落とすと赤になり、ダッシュボードのバナーの検査は絞り込みを外すと赤になる★（壊して確かめた）
- D-Sec 画面: 編集中のボタンは禁止のカーソル／バッジの幅は JP・EN・3状態で同じ／編集中の解消日時は右寄せ／見出しの下は 20px
- `docs/fixtures.md`・`CLAUDE.md`・`docs/code-map.md`・`docs/spec.md`・D-091 項3 が AX の挙動と食い違わない
- D-180 の「実装の記録」に、コミット・テスト件数の前後・画面確認（出所つき）・逸脱が書いてある
- `tsc` 0件・`lint` 0件・`npm test` 全件通過・`USE_FIXTURES=true npm run build` 成功

---

## 12. 完了条件

- [ ] 段階0: AX を2つのコミットに分けて積んだ（0-a は CSS 4本だけ・0-b は42ファイル全部）。`git status --short` に AX の残りが無い。★push していない★
- [ ] 段階0: AX 前のテスト件数を測った（または測れなかった理由を書いた）
- [ ] 段階1: YAML の7か所を直し、§段階1 の grep と `npx js-yaml` が通った
- [ ] 段階2: コメント9か所を直し、「全行」と言い切る行が残っていない。★実行される行は変えていない★
- [ ] 段階3: 3a・3b を足し、★それぞれ一度わざと壊して赤になるのを確かめ、戻した★（壊した変更はコミットしていない）。3c は（やったなら）何をやったか
- [ ] 段階4: CSS の5か所を直した
- [ ] 段階5・6: `docs/fixtures.md`・`CLAUDE.md`・`docs/code-map.md`・`docs/spec.md`・D-091 項3 を直し、§段階6-2 の grep の残りが意図したものだけ
- [ ] 段階7: `tsc` 0件・`lint` 0件・`npm test` 全件通過（件数）・`USE_FIXTURES=true npm run build` 成功・画面の確認（アプリ内ブラウザ。または「監督に任せる」と書いた）
- [ ] 段階8: D-180 の「実装の記録」を書いた
- [ ] §8 の R1〜R4 は直していない
- [ ] 作業報告に: コミット一覧（hash とメッセージ）／テスト件数（AX 前・AX 後・AZ 後）／壊して確かめた結果（3a・3b）／画面確認の結果（出所: 当方の fixtures 由来）／段階7-6 の grep の結果／本書と違う判断をしたところ
