Newer
Older
client_dwatch / docs / handoff / 指示書AQ_データ参照元の切替_20260930.md

指示書AQ — データ参照元の切替(サマリ3粒度 / clean_task_reports / 完了率)

日付: 2026-09-30 / 前提: ユーザー指示 2026-09-30、CSV実測189行、本番DB実測


0. 何が変わるか(ユーザー確定事項)

# 決定 出所
1 ★確定期間のサマリは *_summaries から取得する。★週・月・年の3粒度★が入る(週=毎週日曜作成 / 月=月初作成) ユーザー指示 2026-09-30
2 ★直近・昨日の清掃情報は clean_task_reports から取得する★ 同上
3 ★clean_status_histories は使わない(clean_task_reports に一本化)★ 同上(選択肢の帰結を明示したうえでの選択)
4 ★清掃完了率は clean_ratio を採用する。面積比(Σclean_area÷Σtask_area)は廃止★ 同上
5 ★clean_timetable_id は今後 TeamWorks が埋める前提で実装する★ 同上
6 ★エラーは robot_error_reports に集約する。ただし実装は TeamWorks の入れ方を確認してから★ 同上(本指示書の範囲外)

決定4の根拠(実測。CLAUDE.md §6-6)

出所: ★ユーザー提供CSV clean_task_reports.csv 189行★(2026-09-30 受領。本番DBの clean_task_reports は0行なので、当DBからは取得できない)。

実測 値
clean_area > task_area の行 ★129 / 189(68.3%)★
Σclean_area ÷ Σtask_area 90.2%
DBの clean_ratio の平均 ★78.5%★
個別行の乖離例 面積比 13.8% ↔ clean_ratio 100.0% / 面積比 162.8% ↔ clean_ratio 61.0%

★面積比と clean_ratio は相関しない★。面積比のままでは ★◎(90%以上)が常態化して判定が機能しない★。


1. 監督が決めたこと(エージェントは従うこと)

1-1. ★「未実施」の判定★

clean_task_reports に ★clean_error 相当の列が無い★。代わりに次を正とする。

未実施 = 本清掃の clean_timetables 行に対応する clean_task_reports の行が無い

★これは推測ではなく、現行実装の第1分岐(notExecutedFromHistory() の if (!history) return true)と同じ規則★。 ★「出発失敗」と「未実施」は同一扱いのまま★(ユーザー確認 2026-09-30)。

1-2. ★「清掃結果」列は status の生値を出す★

clean_task_reports.status(CSV実測値 ★3 / 4 / 5 / 6★、分布 3:2 / 4:161 / 5:4 / 6:22)は ★定義書に値の説明が無い★(prisma/schema.prisma:520-521 が明記)。

★★推測で CLEAN_ERROR に対応づけないこと★★ — ★D-077 と同じ扱いにする(生値をそのまま表示)★。 CLEAN_ERROR(lib/config/index.ts:231-300)は ★削除しない★(clean_statuses 側で今後使う可能性があるため)。

1-3. ★面積は残す★

clean_area / task_area は ★総清掃面積(F-08)では引き続き使う★。 ★使わなくなるのは「完了率の計算に使うこと」だけ★。

1-4. ★「最新1件」の順序キー★

clean_task_reports.ended_at は ★nullable★(prisma/schema.prisma:533)。 順序キーは ★ended_at があればそれ、無ければ started_at★ とし、★決める場所は1関数だけ★にする。


2. 担当割り(ファイル所有権。重複禁止)

フェーズ1(並行可)

担当 所有ファイル 内容
★A★ lib/format/period.ts + lib/format/__tests__/period.test.ts 年次対応。periodRange / isCurrentPeriod / periodLabel / prevPeriodLabel / shiftPeriod
★B★ lib/types/index.ts / d-watch-api.yaml / lib/reports/query.ts + そのテスト Period に yearly を追加。month=0 / week=0 を年次で許可
★C★ lib/db/clean-log-mapping.ts / lib/format/clean-result.ts + そのテスト 未実施判定(1-1)と清掃結果の生値化(1-2)、順序キー(1-4)
★D★ lib/db/report-mapping.ts + そのテスト periodOfSummaryRow が month を見るように。完了率を clean_ratio ベースに
★E★ lib/db/consecutive-source.ts / lib/db/clean-area-source.ts + そのテスト 参照元の差し替え
★F★ scripts/seed-local-db.ts / lib/fixtures/ ★clean_task_reports のシードと fixtures を新設★(無いと切替後に全画面0件)

フェーズ2(フェーズ1完了後・単独)

担当 所有ファイル 内容
★G★ lib/db/index.ts 8箇所の参照元置換 + 年次除外 filter 3箇所の削除 + :2191 の fail-loud 見直し

フェーズ3(並行可)

担当 所有ファイル 内容
★H★ components/features/reports/ReportsScreen.tsx 粒度タブを3つに
★I★ lib/clean-logs/csv.ts / components/features/detail-log/CleanLogTable.tsx 清掃結果列の生値化
★J★ app/api/**/__tests__/ モック形状の追従(176ケース)

