DB接続前の開発は、すべて lib/fixtures/ のサンプルデータで行います。 本書は「サンプルデータに必ず含めるべきケース」の一覧です。
正常系だけのきれいなデータで作ると、本番接続時に表示崩れ・判定ミスが一気に噴出します。 異常系・境界値を先に仕込んでおくことが目的です。
lib/fixtures/ サンプルデータ(TypeScript、型付き) clean-logs.ts clean-task-reports.ts ★清掃実績の新しい取得元(指示書AQ 決定2)。§2.6★ task-status-rule.ts ★`status` の分布と巡回列(依存の無い葉モジュール)。§2.6★ prechecks.ts reports.ts ds-devices.ts facilities.ts schedules.ts inspections.ts lib/db/ index.ts USE_FIXTURES で fixtures / prisma を切り替える
USE_FIXTURES=true の間は、APIルートが fixtures を返すUSE_FIXTURES=false にするだけ。画面側のコードは一切変更しないlib/judge/)はこの切替の外側に置く。 fixture開発中も本番同等のロジックが走るd-watch-mock.jsx)の LOG / PRECHK / DSA_INIT / RANK / ROBOTS / SCHED / DSDEV / INSPECTIONS を移植し、本書のケースを追加するモックには実在の店舗名・住所・電話番号が入っています。移植時に必ず置換してください。
| 実データ | ダミー |
|---|---|
| ドン・キホーテ / MEGAドンキ | バリューマート / メガバリューマート |
| ユニー / アピタ | フレッシュタウン |
| PPIH | ARH |
| 住所 | 「東京都○○区1-2-3」形式の架空住所 |
| 電話番号 | 03-0000-0001 形式(連番) |
| メール | store001@example.com |
| 担当者名 | 架空の氏名 |
シリアル番号(8111R5628060011 等)は形式が分かることに意味があるので、桁数・書式を保ったまま連番で構いません。
モックの LOG を移植し、以下を追加します。
| ケース | 完了率 | 期待される判定 | 表示(整数丸め) |
|---|---|---|---|
| ◎の下限すぐ上 | 90.1 | ◎ | 90% |
| ◎/○の境界 | 90.0 | ★◎(「90%以上」なので90.0は◎。D-139)★ | 90% |
| 丸めると90だが○ | 89.5 | ○ | 90% |
| ○の下限すぐ上 | 70.1 | ○ | 70% |
| ○/△の境界 | 70.0 | ★○(「70%以上」なので70.0は○。D-139)★ | 70% |
| △の下限すぐ上 | 10.1 | △ | 10% |
| △/×の境界 | 10.0 | △(「10%未満」が×なので10.0は△。★D-139 でも変わらない★) | 10% |
| ×の代表値 | 9.9 | × | 10% |
| ゼロ | 0 | × | 0% |
| 未実施 | null | × | - |
この10ケースは判定ロジックのテストと同じ値を使うこと。 画面表示とテストで挙動が一致していることを目視でも確認できます。
★境界はすべて「上のランクに入る」★(ユーザー指示 2026-09-16。D-139。旧 D-020b は破棄)。 ★× の境界だけは「10%未満」のまま★なので、10.0 は △。
| ケース | 連続日数 | 期待レベル | 適用ルール |
|---|---|---|---|
| 初回の出発失敗 | 1 | L1 | R1 |
| 完了率×(初回) | 1 | L1 | R2 |
| 2日連続△以下 | 2 | L2 | R3 |
| 3日連続 | 3 | L3 | R4 |
| 5日連続(長期化) | 5 | L3 | R4 |
| スケジュール非存在日を挟む連続 | 実日数3・カレンダー日5 | L3 | R4 |
最後のケースが重要です。「月水金」スケジュールの施設で月・水・金と3回連続で失敗した場合、カレンダー上は5日間ですがスケジュール存在日の連続は3日なのでL3になります。この判定を間違えやすいので必ずデータに含めてください。
事前チェック1回目 / 2回目(★旧見出し 1h前ST / 30分前ST★。D-178)は以下を網羅:
null / null(画面は「-」、CSV は空のセル)★(D-171): ★施設11 バリューマート川下店の履歴25行(6〜30日前)★。lib/fixtures/prechecks.ts に出てこない施設を選んだ。完了率・判定・行数は変えていないPRECHECK_MINUTES_BEFORE。row() の status_1h_minutes / status_30m_minutes を省略した行。status が null の回は分数も null)null・null)result_pending: true(lib/fixtures/clean-logs.ts の pendingCases)。departed:false・task_status:null・completion_rate:null・× のまま、事前チェックは無い(null。D-171)schedule_progress は 11 / 9予定外タスク = clean_task_reports のうち clean_timetable_id が 0 か NULL の行。lib/fixtures/clean-logs.ts の ★unscheduledCleanLogs★(2行)。
| 施設 | 開始(started_at) |
完了率 | 判定 | status |
連続 | 確かめること |
|---|---|---|---|---|---|---|
| 施設1 メガバリューマート中央本店 | 昨日 21:00 | 95.9 | ◎ | 4 | 0 | 表U1 U1-1(予定外の1行。同じ日に予定のある ◎ がある) |
| 施設11 バリューマート川下店 | 2日前 22:00 | 0(clean_area 0) |
× | 6 | 1(L1) | 表U1 U1-2(× でも出発 ✓・未実施ではない)。施設11 は2〜5日前に予定が無いので、この日だけで連続1 |
unscheduledCleanLogItem()(Prisma 版と同じ関数)で作る★。id: null・row_key: "rp-<report_id>"・report_id は19桁の文字列・事前チェック4列は null・departed: true・result_pending: falsecleanLogs(予定のある行)には混ぜていない★ — 清掃結果(clean-task-reports.ts)・エリア(areas.ts)・シード(scripts/seed-local-db.ts)が予定の id を鍵に作られているため。★混ぜるのは fixtureSource.cleanLogs() だけ★(lib/db/index.ts。scheduled_at だけで安定に並べ直すので、予定のある行どうしの順序は変わらない)cleanLogRunMeta()(ダッシュボードの直近モードのメタ)には入れていない(予定外の行は予定の終了を持たない)GET /clean-logs/{id}/areas)lib/fixtures/areas.ts(areaCompletions)。★★1エリア = 1清掃ロボット★★(CLAUDE.md §8 / TeamWorks 第8回 A9-2)。★1回の清掃の中を売り場・通路・レジ前に区切った内訳ではありません★。
★★日付と clean_log_id は lib/fixtures/clean-logs.ts の既存の行から引いています★★ (手書きの日付を作らない。既存ファイルは1行も変更していない)。 行の completion_rate は対応する清掃ログの完了率と同じ値です(一覧とモーダルで数字を食い違わせない)。 ★★全体率(overall_completion_rate)は行の完了率(runCompletionRate())の単純平均です★★(清掃1回=1票。未実施の行は分母に入れない。 lib/judge/kpi.ts の meanCleanRatio())。★指示書AQ §5-5 で面積ベース(Σclean_area ÷ Σtask_area)から変わり、D-155 / 指示書AS で平均する材料が clean_ratio 列から runCompletionRate() に変わりました★。 ★行の完了率は面積から runCompletionRate() で決まります(D-155)★。面積は行の完了率から作ってあり(小数第6位)、 runCompletionRate() で元の完了率に戻ることを lib/fixtures/__tests__/areas.test.ts で確かめています。 ★期間の合計どうし(Σclean_area ÷ Σtask_area)は全体率の分子・分母ではありません★。 ★各行の result_pending(結果待ち。D-182)は対応する清掃ログの値を写しています★(新しい値は作っていない)。 施設11 の結果待ちの清掃ログに対応するエリアの行は無いので、★fixtures のエリアの行はすべて result_pending: false★です (結果待ちのエリアを問題に数えないことは lib/clean-logs/__tests__/areas.test.ts の表6 で確かめています)。
| # | ケース | 施設 / 日 | 仕込んだ値 | 確認できること |
|---|---|---|---|---|
| 1 | 1エリアだけの施設 | 施設1 / 当日 | 90.1%(1000㎡) | ★1件でも正常(エラーにしない)★ / ◎の境界 |
| 2 | ちょうど90.0 | 施設2 / 当日 | 90.0%(1000㎡) | ★「90%以上」が◎なので ◎(D-139)★ |
| 3 | ちょうど70.0 | 施設5 / 当日 | 70.0%(1000㎡) | ★「70%以上」が○なので ○(D-139)★ |
| 4 | ちょうど10.0 | 施設8 / 当日 | 10.0%(1000㎡) | ★「10%未満」が×なので △★ |
| 5 | 0% | 施設10 / 当日 | 0%(1000㎡ / 0㎡) | ★「0%で実施した」は × だが未実施ではない★ |
| 6 | ★全エリア未実施★ | 施設12 / 当日 | null(面積0) |
★completion_rate は null(0% と混ぜない)★ / ★平均する行が0件なので全体率も null★ |
| 7 | ★3エリアの施設 + 担当面積が違う★ | 施設7 / 1日前 | 62%(1000㎡) / 94%(100㎡) / 88%(100㎡) | ★全体率は単純平均の 81.33%(○)★。旧定義の面積ベースだと 66.83…%(△)で判定が割れるので、★面積ベースに戻っていないこと★を確認できる |
| 8 | ★★履歴の行が無いエリアと正常終了のエリアの混在★★ | 施設5 / 1日前 | 履歴なし(面積0) + 97%(1000㎡) | ★履歴なしは completion_rate が null で単純平均の分母に入らない★ → 全体 97.0%(◎) |
| 9 | 該当0件(全部◎○) | 施設1 / 1日前 | 92%(1000㎡) | ★filter=problem で items が空配列(404 にしない)★ |
task_area / clean_area とも 0★(ローカルDBのシードと同じ)。 ★面積は全体率に効かない★ので、実DBで未実施行の task_area が非0でも全体率は変わらない(面積の表示にはDBの値をそのまま出す)section_name はシードと同じ 清掃エリア(ロボット107) の形★。 モックの「1F 生鮮エリア」のような名前は作りません(実装はDBの生値をそのまま出すため)lib/fixtures/__tests__/areas.test.ts で固定していますclean_task_reports(清掃実績の新しい取得元。★指示書AQ 決定2★)lib/fixtures/clean-task-reports.ts(cleanTaskReports)。 期待値の固定は lib/fixtures/__tests__/clean-task-reports.test.ts(19ケース)。 ローカルDBへの投入は scripts/seed-local-db.ts(★同じ純粋関数を import している★)。
★なぜ必要か★: 指示書AQ 決定2 で ★清掃実績の取得元が clean_status_histories → clean_task_reports に変わる★。★このテーブルはローカルDBにも fixtures にも1行も無かった★ため、 ★切替後は全画面が0件になり、他担当が動作確認できない★(指示書AQ 落とし穴5)。 ★clean_status_histories の投入は消していません★ — 切替の前後比較に使うためです。
★これは API の形(CleanLogItem)ではなく DBテーブルの形です★。 そのため型は lib/types/ ではなく lib/fixtures/clean-task-reports.ts に置いています (CleanTaskReportFixture)。
clean_task_reports.csv 189行★。2026-09-30 受領)| カラム | 実測 |
|---|---|
report_id |
★19桁の数値文字列★(例 1295486100215435264)。varchar(20) |
clean_timetable_id |
★CSV では189行すべて NULL★。★NULL と 0 は予定外のタスク★(NULL: ユーザー回答 2026-10-01、0: TeamWorks 回答 2026-10-27)。旧: 「今後 TeamWorks が埋める前提(決定5)」は 2026-10-01 に取り下げ |
status |
★3:2件 / 4:161件 / 5:4件 / 6:22件★。値の意味は第10回 N-2 で受領(★6 は未受領★。D-155 項2) |
task_area |
★清掃エリアごとにほぼ一定★(例: あるエリアは19行すべて 878.524992) |
clean_area |
★毎回変動し、68.3%(129/189行)で task_area を超える★ |
clean_ratio |
★面積比とは一致しない★(例: 面積比130.0% のとき clean_ratio は 76.0) |
ended_at |
★nullable★ |
clean_time |
秒(★0 の行もある★) |
| # | ケース | 仕込み方 | 確認できること |
|---|---|---|---|
| 1 | ★未実施★ | ★行を作らない★(completion_rate === null の清掃) |
★指示書AQ 1-1「未実施 = 対応する行が無い」★。clean_task_reports に clean_error 相当の列は無いので、★行の有無だけが根拠★ |
| 2 | 判定の境界値10ケース | ★clean_area を清掃ログの完了率から作る★(clean_ratio 列にも同じ値)。§2.1 の値(90.1 / 90.0 / 89.5 / 70.1 / 70.0 / 10.1 / 10.0 / 9.9 / 0、未実施は #1) |
★runCompletionRate()(面積から。D-155)でも §2.1 の判定が変わらないこと★。全行で元の完了率に戻ることをテストで固定 |
| 3 | ★status 4種★ |
3 / 4 / 5 / 6 を ★CSV実測の分布どおり★(189要素の巡回列)。★塊にせず散らしてある★ | ★画面・CSV で表示名(3 清掃キャンセル / 4 清掃正常終了 / 5 清掃異常終了)になり、6 は数字のまま出ること(D-155 項2)★。★CLEAN_ERROR に対応づけない★ |
| 4 | ★ended_at が NULL★ |
清掃 id が29の倍数の行 | ★順序キーが ended_at ?? started_at に倒れること(指示書AQ 1-4 / 落とし穴3)★。★非nullを型で要求している箇所は型ごと直す★ |
| 5 | ★clean_timetable_id が NULL★ |
★history ブロック(daysBack 6〜30)で id が37の倍数の行★ |
★落とし穴1★。★行が消えるのではなく「未実施」として静かに集計される(fail-silent)★。稼働率・出発成功率が落ちる |
| 6 | clean_time が 0 |
★ended_at が NULL の行★ |
実測に 0 の行がある。0除算・「0秒だから異常」といった扱いをしていないこと |
| 7 | ★完了率100の行は task_area を超える面積★ |
完了率100なら task_area × 1.00〜1.40(pseudoRandom()) |
★上限100の確認★。★ただし fixtures の清掃ログには完了率100が無い(最大 99.5)ので該当0件★(関数を直接テストで確かめる) |
| 8 | 清掃エリアごとに違う task_area |
エリア(section_id)ごとに一定、600〜1000 m² で散らす(小数第6位まで) |
★既存シードの一律 1000 m² では出ない不具合★(総清掃面積の按分など) |
| 9 | ★clean_timetable_id が 0★(予定外のタスク。TeamWorks 回答 2026-10-27) |
★清掃ログに対応しない追加の1行★(cleanTaskReportZeroTimetableRows。history の実施済みの最初の行のロボットで、その3時間後に始めた清掃。完了率 55.5。report_id は清掃 id + 900万) |
★総清掃面積(F-08)の面積の合計には入り、完了率・実施回数・重複の番人には入らない★(lib/db/timetable-link.ts)。★cleanTaskReports(清掃ログ由来の263行)には含めない★ — 既存の行と期待値を動かさないため。★fixtures 版の画面はこの配列を読まない★(DB 経由=シードでだけ見える) |
★#5 を boundaryCases / escalationCases / statusCases に当てていないのは意図★です。 当てると §2.1 の境界値10ケースと §2.2 のエスカレーションが ★まるごと「未実施」になって 画面で確認できなくなる★ため、history ブロックだけを対象にしています (この制約は lib/fixtures/__tests__/clean-task-reports.test.ts で固定済み)。
★★#5 の行は、DB 経由と fixtures 経由で見え方が違います(既知の構造上の制約。意図した非対称)★★
| 経路 | #5 の清掃の見え方 | なぜ |
|---|---|---|
DB 経由(USE_FIXTURES=false) |
★出発失敗・task_status が null★ |
clean_timetable_id が NULL の行は IN に一致しないので「対応する行が無い」=未実施(指示書AQ 1-1)。★落とし穴1 そのもの★ |
fixtures 経由(cleanLogs) |
★実施済み・task_status あり★ |
cleanLogs の departed / completion_rate / task_status は clean-logs.ts の入力から決まり、clean-task-reports.ts の結果を見ない |
★fixtures 側を DB 経由に合わせないのは意図★です。#5 の対象(cleanTaskReportNullTimetableLogIds)は ★completion_rate !== null の行から作っている★ため、cleanLogs 側でその行を未実施にすると ★対象が0件になり、落とし穴1 を再現するケースそのものが消えます★。 この数行について2経路の画面表示が違うのは不具合ではありません(lib/fixtures/clean-task-reports.ts の cleanTaskReportNullTimetableLogIds の docstring にも同じことを書いています)。
★status の規則(CSV実測の分布と189要素の巡回列)は lib/fixtures/task-status-rule.ts の1箇所だけ★で定義し、 clean-task-reports.ts(status)と clean-logs.ts(task_status)の両方がそこから import します。 ★clean-logs.ts は clean-task-reports.ts を import できません★(あちらが読み込み時に cleanLogs / history を 読むため循環 import になる)。★2つの一致は lib/fixtures/__tests__/areas.test.ts で固定しています★。
| どこ | 行数 |
|---|---|
lib/fixtures/ |
★263行★(cleanLogs 280行のうち実施済み263行。未実施17行には行を作らない)+ ★clean_timetable_id = 0 の1行★(#9。別の配列) |
| ローカルDB(本ループ + 施設7検証) | ★246行★(投入対象253行のうち実施済み240行 + 施設7検証6行)+ ★clean_timetable_id = 0 の1行★(#9) |
| ローカルDB(画面確認用ボリューム) | 実行時に決まる(★シードの完了ログに出力される★) |
★clean_status_histories は未実施でも行を作る(clean_error = 1)ので、★2つのテーブルで 行数が違います。それが意図した状態★です(切替の前後比較の材料)。
★2026-10-02(D-155 / 指示書AS 段階6)★: 完了率が clean_ratio 列から ★1回ごとの面積比(runCompletionRate())★ に 変わったため、clean_area を完了率と独立に作る方式(旧ケース #7「面積比と clean_ratio の乖離」。約7割が task_area 超え)をやめ、 ★清掃ログの完了率から作る★ 方式に変えました(CSV の分布 68.3% の再現はやめた)。
★すべて清掃 id から決まる純粋関数★(Math.random() を使わない=冪等)。 ★scripts/seed-local-db.ts は lib/fixtures/clean-task-reports.ts の関数をそのまま import します★ので、 ★USE_FIXTURES の true/false で同じ値が出ます★(ズレたらどちらかのバグ)。 シードは投入後に ★status 4種 / ended_at NULL / clean_timetable_id NULL / clean_timetable_id 0 / clean_time=0 が 1件も無ければ例外で止まります★(fail-loud。ケースが欠けたまま他担当が動作確認に入らないため)。
| ケース | 内容 |
|---|---|
| 種別 | ★precheck(事前チェック異常)だけ★(ユーザー判断 2026-10-29「2で進めてください」。アラートは出発失敗を出さない)。旧 launch_failed(出発失敗)の id 4 / 8 は消した(id は振り直さない。4・8 は欠番)。出発失敗は §2 の清掃詳細ログ(施設12 今日 03:30 など)で見る |
| 分数の3通り | 60分前 / 30分前 / ★20分前(設定値以外の任意の分数。D-093 項2)★ |
| 3ステータスすべて | 未解消 / 対応中 / 解消(未解消4: id 1・2・3・9 / 対応中1: id 5 / 解消2: id 6・7) |
| 解消済み(時刻あり) | responded_at と resolved_at の両方が入っている |
| 対応中(解消前) | responded_at のみ、resolved_at は null |
| 未解消 | 両方 null |
| バッテリー低下 | battery_level が低い値(Pudu APIで取得可能と確認済み) |
| 該当0件 | 未解消が0件の日(サマリカードが0表示になる)。データは今日と昨日だけなので、2日前・3日前を指定する |
★本清掃は成功(main_run_succeeded)★ |
★true は id 6(出発成功・親の本清掃が ◎○)だけ★。id 7(完了率62% = △)・ほかは false。★対応状況・件数はこの値で変わらない★(D-171。lib/fixtures/prechecks.ts の冒頭コメント) |
モックの RANK を移植し、以下を追加。
| ケース | 内容 |
|---|---|
| 3ステータス | 良好 / 注意 / 要改善 が最低1件ずつ |
| 前期比+ | 改善している施設(▲表示) |
| 前期比− | 悪化している施設(▼表示) |
| 前期データなし | prev が null(新規施設。差分表示なし) |
| 11件以上 | 「全X施設を表示」の発火確認 |
| エラー種別(生値。D-077で変換しない方針に確定) | 実在する値が複数(EmergencyStop 等) / 未知の値 / 空文字 |
| 連続問題施設 | L1 / L2 / L3 が最低1件ずつ |
| 当期データ | 進行中の週・月・年(サマリテーブルに存在しない前提のケース) |
| 週次/月次/年次 | 3モードのデータ(粒度タブ切替の確認)。期間キーは実行日からの相対で6つ(今週 / 先週 / 今月 / 先月 / 今年 / 前年)。★年次は month=0, week=0★(§4.7。D-151 で今年・前年を追加) |
★確定期間のKPI(kpiWeekly / kpiMonthly / kpiYearly)は作り値です★(実データ由来ではない)。 当期(今週・今月・今年)は3つとも kpiCurrentPeriod を使い回しています。
| ケース | 内容 |
|---|---|
| 3状態すべて | 正常 / 通信断 / 異常 |
| 自動ソート確認 | 正常→異常→正常→通信断 の順で定義し、表示時に異常→通信断→正常に並ぶことを確認 |
| 備考あり/なし | note が空文字のケースを含む |
| 全部正常 | 異常0件のケース(サマリカードの表示確認) |
| 11件以上 | ページング確認用(12件) |
| 該当0件 | q に一致しない検索語(例: q=ZZZ-NOMATCH)を指定すると0件になる。専用のfixtureは用意していない |
※ トークン期限(te)は移植しない。 仕様から除外済みです。
取得元は lib/fixtures/error-reports.ts の errorReportRows から、Prisma 版と同じ純粋関数 dsAlertsFromErrorRows() で作ります(指示書AX D13。lib/fixtures/ds-alerts.ts は削除済み)。 対象は error_type が D-S_CONTROL_FAILURE の行だけ(★8行のうち出るのは7行★: FX-ERR-10・12〜17。★FX-ERR-19 は清掃エリアが削除済みなので出ない — U8・表5 V6★)。SECURITY_ON・NOT_STARTED は含みません(エラー一覧 /errors には出ます)。
| ケース | 内容 |
|---|---|
| 3ステータス | 未解消 / 対応中 / 解消(unresolved / in_progress / resolved。エラー一覧と同じ語彙) |
| 備考あり/なし | note が空のケースと「回線業者に確認中」等あり |
errored_at NULL |
FX-ERR-12(検知時刻は created_at) |
| シリアルと施設の食い違い | FX-ERR-16(施設2の制御盤 SN・行の施設は3。U3) |
| 同時刻の並び | FX-ERR-16 と 17(検知時刻同値 → id 昇順で 16 が先) |
clean_timetable_id NULL |
FX-ERR-12 |
security_off |
★fixtures にも無い(D-180)★。API の type=security_off は200・0件(enum は互換のため残す) |
既定(status=open) |
5件(解消の FX-ERR-14・15 以外) |
status=all |
7件 |
summary |
{ unresolved: 3, in_progress: 2, resolved: 2 }(7行に対して。type / status の絞り込みより前) |
| 該当0件 | ★「disconnected × done(旧 status=done)」で意図的に0件にするケースは無くなった★。0件を見たいときは分類(customer_id 等)で絞る |
★エラー一覧の上書き表(fixture-error-report-overrides.ts)を共有するので、PATCH /errors/{error_id}/status で書いた対応状況が D-Sec にも出ます(U4)。
※ モックの DSA_INIT には「トークン期限」種別が含まれています。移植時に削除してください。
| ケース | 内容 |
|---|---|
| 契約フラグ4パターン | ★varchar(10)の10桁文字列(D-080)★。0000000000:未設定 / 1000000000:D-Securityのみ / 0100000000:D-Watchのみ / 1100000000:両方 |
| ロボット0台 | 施設は登録済みだがロボット未設置 |
| ロボット複数台 | 2台、3台のケース(モックの立川店は3台) |
| メーカー・機種 | PUDU CC1 のみ(P1 の対象機種。CLAUDE.md §1)。未対応機種の表示確認は lib/facilities/__tests__/query.test.ts の合成データで担保する(指示書N / D-087) |
| 任意項目が空 | 電話・メール・担当者が null のケース |
| 複数都道府県 | 東京都 / 神奈川県 など |
契約フラグ4パターンはメニュー表示制御のテストに必須です(契約のないセクションはメニューごと非表示)。
| ケース | 内容 |
|---|---|
| 曜日パターン | 毎日 / 月水金 / 平日のみ / 土日のみ |
| 有効・無効 | active の true / false 両方 |
| 日跨ぎ | 23:30開始〜00:30終了 |
無効スケジュールは「連続日数カウント」の対象外になるので、判定ロジックの確認にも使います。
★D-050: 曜日パターンを持つ有効スケジュールは「補完ペア」にしてある★
schedule_progress.planned(lib/dashboard/aggregate.ts)は施設を区別しない、 その日の曜日に該当する active なスケジュールの総数です。一方 clean-logs.ts の 当日分(daysBack=0)は曜日に関係なく毎日必ず11行になります(相対生成のため。★D-173 で結果待ちの1行(施設11)を足して 10 → 11★)。 この2つを常に一致させるため、平日のみ/土日のみ、月水金/日火木土 をそれぞれ 「全曜日を過不足なくカバーする補完ペア」にして、合計が常に11件になるようにしています (★D-173 で「毎日」のスケジュール id 34(施設11・03:30〜04:30)を足して 10 → 11★。§2.3b)。 詳細な内訳は lib/fixtures/schedules.ts 冒頭のコメントを参照してください。
| ケース | 内容 |
|---|---|
| 申し送りあり/なし | notes が空のケースと長文のケース |
| 写真全部あり | Before/After × 7項目 = 14枚 |
| 写真一部欠け | 一部項目のみ撮影(グリッドの欠けた表示確認) |
| 写真なし | 記録のみ登録されたケース |
| 同一施設の複数回 | 劣化傾向の比較表示用に、同じ施設で日付違いの記録 |
写真はダミー画像(単色+項目名を書いたPNG等)で構いません。
すべての一覧APIで以下を確認できるようにします。
npx prisma db pull で実スキーマを取り込み、テーブル定義書(28テーブル)と突き合わせる(この確認だけは早めにやる。カラム名の食い違いが後から見つかると全画面に波及するため)USE_FIXTURES=false に切り替え、1画面ずつ実データで確認各値の定義は docs/decisions.md D-049 が正。集計は lib/dashboard/aggregate.ts(純粋関数)で、 期待値表は lib/dashboard/__tests__/aggregate.test.ts に固定してあります。
clean-logs.ts は実行日からの相対生成(daysBack。0 が当日)で、schedules.ts は 固定データです。GET /api/dashboard?date=YYYY-MM-DD の date を「今日から何日前か」で 指定することで、以下のケースを確認できます(date 省略時は当日=daysBack=0)。 ★schedule_progress は省略時も当日。summary と problem_logs は直近モード(D-159)★ — 下の表の 「当日(date 省略)」の行は ★スケジュール進捗(planned / completed / data.anomaly)だけ★ に当てはまる。 省略時の数値カードと清掃詳細ログ(コンパクト版)は §12.3。
date(当日からの相対) |
planned |
当日ログ行数 | completed |
data.anomaly |
確認できること |
|---|---|---|---|---|---|
当日(daysBack=0、date 省略) |
11 | 11 | 9 | 出ない | 既定が正常であること。曜日に関係なく常にこの値になる(schedules.ts の補完ペア設計。§8参照)。出発なしの2行は施設12 の出発失敗と施設11 の結果待ち(§2.3b) |
| 1日前(daysBack=1) | 11 | 11 | 7 | ★出ない★ | ★D-173 以前は「実績が予定を上回る乖離」(expected=10, actual=11)の再現用だった★。★planned が11になって一致し、★上回る側の乖離は fixtures で再現できなくなった★。★直さない(監督判断 2026-10-07)★: data.anomaly の判定は logsOfDay.length !== planned(app/api/dashboard/route.ts)で上回る・下回るが同じ分岐なので、下回る側(2〜5日前・6〜30日前)で同じ経路を確かめられる |
| 4日前(daysBack=4) | 11 | 1 | 1 | 出る(expected=11, actual=1) | 乖離(実績が予定を大きく下回るケース。D-049が本来想定していた「収集処理が止まった」ケースに近い) |
| 2〜3日前・5日前 | 11 | 3 / 3 / 2 | 2 / 2 / 2 | 出る | 同様の乖離(不足側)の追加サンプル |
| 6〜30日前 | 11 | 10 | 変動 | ★出る(expected=11, actual=10)★ | 履歴データ(history)は1日10行の生成。★D-173 以前は planned と偶然一致して出なかった★。乖離確認には使わない |
★上の数字は lib/fixtures を import して db.cleanLogs()・db.schedules()・computeScheduleProgress() で数えたもの★ (当方の fixtures 由来。2026-10-07 11:3x JST。completed は出発した行の数なので相対生成の日によって変わりうる)。
planned はどの date を指定しても常に11(schedules.ts の設計上、曜日に関係なく 有効スケジュールの該当件数が11で一定のため。★D-173 で 10 → 11★)。乖離が起きるのは常に清掃ログ側の行数が 日によって変わるからで、これは意図的な相対生成データの性質です。
planned = 0 の日は fixtures では再現しない(★意図的★)上記の通り、既定(当日・曜日を問わず)を常に「正常」にするという要件(D-050)を満たすには、 schedules.ts の有効スケジュールの曜日該当件数を全曜日で一定(11件。D-173 以前は10件)にする必要があり、 その結果どの date を指定しても planned は0にならない設計になっています (0になる曜日が1つでもあると、その曜日が「当日」に回ってきたときに既定が異常表示になってしまうため)。
そのため planned = 0(全スケジュールがその日該当なし → rate が null)のケースは、 fixtures 経由では再現できません。 このケースは computeScheduleProgress 単体の 性質(0除算をしないこと)であり、lib/dashboard/__tests__/aggregate.test.ts の 「planned = 0(全施設が定休日)なら rate は null」テストで合成データ(fixtures非依存) により直接検証済みです。画面から確認したい場合はこのテストを参照してください。
/dashboard の描画経路を直接確認したい場合(★手順・要注意★)上の aggregate.test.ts は computeScheduleProgress という集計関数を直接呼んでいるだけで、 「planned = 0 のレスポンスを /dashboard 画面がどう描画するか」(例: 「本日の清掃予定はありません」といった表示)は検証していません。画面の描画経路まで 目視で確認したい場合は、以下の手順で一時的に再現してください。
lib/fixtures/schedules.ts の全スケジュールの active を一時的にすべて false に変更する (曜日を問わず該当件数が0になるため planned = 0 になる)npm run dev で /dashboard を開き、表示を確認するactive を元の値に戻す。 戻し忘れても、lib/fixtures/__tests__/schedules.test.ts(修正1で追加)が 「有効スケジュールの該当件数が当日の清掃ログ行数と一致しない」として落ちるため、 npm test を実行すれば戻し忘れにすぐ気付けますschedules.ts の有効スケジュールの曜日該当件数を全曜日で一定(11件)に保つという制約 (12.2冒頭・D-050)がある限り、planned = 0 を fixtures に常設することはできません。 常設すると、どこかの曜日で該当件数が0になってしまい、その曜日が「当日」に回ってきたときに 既定表示(date 省略・daysBack=0)が異常系になってしまうためです。そのため常設ではなく、 確認したいときだけ上記の手順で一時的に active を落とす運用にしています。
| ケース | 何を確認するか |
|---|---|
planned = 0 の日(全施設が定休日) |
rate が null になる。0除算で NaN / Infinity を出さないこと。★fixturesでは再現不可。12.2参照。aggregate.test.ts で検証済み★ |
security_banner が 0件 |
バナーを出さない(空配列) |
security_banner が 複数件 |
複数行の並び。security_off かつ未解消だけが出る。★fixtures・DB とも security_off が無いので出ない(D-180)。描画は aggregate.test.ts で検証★ |
| 当日の問題行が 0件 | コンパクト版清掃詳細ログが空のときの表示。★date 省略時は problem_logs(直近モード。§12.3)、date 指定時はその日の △×(D-159)★。旧: /clean-logs?result=problem を画面が別に呼んでいた |
success_rate = 100.0 |
全件 ◎○。丸め前の生値が返る(表示の丸めは画面側) |
success_rate = 0.0 |
全件 △× または未実施。null(分母0=ログ0件)と区別できること |
planned と清掃ログ行数が乖離する日 |
data.anomaly が出る(収集処理の障害検知)。期待値と実測値だけを記録し、原因は断定しない。★再現手順は12.1参照★ |
failure_breakdown は fixtures を用意しません。 M2 では返さない(D-048)。 M3 でエラーテーブルを扱うときに、型・DataSource メソッド・fixtures をまとめて作ります。
date 省略時(直近モード)に何が出るか(★D-159 / 指示書AV★)date を省略すると(?date= の空文字も同じ)、summary(数値カード)と problem_logs(コンパクト版の表)は ★各清掃エリアの直近の清掃1件★ から作られます(規則は lib/dashboard/latest-run.ts の pickLatestRunPerSection()、 日数・分数は lib/config の DASHBOARD_LATEST_RUN)。
settleMinutes)をやめた★ — 終わってからレポートが届くまでは、行の旗 result_pending で「結果待ち」と出すsummary.pending に数え、★未実施にも成功率の分母にも入れない★。★problem_logs には出さない★(D-173)schedule_progress・要レスキュー・セキュリティバナーは当日のまま★(§12.1 の「当日」の行: 予定11・実施9)★fixtures には予定の終了も清掃エリアも無い★ので、fixtures 版の cleanLogRunMeta() は ★終了=予定の開始(scheduled_at)・清掃エリア=ロボット(serial_number)★ とみなします(D10。★fixtures にデータは足さない★)。 つまり fixtures では「★開始時刻を過ぎた予定★」が「終わった予定」になります。 当日の行は 01:30〜03:30(最後は施設12 と施設11 の 03:30)なので、★JST 3:30 が境目★です(D-173 以前は 4:00)。 ★fixtures の result_pending は時刻で決めず行に直書き★(施設11 の 03:30 だけが true。§2.3b)なので、時刻によって結果待ちが確定に変わることはありません。
★下の数字は lib/fixtures を import して db.cleanLogs()・db.cleanLogRunMeta()・pickLatestRunPerSection()・computeSummary() で数えたもの (当方の fixtures 由来。2026-10-07 11:3x JST。★D-173 の後★)★。
JST 3:30 以降(3:30 ちょうどを含む。その日のうちは同じ値):
| 項目 | 値 |
|---|---|
| 選ばれる行 | ★15行(ロボット15台)★ — 当日11行・前日4行(施設5 の2台目・施設7 の3台)。★施設11 は当日の結果待ちの行が選ばれる★(D-173 以前は6日前の行) |
summary |
★成功8 / 失敗5 / 未実施1 / 結果待ち1 / 成功率 57.14…%(8 ÷ 14)★ |
△×(problem_logs) |
★6行★ — 当日の5行(施設12 ×出発失敗・10 ×・9 ×・6 △・8 △)+ 前日の施設7(△。8111R5628060099)。★施設11 の結果待ちは出ない★ |
| 表に出る先頭5件 | ★当日の5行: 施設 12・10・9・6・8★(データソースの順) |
cleanLogs(lib/fixtures/clean-logs.ts)の並べ替えは scheduled_at しか見ないため、 同じ時刻の行は ★実際には id の降順★(施設9 = id 大 → 施設6)で出ます。Prisma 版は id の昇順なので、DB では 6・9 の順になります。 ★先頭5件の顔ぶれは変わりません★JST 3:30 より前は、当日の行の一部が「終わっていない」扱いになり、そのロボットは前日以前の行が出ます。 ★施設12(8111R5628060166)は7日以内に当日の行しか無いので消えます。それが正しい★。
| 現在(JST) | 選ばれる行 | summary |
△× | 表に出る先頭5件 |
|---|---|---|---|---|
| 02:00 | 14行(当日5行) | 成功9 / 失敗3 / 未実施2 / 結果待ち0 / 成功率 64.28…% | 5行 | 施設 8・4・9・6・7 |
| 03:29 | 14行(当日9行) | 成功9 / 失敗5 / 未実施0 / 結果待ち0 / 成功率 64.28…% | 5行 | 施設 10・9・6・8・7 |
(02:00 は当日の 02:00 までの予定が終わった扱い。03:29 は 03:30 の施設12・施設11 だけが終わっていない扱い。 ★D-173 以前の表(終了+30分。02:00 は 01:30 だけ・03:59 が境目の直前)とは値が違う★)
GET /errors(/errors 画面)のサンプルデータは lib/fixtures/error-reports.ts の errorReportRows(20行)と errorReportTimetables(予定5件)です。
toDbJst() を通した壁時計値の Date、id は bigint)。 ★fixtures と Prisma は同じ純粋関数を通す★(errorReportKeyFromRow() → filterSortErrorReportKeys() → errorReportItemFromRow())ので、 USE_FIXTURES で件数・並びが変わりませんFX-ERR-03 / 14 / 15 以外)・「解消済みも表示」で18行★FX-ERR-18(削除済みの施設)・19(削除済みの清掃エリア)はエラー一覧にも D-Sec アラートにも出ない★(isVisibleErrorRow()。指示書AX U8・表5 V2/V6)。PATCH /errors/{error_id}/status は404FX-ERR-18・19)だけ★ — 清掃ログ・予定・スケジュール・エリア・制御盤などの fixtures は deleted_at を持たない(D-182 で全画面に広げた「削除済みの施設・清掃エリアの行は出さない」は、Prisma 版では SQL の条件で外し、fixtures では外す対象が無い。★fixtures の件数は変わらない★)robot_id は読みません★(select で絞る。指示書AU 段階0-4)。fixtures にも値はありますが使いません — ★制御盤・セキュリティ・清掃開始失敗の行は robot_id が NULL★ という実データの形を示すためだけに持っていますerror_level の値(CRITICAL 以外)と、SECURITY_ON の error_level は実データ未受領のダミー★です。 NOT_STARTED・CRITICAL・シリアル --- の組はステージングの実測の形(D-158 2026-10-06 実測・先方投入)facilities から、ロボットのシリアルは各施設の先頭のロボットから、制御盤のシリアルは ds-devices から id で引きます(★直書きしない・実在の店名を入れない★)FX-ERR-06 の予定は「実DBでは履歴にだけある」想定ですPATCH /errors/{error_id}/status)は lib/db/fixture-error-report-overrides.ts の上書き表★に入ります (fixtures は書き換えない。プロセスを再起動すると消える。アラートの上書き表とは状態を共有しない)at())です| id | 内容 | status |
紐づく予定 | 表1(指示書AW §3) |
|---|---|---|---|---|
| FX-ERR-01 | ロボットのエラー(EmergencyStop / ERROR)・施設1 |
0 未解消 | 本清掃 | E1 |
| FX-ERR-02 | ロボットのエラー(LowBattery / WARNING)・施設1 |
1 対応中(responded_at あり) |
事前チェック(30分前。PRECHECK_MINUTES_BEFORE[1]) |
E2 |
| FX-ERR-03 | 解消済み(HandleUp)・施設3(responded_at / resolved_at / 備考あり) |
2 解消 | 本清掃 | E3(★既定では出ない★) |
| FX-ERR-04 | clean_timetable_id が NULL・施設2 |
0 | 予定なし | E4 |
| FX-ERR-05 | clean_timetable_id がどの予定にも無い id(9999)・施設2 |
0 | 予定不明 | E5 |
| FX-ERR-06 | 予定が履歴にだけある想定・施設4 | 0 | 本清掃 | E6 |
| FX-ERR-07 | errored_at が NULL(検知時刻は created_at)・施設4 |
0 | 本清掃 | E7 |
| FX-ERR-08 | ★robot_id NULL・シリアル ---・SECURITY_ON★・施設5 |
0 | 本清掃 | E8 |
| FX-ERR-09 | 事前チェック(★10分前。設定に無い値★)・施設1 | 0 | 事前チェック(10分前) | E9 |
| FX-ERR-10 | ★robot_id NULL・シリアル = 制御盤の SN(DS-001)・D-S_CONTROL_FAILURE★・施設1 |
0 | 本清掃 | 制御盤のエラー(D-158 P-8 a)・指示書AX R1(D-Sec にも出る) |
| FX-ERR-11 | ★robot_id NULL・シリアル ---・NOT_STARTED・CRITICAL★・施設5 |
0 | 本清掃 | 清掃開始失敗(ステージング実測の形) |
| FX-ERR-12 | ★D-S_CONTROL_FAILURE・施設11★・errored_at NULL・clean_timetable_id NULL |
0 | 予定なし | 指示書AX R4・R13(D-Sec にも出る) |
| FX-ERR-13 | ★D-S_CONTROL_FAILURE・施設5★・対応中・備考「回線業者に確認中」 |
1 | 本清掃 | 指示書AX R2(D-Sec にも出る) |
| FX-ERR-14 | ★D-S_CONTROL_FAILURE・施設4★・解消済み |
2 | 本清掃 | 指示書AX R3(★既定では出ない★。D-Sec は「全件」「解消済み」で出る) |
| FX-ERR-15 | ★D-S_CONTROL_FAILURE・施設10★・解消済み(2日前) |
2 | 本清掃 | 指示書AX R3(★既定では出ない★。D-Sec は「全件」「解消済み」で出る) |
| FX-ERR-16 | ★D-S_CONTROL_FAILURE・行は施設3・シリアルは施設2の制御盤★ |
0 | 本清掃 | 指示書AX R11(D-Sec にも出る) |
| FX-ERR-17 | ★D-S_CONTROL_FAILURE・施設8★・FX-ERR-16 と同じ検知時刻・対応中 |
1 | 本清掃 | 指示書AX R12(D-Sec にも出る) |
| FX-ERR-18 | ロボットのエラー(EmergencyStop)・★削除済みのダミー施設(id 99)★ |
0 | 本清掃 | 表5 V2(★どこにも出ない★) |
| FX-ERR-19 | ★D-S_CONTROL_FAILURE・施設2・清掃エリア削除済み★ |
0 | 本清掃 | 表5 V6(★どこにも出ない★。施設2の 04・05 は出続ける — V9) |
| FX-ERR-20 | ★clean_timetable_id が 0★(予定外のタスク。TeamWorks 回答 2026-10-27)・LostLocation・施設6 |
0 | ★予定なし★(API の clean_timetable_id は null。★予定不明に化けないこと★) |
E4 と同じ扱い |
★「解消済みも表示」の並び(検知時刻の降順。同値は id 昇順)★ — ★表の時刻から手で導いた順★: FX-ERR-07(当日 06:40)→ 12(02:55)→ 16(01:30)→ 17(01:30)→ 05(前日 23:50)→ 11(23:30)→ 01(23:10)→ 13(23:10)→ 08(22:55)→ 09(22:50)→ 10(22:45)→ 02(22:30)→ 04(15:20)→ 20(14:40)→ 14(03:55)→ 03(2日前 23:40)→ 15(2日前 02:00)→ 06(3日前 23:05)。 ★FX-ERR-18・19 は含まない★ (★当方の fixtures 由来。lib/db/__tests__/fixture-error-reports.test.ts が件数と降順を固定★)。
★既定(未解消・対応中)の並び★ — 上の並びから FX-ERR-03・14・15(解消)を除いたもの(15行): FX-ERR-07 → 12 → 16 → 17 → 05 → 11 → 01 → 13 → 08 → 09 → 10 → 02 → 04 → 20 → 06。 (件数はテストで固定。並びは手で導いたもの)
error_list_id / error_lists)(★D-184 / 指示書BD §5-2★)★選択肢★(GET /error-lists)は lib/fixtures/error-lists.ts の errorLists(★131行。スプレッドシート「PUDUエラー一覧_20261016」の「PUDUエラー 決定稿」シートを監督が抽出したもの★)です。 ★全行 inactive: 0・deleted_at: null★(無効化・削除済みの選択肢は fixtures に無い。テストでは各テストの中で作る)。 ★id 131 = 「OTHER ERROR / その他(該当なし)」★ — 備考必須(ERROR_LIST_NOTE_REQUIRED_IDS。note_required: true)。 ★Pudu の error_type は入れない★(error_lists にその列が無い)。★実DBの error_lists と中身が一致するかは未確認★(ステージングに接続できない。指示書BD §8)。
★エラー一覧の行の error_list_id★ — ★大半は null(未選択)★。値があるのは次の5行だけです(lib/db/__tests__/fixture-error-reports.test.ts が固定)。
| id | error_type |
error_list_id |
error_list |
何を見るための行か |
|---|---|---|---|---|
| FX-ERR-01 | EmergencyStop |
40 | 40「非常停止スイッチが作動しました」 | 有効な id の名前解決 |
| FX-ERR-03 | HandleUp(解消済み) |
39 | 39「ハンドルが持ち上げられました」 | 解消済みの行でも値を持つ |
| FX-ERR-05 | BrushError |
★9999★ | ★null★(error_lists に無い。error_list_id は 9999 のまま) |
画面の「不明(9999)」 |
| FX-ERR-06 | Offline |
37 | 37「ロボットがオフラインです」 | 有効な id の名前解決 |
| FX-ERR-11 | ★NOT_STARTED★ |
★131★(備考あり) | 131「その他(該当なし)」・note_required: true |
★清掃開始失敗は選べる★・その他は備考必須 |
error_list_selectable★ は error_type が D-S_CONTROL_FAILURE・SECURITY_ON(ERROR_LIST_UNSELECTABLE_ERROR_TYPES。完全一致)なら false — fixtures では FX-ERR-08(SECURITY_ON)と D-S_CONTROL_FAILURE の行(10・12〜17・19)。★これらの行には error_list_id を入れていない★error_lists を id IN で1回引く(lib/db/error-list-source.ts)D-S_CONTROL_FAILURE)はローカルDBに投入される★(scripts/seed-local-db.ts)が、選べない種別なので error_list_id は入れない(null)FX-ERR-11 に備考(ダミーの文)を足した★(指示書BD で追加。それまでは null)dwatch_local)に表と列を足す・入れ直す(★D-184 / 指示書BD §8★)★dwatch_local には元々 error_lists も robot_error_reports.error_list_id も無い★(実DBモードでローカルを使うと読み取りが落ちる)。次の順で足す:
npx tsx scripts/local-db/apply-error-lists.ts — scripts/local-db/20261027_error_lists.sql を流す(表は CREATE TABLE IF NOT EXISTS、列は information_schema を見て無いときだけ ADD COLUMN。★何度流しても同じ★)。 ★DATABASE_URL が localhost / 127.0.0.1 の dwatch_local でなければ接続前に止まる★(lib/db/local-guard.ts)。.env.local の DATABASE_URL がステージングを指している間は、実行するシェルでだけローカルに向けて渡すnpm run seed:local — error_lists を131行(lib/fixtures/error-lists.ts)で消して入れ直し、本清掃エラー(RER-<id>-main)の通番1・2・3 に error_list_id を入れる: ★38(有効)/131(その他・備考あり)/9999(error_lists に無い)★。残り(事前チェック行・D-Sec・決定3の2件・本清掃エラーの他の行)は null★ステージング・本番には流さない★(スキーマは TeamWorks の領域。CLAUDE.md §7)。prisma db push / migrate の代わりでもある(指示書M 禁止事項3・4)。 ★fixtures(FX-ERR-*)とローカルDB(RER-*)では error_list_id の入る行が違う★(ローカルDBは fixtures のロボットエラー行を投入しないため)