Newer
Older
client_dwatch / docs / handoff / 指示書AZ_指示書AXのレビュー指摘を直す_20261019.md

指示書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が渡っていること★を足す。

// ★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 を次に置き換える(コメントも直す):
// ★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項目足す:

- ★★追記(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 は変えない★):

#### 実装の記録

- ★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 の結果/本書と違う判断をしたところ