inspections の一時非表示(D-079 項3)| 項目 | 内容 |
|---|---|
| 実行環境 | ★Cursor 内の Claude が実装します★(.claude/commands/d-watch.md の役割分担表を参照) → 実際にはユーザーの直接指示によりClaude Code(Sonnet 5。監督役+opusサブエージェント委譲)が実行した(2026-09-08) |
| 実行状態 | ★完了(2026-09-08。D-084)★。段階0〜11すべて実施。段階10(ブラウザ確認)はcurl代替のため一部未確認 |
| 実行順 | ★指示書K / 指示書I とはコードのファイルが重なりません★(K は lib/reports/ lib/theme-status.ts lib/judge/advice.ts 系、I は lib/auth/ proxy.ts 系)。★ただし d-watch-api.yaml と docs/decisions.md / docs/handoff.md は3本とも触ります★。★同時に走らせないこと★ |
| 取得する決定番号 | ★着手直前に grep -n "^### D-0" docs/decisions.md で最終番号を確認すること★。★★本指示書の作成中(2026-09-08 18:11)に、別セッションが D-083(本指示書作成のための調査結果)を追記しました。したがって最初の空き番号は D-084 です★★。★指示書K(D-079 を予定→すでに別作業で使用済み)と指示書I が先に走るとさらに繰り上がります★。★2026-09-07 に D-068 の二重採番が実際に起きています。必ず自分で確認してください★ |
| 前提 | ★D-079 項3★(docs/decisions.md:2146 以降。他メンバーとの合意。作業順序の1番目) / ★D-032★(:198。system の限定スコープ) / ★D-031★(:194。点検記録は P1 スコープ) / ★D-053★(:330。機能しないUIを出さない) / ★D-060★(:403。end_time は整形済み文字列) / ★D-080★(:2202。contract は10桁文字列) / ★D-072 項7★(:1052。点検記録は最後) |
| 段階数 | ★12段階★(段階0〜段階11) |
| 着手前の基準 | npm test が ★22ファイル / 461テスト 全パス★、npx tsc --noEmit エラー0、npm run lint 0(★2026-09-08 実測。Vitest 4.1.11★)。着手直前に自分で実行して実測値を基準にすること |
| 作成 | 2026-09-08(作成時点の決定事項最終番号 D-082) |
実行後はこの表と、文書末尾の「実行状態」表を更新してください。
★この指示書を読んでいるあなたへ★
.claude/commands/d-watch.mdに「実装は Cursor 側、Claude Code は指示書作成まで」とありますが、 これは2つの環境の役割分担です。Cursor の中で動いている Claude は実装担当です。 この指示書を渡されたなら、調査や改訂ではなく実装を行ってください。
★この2件はどちらも「YAML に無いものを画面に出すかどうか」という契約の話です。★ ★先に決めないと、段階1(API契約の修正)の内容が変わります。実装を始める前に必ず確認してください。★
system 画面のスコープ★| # | 事実 |
|---|---|
| 1 | ★D-032(docs/decisions.md:198-201)は「表示設定」と「運用設定」の2つを実装対象としている★ |
| 2 | ★しかし d-watch-api.yaml に「表示設定」「運用設定」のエンドポイントは1本も無い★。あるのは /settings/advice(:554-599)だけで、★これは実装済み★(app/api/settings/advice/route.ts) |
| 3 | ★「表示設定」(ダッシュボードの表示項目 ON/OFF。d-watch-mock.jsx:1182-1217)は、設定の永続化とダッシュボード側の読み取り対応の両方が必要★で、★本作業(マスタ画面3枚)の範囲を超えます★ |
★当方の推奨スコープ(この指示書はこれで書いています)★
| # | 内容 |
|---|---|
| 1 | ★「運用設定」タブのみ★を作る |
| 2 | ★読み取り専用★。閾値(完了率 90/70/10、事前チェック 60分/30分、エスカレーション L2=2日/L3=3日)を ★lib/config/ から読んで表示する★(★ハードコード禁止★。CLAUDE.md §7) |
| 3 | アドバイス文言の一覧を ★GET /api/settings/advice(実装済み)★ から取得して表示する |
| 4 | ★画面に「編集は P1 後半で対応します」と明示する★ |
| 5 | ★「表示設定」タブは作らない★ |
★理由★: ★D-053(docs/decisions.md:330-334)が「機能しない絞り込みUIを画面に出さない」と定めています★。 「固定の選択肢だけがあって何も起きないUIは、不具合と区別できない」というのがその理由です。 ★動かないトグルやテキストボックスを並べるのは D-053 に抵触します。★ ★一方、「読み取り専用です」と明示した表示は抵触しません★ — 何も起きないのではなく、何も起きないことが宣言されているためです。
★この方針で問題ないかを着手前に確認してください。★ ★編集まで作るなら、先に d-watch-api.yaml に「表示設定」「運用設定」のエンドポイントを追加する必要があります★ (CLAUDE.md §6-1「API契約を変えたくなったら、先に d-watch-api.yaml を直す」)。その場合この指示書の段階1と段階6を書き直してください。
facilities の検索ボックスと API パラメータの食い違い(★調査で新たに判明★)★★モックの検索ボックスは1つですが、YAML のクエリパラメータは3つに分かれています。そのままでは繋がりません。★
| 側 | 実際の姿 |
|---|---|
★モック(d-watch-mock.jsx:977)★ |
★入力欄は1つ★(placeholder = 施設名 / シリアル / 住所)。:998-1002 のフィルタは ★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 の6項目を OR で★ 部分一致させている |
★YAML(d-watch-api.yaml:739-753)★ |
★facility_name / serial / address の3パラメータ★。一覧APIのパラメータは通常 ★AND★ で組む |
★1つの入力欄の値を3つのパラメータに同時に入れると、AND になって「施設名にも住所にもシリアルにも同じ文字列が含まれる施設」しかヒットしません(=ほぼ常に0件)。★ ★これは「検索が壊れている」ように見える挙動です。★
★当方の推奨(この指示書はこれで書いています)★: ★q パラメータを /facilities に追加する★
| # | 内容 |
|---|---|
| 1 | ★q を追加★ — ★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 を OR で部分一致★(モックの挙動そのまま) |
| 2 | ★既存の facility_name / serial / address は残す★。3つは互いに AND、q はそれらと AND(q 内部だけが OR)。★画面は q だけを使う★ |
| 3 | ★前例がある★ — /ds-devices の q(d-watch-api.yaml:613-616「施設名 or D-S制御盤シリアル番号(部分一致)」)と /inspections の q(:815-818)。★既存2本と同じ形にするので新しい概念は増えません★ |
★q を足す=API契約の変更です。段階1(YAML を先に直す段階)で行ってください★(CLAUDE.md §6-1)。 ★この方針で問題ないかを着手前に確認してください。★ ★もし「YAML を増やしたくない」なら、代案は「画面の入力欄を3つに分ける(モックから外れる)」ですが、CLAUDE.md §5 は「モックが画面レイアウトの正」としているため、★当方は推奨しません★。★どちらを採るにせよ、採った理由を段階11 で記録すること★。★/schedules も同じ問題を抱えています(facility_name / serial の2つ。:773-781)。同じ判断を適用すること★
★D-079 項3(他メンバーとの合意。docs/decisions.md:2146-2179)で、作業順序の1番目に置かれたものです。★
1. プレースホルダ画面(facilities / schedules / system) ★inspections はメニューから隠してください★
★理由(メンバーの言)★: メニューを開いて空画面が出るのはデモで印象を損なう。 ★デモの目標は9月中に PPIH 向け★(同 :2155)。
★4画面はすでに PlaceholderScreen で、いずれも5行しかありません★(実測):
app/(dashboard)/facilities/page.tsx → <PlaceholderScreen title="施設ロボットマスタ" /> app/(dashboard)/schedules/page.tsx → <PlaceholderScreen title="スケジュール管理" /> app/(dashboard)/system/page.tsx → <PlaceholderScreen title="システム管理" /> app/(dashboard)/inspections/page.tsx → <PlaceholderScreen title="点検記録" />
したがって本作業は ★「プレースホルダを作る」ではなく「プレースホルダを実装済み画面に置き換える」★ です。
| 材料 | 状態 |
|---|---|
| API契約 | ★d-watch-api.yaml:731(/facilities)/ :768(/schedules)に定義済み★ |
| TS型 | ★lib/types/index.ts:317-322(RobotSummary)/ :324-347(Facility)/ :349-360(Schedule)★ |
| fixtures | ★lib/fixtures/facilities.ts 12件 / lib/fixtures/schedules.ts 13件★ |
db.facilities() / db.schedules() |
★lib/db/index.ts:99-104 に fixtures 実装あり(全件返す)★。インターフェース宣言は :60-61 |
GET /api/settings/advice |
★実装済み★(app/api/settings/advice/route.ts) |
| 閾値の設定値 | ★lib/config/index.ts に全部ある★(GRADE_THRESHOLDS / ESCALATION_THRESHOLDS / PRECHECK_MINUTES_BEFORE) |
| ★不足しているもの★ | ★API ルート2本(app/api/facilities/route.ts / app/api/schedules/route.ts)と画面3枚★ |
★app/api/ に facilities / schedules / inspections のルートは存在しません★(実測。あるのは clean-logs / dashboard / ds-alerts / ds-devices / prechecks / reports / settings の7つ)。
| # | 禁止 | 理由 |
|---|---|---|
| 1 | ★モックの実在の店舗名・住所・電話番号・氏名・メールをコピーすること★ | CLAUDE.md §7 / D-043。★d-watch-mock.jsx:54-63 の ROBOTS 9件は実在の値★(MEGAドンキ渋谷本店 / 渋谷区宇田川町28-6 / 03-5428-4086 / shibuya@donki.co.jp 等)。★1文字もコピーしないこと★。★必ず lib/fixtures/facilities.ts を使う★(架空値に置換済み)。★d-watch-mock.jsx:81-88 の INSPECTIONS 7件にも実在の人名・店舗名が入っています★(段階1-6 参照。★今回は使いませんが、目に入るので明記しておきます★) |
| 2 | ★lib/fixtures/schedules.ts に active: true のスケジュールを追加すること★ |
★ダッシュボードの既定表示が異常系になります★。詳細は ★段階3 の地雷警告★ を必ず読むこと |
| 3 | ★既存の active: true スケジュールの削除・無効化・weekdays の書き換え★ |
同上。特に補完ペア(id23↔id30 / id25↔id26) |
| 4 | ★id: 24 の削除★ |
★唯一の active: false★(lib/fixtures/schedules.ts:94-105)。判定ロジックの確認に使う(同ファイル :17-18 / :46-47) |
| 5 | ★動かないUIを画面に出すこと★ | D-053。★モックの 📥 インポート / + 新規追加 ボタン(d-watch-mock.jsx:978-979)は onClick の無い飾り★。★運用設定の入力欄も同じ★ |
| 6 | ★閾値(90 / 70 / 10、60分 / 30分、L2=2日 / L3=3日)をハードコードすること★ | CLAUDE.md §7。★必ず lib/config/ から読む★ |
| 7 | ★customers.contract を参照すること★ |
CLAUDE.md §7 / D-010。★facilities.contract のみが正★ |
| 8 | ★contract を数値として比較すること★ |
★D-080★。★varchar(10) の文字列で桁位置がサービスに対応★。Number("0000000000") は例外を出さずに 0 になるので、★全施設が「契約なし」になってもエラーもテスト失敗も出ません★ |
| 9 | ★lib/db/ の prismaSource に手を付けること★ |
実DB接続は別作業。notImplemented のままにする |
| 10 | ★点検記録(inspections)の実装に手を出すこと★ |
★D-072 項7★(docs/decisions.md:1052-1058)。★写真の置き場所・バケット・署名URLが未決★。先に作ると「写真が表示できない画面」ができる |
| 11 | ★git add -A を使うこと★ |
過去に別作業の途中ファイルを巻き込む事故が起きています。★必ずファイルパスを明示★ |
| 12 | ★メインDBへの書き込み★ | CLAUDE.md §7 / D-042。今回そもそも書き込みは発生しません |
| 13 | ★components/layout/PlaceholderScreen.tsx を削除すること★ |
★inspections がまだ使っています★(段階7 で inspections は残す) |
| 段階 | 内容 | コミット |
|---|---|---|
| 段階0 | 前提の確認(★読むだけ★) | コミットなし |
| 段階1 | ★API契約を直す★(d-watch-api.yaml)+ 型を足す |
段階1で1コミット |
| 段階2 | GET /api/facilities を作る(+ lib/facilities/query.ts + テスト) |
段階2で1コミット |
| 段階3 | GET /api/schedules を作る(+ lib/schedules/query.ts + テスト)★地雷あり★ |
段階3で1コミット |
| 段階4 | 施設ロボットマスタ画面(F-08) | 段階4で1コミット |
| 段階5 | スケジュール管理画面(F-09) | 段階5で1コミット |
| 段階6 | 運用設定画面(F-10、★読み取り専用★) | 段階6で1コミット |
| 段階7 | inspections をメニューから隠す |
段階7で1コミット |
| 段階8 | i18n | 段階8で1コミット |
| 段階9 | テスト(★段階ごとに実行済みのはず。ここは最終確認★) | コミットなし |
| 段階10 | ブラウザで動作確認 | コミットなし |
| 段階11 | 記録と push | 段階11で1コミット + push |
★段階ごとに npx tsc --noEmit / npm run lint / npm test を実行し、通ってからコミットすること★(D-050。docs/decisions.md:308)。
| 資料 | 何を読むか |
|---|---|
docs/spec.md:90-96 |
★F-08 施設ロボットマスタ(参照のみ)★。★:95「登録・更新はD-Security側の画面で行うため、D-WatchはGETのみ」★ |
docs/spec.md:98-101 |
★F-09 スケジュール(参照のみ)★。「Pudu Cloud由来。変更はPudu Cloud管理画面で行う」 |
docs/spec.md:103-109 |
★F-10 システム管理(P1限定スコープ)★。サブタブごとの扱いの表 |
docs/decisions.md:194-196(D-031) |
点検記録は P1 スコープ。★隠すのはデモまでの一時対応であって、スコープは変えない★ |
docs/decisions.md:198-201(D-032) |
system の限定スコープ。★実装する = 表示設定 / 運用設定★、★実装しない = 通知設定 / 顧客管理 / グループ管理★、★スコープ外 = ユーザー管理 / 権限管理 / 監査ログ★ |
docs/decisions.md:330-334(D-053) |
★機能しない絞り込みUIを画面に出さない★。「固定の選択肢だけがあって何も起きないUIは、不具合と区別できない」 |
docs/decisions.md:403-412(D-060) |
★Schedule.end_time は「翌04:30」の整形済み文字列で返す★。2830 → "翌04:30" |
docs/decisions.md:1052-1058(D-072 項7) |
★点検記録は最後★。写真の置き場所・バケット・期限付き署名URLが未決 |
docs/decisions.md:2146-2179(D-079 項3) |
★本作業の発端★。★:2171「schedules の fixtures 地雷は、プレースホルダ画面の指示書に必ず入れる」★/★:2173「inspections は『デモまで一時的に隠す』で正しい。D-031 のスコープは変えない」★ |
docs/decisions.md:2202-2245(D-080) |
★facilities.contract は10桁文字列★。★数値比較禁止★ |
docs/fixtures.md:165-178(§7) |
施設ロボットマスタの用意すべきケース |
docs/fixtures.md:180-198(§8) |
★スケジュールの補完ペア設計★。段階3 の地雷の一次資料 |
docs/fixtures.md:235-268(§12) |
★ダッシュボードの日付ごとの期待値表★。★当日は planned=10 / completed=9 / anomaly 出ない★ |
CLAUDE.md §4.1 / §4.6 / §6-1 / §7 / §9.3 / §9.4 |
判定閾値 / 契約フラグ / YAMLが先 / 禁止事項 / API規約 / 判定ロジックのテスト |
| ファイル | 何の雛形か |
|---|---|
★app/(dashboard)/alerts/page.tsx(5行)★ |
★ページの雛形★。"use client" は付けず、Screen コンポーネントを1つ返すだけ |
★components/features/alerts/AlertsScreen.tsx(208行)★ |
★画面の雛形★。"use client" / useTheme() / apiFetch / loading・error・0件 の3分岐(:148-153)/ CSS Modules |
components/features/alerts/AlertsScreen.module.css |
★CSS Modules の雛形★。★色は var(--tx-d) 等の CSS変数で書く★(app/globals.css:1-40)。★インラインの色が要るときだけ THEME_TOKENS[theme] を使う★(AlertsScreen.tsx:48) |
★app/api/ds-devices/route.ts★ |
★APIルートの雛形★。withRequestId / parseXxxQuery の422 / logApiError の500 / meta の組み立て |
★lib/ds-devices/query.ts★ |
★クエリ純粋関数の雛形★。parseDsDeviceQuery / filterDsDevicesByQ(:58-68。★大文字小文字を無視した部分一致★)/ sortDsDevices |
★lib/ds-devices/__tests__/query.test.ts★ |
★テストの雛形★。row(overrides) ヘルパ + describe ごとの分割 |
app/api/prechecks/route.ts / lib/prechecks/query.ts |
同上のもう1例(ds-devices と見比べて共通の作法を掴む) |
| # | 内容 |
|---|---|
| 1 | ★lib/fixtures/schedules.ts に active: true を足すとダッシュボードが壊れます★。★段階3 の地雷警告を必ず読んでから触ること★ |
| 2 | ★cwd のドライブレターは必ず大文字 C:\★。小文字だと Vitest が全滅します(既知の罠) |
| 3 | ★--reporter=basic は Vitest 4 で削除済み★。使うとロードに失敗しても exit 0 になり、★壊れていることに気づけません★。素の npm test を使うこと |
| 4 | ★lint は npm run lint(= eslint)★。★next lint は Next 16 で削除済み★ |
| 5 | 決定番号は追記直前に最終番号を確認する。★2026-09-07 に D-068 の二重採番が実際に起きました★ |
| 6 | ★d-watch-mock.jsx:54-63 の ROBOTS は実在の店舗情報★。★見た瞬間にコピーしたくなる形をしていますが、絶対に使わないこと★ |
git status がクリーンであることnpm test / npx tsc --noEmit / npm run lint を実行し、★実測値を控えたこと★ (作成時点の基準は 22ファイル / 461テスト / tsc 0 / lint 0。古くなっている可能性があります)d-watch-api.yaml)+ 型を足す★CLAUDE.md §6-1「API契約を変えたくなったら、先に d-watch-api.yaml を直す」に従い、この段階を最初に置きます。★ 実装だけ変えて YAML と乖離させないためです。
Schedule スキーマに facility_id が無い★d-watch-api.yaml:1361-1375:
Schedule: # :1361
type: object
description: モックのSCHED(s/f/d/st/en/on)に対応
properties:
id: { type: integer, example: 21 }
serial_number: { type: string, example: "8111R5628060011" }
facility_name: { type: string, example: "バリューマート渋谷本店" }
weekdays:
type: string
example: "1111111"
description: 日月火水木金土(清掃する曜日=1)。link_schedules同様の7桁形式
weekdays_label: { type: string, example: "毎日", description: 表示用ラベル(サーバ生成) }
start_time: { type: string, example: "02:00" }
end_time: { type: string, example: "03:00" }
active: { type: boolean }
★facility_id がありません。★ しかし ★lib/types/index.ts:352 には facility_id: number があり、fixtures 13件すべてが値を持っています★。 ★YAML に追加してください★(serial_number の後、facility_name の前が自然):
facility_id: { type: integer, example: 1 }
★「型と fixtures にあるものが YAML に無い」は、YAML を正とすると実装のほうが違反している状態です。★ ★実装側を削るのではなく YAML に足すのは、facility_id が「施設別の絞り込み」に将来必要になるためです★ (DsDevice(:1254-1258)も同じ形で facility_id と facility_name の両方を持っています)。
q パラメータを追加する(★確認2 の回答が「推奨どおり」だった場合★)★★確認2 でユーザーが q の追加を承認した場合のみ実施してください。★
/facilities(:739-753)に追加:
- name: q
in: query
schema: { type: string }
description: 施設名 or 都道府県 or 住所 or シリアル番号 or メーカー or 機種(部分一致・大文字小文字を区別しない)
/schedules(:773-781)に追加:
- name: q
in: query
schema: { type: string }
description: 施設名 or シリアル番号(部分一致・大文字小文字を区別しない)
★既存の facility_name / serial / address は消さないこと★。 ★description に「画面の検索欄は q を使う。個別パラメータは互いに AND、q は個別パラメータと AND(q の内部だけが OR)」と明記すること★。 ★この AND / OR の関係を書いておかないと、次に触る人が必ず迷います。★
Facility / Schedule / Meta を実装と突き合わせる★★facility_id 以外にも食い違いが無いか、必ず自分の目で突き合わせてください。★
| YAML | TS | 突き合わせ結果(★作成時点の実測★) |
|---|---|---|
Facility(:1337-1359) |
lib/types/index.ts:324-347 |
★一致★(id / facility_name / prefecture / address / phone / manager_name / charger_name / email / monitoring_enabled / d_security_enabled / robots) |
Facility.robots[](:1352-1359) |
RobotSummary(:317-322) |
★一致★(id / maker / model / serial_number) |
Schedule(:1361-1375) |
:349-360 |
★facility_id だけ不足★ → 1-1 で追加 |
Meta(:1004-1009) |
lib/types/index.ts の Meta |
total / page / per_page。★一覧APIは必ずこれを返す★(CLAUDE.md §9.3) |
★突き合わせて新たな食い違いを見つけたら、この表に追記したうえで直し、段階11 で記録すること。★
AdviceSetting の TS 型が存在しない(★調査で判明★)★★d-watch-api.yaml:1229-1252 に AdviceSetting スキーマがありますが、lib/types/index.ts に対応する型がありません★(実測。grep -n "AdviceSetting" lib/types/index.ts が 0件)。 app/api/settings/advice/route.ts の GET は ★インラインのオブジェクトリテラル★ を返しています。
★CLAUDE.md §9.3「APIレスポンスは必ず型を定義してから実装する」に従い、lib/types/index.ts に AdviceSetting を追加してください★(段階6 の画面がこれを使います)。 ★YAML の :1229-1252 に合わせること★:
| フィールド | 型 | ||||||
|---|---|---|---|---|---|---|---|
rule |
`"R1" \ | "R2" \ | "R3" \ | "R4" \ | "B1" \ | "B2" \ | "B3"` |
phase |
`"A" \ | "B"` | |||||
level |
`1 \ | 2 \ | 3` | ||||
icon |
string |
||||||
title |
string |
||||||
text |
string |
||||||
actions |
string[] |
||||||
condition |
string(★発火条件の説明。編集不可★) |
||||||
customized |
boolean(既定値から変更されているか) |
★AdviceRuleId は lib/config/advice-rules.ts:16 にすでにあります★。★lib/types/ から lib/config/ を import するか、型を再定義するかは、既存の依存方向に合わせて判断してください★(★どちらにせよ2箇所に別々の union を書かないこと★)。
★ルート側(app/api/settings/advice/route.ts の GET)を、この型を返すように注釈すること★。★ロジックは変えないこと★ — 型注釈を足すだけです。
★InspectionDetail.photos の項目名が YAML と TS で食い違っています。★
| 側 | 実際の姿 | ||
|---|---|---|---|
★YAML(d-watch-api.yaml:1402-1405)★ |
★item_type★ / enum: [brush, dust_box, filter, squeegee, suction_hose, waste_tank, brush_back](★英語 enum★) |
||
★TS(lib/types/index.ts:364-377)★ |
★item★ / `InspectionItemName = "ブラシ" \ |
"ダストボックス" \ | ...`(★日本語リテラル★) |
★キー名も値の形も違います。★ ★今回は inspections を実装しないので直しません★(禁止事項10 / D-072 項7)。 ★段階11 で「既知の不整合として未解決のまま残っている」ことを docs/decisions.md に記録してください。★ ★点検記録に着手する人が、実装を始める前にこれを解決する必要があります。★
d-watch-api.yaml に実在の人名が漏れている(★調査で判明。ついでに直すこと★)★★★d-watch-api.yaml の2箇所に、実在の人名がそのまま example として書かれています★(実測):
| 行 | 内容 |
|---|---|
★d-watch-api.yaml:861★ |
inspector_name: { type: string, maxLength: 100, example: "香原秀俊" } |
★d-watch-api.yaml:1383★ |
inspector_name: { type: string, example: "香原秀俊" } |
★出所は d-watch-mock.jsx:81-88 の INSPECTIONS 7件★(★点検者名が全件この名前。実在の店舗名も入っています★)。 ★CLAUDE.md §7「モックに残っている実在の住所・電話番号をそのまま使うこと」の禁止に該当します★(D-043 と同趣旨)。
★この段階で d-watch-api.yaml を開いているので、ついでにダミー名へ置換してください★(例: "点検 太郎")。 ★2行だけの変更で、inspections の実装には一切踏み込みません★(禁止事項10 に抵触しません)。 ★d-watch-mock.jsx 側は書き換えないこと**★ — ★モックは「画面レイアウト・文言・遷移の正」として保存されている資料で、本作業の対象外です★。 ★段階11 で「YAML の inspector_name の example をダミー名に置換した」ことを記録すること★。
d-watch-api.yaml の Schedule に facility_id があること★(grep -n "facility_id" d-watch-api.yaml で Schedule 配下にヒットすること)/facilities と /schedules に q があり、★AND / OR の関係が description に書かれていること★lib/types/index.ts に AdviceSetting があること★InspectionDetail.photos の不整合を直していないこと★(記録するだけ。★直すと段階11 の記録と矛盾します★)grep -n "香原" d-watch-api.yaml が 0件であること★(1-6)npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★この段階ではまだ全部通るはず★)GET /api/facilities を作る| ファイル | 内容 |
|---|---|
★新規★ app/api/facilities/route.ts |
ルート本体。★雛形は app/api/ds-devices/route.ts★ |
★新規★ lib/facilities/query.ts |
★フィルタ・ページングの純粋関数★。★雛形は lib/ds-devices/query.ts★ |
★新規★ lib/facilities/__tests__/query.test.ts |
テスト。★雛形は lib/ds-devices/__tests__/query.test.ts★ |
★必ず ds-devices / prechecks の現物を開いて、エラー形式・meta・ログの作法を写してください。★ ★この指示書に書いてある形と現物が違ったら、★現物が正★です(この指示書のほうが古い可能性があります)。★
★db.facilities()(lib/db/index.ts:99-101)は全件返すだけです。★ これは意図した設計で、lib/db/index.ts:50-54 にこう書かれています:
データソースが実装すべきインターフェース。 フィルタや集計はこの層では行わず、APIルート側で組み立てます (実DB接続時にクエリへ落とすときの差分を小さくするため)。
★この方針に従ってください。lib/db/ にフィルタを足さないこと。★
★注記(実測)★: ★prismaSource 側(lib/db/index.ts:153-164)は facilities / schedules / inspections / inspectionDetail のいずれも notImplemented() です★。 ★したがって今回作る API ルート2本は USE_FIXTURES のときだけ動きます★。★これは意図した状態です★(実DB接続は別作業。禁止事項9)。 ★prismaSource を実装しようとしないこと。段階11 で「実DB接続時には別途 prismaSource の実装が要る」ことを申し送りとして記録してください。★
| パラメータ | 挙動 |
|---|---|
q |
★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 を OR で部分一致★(★確認2 で承認された場合★) |
facility_name |
施設名の部分一致 |
serial |
★robots[].serial_number を横断して部分一致★(下記 2-4) |
address |
住所の部分一致 |
page / per_page |
PAGINATION(lib/config/index.ts)の defaultPerPage: 50 / maxPerPage: 200。★不正値でも422にせず既定値・上限へ丸める★(parseDsDeviceQuery と同じ挙動) |
★大文字小文字を無視した部分一致にすること★(モックの挙動。d-watch-mock.jsx:998-1002 が .toLowerCase() している)。 ★filterDsDevicesByQ(lib/ds-devices/query.ts:59-68)がそのまま雛形になります。★
serial は施設が持つロボットを横断する★★施設は0台〜3台のロボットを持ちます。★ serial の部分一致は ★どれか1台でも一致すればその施設をヒットさせる★ 形にしてください。
// イメージ(実装は任せます) items.filter((f) => f.robots.some((r) => r.serial_number.toLowerCase().includes(needle)))
★robots が空配列の施設で落ちないこと★ — some() は空配列に対して false を返すので自然に安全ですが、★テストで固定してください★(lib/fixtures/facilities.ts の ★id12(フレッシュタウン湖畔店)が robots: []★)。
meta を返す★一覧APIは必ず meta: { total, page, per_page } を返す★(CLAUDE.md §9.3)。 ★total は「フィルタ後・ページング前」の件数★(app/api/ds-devices/route.ts の const total = sorted.length; と同じ)。
★/facilities に summary はありません★(d-watch-api.yaml:754-765 は items と meta だけ)。 ★SummaryListResponse ではなく items + meta のレスポンス型を使うこと★(lib/types/index.ts の既存の一覧レスポンス型を確認してから決めること)。
★YAML にもモックにも並び順の指定がありません。★ ★id の昇順で安定させてください★(sortDsDevices が「安定化のためだけの規則」として serial_number 昇順にしているのと同じ趣旨)。 ★理由を関数の docstring に書くこと★ — 「運用上の優先度を表すものではなく、画面の順序がリロードで変わらないようにするための規則」。
CLAUDE.md §9.4)| # | ケース | 期待 |
|---|---|---|
| 1 | ★0件★(空配列を渡す) | [] / meta.total = 0。★落ちない★ |
| 2 | ★1件★ | そのまま返る |
| 3 | ★部分一致(施設名)★ | メガバリュー で複数ヒット |
| 4 | ★大文字小文字違い★ | 8111r で 8111R5628060011 にヒットする |
| 5 | ★該当なし★ | [] / meta.total = 0 |
| 6 | ★ページング境界★ | per_page=5 で page=1 / page=2 / page=3(★最終ページが端数になること★)/ 範囲外の page=99 は [] だが ★meta.total は全件数のまま★ |
| 7 | ★ロボット0台の施設★ | serial 検索で落ちない・ヒットしない |
| 8 | ★複数台の施設★ | 3台のうち3台目のシリアルで検索してもヒットする(lib/fixtures/facilities.ts の ★id7 が3台★) |
| 9 | ★q の OR★ |
住所の文字列で検索して施設名が違う施設がヒットする |
| 10 | ★複数パラメータの AND★ | facility_name と address を同時に指定して、両方満たす施設だけが残る |
| 11 | ★per_page の丸め★ |
per_page=9999 → 200(maxPerPage)/ per_page=0 → 1 / page=-1 → 1 |
★テストは fixtures ではなく row(overrides) ヘルパで組んだ合成データで書くこと★(lib/ds-devices/__tests__/query.test.ts:11-21 の作法)。 ★fixtures に依存すると、fixtures を1件足しただけでテストが落ちます。★
app/api/facilities/route.ts / lib/facilities/query.ts / lib/facilities/__tests__/query.test.ts が存在することlib/db/index.ts に変更が入っていないこと★(git diff --stat lib/db/ が空)npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★テスト数が増えていること★)GET /api/schedules を作る| ファイル | 内容 |
|---|---|
★新規★ app/api/schedules/route.ts |
段階2 と同じ形 |
★新規★ lib/schedules/query.ts |
フィルタ・ページングの純粋関数 |
★新規★ lib/schedules/__tests__/query.test.ts |
テスト |
| パラメータ | 挙動 |
|---|---|
q |
★施設名 / シリアル を OR で部分一致★(★確認2 で承認された場合★) |
facility_name |
施設名の部分一致 |
serial |
★serial_number の部分一致★(★Schedule は1レコードに1シリアルなので、段階2 のような横断は不要★) |
page / per_page |
段階2 と同じ |
並び順は ★id の昇順★(段階2 と同じ理由)。
lib/fixtures/schedules.ts に active: true を追加しないこと★★★★この地雷は「エラーも出ず、テストも通るのに、ダッシュボードの既定表示が異常系になる」タイプです。★ ★D-079 項3(docs/decisions.md:2171)が「この指示書に必ず入れる」と名指しした項目です。★
★lib/dashboard/aggregate.ts:93 の1行がダッシュボードの「清掃予定件数」です★:
// lib/dashboard/aggregate.ts:89-93
const dow = weekdayIndex(date);
const planned =
dow === null
? 0
: schedules.filter((s) => s.active && s.weekdays[dow] === "1").length; // :93
★施設を区別しない、フラットな件数カウントです。★ どの施設のログかは一切参照しません。
一方 lib/fixtures/clean-logs.ts の当日分は ★曜日に関係なく毎日必ず10行★ 生成されます(実行日からの相対生成)。 ★この2つを常に一致させるために、fixtures は「どの曜日でも planned = 10 になる」よう設計されています。★
| 構成 | 内訳 |
|---|---|
| 補完ペア① | ★id25(平日のみ 0111110)+ id26(土日のみ 1000001)★ → 全曜日を過不足なくカバー → ★常に合計1件★ |
| 補完ペア② | ★id23(月水金 0101010)+ id30(日火木土 1010101、id23 の反転)★ → ★常に合計1件★ |
毎日(1111111) |
id21 / id22 / id27 / id28 / id29 / id31 / id32 / id33 の ★8件★ |
| ★合計★ | ★1 + 1 + 8 = 10。どの曜日でも常に10件★ |
| 操作 | 症状 |
|---|---|
★active: true を1件追加する★ |
★planned が 11 になる★。当日ログは10行のまま → 画面が ★「9 / 11 完了」★ と出る(components/features/dashboard/ScheduleProgressCard.tsx:25-27 が {completed} / {planned} 完了 を描画)。さらに ★app/api/dashboard/route.ts:84-92 の data.anomaly warn が出続けます★ |
★曜日パターン付きで active: true を追加する★ |
★その曜日に当たった日だけ症状が出ます★。★一番タチが悪い★ — 実装した日には再現せず、数日後に「なぜか壊れている」状態で発見されます |
★既存の active: true を削除・無効化する★ |
★planned が 9 以下になる★。同じく anomaly が出ます |
★補完ペアの weekdays を書き換える★ |
★曜日によって planned が変動します★。id23↔id30 / id25↔id26 の対応が崩れるため |
| ★id24 を削除する★ | ★planned は変わりません(active: false なので)が、★唯一の無効スケジュール★ が消えて判定ロジックの確認ケースが失われます★ |
| 操作 | 可否 |
|---|---|
★active: false の追加★ |
★何件でも安全★。s.active が先に false になるため planned に寄与しません |
フィールドの追加(facility_id など) |
安全 |
start_time / end_time / weekdays_label の変更 |
安全(planned は active と weekdays しか見ていないため) |
★lib/fixtures/__tests__/schedules.test.ts(59行)が番人です。★
| 行 | 内容 |
|---|---|
:29 |
describe("fixtures の不変条件: schedules と clean-logs の当日行数(D-050)") |
:36 |
test("前提: 当日分の清掃ログが1件以上存在する") |
:41 |
★7曜日分をループで生成するテスト★ — 「◯曜日: 有効スケジュールの該当件数が当日の清掃ログ行数と一致する」 |
| ★合計★ | ★8テスト★(前提1 + 7曜日) |
★lib/fixtures/schedules.ts を変更したら必ず npm test を実行し、この8テストが通ることを確認してください。★
★この設計を説明するときに「D-050」と書かないでください。★
| 番号 | 実際の内容 |
|---|---|
docs/decisions.md:308 の D-050 |
★「検証(型チェック・lint・テスト)が通った時点で作業ブランチにコミットする」★ — ★補完ペア設計とは無関係★ |
lib/fixtures/schedules.ts のコメント内の「D-050」 |
★補完ペア設計を指している★(:21 / :83 / :108 / :121 / :170 / :184 / :197 / :209) |
★番号で参照すると必ず混乱します。★ ★参照するなら docs/fixtures.md §8(:180-198)と §12(:235-268)を使ってください。★ ★既存コメント内の「D-050」表記は、今回の作業では書き換えないこと★(本作業の範囲外で、差分が増えるだけです)。
prismaSource 実装者向け。★今回は実装しません★)★★今回 prismaSource には手を付けません(禁止事項9)★が、 ★lib/schedules/query.ts の docstring に次の4点を書き残してください。★ ★実DB接続時に「型エラーもテスト失敗も出ないまま静かに壊れる」箇所だからです。★
| # | 内容 |
|---|---|
| 1 | ★論理が反転している★ — prisma/schema.prisma:512 の CleanSchedule.inactive(Int @default(0)。★0 = 有効★)。API/TS は active: boolean。★active: Boolean(row.inactive) と書くと全件反転します★。正しくは active: row.inactive === 0 |
| 2 | ★カラム名が違う★ — DB は weeks(prisma/schema.prisma:504、VarChar(7))、API/TS は weekdays |
| 3 | ★時刻は HHMM の4桁文字列★(prisma/schema.prisma:506 / :509)。★end_time の「時」は 24〜29 を取りうる★("2830" = 翌日4:30)。★素朴な HH:MM パースは壊れます★。★API は D-060 に従い "翌04:30" の整形済み文字列で返す★ |
| 4 | ★weekdays_label は DB に存在しません★。★サーバ側で weeks から生成する必要があります★ |
| # | ケース | 期待 |
|---|---|---|
| 1 | ★0件★ | [] / meta.total = 0 |
| 2 | ★1件★ | そのまま返る |
| 3 | ★部分一致(施設名)★ | ヒットする |
| 4 | ★大文字小文字違い★ | 8111r で 8111R... にヒット |
| 5 | ★該当なし★ | [] |
| 6 | ★ページング境界★ | 段階2 の #6 と同じ |
| 7 | ★active: false の行も返る★ |
★一覧は有効・無効の両方を返す★(画面が「有効」列で見せ分ける。★API 側でフィルタしないこと★) |
| 8 | ★q の OR★ |
シリアルの一部で検索して施設名が違う行がヒット |
| 9 | ★per_page の丸め★ |
段階2 の #11 と同じ |
app/api/schedules/route.ts / lib/schedules/query.ts / lib/schedules/__tests__/query.test.ts が存在することgit diff --stat lib/fixtures/schedules.ts が空であること★(★この段階では fixtures を1文字も触っていないはず★)lib/fixtures/__tests__/schedules.test.ts の8テストが全部通ること★lib/schedules/query.ts の docstring に書かれていること★npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★テスト数が増えていること★)| ファイル | 内容 |
|---|---|
★新規★ components/features/facilities/FacilitiesScreen.tsx |
画面本体 |
★新規★ components/features/facilities/FacilitiesScreen.module.css |
スタイル |
★差し替え★ app/(dashboard)/facilities/page.tsx |
PlaceholderScreen → FacilitiesScreen |
page.tsx は ★app/(dashboard)/alerts/page.tsx と同じ5行の形★ にしてください。
CLAUDE.md §5)★d-watch-mock.jsx:971-1035 を実際に開いて写してください。★ 以下は要点です。
| 要素 | 内容 |
|---|---|
| h1 | ★施設ロボットマスタ★(:975)。★サブタイトルなし★(AlertsScreen.tsx:98 のような subtitle は付けない) |
| 検索input | ★1つ★。placeholder = ★施設名 / シリアル / 住所★(:977) |
表の列(★10列・原文のまま★。:986-995) |
★施設名 / 都道府県 / 住所 / 電話番号 / 責任者名 / 担当者名 / メール / 監視 / D-Sec / ロボット(メーカー / 機種 / シリアル)★ |
監視 列(:1013) |
★true → ○(緑 c.ok)/ false → ー(c.txM)★。中央寄せ・fontSize 16 |
D-Sec 列(:1014) |
★true → ○(★シアン c.ac★)/ false → ー(c.txM)★ |
ロボット列(:1015-1025) |
★1台1行★。★メーカーをピル(Pill)★ / ★機種は通常テキスト★ / ★シリアルは monospace★ |
フッタ(:1032) |
★全{n}施設★ |
横スクロール(:983-984) |
★minWidth: 1300 相当の表を overflow-x: auto で包む★ |
| 施設名 | fontWeight: 600(:1006) |
| メール | ★monospace・fontSize 11★(:1012) |
| 行 | verticalAlign: top(:1005。★ロボット複数台のとき先頭行に揃うようにするため★) |
★色は CSS変数(var(--ok) / var(--ac) / var(--tx-m) 等)で書くこと★(app/globals.css:1-40)。 ★Pill は color を文字列で受け取る(components/ui/Pill.tsx)ので、メーカーのピルだけは THEME_TOKENS[theme].pr を渡してください★(AlertsScreen.tsx:48, 166 が前例)。
📥 インポート と + 新規追加 ボタンは実装しないこと★★| 事実 | 出典 |
|---|---|
| ★登録・更新は D-Security 側の画面で行うため、D-Watch は GET のみ★ | ★docs/spec.md:95★ / d-watch-api.yaml:736 |
★モックのボタンには onClick がありません★ |
★d-watch-mock.jsx:978-979★(★飾りです★) |
| ★動かないボタンを出すのは D-053 に抵触します★ | docs/decisions.md:330-334 |
★ボタン自体を出さないこと。★ ★グレーアウトして置いておくのも駄目です★ — 「あるのに使えない」は「不具合と区別できない」の典型です。
★d-watch-mock.jsx:54-63 の ROBOTS 9件は、実在の店舗名・住所・電話番号・メールです。★
例: MEGAドンキ渋谷本店 / 渋谷区宇田川町28-6 / 03-5428-4086 / shibuya@donki.co.jp
★1文字もコピーしないこと★(CLAUDE.md §7 / D-043)。 ★必ず lib/fixtures/facilities.ts を使ってください★ — こちらは架空値に置換済みです:
メガバリューマート中央本店 / 東京都○○区1-2-3 / 03-0000-0001 / store001@example.com
★画面のプレビュー用のダミー、コメント内の例、テストの期待値、いずれにも使わないこと。★
★モックには0件の分岐がありません。★ ★AlertsScreen.tsx:151-153 の作法に倣ってください★:
{!loading && !error && items.length === 0 && (
<div className={styles.empty}>{t("該当する施設はありません")}</div>
)}
★loading / error / 0件 / データあり の4分岐すべてを作ること★(AlertsScreen.tsx:148-205 が全部の例です)。
apiFetch(lib/api/client.ts)を使う★。エラーは ApiFetchError の serverMessage を優先し、無ければ既定文言(AlertsScreen.tsx:78-81)per_page は PAGINATION.maxPerPage(200)を渡す★(AlertsScreen.tsx:64 と同じ。★fixtures は12件なので1ページに収まります★)q を送る★(★確認2 で承認された場合★)meta.total を使うこと★(items.length ではありません。★ページングが入ったときに嘘の数字になります★)/facilities が PlaceholderScreen でなくなっていることgrep -rn "MEGAドンキ\|ドンキ\|donki.co.jp\|宇田川町\|03-5428" components/features/facilities/ が 0件★grep -n "インポート\|新規追加" components/features/facilities/ が 0件★npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス| ファイル | 内容 |
|---|---|
★新規★ components/features/schedules/SchedulesScreen.tsx |
画面本体 |
★新規★ components/features/schedules/SchedulesScreen.module.css |
スタイル |
★差し替え★ app/(dashboard)/schedules/page.tsx |
PlaceholderScreen → SchedulesScreen |
d-watch-mock.jsx:1037-1069)| 要素 | 内容 |
|---|---|
| h1 | ★スケジュール管理★(:1041) |
| ★注意★ | ★ナビのラベルは 📅 スケジュール(components/layout/AppShell.tsx:22)で、h1 と一致しません★。★これはモックどおりです★(モックのナビも 📅 スケジュール、h1 は スケジュール管理)。★揃えないこと★ |
| 検索input | placeholder = ★施設名 / シリアル★(:1042) |
表の列(★5列★。:1047-1051) |
★シリアル / 施設名 / 曜日 / 時間 / 有効★ |
シリアル |
★monospace・fontSize 12★(:1057) |
時間 |
★{start_time} - {end_time}★(:1060) |
有効 列(:1061) |
★on → ●(緑 c.ok)/ off → ○(★赤 c.ng★)★。★fontSize 18・中央寄せ★ |
| 無効行 | ★行全体 opacity: 0.5★(:1056) |
| ★ボタン・行クリック★ | ★無し。完全な参照専用★ |
| ★フッタ★ | ★モックには無い★。★付けないこと★(施設マスタと違って 全{n}件 の表示はモックに存在しません) |
曜日 は weekdays_label を出す★★weekdays(7桁の "1111111")を画面で解釈しないこと。★ ★weekdays_label(サーバ生成の表示用ラベル。"毎日" / "月水金" / "平日のみ" / "土日のみ" / "日火木土")をそのまま出してください。★
★理由★: CLAUDE.md §9.6「判定結果はAPIから受け取る。フロントで再計算しない」と同じ趣旨です。 ★7桁の解釈ロジックが画面とサーバの2箇所にあると、曜日の起点(日曜始まり)がズレたときに片方だけ直る事故が起きます。★
end_time をパースしないこと★★end_time は「翌04:30」のような整形済み文字列で来ます★(★D-060★。docs/decisions.md:403-412)。
| DB の値 | API が返す値 |
|---|---|
0300 |
"03:00" |
2830 |
★"翌04:30"★ |
★画面で時刻をパースして計算しないこと。★ ★{start_time} - {end_time} と並べるだけです。★ ★fixtures には日跨ぎのケースがあります★ — ★id27(メガバリューマート港南総本店)が start_time: "23:30" / end_time: "00:30"★(lib/fixtures/schedules.ts:133-143)。 ★この行が「23:30 - 00:30」と表示されて崩れないことを、段階10 で目視確認してください。★
段階4 と同じ作法(AlertsScreen.tsx:151-153)。
/schedules が PlaceholderScreen でなくなっていることweekdays の7桁を画面で解釈していないこと★(grep -n "weekdays\[" components/features/schedules/ が 0件)end_time をパース・計算していないこと★(grep -n "split(\":\")\|parseInt\|Number(" components/features/schedules/ を見て、時刻の計算が無いこと)opacity: 0.5 になっていることnpx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス★着手前確認1 の結果に従ってください。以下は当方の推奨スコープ(運用設定のみ・読み取り専用)での手順です。★
| ファイル | 内容 |
|---|---|
★新規★ components/features/system/SystemScreen.tsx |
画面本体 |
★新規★ components/features/system/SystemScreen.module.css |
スタイル |
★差し替え★ app/(dashboard)/system/page.tsx |
PlaceholderScreen → SystemScreen |
★モックは9タブありますが(d-watch-mock.jsx:1156-1166)、D-032(docs/decisions.md:198-201)で実装対象は2つだけです。★
| タブ | D-032 での扱い | 今回 |
|---|---|---|
| 表示設定 | ★実装する★ | ★作らない★(確認1。永続化とダッシュボード側の対応が本作業の範囲を超えるため。★P1 後半の宿題として段階11 で記録★) |
| ★運用設定★ | ★実装する★ | ★作る(読み取り専用)★ |
| 通知設定 / 顧客管理 / グループ管理 | ★実装しない★(D-Security側画面を流用) | 作らない |
| ユーザー管理 / 権限管理 / 監査ログ | ★スコープ外★(P2以降) | 作らない |
★タブが1つしかないなら、タブUIそのものを出さないことも検討してください。★ ★1つしか選べないタブ列は「他にもあるはずなのに無い」という誤解を生みます。★ ★当方の推奨は「タブUIを出さず、h1 システム管理 の下にセクション見出し 運用設定 を置く」★ですが、★判断は実装者に委ねます。採った形を段階11 で記録すること★。
ops タブが二重定義されている★★モックの system にはバグがあります。実装前に知っておいてください。★
| 箇所 | 内容 |
|---|---|
d-watch-mock.jsx:1158 |
{ id: "ops", label: t("運用設定") } ★1回目★ |
★d-watch-mock.jsx:1164★ |
★{ id: "ops", label: t("運用設定") } 2回目(同じ id)★ |
d-watch-mock.jsx:1221 |
{sysTab === "ops" && ( ★本文1回目★ |
★d-watch-mock.jsx:1628★ |
★{sysTab === "ops" && ( 本文2回目★ |
★React は同じ条件の分岐を2つとも描画するので、モックでは運用設定のカードが縦に2つ並びます。★ ★どちらかに寄せる必要があります。★
★当方の推奨は :1628 側です★:
| 理由 | 内容 |
|---|---|
| 1 | ★カード1枚に3セクションが統合されている★(:1630 が1枚のカード、その中に事前チェック / 判定閾値 / エスカレーション)。:1221 側はカードが分かれている |
| 2 | ★× グレードに「上記未満」表記がある★(:1670)。:1221 側にはこの配慮が無い |
| 3 | ★「変更はDFAシステム管理者のみ」の注記がある★(:1633)。★権限の話が入っている=後から書かれたように見える★ |
★ただし、どちらが正かはモックからは判断できません。★ ★「推奨」であって「確定」ではないことを理解したうえで採用し、採った側を段階11 で記録してください。★
★CLAUDE.md §7 の禁止事項です。必ず lib/config/ から読んでください。★
★lib/config/index.ts の実際のエクスポート名を自分で読んで確認すること。★ ★作成時点の実測は次のとおりです★:
| 表示するもの | 読む先 | 作成時点の値 |
|---|---|---|
| 事前チェック 第1回 / 第2回 | ★PRECHECK_MINUTES_BEFORE★ |
[60, 30] as const |
| ◎ の閾値 | ★GRADE_THRESHOLDS.excellent★ |
90 |
| ○ の閾値 | ★GRADE_THRESHOLDS.good★ |
70 |
| △ の閾値 | ★GRADE_THRESHOLDS.poor★ |
10 |
| Lv2 の連続日数 | ★ESCALATION_THRESHOLDS.level2Days★ |
2 |
| Lv3 の連続日数 | ★ESCALATION_THRESHOLDS.level3Days★ |
3 |
★PRECHECK_MINUTES_BEFORE は配列です★。★「第1回 = [0]、第2回 = [1]」と決め打ちせず、配列を map して「第{i+1}回チェック: {n}分前」と描くほうが安全です★(将来3回になっても壊れません)。
★モックと確定仕様が食い違っています。★
| 側 | ◎ | ○ | △ | × |
|---|---|---|---|---|
★モック(d-watch-mock.jsx:1660-1663)★ |
★90 以上★ | ★70 以上★ | 10 以上 | 上記未満 |
★CLAUDE.md §4.1(★確定仕様★)★ |
★90% 超★ | ★70% 超★ | ★10% 以上 70% 以下★ | 10% 未満、または未実施 |
★lib/config/index.ts のコメント(★実装★)★ |
★「この値を超えると ◎(90.0 は ○ になる)」★ | ★「この値を超えると ○(70.0 は △ になる)」★ | 「この値を下回ると ×(10.0 は △ のまま。D-020b)」 | — |
★CLAUDE.md §5 の「モックが文言の正」より、§4.1 の確定仕様が上位です。★ ★画面には「90% 超」「70% 超」「10% 以上」と書いてください。★ ★モックの「以上」を写すと、90.0% が ◎ に見える誤った説明になります。★ ★この判断を段階11 で記録すること。★
| セクション | 内容 |
|---|---|
| ★事前チェック設定★ | 第1回 60分前 / 第2回 30分前(★PRECHECK_MINUTES_BEFORE から★)。説明「清掃開始予定時刻の何分前にロボット状態をチェックするか」 |
| ★完了率の判定閾値★ | ◎ 90% 超 / ○ 70% 超 / △ 10% 以上 / × 上記未満(★6-5 の文言★)。★GradeBadge(components/ui/GradeBadge.tsx)が使えるか確認すること★ |
| ★アドバイス エスカレーション閾値★ | Lv2 = 2日以上連続 / Lv3 = 3日以上連続。★注記「『連続』はカレンダー日ではなくスケジュール存在日の連続」を必ず入れること★(★D-026★。docs/decisions.md:122。CLAUDE.md §4.5 も同旨) |
| ★アドバイス文言の一覧★ | 下記 6-7 |
★GET /api/settings/advice(実装済み)から取得してください。★ ★レスポンスは { items: AdviceSetting[] }★(段階1-4 で型を足しています)。7件(R1〜R4 / B1〜B3)が返ります。
| フィールド | 表示 |
|---|---|
rule |
ルールID(R1 等) |
icon / level |
アイコンとレベルバッジ(level は 1=注意 / 2=警告 / 3=重大。lib/config/advice-rules.ts:22) |
title |
見出し |
text |
推定原因 |
actions |
推奨アクション(★配列なのでリストで出す★) |
★condition★ |
★発火条件。「編集不可」であることを画面に明示すること★(d-watch-api.yaml:1246-1249「発火条件の説明(編集不可)」/ lib/config/advice-rules.ts:30) |
customized |
既定値から変更されているか。★「編集済み」バッジに使えます★ |
★GET だけを使うこと。PATCH(d-watch-api.yaml:572-599)は今回使いません。★ ★lib/config/advice-rules.ts を画面から直接 import しないこと★ — ★API は既定値に運用設定の編集内容を重ねて返します★(app/api/settings/advice/route.ts の loadAdviceRules())。★設定ファイルを直接読むと、編集済みの文言が画面に出なくなります。★
★注意★: ★指示書K の段階7-B が lib/config/advice-rules.ts:111(B2)と :121(B3)の condition 文字列を書き換えます★。 ★この画面は API 経由で読むので影響を受けませんが、★指示書K を先に実行した場合は表示される文言が変わります★。★不具合ではありません。★
★画面のどこか(見出しの近く、または各セクションの上)に明示してください。★
★この画面は現在★参照のみ★です。設定値の編集は P1 後半で対応します。★
★動かないトグル・入力欄・保存ボタンを置かないこと★(D-053)。 ★モックの <input type="number">(:1643 / :1648 / :1668 / :1684 / :1689)は ★defaultValue だけで onChange も保存先も無い飾り★ です。★値をテキストとして表示してください。★
/system が PlaceholderScreen でなくなっていることgrep -nE "\b(90|70|10|60|30)\b" components/features/system/SystemScreen.tsx に閾値の数値リテラルが無いこと★(★すべて lib/config/ 由来★。★CSS の px 値は対象外なので .module.css は除いて確認すること★)condition が「編集不可」と明示されていること★<input> / <button>(保存系)を1つも置いていないこと★npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パスinspections をメニューから隠す★components/layout/AppShell.tsx:12★:
const MENU_MONITORING = [
{ href: "/detail-log", id: "detailLog", label: "📋 清掃詳細ログ" },
{ href: "/alerts", id: "alert", label: "🔔 アラート" },
{ href: "/reports", id: "report", label: "📈 レポート" },
{ href: "/inspections", id: "inspection", label: "🔧 点検記録" }, // ★:12 この行★
] as const;
★復活させるときに、何を復活させればよいかが1行で分かる形にしてください。★
// ★デモまで一時的に隠す(D-079 項3)★
// D-031 の「点検記録は P1 スコープ」は変えていない。
// 写真ストア(バケット・期限付き署名URL)が未着手のため画面が成立しないため(D-072 項7)。
// ★復活させるときはこの1行のコメントを外すだけでよい★
// (`app/(dashboard)/inspections/page.tsx` と `lib/i18n.ts:14` は残してある)。
// { href: "/inspections", id: "inspection", label: "🔧 点検記録" },
| 対象 | 理由 |
|---|---|
★app/(dashboard)/inspections/page.tsx★ |
★直URLでは到達可能なままにする。これは意図した状態です★(メニューから消すだけで、スコープからは外していないため) |
★lib/i18n.ts:14 の "🔧 点検記録": "🔧 Inspections"★ |
★復活させるときに要ります★ |
★lib/i18n.ts:39 の 点検記録: "Inspection Records"★ |
★同上★(page.tsx が PlaceholderScreen title="点検記録" で使っています) |
★components/layout/PlaceholderScreen.tsx★ |
★inspections がまだ使っています★(禁止事項13) |
★lib/fixtures/inspections.ts / db.inspections()★ |
触らない |
★MENU_MONITORING は as const の配列リテラルです。★ ★この1行を消しても、要素数に依存した型は無く、m.id は key にしか使われていないため型エラーは出ません★(AppShell.tsx を読んで確認してください)。 ★逆に言えば、消したことをコンパイラは教えてくれません。段階10 の目視確認が唯一の検証です。★
npm run dev 相当の環境でメニューに「🔧 点検記録」が出ないこと★(★段階10 で確認★)app/(dashboard)/inspections/page.tsx が残っていること★lib/i18n.ts:14 と :39 が残っていること★npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パスlib/i18n.ts の EN に足す★★lib/i18n.ts はキーが日本語原文のフラット辞書1枚です。完全一致でしか引けません。★ ★キーに無い文言は原文(日本語)のまま出ます — エラーにはならないので、★足し忘れに気づけません★。
| 分類 | キー | 行 |
|---|---|---|
| メニューラベル | 🔧 点検記録 / 🏢 施設ロボットマスタ / 📅 スケジュール / ⚙ システム管理 |
★:14 / :17 / :18 / :19★ |
| セクション見出し | モニタリング / 設定 |
★:20 / :21★ |
| 画面タイトル | 施設ロボットマスタ / スケジュール管理 / システム管理 / 点検記録 |
★:36 / :37 / :38 / :39★ |
| その他 | 準備中 |
★:50★ |
| 表の列(★流用できるもの★) | 施設名 / シリアル / 機種 |
★:22 / :24 / :23★ |
| 数値混じり | 全{n}施設を表示 → |
★:95★ |
★上のキーを再定義しないこと。★ ★オブジェクトリテラルの重複キーは後勝ちで上書きされ、lint が拾わない可能性があります。★ ★足す前に必ず grep -n "キー名" lib/i18n.ts で確認してください。★
| 画面 | 足す必要があるキーの例 |
|---|---|
| F-08 | 都道府県 / 住所 / 電話番号 / 責任者名 / 担当者名 / メール / 監視 / D-Sec / ロボット(メーカー / 機種 / シリアル) / 該当する施設はありません |
| F-09 | 曜日 / 時間 / 有効 / 該当するスケジュールはありません |
| F-10 | 運用設定 / 事前チェック設定 / 完了率の判定閾値 / アドバイス エスカレーション閾値 / 分前 / 日以上連続 / 編集不可 / 編集済み / 推定原因 / 推奨アクション / 発火条件 / 編集は P1 後半で対応します ほか |
★この表は網羅ではありません。★ ★実装した文言を自分で洗い出してください。★ ★t() を通していない日本語リテラルが画面に残っていないかを、実装後に目で確認すること。★
★translate() はキーの完全一致でしか引けません。★ ★全12施設 をキーにはできません。★
★方式A(プレースホルダ + replace)を使ってください★(lib/i18n.ts:78-99 にこの2方式の説明とトレードオフが書いてあります。★方式A が推奨★):
t("全{n}施設").replace("{n}", String(meta.total))
★全{n}施設を表示 →(:95)はすでにありますが、全{n}施設 はありません(実測)。★ ★追加が必要かを実装時に確認してください★ — フッタの文言をどちらにするかで変わります(★モックのフッタは 全{n}施設★)。
★方式B(t("全") + n + t("施設"))は使わないこと★ — ★全 のような1文字キーは他画面の文言と衝突します★(lib/i18n.ts:92-93 の警告)。
lib/i18n.ts に重複キーが無いこと★(grep -o '^ "\?[^":]*"\?:' lib/i18n.ts | sort | uniq -d が 0件、程度の確認でよい)t() を通していない日本語リテラルが無いこと★(★見出し・列名・空表示・注記すべて★)npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス★段階ごとに実行しているはずなので、ここは最終確認です。★
npx tsc --noEmit npm run lint npm test
| ファイル | 内容 |
|---|---|
★lib/facilities/__tests__/query.test.ts(★新規★)★ |
段階2 の期待値表11ケース |
★lib/schedules/__tests__/query.test.ts(★新規★)★ |
段階3 の期待値表9ケース |
★lib/fixtures/__tests__/schedules.test.ts★ |
★7曜日分 + 前提1 = 8テスト★。★地雷を踏んでいないことの検証★ |
lib/dashboard/__tests__/aggregate.test.ts |
planned の集計。★念のため★ |
| # | 内容 |
|---|---|
| 1 | ★cwd のドライブレターは大文字 C:\ でなければ全く動きません★。vitest run の出力に RUN v4.x C:/Users/... と大文字で出ているか確認すること |
| 2 | ★--reporter=basic は Vitest 4 で削除済みです★。使うと ★ロードに失敗しても exit 0 になり、壊れていることに気づけません★。素の npm test を使うこと |
| 3 | ★lint は npm run lint(= eslint)★。★next lint は Next 16 で削除済み★ |
| 4 | ★テスト数が減っていないこと★。基準は作成時点で ★22ファイル / 461テスト★(★着手直前の実測値を基準にすること★)。★段階2 と段階3 で増えるのが期待値★ |
★npm run dev を直接叩かず、Browser pane の preview_start を使ってください。★ (★.claude/launch.json に設定が無ければ作ること。runtimeExecutable: "npm" / runtimeArgs: ["run", "dev"] / port: 3000★)
/facilities / /schedules / /system / ★/dashboard(★地雷を踏んでいないかの確認★)★
| # | 項目 |
|---|---|
| 1 | ★3画面が実際に表示されること★(★「準備中」が出ないこと★) |
| 2 | ★検索が動くこと★ — 施設名(メガバリュー)/ シリアル(8111R、★小文字 8111r でも★)/ 住所(○○区)の部分一致 |
| 3 | ★/facilities のフッタが 全12施設 であること★(fixtures 12件) |
| 4 | ★ロボット3台の施設(メガバリューマート緑野店)が3行で出ること★ / ★ロボット0台の施設(フレッシュタウン湖畔店)で崩れないこと★ |
| 5 | ★/schedules で id27 が 23:30 - 00:30 と出ること★(日跨ぎ) / ★無効行(id24)が薄く表示されること★ |
| 6 | ★/system の閾値が 90 / 70 / 10 / 60 / 30 / 2 / 3 で出ること★ / ★アドバイス7件(R1〜R4 / B1〜B3)が出ること★ |
| 7 | ★★/dashboard が「9 / 10 完了」のままであること★★ — ★11 や 6 になっていたら段階3 の地雷を踏んでいます★ |
| 8 | ★メニューに「🔧 点検記録」が出ていないこと★ |
| 9 | ★/inspections に直URLで飛べること★(「準備中」が出る。★これが意図した状態★) |
| 10 | ★ダーク / ライト 両方で崩れないこと★ |
| 11 | ★JP / EN 切替で英語が出ること★(★列名・見出し・空表示すべて★) |
| 12 | ★コンソールにエラーが出ていないこと★(read_console_messages) |
| 13 | ★★data.anomaly の warn が出ていないこと★★(preview_logs。★出たら地雷★) |
| 14 | ★横スクロールが /facilities の表の中だけで起きること★(★body 全体が横に伸びないこと★) |
lib/fixtures/schedules.ts の差分を git diff で確認すること★docs/decisions.md に新しい決定を追記する★着手直前に grep -n "^### D-0" docs/decisions.md で最終番号を確認すること★ (★本指示書の作成時点(2026-09-08)の最終は D-082(:2390)★。★最初の空き番号は D-083★。★ただし指示書K / 指示書I が先に走ると繰り上がります★)。
記録すべきもの:
| # | 内容 |
|---|---|
| 1 | 指示書L を実行した。★3画面(F-08 / F-09 / F-10)を実装し PlaceholderScreen から差し替えた★ |
| 2 | ★system の実装スコープ(運用設定のみ・読み取り専用)と、そう決めた理由★(★D-053 に抵触しないため / 表示設定は永続化とダッシュボード側の対応が要り本作業の範囲を超えるため★) |
| 3 | ★「表示設定」タブを作らなかったこと★。★D-032 では実装対象なので、P1 後半に残る宿題である★ことを明記する |
| 4 | ★モックの ops タブ二重定義(d-watch-mock.jsx:1158 / :1164、本文 :1221 / :1628)のうちどちらを採ったか★と、その理由 |
| 5 | ★閾値の文言をモックの「以上」ではなく確定仕様の「超」にしたこと★(★CLAUDE.md §4.1 が §5 の「モックが文言の正」より上位★。段階6-5) |
| 6 | ★モックの 📥 インポート / + 新規追加 ボタンを実装しなかったこと★(★docs/spec.md:95 で GET のみ / モックのボタンは onClick の無い飾り / D-053★) |
| 7 | ★inspections を隠したのは一時対応で、D-031 の P1 スコープは変えていないこと★。★復活手順(AppShell.tsx:12 のコメントを外すだけ)★ |
| 8 | ★d-watch-api.yaml の Schedule に facility_id を追加したこと★(型と fixtures には既にあった) |
| 9 | ★q パラメータを追加したかどうか(確認2 の結果)と、AND / OR の関係★。★追加しなかった場合は、検索欄をどう扱ったか★ |
| 10 | ★lib/types/index.ts に AdviceSetting を追加したこと★(YAML にはあったが TS に無かった。CLAUDE.md §9.3) |
| 11 | ★InspectionDetail.photos の item_type(YAML :1402)vs item(TS :373)の不整合が未解決で残っていること★。★点検記録に着手する前に解決が必要★ |
| 12 | ★★契約フラグ(facilities.contract)によるメニュー表示制御は未実装のままであること★★。★CLAUDE.md §4.6 が「契約のないセクションはメニューごと非表示」と定めているが、★メニューは施設横断のグローバルUIなので「どの施設の契約か」が決まらない★。★P1 では全メニューを表示したままにする★。★この論点そのものを記録すること★(★P2 で顧客アカウントが入ったときに、顧客単位で判定できるようになる★) |
| 13 | ★lib/fixtures/schedules.ts を一切変更していないこと★と、★その理由(planned の補完ペア設計。D-079 項3 の申し送り)★ |
| 14 | ★d-watch-api.yaml:861 / :1383 の inspector_name の example にあった実在の人名をダミー名に置換したこと★(CLAUDE.md §7 / D-043。段階1-6) |
| 15 | ★実DB接続時には prismaSource(lib/db/index.ts:153-164)の facilities / schedules の実装が別途必要であること★。★lib/schedules/query.ts の docstring に書いた4つの罠(inactive の反転 / weeks vs weekdays / HHMM の24〜29 / weekdays_label はDBに無い)を申し送ること★ |
| 16 | docs/architecture.md:66-70 の実装状況表を最新化したこと |
| 17 | 実測値(npm test のファイル数・テスト数 / npx tsc --noEmit / npm run lint) |
| 箇所 | 内容 | |
|---|---|---|
★docs/architecture.md:66-70★ |
★画面の実装状況の表が古い★(実測)。★:66 alerts/ / :67 reports/ / :69 ds-logs/ ds-alerts/ が「プレースホルダ」と書かれているが、★いずれも実装済み★(D-069 ほか)。★:70 の facilities/ schedules/ system/ は本作業で実装済みになる★。★実際にプレースホルダとして残るのは :68 の inspections/ だけ★。★この5行をまとめて直すこと★ |
|
★docs/fixtures.md:169★ |
「契約フラグ4パターン \ | ★0:未設定 / 1:D-Securityのみ / 2:D-Watchのみ / 3:両方★」 — ★D-080 で訂正された古い表現★。★10桁文字列(0000000000 / 1000000000 / 0100000000 / 1100000000)に書き換えること★ |
docs/handoff.md に追記する:6-8 付近)も更新すること★inspections は D-072 項7 のとおり最後★CLAUDE.md §4.6。判定単位が決まらないため)★InspectionDetail.photos の不整合★lib/schedules/query.ts の docstring に書いた DB 側の4つの罠(inactive の反転 / weeks vs weekdays / HHMM の24〜29 / weekdays_label はDBに無い)★docs/handoff/analysis/prismaSource実装前チェックリスト.md があれば、そちらにも4つの罠を足すこと★★git add は明示的にファイルパスを指定すること。git add -A は禁止★ (過去に別作業の途中ファイルを巻き込む事故が起きています)。
git status # 何が変わったか目で確認する git add docs/decisions.md docs/handoff.md docs/fixtures.md git add "docs/handoff/指示書L_マスタ画面3枚とinspectionsの一時非表示.md" git commit -m "docs: 指示書L完了(D-0XX)を記録する" git push origin develop
main へは push しないこと★。CLAUDE.md §6-5 のとおり main へのマージは PR 経由で、もう1人のレビューを通してから行います--force は使わないことgit credential fill は禁止)push 後に確認すること:
git log --oneline -1 origin/develop # ローカルの HEAD と同じコミットか git status -sb # 1行目に ahead/behind が無いか
★この2つを段階11 の記録に実測値として書き足すこと。★
docs/decisions.md に新しい決定(★着手直前に確認した番号★)が追記されていることdocs/fixtures.md:169 の契約フラグ表現が10桁文字列に直っていることdocs/architecture.md:66-70 の実装状況表が直っていることdocs/handoff.md の末尾に追記があり、冒頭のポインタも更新されていることorigin/develop へ push 済みで、git status -sb に ahead/behind が無いこと★| 対象 | 理由 |
|---|---|
★点検記録(inspections)の画面実装★ |
★D-072 項7★。写真の置き場所・バケット・期限付き署名URLが未決(禁止事項10) |
★InspectionDetail.photos の item_type / item 不整合の修正★ |
★今回 inspections を実装しないため★。★記録だけする(段階1-5 / 段階11 #11)★ |
| ★「表示設定」タブ★ | 確認1。★永続化とダッシュボード側の対応が要り、本作業の範囲を超える★。★P1 後半の宿題として記録する★ |
| ★運用設定の編集機能★ | ★YAML にエンドポイントが無い★。作るなら ★先に d-watch-api.yaml を直す★(CLAUDE.md §6-1) |
★📥 インポート / + 新規追加 ボタン★ |
docs/spec.md:95 で GET のみ。★モックのボタンは飾り★。D-053 |
★lib/fixtures/schedules.ts の変更★ |
★段階3 の地雷★。★active: true の追加・既存の削除・weekdays の書き換えすべて禁止★ |
★lib/db/ の prismaSource の実装★ |
実DB接続は別作業。notImplemented のまま(禁止事項9) |
★lib/db/ へのフィルタ処理の追加★ |
★lib/db/index.ts:50-54 の設計方針★。フィルタは API ルート側 |
| ★契約フラグによるメニュー表示制御★ | ★判定単位(どの施設の契約か)が決まらない★。★P1 では全メニューを表示したままにし、論点を記録する★(段階11 #12) |
★components/layout/PlaceholderScreen.tsx の削除★ |
★inspections がまだ使っています★ |
★app/(dashboard)/inspections/page.tsx の削除★ |
★直URLでの到達は意図した状態★ |
★lib/i18n.ts:14 / :39 の点検記録エントリの削除★ |
★復活させるときに要ります★ |
| ★メインDBへの書き込み★ | CLAUDE.md §7 / D-042 |
★customers.contract の参照★ |
CLAUDE.md §7 / D-010。★facilities.contract のみが正★ |
q パラメータ)npx tsc --noEmit エラー0 / npm run lint 0npm test 全パス。★テスト数が着手前の実測値から増えていること★(作成時点の基準: 22ファイル / 461テスト)/facilities /schedules /system が PlaceholderScreen でなくなっていること★ (grep -rn "PlaceholderScreen" "app/(dashboard)/" が ★inspections にしかヒットしないこと★)app/api/facilities/route.ts と app/api/schedules/route.ts が存在すること★lib/facilities/query.ts と lib/schedules/query.ts が純粋関数で、テストがあること★git diff --stat lib/fixtures/schedules.ts が空であること★(★地雷を踏んでいない★)/dashboard が「9 / 10 完了」で、data.anomaly の warn が出ないこと★app/(dashboard)/inspections/page.tsx は残っていること★grep -rn "MEGAドンキ\|donki.co.jp\|宇田川町\|03-5428" components/ lib/facilities/ lib/schedules/ が 0件★components/features/system/SystemScreen.tsx に閾値の数値リテラルが無いこと★(lib/config/ から読んでいる)d-watch-api.yaml の Schedule に facility_id があること★lib/types/index.ts に AdviceSetting があること★grep -n "香原" d-watch-api.yaml が 0件であること★(段階1-6)docs/decisions.md / docs/handoff.md / docs/fixtures.md / docs/architecture.md の更新origin/develop へ push 済み★(★main へは push しない★)| 段階 | 状態 | コミット |
|---|---|---|
★着手前の確認(system スコープ / q パラメータ)★ |
★済(両方とも指示書の推奨どおり採用)★ | — |
| 段階0 前提の確認 | 済 | (コミットなし) |
| 段階1 API契約を直す + 型を足す | 済 | a666dcf |
段階2 GET /api/facilities |
済 | 6bba958 |
段階3 GET /api/schedules(★地雷あり★) |
済(地雷回避済み) | 6df83e9 |
| 段階4 施設ロボットマスタ画面(F-08) | 済 | 5d3fe60 |
| 段階5 スケジュール管理画面(F-09) | 済 | 896e428 |
| 段階6 運用設定画面(F-10・読み取り専用) | 済 | d6741a3 |
段階7 inspections をメニューから隠す |
済 | 2f768ba |
| 段階8 i18n | 済 | 6f1b509 |
| 段階9 テスト | 済(24ファイル/530テスト全パス) | (コミットなし) |
| 段階10 ブラウザで動作確認 | ★一部実施★(curl+APIレスポンスで代替。クライアント描画・テーマ・JP/EN切替・コンソールは未確認) |
(コミットなし) |
| 段階11 記録と push | 済 | このコミット + push |
実行日: 2026-09-08 取得した決定番号: D-084 着手前の実測値: 22ファイル / 461テスト / tsc 0 / lint 0(Vitest 4.1.11) system の実装スコープ: 運用設定のみ・読み取り専用(確認1。指示書の推奨どおり採用) q パラメータ: /facilities と /schedules に追加(確認2。指示書の推奨どおり採用) 完了後の実測値: 24ファイル / 530テスト / tsc 0 / lint 0 詳細: docs/decisions.md D-084 / docs/handoff.md 追記20 を参照