3. ★落とし穴(全担当が読むこと)★

# 罠 なぜ危険か
1 ★clean_timetable_id が nullable★ ★NULL は IN に一致しない★。行が消えるのではなく ★「未実施」として集計される★(fail-silent)。稼働率・出発成功率が0に落ちる
2 ★periodOfSummaryRow() が week===0 → monthly だけ見ている★ 年次除外 filter を消すと ★年次行が「月次」として静かに混入★し、customerSummariesByPeriodKey() が重複検知で ★500★
3 ★ended_at が nullable★ latestHistoryByTimetableId() は非nullを型で要求している。型ごと直す
4 ★status の意味は未受領★ 推測でマッピングしない(1-2)
5 ★clean_task_reports はローカルDB 0行★ ★担当F が先にシードを入れないと、他担当は動作確認できない★
6 ★年次は month=0 かつ week=0★ Month の minimum: 1(d-watch-api.yaml:1491)と MONTH_MIN = 1(lib/reports/query.ts:57)に当たる

4. ★本指示書の範囲外★

  • ★制御盤エラーの robot_error_reports への集約★ — robot_id が NOT NULL で FK があり、★値を捏造せずに入れる手が無い★。TeamWorks に入れ方を確認してから着手する(決定6)
  • ★4カラムの UPDATE★ — 本番DBへの書き込み禁止が続いているため未着手のまま(CLAUDE.md §3)

5. ★追補(フェーズ1の完了報告を受けて監督が決めたこと。2026-09-30)★

# 決定 理由
5-1 ★総清掃面積画面(F-08)の completion_rate も clean_ratio 由来にする★。★面積の合計(Σclean_area / Σtask_area)は表示に残す★ ★同じ「清掃完了率」が画面によって別の式になるのを防ぐ★。面積比のままだと、同じ施設が★レポート画面で78%・F-08で120%★と出うる(CSV実測: 面積比90.2% ↔ clean_ratio 平均78.5%)。複数行の畳み方は★担当Dが lib/db/report-mapping.ts に決めた関数を共用する★(2箇所で別々に畳まない)
5-2 ★API のフィールド CleanLogItem.clean_error を task_status に改名する★。★d-watch-api.yaml を先に直す★(CLAUDE.md §6-1) ★中身が clean_task_reports.status に変わるのに名前が clean_error のままだと、読み手が旧コード表(0:正常 / 1:未実施 …)で解釈する★。担当Cが関数名を formatCleanTaskStatus に変えたのと同じ理屈(型が同じ `number \ null` なので、名前を変えないと直し忘れが型エラーにならない)
5-3 ★総清掃面積の集計は lib/db/clean-area-source.ts の loadCleanAreaFacilityStats() / countDuplicatedTimetables() を必ず経由する★。lib/db/index.ts に groupBy を直書きしない ★重複検知の番人に clean_timetable_id IS NOT NULL の除外が入っている★。直書きすると除外が落ち、★NULL が1グループにまとまって毎回偽陽性★になる(担当E 申し送り)
5-4 ★シードは dwatch_local 以外に書けない★ことを確認済み(lib/db/local-guard.ts:19 / scripts/seed-local-db.ts:89) ★.env.local は本番DB(133.125.238.144)を指している★ため、実行前に必ずガードが効くことを監督が確認した

フェーズ2の担当(更新)

担当 所有ファイル 内容
★G★ lib/db/index.ts 8経路の置換 + 年次除外3箇所の削除 + :2191 の fail-loud 見直し + ★5-3 の関数経由化★
★K★ d-watch-api.yaml / lib/types/index.ts ★5-2 の改名★ + ★型の docstring に残る旧取得元(clean_status_histories)と面積比の定義(5-1)の書き換え★

5-5. ★完了率の定義は全画面で1つ★(§5-1 を拡張。担当K の指摘を受けて)

§5-1 は総清掃面積(F-08)だけを名指ししていたが、★理由(同じ「清掃完了率」が画面ごとに別の式になるのを防ぐ)は全画面に当てはまる★。次をすべて ★clean_task_reports.clean_ratio の単純平均(清掃1回=1票。lib/judge/kpi.ts の meanCleanRatio())★ に揃える。

画面 / フィールド 旧 新
レポートKPI completion_rate 面積比 ★単純平均★(担当D で済)
総清掃面積 F-08 completion_rate 面積比 ★単純平均★
★エリア別完了率モーダル overall_completion_rate★ 面積比 ★単純平均★
★要レスキュー R-3・RescueRequiredItem.completion_rate★ 面積加重 ★単純平均★
清掃詳細ログ(1行=1清掃) clean_ratio 変更なし(平均する対象が1件)

★面積の合計フィールドは、表示用として残す(完了率の分子・分母ではない)★。

担当L の所有範囲に ★lib/types/index.ts の CleanAreaFacilityStats / CleanAreaRow / CleanAreaTotal / AreaCompletionsResponse / RescueRequiredItem と、d-watch-api.yaml の対応スキーマ★ を追加する(担当K は完了済みなので衝突しない)。