task_area = 0 は 0%・当期KPIをサマリの式に・「屋号」を「顧客」に・古いコメント4件)日付: 2026-10-05 / 担当: Cursor / 基点: develop 74cffd5(指示書AR・AS・AT は実装済み) 前提: D-155 / D-156 / D-157 / ★D-158(本書の根拠)★ / CLAUDE.md §4.2・§4.3・§4.7・§6・§7・§9.4 / TeamWorks 第11回の回答(原文 docs/handoff/TeamWorks回答_第11回_20261005.md。設問は docs/handoff/TeamWorks確認事項_第11回_20261002_送付版.md)
★CLAUDE.md §4.2 は監督が直してある★(CLAUDE.md:159-182)。本書はそれにコードを合わせる作業。 ★期待値表(§3 の表1・表2)は監督が確定した正。変えないこと★(CLAUDE.md §0-2・§6-2・§9.4)。
| # | 回答 | やること | 段階 |
|---|---|---|---|
| 1 | ★P-5=B★ | ★task_area = 0 の清掃の1回ごとの完了率を null から 0.0 にする★(runCompletionRate())。null を前提にした説明・テストを直す |
段階2 |
| 2 | ★P-6=A/A/B★ | ★当期(アプリがその場で集計する期間)の稼働率・出発成功率・エラー発生率を、サマリと同じ式にする★ | 段階3 |
| 3 | P-7=C | 予定を clean_timetables と clean_timetable_histories から読む |
★段階3b★ |
| 4 | ★P-15=B★ | ★画面の見出し「屋号」を「顧客」にする★(「全屋号」→「全顧客」ほか)。★データの説明の「屋号(customers.id)」も「顧客」に(§11 Q2)★ |
段階4 |
| 5 | (D-157)・P-4 | ★回答が来たら直すと控えていた古いコメント4件★と、★status 6 の説明3か所(§11 Q4)★を直す | 段階5 |
| 6 | (P-6 の帰結) | ★fixtures の作り値で稼働率 > 出発成功率になっている1行★を直す(§11 Q5) | 段階3(3-4 の表の下) |
★変えないもの★: 確定期間(サマリ *_summaries)の値の読み方(そのまま読む)/完了率の平均の取り方(meanCleanRatio())/ 判定(◎○△×・L1〜L3・アドバイス・要レスキュー)の規則/未実施を departed で数えること(指示書AS 案A。D-156 項1)。
task_area = 0 の行)= B「0% として数える」いまは runCompletionRate() が task_area === 0 で null を返し(lib/judge/kpi.ts:148)、分子にも分母にも入れていない(D-155 の暫定。D-156 項1)。 ★これを 0.0 にする★。帰結:
completion_rate === null ⟺「レポートの行が無い(未実施)」が、再び両向きに成り立つ★(指示書AS で崩れた不変条件が戻る)departed で数え続ける★(AS 案A を残す。理由は D3)cleanRatioCount / clean_ratio_count)は、実施と数えた回数と常に同じ値になる(task_area = 0 も件数に入るため)| 指標 | ★新しい式(サマリと同じ)★ | いまの当期の式 |
|---|---|---|
| 稼働率 | ★正常終了(status = 4)の回数 ÷ 予定回数★ |
レポート行がある回数 ÷ 予定回数(★出発成功率と同じ値になっていた★) |
| 出発成功率 | ★開始できた回数(レポート行がある回数)÷ 予定回数★(★時刻の条件なし★) | 同じ(「定刻出発」と書いてあるが、実際は時刻を見ていない) |
| エラー発生率 | ★エラー回数 ÷ ★予定回数★★ | エラー回数 ÷ 実施回数 |
★確定期間はサマリの値をそのまま読んでいる★(kpiFromSummaryRatios()。lib/db/report-mapping.ts:231-241)ので、 ★変えるのは当期だけ★。式が揃うので、前期比(サマリ)と当期(アプリ)の差が同じ式どうしの差になる。
customers の単位)= B「法人」customers は法人の単位で確定。★画面の見出し語「屋号」を「顧客」に変える★(D-158 当方の対応3)。 ★DB の物理名(customers / customer_name)・API のキー(customer_id)は変えない★(見出し語だけ)。
| # | 決定 | 理由 | |
|---|---|---|---|
| D1 | ★runCompletionRate() は task_area === 0 のとき 0 を返す★。★戻り値の型を number(null なし)にする★ |
P-5=B。null を返す場合がもう無いので、型で示す(呼び出し側の「null なら足さない」分岐が要らなくなったことを tsc が教えてくれるわけではないので、§段階2 の一覧で手で消す) |
|
| D2 | ★clean_area > 0 かつ task_area = 0 も 0★(Infinity / NaN / 100 にしない) |
P-5=B は「0% として数える」。割り算をしないで返す | |
| D3 | ★未実施は引き続き departed で数える★(ConsecutiveInput.departed / RescueRowInput.departed / launchFailedDaysInRun() / foldRescueDays() は中身を変えない) |
★完了率の規則がまた変わっても、未実施の数え方が巻き込まれないため★(AS 案A の理由のうち「規則を2つの意味に兼用しない」はいまも正しい)。監督指示 | |
| D4 | ★稼働率の分子=「その本清掃の(最新の)レポート行があり、その status が CLEAN_TASK_STATUS.completed」の回数★。★4 を直書きしない★(lib/config/index.ts:348-361 に既にある) |
P-6=A。CLAUDE.md §7(数値の直書き禁止)の趣旨 |
|
| D5 | ★「正常終了か」を決める述語は1つだけ★: lib/judge/kpi.ts に `isCompletedTask(report: { status: number } \ |
undefined): booleanを足す(lib/judge/index.tsはexport *` なので自動で出る) |
規則を2箇所に書かない(D-103 項1 と同じ考え方)。判定層は lib/db/ を import しないので構造的な型にする(runCompletionRate() と同じ作法) |
| D6 | ★CleanStatsBucket に completed: number(正常終了の回数)を足す★。★既存の executed は名前を変えず、意味を「開始できた回数(レポート行がある回数)=出発成功率の分子」と書き直す★ |
名前を変えると機械的な差分がレビュー(daichi。D-154)を読みにくくする(指示書AS D7 と同じ判断)。executed を数える規則(isNotExecuted 述語)はいまのまま正しい |
|
| D7 | ★CleanStatsReportLike に status: number を足す★ |
当期の2経路(reportKpis() / facilityPerformance())は cleanTaskReport.findMany を ★select なし(全列)★で引いている(lib/db/index.ts:2085 / :2352)ので、status は既に載っている。★select を足さないこと★(足すなら status を落とさない) |
|
| D8 | lib/judge/kpi.ts の3関数は名前を変えず、引数名と docstring を変える: operationRate(completed, planned) / launchRate(started, planned) / ★errorRate(errors, planned)★ |
中身はどれも rate(分子, 分母) のまま。変わるのは呼び出し側(kpiFromCleanStats())が渡すもの |
|
| D9 | ★エラー発生率は100%で切らない★(エラー件数が予定回数より多ければ100を超える) | サマリの式(error_count ÷ task_count)に上限は無い。1回の清掃に複数のエラーが紐づきうる |
|
| D10 | ★未来の予定(isFutureSchedule())は、予定・開始・正常終了・エラーのどれにも足さない★(いまと同じ) |
指示書V 不具合A・決定1。変えない | |
| D11 | ★確定期間(サマリ)の値は1つも変えない★。kpiFromSummaryRatios() / SummaryRatios / periodOfSummaryRow() に触らない |
D-158。サマリは既に新しい式 | |
| D12 | ★画面の見出し語は lib/i18n.ts のキー(日本語原文)で持つ★。キーを 屋号 → 顧客 に改名し、★すべての t("屋号…") 呼び出しを新しいキーに直す★(旧キーは残さない) |
旧キーを残すと、片方だけ直した画面が日本語で「屋号」のまま出ても気づけない。重複キーは lint が落とす | |
| D13 | ★英語は仮★: 「顧客」"Customer" / 「全顧客」"All Customers"(★大文字は既存の "All Holdings" にそろえる。§11 Q7★)ほか(段階4 の表)。★英語は後でユーザーがまとめて見直す★とコメントに書く | 監督指示(暫定) |
★表1・表2 は監督が確定した正である。Cursor は値を変えないこと★(CLAUDE.md §0-2・§6-2・§9.4)。 ★段階1 で、実装より先にこの表をテストにする★。表とテストが食い違ったら、テストを表に合わせる。実装の都合で表を直さない。
runCompletionRate の変更分。AS 表1 の R9 を差し替え、R12 を追加。他の R1〜R11 はそのまま)★正・変えない★| # | clean_area | task_area | 期待値 | 確かめること |
|---|---|---|---|---|
| R9 | 10 | 0 | 0.0 | 対象面積0は 0%(P-5=B)。旧: null |
| R12 | 0 | 0 | 0.0 | 両方0も 0% |
| # | 予定 | レポート行あり(開始) | うち status=4 | エラー件数 | 稼働率 | 出発成功率 | エラー発生率 |
|---|---|---|---|---|---|---|---|
| K1 | 10 | 9 | 7 | 2 | 70.0 | 90.0 | 20.0 |
| K2 | 0 | 0 | 0 | 0 | null | null | null |
| K3 | 5 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 |
| K4 | 4 | 4 | 4 | 0 | 100.0 | 100.0 | 0.0 |
| K5 | 3 | 3 | 2(残り1行は status=5) | 3 | 66.666… | 100.0 | 100.0 |
| K6 | 2 | 2 | 1(残り1行は status=6) | 0 | 50.0 | 100.0 | 0.0 |
| K7 | 2 + 予定外1行(status=4・予定 ID NULL) | 2 | 2 | 0 | 100.0 | 100.0 | 0.0(予定外は数えない) |
| K8 | 1 | 1 | 1(status=4・clean_area=0) | 0 | ★100.0★ | 100.0 | 0.0 |
lib/judge/kpi.ts:22-23)。★K3 は「予定はあったが全部出発失敗」★なので 0.0。★エラー発生率も 0.0★(旧式では実施0回で null だった)。テストの書き方の注意(表2):
aggregateCleanStatsByFacility() → sumCleanStatsBuckets() → kpiFromCleanStats() を通して★ ReportKpi の value を確かめる(lib/db/__tests__/report-mapping.test.ts に新しい describe)。自前で割り算を書かない。now より前)にする。1施設でよい。前期(prev)は undefined。errorCount の Map(本清掃 id → 件数)で渡す。K1 は2件を別々の予定に、K5 は3件を1つの予定に寄せてよい。latestReportByTimetableId() を通して★レポートの Map を作る(予定外=clean_timetable_id: null の行が Map に入らないことまで含めて確かめる)。予定 ID が NULL のエラー行も errorCountByMainTimetable() を通して落ちることを1件足してよい。toBe。★K5 の稼働率だけ toBeCloseTo(200 / 3, 10)★。稼働率 ≤ 出発成功率(正常終了は開始の部分集合)を確かめる。AS の期待値表のうち、task_area = 0 に当たる行だけが変わる。★他の行は変えない★。
| 元の表 | # | 入力 | 旧の期待値 | ★新の期待値★ |
|---|---|---|---|---|
| AS 表4(F-08) | F5 | 本清掃 10/0 の1行だけ | executed_count 1 / completion_rate null | executed_count 1 / ★completion_rate 0.0★ |
| AS 表5(未実施の数え方) | U2 | 行がある・task_area = 0 |
departed true / completion_rate null / R-1 数えない / 出発失敗日 数えない / 問題日 | departed true / ★completion_rate 0.0★ / R-1 数えない / 出発失敗日 数えない / 問題日(★0.0 は ×★) |
| AS 段階3-2(当期KPI の完了率) | w11 | task_area = 0 の行 |
実施1・完了率の件数0 | 実施1・★件数1・Σ に 0 を足す★ |
| 詳細ログの1行 | — | 行がある・task_area = 0 |
完了率 -・判定 × |
★完了率 0%・判定 ×★(displayRate(0)) |
| # | 罠 | どう避けるか | |
|---|---|---|---|
| 4-1 | ★サマリの値まで計算し直す★ | ★確定期間はそのまま読む★(D11)。kpiFromSummaryRatios()(lib/db/report-mapping.ts:231-241)・periodOfSummaryRow() に触らない。★route.test.ts の確定期間のテスト(app/api/reports/__tests__/route.test.ts:563-600 / :1020-1229)の期待値は1つも変わらないのが正しい★ |
|
| 4-2 | ★status の 4 を直書きする★ |
CLEAN_TASK_STATUS.completed(lib/config/index.ts:358)を読む。`grep -rnE "status ?===? ?4([^0-9] |
$)" lib app componentsが0件になること(★status === 422(lib/reports/block-visibility.ts:160`)に当たらない形で探す★) |
| 4-3 | ★正常終了の判定を2箇所に書く★ | isCompletedTask()(D5)だけ。report-mapping.ts の中で report.status === … と書かない |
|
| 4-4 | ★cleanTaskReport.findMany に select を足して status を落とす★ |
いまは select なし(D7)。★足さない★。テストのスタブ行にも status を必ず入れる |
|
| 4-5 | ★正常終了の判定に面積を混ぜる★(「clean_area = 0 なら正常終了でない」) |
★status だけで数える★(表2 K8)。面積は完了率の話 | |
| 4-6 | ★エラー発生率を100で切る★ | 切らない(D9) | |
| 4-7 | ★未実施の数え方を completion_rate === null に戻す★ |
★departed のまま★(D3)。P-5 で null ⟺ 未実施が戻っても、launchFailedDaysInRun()(report-mapping.ts:648)・foldRescueDays()(lib/judge/rescue.ts:168)は変えない |
|
| 4-8 | ★runCompletionRate() で割り算を先にしてから 0 を判定する★ |
task_area === 0 を ★割る前に★ 見て 0 を返す(10 / 0 = Infinity → Math.min(Infinity, 100) = 100 になる) |
|
| 4-9 | ★生SQL($queryRaw / $executeRaw)★ |
★禁止★(CLAUDE.md §3。eslint が止める)。本書の変更はすべて JS の中で済む |
|
| 4-10 | ★閾値・コード値の直書き★ | 90/70/10 は GRADE_THRESHOLDS、status は CLEAN_TASK_STATUS、上限100と桁数は RUN_COMPLETION_RATE |
|
| 4-11 | ★画面の文字列を i18n に通さない★ | JP/EN は必ず t()(lib/i18n.ts)。★新しい見出し語をコンポーネントに直書きしない★ |
|
| 4-12 | ★JP/EN 切替でレイアウトが崩れる★ | ★日本語は「屋号」「顧客」とも2文字、「全屋号」「全顧客」とも3文字で幅は変わらない★。英語は "Brand" → "Customer" で少し長くなる。セレクトは幅指定なし(内容の長さで決まる。例 components/features/alerts/AlertsScreen.module.css:58-65)で、ツールバーは flex-wrap: wrap。★幅を固定する CSS を新たに足さない★。段階6 の画面確認で EN の折り返しを見て、崩れていたら直さずに報告する |
|
| 4-13 | ★顧客 の i18n キーが既存と重なる★ |
2026-10-05 時点で 顧客 / 全顧客 / 顧客を選ぶ / 選べる顧客が{n}件あります / この条件では選べる顧客がありません は未登録(既存は 顧客を選んでください(lib/i18n.ts:357)だけ)。重複は lint が落とす |
|
| 4-14 | ★「屋号」を一括置換する★ | ★しない★。§7 の分類どおり、画面に出る文字列・それを直接説明するコメント・★データの説明(段階4 の 4-3 に列挙した行。§11 Q2)★だけを直す。経緯・処理の理由のコメントは残す | |
| 4-15 | ★git add -A★ |
★禁止★(CLAUDE.md §7)。ファイルパスを明示する |
git status が clean で、develop が 74cffd5 以降であること(.claude/worktrees/ ではなく本体で作業する)。74cffd5 で確かめたもの。★段階3b(P-7)が先に当たるとずれる★ので、記述(関数名・文)で探すこと。npx tsc --noEmit -p . と npm test が通る状態から始める(通らなければ着手前に報告)。robotErrorReport の読み取りを select で必要な列だけにする(§11 Q6)★。先方の DDL では robot_id が NULL 可になった(第11回 P-8 b)が、Prisma のスキーマは NOT NULL のまま。★robot_id と robot リレーションを読まなければ、NULL の行が入っても読み取りで落ちない★。grep -rn "robotErrorReport\." app lib で全部の読み取りを洗い、select を付ける(書き込み lib/db/robot-error-write.ts は対象外)。★prisma/schema.prisma は変えない★(db pull は監督が行う)。テスト: スタブに robot_id: null の行を混ぜても落ちないことlib/judge/__tests__/run-completion-rate.test.ts:
:13-27)の R9 を表1 の行に差し替え、R12 を足す。:8 の「★暫定★」と :11 の「task_area = 0 は null(分子にも分母にも入れない)」を「task_area = 0 は 0(P-5=B。第11回)」に直す。★「本書 §3 が正。変えないこと」と出典に本書を足す★it.each(:74-86)の R9 を ["R9 対象面積0は 0%(P-5=B)", 10, 0, 0.0] に、R12 を足すmeanCleanRatio() に渡すテストなので ★そのまま★(null は「未実施=レポート行が無い」の意味で残る)lib/judge/__tests__/kpi.test.ts:
:13-22)を CLAUDE.md §4.2 の新しい式に直すoperationRate(:24-35): 引数の意味を「正常終了の回数 ÷ 予定回数」に。値のテストは変えなくてよいlaunchRate(:37-46): :38-39 の「定刻出発85件」の例を「開始できた回数 ÷ 予定回数(時刻の条件なし)」に書き直すerrorRate(:100-109)を逆の仕様に直す★: 「分母は清掃予定回数」errorRate(9, 100) === 9/予定0は null/★上限で切らない★ errorRate(4, 3) が toBeCloseTo(400 / 3, 10)isCompletedTask() のテストを足す★: undefined → false/status 4 → true/0・1・2・3・5・6・255 → false/★期待値の 4 は CLEAN_TASK_STATUS.completed から読む★lib/db/__tests__/report-mapping.test.ts に ★表2 の K1〜K8 と「稼働率 ≤ 出発成功率」★を新しい describe で書く(§3 の注意どおり)isCompletedTask が無い・completed が無い・R9 が null を返す)のが正しい★。コミットはテストだけで1つtask_area = 0 を 0% にする(P-5)lib/judge/kpi.ts:144-153 の runCompletionRate():
if (report.task_area === 0) return 0;(★割る前に★。4-8)number にする(D1):112-143)を直す:
:120-123「★★暫定(D-155。ユーザー判断「一旦B」)★★ — 第11回で…見直す」→ ★確定★(第11回 P-2=A「今の式のまま」・P-1「訂正後の clean_ratio 列もこの式と同じ値」。D-158)。「clean_ratio 列に戻すときはこの関数の中身だけを直す」「呼び出し側は行をそのまま渡すこと(D6)」は ★残す★(1関数に閉じ込める作法として今も正しい):125-126「task_area === 0 は null(…暫定・第11回で確認)」→ ★0(P-5=B。第11回)★。★clean_area > 0 でも 0★(D2)。旧は null だったことを1行:142 の @returns から「task_area === 0 なら null」を消す:4-24)の :12 の「(暫定)」を「(第11回で確定。D-158)」にlib/config/index.ts:27-36 の RUN_COMPLETION_RATE の docstring: :34-35 の「暫定…第11回で…見直す」を ★確定(第11回 P-2=A。D-158)★ に。★値(cap: 100 / decimals: 1)は変えない★。
runCompletionRate() の戻りを直接受けている所だけ★)| 場所 | いま | 直し方 |
|---|---|---|
lib/db/report-mapping.ts:488-501 |
runRate ?? 0 / runRate === null ? 0 : 1 |
runRate は「実施と数えた行 かつ 結果行がある」ときだけ数値、それ以外 null のまま(:492)。★:500-501 はそのままでよい★(null になるのは結果行が無いときだけ)。コメント :488-491 の「task_area = 0 なら null で…件数には入れない」を消す |
lib/db/clean-area-source.ts(cleanAreaStatsFromRows() の中。:290 以降) |
const rate = runCompletionRate(report)。null でなければ足す |
★常に足す★(clean_ratio_sum += rate / clean_ratio_count += 1)。docstring :251-253 の「task_area = 0 の清掃も実施1回に数える(表4 F5)」「null でなければ」を表3 の F5 に合わせる |
lib/db/fixture-clean-area.ts:76-99 |
rate ?? 0 / rate === null ? 0 : 1 / if (rate !== null) |
★常に足す★。コメント :30-31 / :84-85 の「null(task_area = 0)なら Σ にも件数にも足さない」を消す |
lib/db/clean-log-mapping.ts:203-210(completionRateFromReport()) |
中身はそのまま(結果行が無ければ null、あれば runCompletionRate()) |
★中身は変えない★。docstring を 2-3 のとおり直す |
| ファイル:行 | いま | 直し方 |
|---|---|---|
lib/judge/kpi.ts:59-62(CleanRatioTally.cleanRatioCount) |
「未実施の清掃と task_area = 0 の清掃は数えない」 |
「★未実施の清掃は数えない★(task_area = 0 は 0% として数える。P-5=B)」 |
lib/db/clean-log-mapping.ts:171-199(completionRateFromReport()) |
表の2行目「行があり task_area = 0 → null」/不変条件「逆は成り立たない」(:192-199) |
表を「行が無い → null/それ以外 → runCompletionRate()(task_area = 0 は 0)」の2行に。★不変条件を「departed === false ⟺ completion_rate === null(P-5=B で両向きに戻った)」★に直し、★「それでも未実施は departed で数える(D3。完了率の規則が変わっても未実施の数え方を巻き込まないため)」★と書く。:180-185 の経緯は残し、D-158(確定)を1行足す |
lib/db/clean-log-mapping.ts:94(CleanTaskReportLike) |
「(D-155。暫定)」 | 「(D-155。第11回で確定。D-158)」 |
lib/db/clean-log-mapping.ts:350-363(ConsecutiveInput) |
:352「未実施と task_area = 0 の清掃は null」/:358-361「task_area = 0 の清掃は completion_rate === null だが出発はしている」 |
:352 は「未実施は null」。:358-361 は「未実施は departed で数える(D3)」の理由を、task_area = 0 の例ではなく D3 の理由に差し替える |
lib/db/consecutive-source.ts:35 / :254-255 |
「(D-155。暫定)」/「task_area = 0 の清掃は…」 |
確定に/D3 の理由に |
lib/db/report-mapping.ts:293-298(cleanRatioCount)/ :433-440(aggregateCleanStatsByFacility())/ :637-640(launchFailedDaysInRun()) |
「task_area = 0 の清掃は実施には数えるが、ここには数えない」/「逆は成り立たない」 |
「★いまは executed と同じ値になる★(task_area = 0 も 0% として数えるため。P-5=B)。★それでも別に持つ★(Σ と件数の組で meanCleanRatio() に渡す形を変えないため)」/不変条件を両向きに、departed で数える理由は D3 |
lib/judge/rescue.ts:20-22 / :75-79 / :93-96 / :166-169 |
「task_area = 0 の清掃は completion_rate が null だが出発はしている」 |
D3 の理由に差し替える。★:168(!row.departed)と :170-171(null を数えない)は中身を変えない★ |
lib/db/index.ts:977-980 |
「逆は成り立たない — task_area = 0 は出発しているが null」 |
両向きに成り立つ(P-5=B)。★report ? report.clean_ratio : null の形に戻さないこと★(:977-978)は残す |
lib/types/index.ts:248-255(CleanLogItem.completion_rate)/ :347 / :1272-1277(CleanAreaFacilityStats.clean_ratio_count) |
「行があっても task_area = 0 なら null」/「executed_count を流用せず別に持つ — task_area = 0 は…入らない」 |
「行があって task_area = 0 なら 0(P-5=B)」/「いまは executed_count と同じ値。形を変えないために別に持つ」。:250 の「★暫定★」を確定に |
components/features/detail-log/AreaModal.tsx:42-43 |
「未実施・task_area = 0=完了率が null の行は…」 |
「未実施=完了率が null の行は…」 |
d-watch-api.yaml :340 / :563 / :567 / :598-599 / :918 / :1743 / :1746 / :1796-1797 / :2056 |
「task_area = 0 は除く」「task_area = 0 のときも null」「D-155(暫定)」 |
「task_area = 0 は 0」「(D-155。第11回 P-2・P-5 で確定。D-158)」。★:1746「★task_area = 0 のときも null★(このとき departed は true)」と :1797「task_area = 0 も null」は消す★ |
★最後に次の grep を流し、残ったものが「経緯(旧: …)」の説明だけになっていること★:
grep -rn "task_area = 0\|task_area === 0\|task_area=0\|task_area が 0" app lib components d-watch-api.yaml docs/fixtures.md --include=*.ts --include=*.tsx --include=*.yaml --include=*.md | grep -v "lib/generated" | grep -v __tests__
| ファイル:行 | 直し方 |
|---|---|
lib/db/__tests__/clean-log-mapping.test.ts:319 / :374-378 / :382-402 / :420-421 |
表3 の「詳細ログの1行」: { clean_area: 10, task_area: 0 } → completion_rate は 0。:420 の「逆は成り立たない」のテストは ★「両向きに成り立つ」★に書き換える |
lib/db/__tests__/clean-log-mapping.test.ts:583-587(isProblemCompletion() の U2) |
入力が面積から来ているなら 0 → 問題(×)。期待値(問題)は変わらない。ラベルを直す |
lib/db/__tests__/consecutive-source.test.ts:80(Q9)/ :262-266(テスト内の再実装) / :655-697 |
★:265 のテスト内の r.task_area === 0 ? null を消し、runCompletionRate() を呼ぶ形にする★(テストの中に規則を写さない)。Q9 の「task_area = 0 は null」→ 0 |
lib/db/__tests__/report-mapping.test.ts:318 / :689-700(w11) |
表3 の w11(実施1・件数1・Σ に 0) |
lib/db/__tests__/clean-area-source.test.ts:226 / :252(F5) |
表3 の F5(completion_rate 0.0) |
lib/db/__tests__/fixture-clean-area.test.ts:145 |
「実施回数に入り、完了率の件数にも入る(0% として)」に |
★completion_rate: null, departed: true を直接渡しているテスト★ — lib/judge/__tests__/rescue.test.ts:27 / :227 / :241、lib/db/__tests__/report-mapping.test.ts:91-93 / :1101 / :1119、lib/db/__tests__/rescue-mapping.test.ts:41 |
★入力の組み合わせは DB からは来なくなったが、テストは残す★(「未実施は departed で数える」ことの確認。D3)。ラベルの「task_area = 0」を「departed と completion_rate が食い違う行(防御)」に直すだけ。期待値は変えない |
lib/clean-area/__tests__/aggregate.test.ts:19 / :183(A-4) |
渡された Σ と件数から出すテストなので中身はそのまま。説明だけ(「clean_ratio から出る」→「渡された Σ と件数から出る」) |
lib/judge/kpi.ts):4-24)の式を CLAUDE.md §4.2(CLAUDE.md:161-166)と同じ4行に直す。「★3つの率はサマリと同じ式(第11回 P-6)★」と、旧の式(実施回数 ÷ 予定・定刻出発 ÷ 予定・エラー ÷ 実施)を1行で残すoperationRate()(:32-35): 引数を (completed, planned) に。docstring「稼働率 = 正常終了(status = 4)の回数 ÷ 清掃予定回数(P-6=A)」launchRate()(:37-40): 引数を (started, planned) に。docstring「出発成功率 = 開始できた回数(レポート行がある回数)÷ 清掃予定回数。★時刻の条件なし(P-6=A)★」errorRate()(:155-158): 引数を (errors, planned) に。docstring「エラー発生率 = エラー発生回数 ÷ ★清掃予定回数★(P-6=B)。★上限で切らない(D9)★。旧: 分母は実施回数」isCompletedTask() を足す★(D5):
import { CLEAN_TASK_STATUS, FACILITY_STATUS_THRESHOLDS, RUN_COMPLETION_RATE } from "@/lib/config";
/** その清掃が正常終了したか(稼働率の分子。P-6=A)。★status だけで決める。面積は見ない★ */
export function isCompletedTask(report: { status: number } | undefined): boolean {
return report !== undefined && report.status === CLEAN_TASK_STATUS.completed;
}docstring に: 出所(第11回 P-6=A・送付版 :87)/★「最新の1行」で見る★(呼び出し側が latestReportByTimetableId() で選んだ行を渡す)/★◎○△× の判定には使わない★(D-155 項2 は変わらない)/★面積は見ない(表2 K8)★judgeFacilityStatus()(:178-203)は ★中身を変えない★。ただし docstring に「★当期の稼働率は P-6 で『正常終了 ÷ 予定』になった(以前は出発成功率と同じ値)。当期の施設ステータスは以前より低めに出る★」と1行足すlib/db/report-mapping.ts)CleanStatsBucket(:245-299):
:245-256 を書き直す★(D-157 の :249 もここで直る。段階5 を参照)。新しい中身:
planned★planned = 期間内・過去の本清掃の予定の数/executed = そのうちレポート行がある数(★開始できた回数=出発成功率の分子★)/★completed = そのうち最新のレポート行の status が正常終了の数(稼働率の分子)★/errorCount = エラーの数(エラー発生率の分子)clean_task_reports.started_at は、予定のある清掃では予定の start_at と同じ値が入る(ユーザー回答 2026-10-05。D-155 項5 の N-9)ので、★定刻かどうかはそもそも区別できない★completed ≤ executed ≤ planned★(だから 稼働率 ≤ 出発成功率 ≤ 100)executed(:260)の docstring「清掃実施回数(=定刻出発回数。上記コメント参照)」→「開始できた回数(レポート行がある回数)。出発成功率の分子」completed: number を足す★(executed の直後)errorCount(:266-282)の docstring: :278-280 は段階5 の文に差し替える。★分母は予定回数★になったことを書くemptyCleanStatsBucket()(:301-311)・addCleanStats()(:313-323)に completed を足すCleanStatsReportLike(:394-416)に ★status: number★ を足す(D7)。docstring に「★status は稼働率の分子(isCompletedTask())にだけ使う★」aggregateCleanStatsByFacility()(:460-505):
const completed = executed && isCompletedTask(report);(isCompletedTask は @/lib/judge から import。:16-24 の import に足す)completed: bucket.completed + (completed ? 1 : 0),completed にも足さない★(:480-483 の continue の前に何も足さない。D10):418-459)の :422-424「稼働率・出発成功率が実際より下振れする」は ★エラー発生率も★ にkpiFromCleanStats()(:507-535):
operation_rate: toKpiValue(operationRate(bucket.completed, bucket.planned), prev?.operation_ratio ?? null), launch_rate: toKpiValue(launchRate(bucket.executed, bucket.planned), prev?.launch_ratio ?? null), completion_rate: toKpiValue(meanCleanRatio(bucket), prev?.clean_ratio ?? null), // ★変えない★ error_rate: toKpiValue(errorRate(bucket.errorCount, bucket.planned), prev?.error_ratio ?? null),docstring
:510-511「★エラー発生率の分母は「実施回数」のまま★(予定回数にしない)」は ★逆の仕様★。「★3つとも分母は予定回数(第11回 P-6。サマリと同じ)★」にcountMainErrorTypesInRange() の docstring :946-947「エラー率の分母は「清掃実施回数」…なので、分子も清掃を基準にする」→「エラー率の分母は清掃予定回数(P-6=B)なので、分子も予定(本清掃)を基準にする」。★中身は変えない★(期間の帰属は本清掃の start_at のまま)lib/db/index.ts)reportKpis()(:2042-2140)・facilityPerformance()(:2330-2400)は ★コードを変えない★(findMany に select が無いので status は載っている。D7)。aggregateCleanStatsByFacility() の引数も変わらないerrorBreakdown() の docstring :2493「エラー率の分母が「清掃実施回数」なので」→「清掃予定回数(P-6=B)なので」| ファイル:行 | 直し方 |
|---|---|
lib/config/index.ts:337-347(CLEAN_TASK_STATUS) |
:343-344「★★判定には使わない★★」を「★◎○△× の判定・未実施の判定には使わない。稼働率の分子(正常終了の回数。isCompletedTask())にだけ使う(第11回 P-6=A)★」に。:368-369(6 は「第11回で確認」)は ★段階5 の C5 で直す★(§11 Q4) |
lib/reports/target-customer.ts:10-17 の表 |
出発成功率: 分子 launch_count/分母 task_count(★P-6=A で確定★)/合算「材料はある」。稼働率: 分子 ★列が無い(正常終了の回数)★/分母 task_count/★できない★。エラー発生率: 分子 error_count/分母 ★task_count(P-6=B)★/合算「材料はある」。★表の下に「4指標を揃えて出せない(稼働率・清掃完了率の材料が無い)ので、合算しない方針は変えない」と書く★(★方針は変えない★。§11 Q3) |
d-watch-api.yaml:740-741(GET /reports/kpi) |
「稼働率の分子(清掃実施回数)とエラー率の分母に当たる列がサマリに無く」→「稼働率の分子(正常終了の回数)と清掃完了率の分子・分母(1回ごとの完了率の合計・件数)に当たる列がサマリに無く」 |
d-watch-api.yaml:1896-1903(ReportKpi)/ :1905-1907(FacilityPerformance) |
description に4つの式(CLAUDE.md §4.2)と「確定期間はサマリの値そのまま/当期はアプリが同じ式で集計(第11回 P-6。D-158)」を書く。★$ref の隣に description を書いても無視される★(OpenAPI 3.0)ので、★スキーマ本体の description に書く★ |
d-watch-api.yaml:1924-1926(status) |
「当期の稼働率は正常終了 ÷ 予定」を1行 |
lib/types/index.ts:713-718(ReportKpi) |
各フィールドに1行の docstring(4つの式)。型は変えない |
scripts/seed-local-db.ts:1838-1848 / :1875-1876 |
★サマリのシード(作り値)の辻褄★: error_count = round(task_count * error_ratio / 100)(分母=予定)に直し、コメント :1844 を「分母=予定回数(第11回 P-6=B)」に。:1843 の executedCount は「稼働率の分子=正常終了の回数」と読み替えるコメントに。★シードの接続先・ガード(lib/db/local-guard.ts)には触らない★。★シードを流すのは任意★(流すなら dwatch_local だけ。ステージングには絶対に向けない。CLAUDE.md §3) |
app/api/reports/__tests__/route.test.ts:634-635 |
当期のエラー発生率: 分子1・★分母は予定2★ → ★50★(旧 100)。:626-628(稼働率・出発成功率 50)は、スタブのレポート行が status: 4(:330)なのでそのまま 50 のはず。★落ちたら status を確かめる★。★スタブのコメント :327-329「意味を持たない任意の生値…集計・未実施の判定には使われない」は逆になった★ので、「★稼働率の分子(正常終了)に使われる★。4 以外にすると当期の稼働率が変わる」に直す |
lib/db/__tests__/report-mapping.test.ts の既存テスト |
toEqual<CleanStatsBucket>({...}) に ★completed を足す★(:364-383 / :416-424 ほか。tsc が全部教える)。CleanStatsReportLike のリテラル行に ★status: CLEAN_TASK_STATUS.completed★ を足す(status を見るテスト以外)。:755-800 の kpiFromCleanStats: ★:790-795 の「executed=0 のときエラー発生率も null」は逆の仕様★ → planned>0 なら 0.0、planned=0 なら null |
lib/judge/__tests__/kpi.test.ts |
段階1 で済み |
★lib/fixtures/reports.ts の KPI(:159-373)は作り値で、当期も「顧客単位の集計値」として置いてある★(lib/db/fixture-reports.ts:68-69)ので ★式を変えても画面の数字は変わらない★。 ★値は1か所だけ直す(§11 Q5)★: 新しい式では ★稼働率 ≤ 出発成功率★ が必ず成り立つが、:256-257(施設6 バリューマート南丘駅前店)だけが 稼働率 72.4(前期 70.1)> 出発成功率 65.0(前期 68.0)になっている(2026-10-05 監督が全行を走査。他の行は成り立っている)。
launch_rate: toKpiValue(65.0, 68.0) → ★toKpiValue(75.0, 71.0)★。★稼働率(72.4 / 70.1)・status・並び順は変えない★lib/fixtures/__tests__/reports.test.ts:212(「稼働率の昇順(ワースト順)に並んでいる」)が守っている。 60.5 にすると直前の施設9(68.0。:245)より小さくなり、このテストが落ちる。並べ替えると画面のワースト1位が変わるlib/fixtures/__tests__/reports.test.ts にテストを1件足す★: 施設別成績の全行と KPI の全期間で、operation_rate と launch_rate が ともに数値なら value も prev も ★稼働率 ≤ 出発成功率★(作り値が新しい式の不変条件を破らないことを固定する)65.0 / 68.0 を期待値に持つテストは無い★(2026-10-05 監督が grep で確認)。落ちるテストが出たら値を確かめてから報告するclean_timetables と clean_timetable_histories の両方から読む(P-7。D-158 項4)★予定(本清掃・事前チェックの行)は2つの表を合わせて読む★。★同じ id は1件として扱い、clean_timetables 側を採る★。 ★実績は clean_task_reports だけのまま★(D-151。clean_statuses / clean_status_histories は読まない)。 ★期間の絞り込みは今と同じく start_at★(end_at で絞る経路は今も無い。足さない)。
prisma/schema.prisma:587-619 / :621-650)| 列 | CleanTimetable |
CleanTimetableHistory |
アプリの読み |
|---|---|---|---|
id |
BigInt UNSIGNED・★AUTO_INCREMENT★ | BigInt UNSIGNED・★AUTO_INCREMENT 無し★(:622-624) |
読む(突き合わせのキー) |
facility_id / section_id / clean_schedule_id / parent_id |
同じ型・NOT NULL | 同じ | 読む |
start_at / end_at |
DateTime(0) NOT NULL | 同じ(索引名だけ started_at/ended_at。:642-648) |
start_at を読む |
precheck |
UnsignedTinyInt・既定 0 | 同じ | 読む |
inactive |
UnsignedTinyInt | ★無い★ | ★読んでいない★(どの経路も inactive で絞らない。lib/db/index.ts:726 / :1193) |
created_at / updated_at |
Timestamp / ★updated_at あり★ |
created_at のみ・★updated_at 無い★ |
どちらも読んでいない |
| リレーション | clean_schedule / facility / section |
★同じ3つ★ | include: { facility, section } はどちらにも書ける |
★アプリが使う列は全部、履歴側にもある★。★where に inactive を書くと履歴側で型エラーになる★(それでよい。書かないこと)。 ★他のモデルから clean_timetables へのリレーションは無い★(clean_task_reports / robot_error_reports / clean_statuses の clean_timetable_id は FK 無し)ので、include 経由の読みは0件。
grep -rn "cleanTimetable\." app lib で確かめる★)| # | 場所 | 何で絞るか | 何に使うか |
|---|---|---|---|
| 1 | lib/db/index.ts:765 cleanLogs() |
本清掃・start_at 範囲・id(単一)・facility_id IN。include: facility, section.robots.device。orderBy あり |
詳細ログ F-02・ダッシュボード F-01・アラート F-03・/clean-logs/{id}/advice・/{id}/areas |
| 2 | lib/db/index.ts:831 cleanLogs() |
parent_id IN(塊ごと)。select: id, parent_id, precheck |
1 の事前チェック行(status_1h / status_30m) |
| 3 | lib/db/index.ts:1104 areaCompletions() |
本清掃・facility_id・1日ぶんの start_at。include: section |
エリア別完了率モーダル |
| 4 | lib/db/index.ts:1230 prechecks() |
本清掃・start_at 範囲・facility_id IN。include: facility, section.robots |
事前チェックアラート・出発失敗 |
| 5 | lib/db/index.ts:1271 prechecks() |
parent_id IN(塊ごと)。select 3列 |
4 の事前チェック行 |
| 6 | lib/db/index.ts:1448 precheckItemById() |
findUnique({ id })。select 3列 |
PATCH /prechecks/{id}/status(指示書AT) |
| 7 | lib/db/index.ts:1457 precheckItemById() |
findFirst({ id: parent_id, precheck: 本清掃 })。select: start_at |
6 の親(scheduled_at) |
| 8 | lib/db/index.ts:2067 reportKpis() 当期 |
本清掃・start_at 範囲・facility_id IN。select 3列 |
レポート KPI(当週・当月・当年) |
| 9 | lib/db/index.ts:2333 facilityPerformance() 当期 |
8 と同じ | 施設別成績 |
| 10 | lib/db/index.ts:2552 errorBreakdown() 当期 |
8 と同じ | エラー内訳 |
| 11 | lib/db/consecutive-source.ts:356 loadConsecutiveInputs() |
本清掃・start_at(遡りぶんを足した範囲。無制限もありうる)。select 4列 |
連続日数・L1〜L3(cleanLogs :1001 / rescueRequired :1834 / facilityPerformance :2236 / continuousProblems :2457)・要レスキュー |
| 12 | lib/db/clean-area-source.ts:399 loadCleanAreaFacilityStatsWithRowCount() |
id IN(レポートの clean_timetable_id)+本清掃。select: id |
総清掃面積 F-08 の「本清掃に紐づく行か」(指示書AS 段階4) |
★count / groupBy / skip / take で clean_timetables を読む箇所は0件★(take/skip は P1 では SQL に降ろさない決定。lib/db/index.ts:743-745)。 ★/schedules は clean_schedules だけを読む★(lib/db/index.ts:1759-1797)。予定表(timetable)は読まない → ★本段階の対象外★。
★12 は今のままだと静かに壊れる★: レポートの clean_timetable_id が履歴にしか無いと「本清掃に紐づかない行」になり、★完了率・実施回数から黙って落ちる★(面積だけ残る)。
lib/db/timetable-source.ts。新規)mergeTimetableRows<T extends { id: bigint }>(mainRows: T[], historyRows: T[], shadowedIds: ReadonlySet<string>): T[]
mainRows を全部採る。historyRows は ★id.toString() が mainRows にも shadowedIds にも無いものだけ★足すhistoryRows の中で同じ id が2回出たら例外★(履歴の主キーは id なので起きない。起きたら呼び出しの誤り)findTimetables(prisma, args) — ★同じ args を cleanTimetable.findMany と cleanTimetableHistory.findMany に Promise.all で渡す★
args の型は ★両モデルの FindMany 引数の両方を満たすもの★(satisfies で両方に通す、または ConsecutiveSourcePrisma(consecutive-source.ts:105)と同じ「最小の形」の interface を書く)。★where を2回書かないこと★(片方だけ直すと静かにずれる)args.select / args.include には id が必ず含まれること★(型で強制する)clean_timetables 側が勝つ」を厳密に守るための影チェック★: 履歴だけに出た id を chunkForInClause() で分けて cleanTimetable.findMany({ where: { id: { in } }, select: { id: true } }) を撃ち、★当たった id を shadowedIds にする★。 理由: 同じ id で start_at や precheck が2表で違うと、clean_timetables 側は where から外れ、履歴側だけが当たる。影チェックが無いと★負けるはずの履歴の行が出る★。★履歴だけの id が0件ならクエリを撃たない★mergeTimetableRows() の結果orderBy: ★渡してよいが、合わせた後の順序は保証されない★。1(cleanLogs())は :1017-1022 の .sort() が正なので問題ない。★他の11本は順序に依存しない★(集計・Map 化・ルート側の sortPrechecks())。docstring の「orderBy はその写し」(:798-803)に「2表を合わせるので DB の順序はもう写しにもならない」と1行足すcount / groupBy を2表にまたがって書かない★(同じ id の重複を引けない)。必要になったら ★findTimetables() で id を取ってから数える★。今は該当0件precheckItemById() 用に findTimetableById(prisma, id, select) を足す(clean_timetables を findUnique → 無ければ cleanTimetableHistory.findUnique)。7 は findTimetableById(row.parent_id) を引き、precheck === 本清掃 を JS で確かめる(findFirst の条件をそのまま移す)prisma.cleanTimetable.findMany(args) → findTimetables(prisma, args)。★where の中身は1文字も変えない★parent_id IN): 塊ごとに findTimetables() を呼び、★.flat() の後にもう一度 id で重複を落とす★ (2表で parent_id が違う同じ id は別の塊に入りうるので、塊の中の重複落としだけでは足りない)。 findTimetables() に { dedupeAcrossChunks } を持たせるより、★timetable-source.ts に findTimetablesByChunks(prisma, chunks, buildArgs) を置き、全塊を2表とも引いてから1回だけ mergeTimetableRows() を通す★ほうが規則が1箇所で済むCleanAreaStatsSourcePrisma.cleanTimetable(clean-area-source.ts:147-153)の隣に cleanTimetableHistory を足し、findTimetables() を使う。★where: { id: { in }, precheck } は両表に同じものを渡す★ConsecutiveSourcePrisma(consecutive-source.ts:105-125)に cleanTimetableHistory を足すrobot_error_reports / clean_task_reports の引き直し(clean_timetable_id IN)は ★変えない★(合わせた後の id で引くので、履歴の予定に紐づく行も取れる)Promise.all で並べる。両表とも start_at / facility_id / parent_id に索引あり(:612-617 / :641-648)cleanLogs() の日付なし・CONSECUTIVE_RANGE_UNBOUNDED・12 の期間なし)は★履歴も全期間読む★。今と同じ性質なので新たに絞らないが、judge.* ログの行数が増えることを docstring に書くIN の分割は既存の chunkForInClause()(上限 DB_IN_CLAUSE_MAX_ITEMS = 1000。lib/config/index.ts:548)をそのまま使うlib/fixtures/ は結合済みの CleanLogItem を持つ。lib/fixtures/clean-logs.ts:222 の history は★「過去の清掃ログ」の意味で、clean_timetable_histories とは無関係★。名前で取り違えないこと)。 → ★fixtures 版のデータソースは変えない★。USE_FIXTURES の true/false で数字は変わらないscripts/seed-local-db.ts: ★clean_timetable_histories を今は一切書かず、消してもいない★(:848-858)。
cleanSchedule.deleteMany より前(:854 の隣)に cleanTimetableHistory.deleteMany({}) を足す(FK が clean_schedules に向いているため):1525-1532 の dangling 検査に履歴も足す★): (a) ★履歴だけの予定★: 過去の本清掃1件とその事前チェック2行を clean_timetables に入れず履歴に入れる。clean_task_reports を1行紐づける (b) ★両方にある同じ予定(中身も同じ)★ (c) ★両方にある同じ id で中身が違う★(履歴側の start_at を1日ずらす):2062)に clean_timetable_histories= を足すlib/db/__tests__/timetable-source.test.ts(新規。スタブの prisma で):
| # | 入力 | 期待 |
|---|---|---|
| T1 | 本表だけに id=1 | id=1 が1件 |
| T2 | 履歴だけに id=2 | id=2 が1件(影チェックで本表に無い) |
| T3 | 両方に id=3(同じ中身) | ★1件★。中身は本表のもの |
| T4 | 両方に id=4(start_at が違う。どちらも期間内) |
★1件・本表の start_at★ |
| T5 | id=5: 本表は期間外、履歴は期間内 | ★0件★(影チェックで履歴を捨てる) |
| T6 | 履歴だけの id が0件 | 影チェックのクエリを撃たない |
| T7 | 2表に同じ where が渡る |
両方の呼び出し引数が toEqual で一致 |
| T8 | parent_id IN の塊をまたいで同じ id |
flat 後に1件 |
既存のスタブ(★cleanTimetableHistory が無いと undefined で落ちる★): app/api/{clean-logs,clean-logs/[id],dashboard,prechecks,prechecks/[id]/status,reports,clean-area}/__tests__/route.test.ts・lib/db/__tests__/{consecutive-source,clean-area-source,report-mapping}.test.ts。 履歴は空配列を返すスタブを足し、★calls.cleanTimetable の引数を見ているテストには calls.cleanTimetableHistory も同じ引数であることを足す★。 経路ごとに1本ずつ「履歴だけの予定が出る」ケースを足す(12 は「履歴だけの予定に紐づくレポートが完了率・実施回数に入る」)。
| # | 論点 | 決定 |
|---|---|---|
| Q1 | 履歴の id は本表の id か | ★本表の id をコピーしている(ユーザー回答 2026-10-05)★。★id で重複を除く設計で正しい★。同じ id で facility_id / section_id / start_at のどれかが違ったら [db] の warn を出す(Q2) |
| Q2 | 同じ id の中身が違うとき | ★本表を採り、warn ログを出す★(イベント名は既存の db.* の流儀に合わせる。id・どの列が違ったか・両方の値を出す。認証情報は出さない) |
| Q3 | 期間の基準 | ★start_at のまま★(期間の振り分けの基準を変えない。CLAUDE.md §4.7) |
| Q4 | 履歴の予定に紐づくエラー行も PATCH で書けるようになる | ★それでよい★(実在するアラートなので) |
| Q5 | /schedules |
★対象外★(clean_schedules だけを読む) |
| Q6 | 移る時期が未実測 | ★実装はどちらの表にあっても読めるので影響しない★。接続できたら行数・移る時期を実測して D-158 に記録する(監督) |
lib/i18n.ts)— ★キーごと改名する(D12)★| 行 | いま | ★新★ |
|---|---|---|
:54 |
屋号: "Brand" |
顧客: "Customer" |
:56 |
全屋号: "All Brands" |
全顧客: "All Customers"(§11 Q7) |
:358 |
"選べる屋号が{n}件あります": "{n} brands to choose from" |
"選べる顧客が{n}件あります": "{n} customers to choose from" |
:359 |
屋号を選ぶ: "Choose a brand" |
顧客を選ぶ: "Choose a customer" |
:360 |
この条件では選べる屋号がありません: "No brands available for this filter" |
この条件では選べる顧客がありません: "No customers available for this filter" |
:44-52 を書き直す: 「★第11回 P-15=B(customers は法人の単位)で確定。2026-10-05 に見出し語を『屋号』から『顧客』に変えた(D-158)★」。旧の経緯(2026-09-15「屋号でよいです…」)は1行で残す。★英語は仮(D13)★:364 / :375 の 屋号 を 顧客 に(キー名を指しているため):357 の 顧客を選んでください: "Select a customer" は ★そのまま★| ファイル:行 | いま | ★新★ |
|---|---|---|
lib/masters/options.ts:46 |
ALL_CUSTOMERS_LABEL = "全屋号" |
"全顧客"(docstring :33 の「全屋号」も) |
components/features/clean-area/CleanAreaScreen.tsx:66 |
customer: "屋号" |
customer: "顧客"(粒度タブ :356 と表の見出し :385 に出る)。docstring :61 の「ホールディングス / 屋号 / 店舗」も |
components/features/clean-area/CleanAreaScreen.tsx:238 |
aria-label={t("屋号")} |
t("顧客") |
components/features/alerts/AlertsScreen.tsx:392 |
同上 | 同上 |
components/features/detail-log/DetailLogScreen.tsx:370 |
同上 | 同上 |
components/features/ds-alerts/DsAlertsScreen.tsx:181 |
同上 | 同上 |
components/features/ds-logs/DsLogScreen.tsx:346 |
同上 | 同上 |
components/features/reports/ReportsScreen.tsx:376 |
同上 | 同上 |
components/features/reports/ReportsScreen.tsx:509 / :522 / :530 |
t("選べる屋号が{n}件あります") / t("屋号を選ぶ") / t("この条件では選べる屋号がありません") |
4-1 の新キー |
d-watch-api.yaml:51 / :905(清掃面積の粒度) |
「ホールディングス/屋号/店舗」 | 「ホールディングス/顧客/店舗」 |
d-watch-api.yaml:172-177(GET /customers) |
「屋号一覧」「画面の見出し語は「屋号」…TeamWorks 照会中(第9回 Q7-1)」 | 「顧客一覧」「画面の見出し語は「顧客」(第11回 P-15=B: customers は法人の単位。2026-10-05。D-158)。旧: 「屋号」(2026-09-15)」。★照会中の記述は消す★ |
d-watch-api.yaml:1680(Customer) |
「屋号(customers)」 |
「顧客(customers。法人の単位。第11回 P-15)」 |
lib/hooks/use-classification-filter.ts:161 は t(ALL_CUSTOMERS_LABEL) なので ★直さなくてよい★t() に生の文字列 "屋号" を渡している所が他に無いこと★を最後に確かめる: grep -rn "\"屋号\|屋号\"\|'屋号" app lib components --include=*.ts --include=*.tsx | grep -v __tests__ が ★0件★
P-15=B で customers は法人の単位と確定したので、「屋号(customers.id)」という説明は ★誤り★ になった。 ★次の行の中の「屋号」だけを「顧客」に直す★(所属屋号 → 所属顧客、屋号・施設は → 顧客・施設は など。★行の他の部分は変えない★):
lib/clean-area/query.ts:58・lib/clean-logs/query.ts:31・lib/ds-alerts/query.ts:25・lib/ds-devices/query.ts:21・lib/facilities/query.ts:28・ lib/prechecks/query.ts:32・lib/reports/query.ts:120・lib/schedules/query.ts:53・lib/api/master-id.ts:89 (どれも /** 屋号(\customers.id`)… */`)lib/types/index.ts:180 / :196 / :954 / :985 / :1299 / :1308-1310d-watch-api.yaml:1519-1520 / :1534 / :2086 / :2100-2101 / :2287★経緯を書いた文(「旧: 屋号」「2026-09-15『屋号でよいです』」等)は残す★。★処理の理由を述べるコメント・fixtures の説明・テストは対象外★(§7 の表)。
lib/masters/__tests__/options.test.ts:157-181 の "全屋号" は ★引数で渡しているだけなので直さなくても通る★。直すなら "全顧客" に(任意)。"屋号A1" などはテスト用の名前なのでそのまま★どれもコメントだけで、動作は変わらない★(C5 も同じ)。行番号は 2026-10-05(74cffd5)で確かめた。
| # | 場所 | いま | ★新しい文(この中身で書く)★ |
|---|---|---|---|
| C1 | lib/db/clean-area-source.ts:424-425 |
「clean_task_reports.clean_timetable_id は nullable で、★TeamWorks がまだ埋めていない★(指示書AQ 決定5 — 「今後埋める前提」)」 |
「clean_task_reports.clean_timetable_id は nullable(prisma/schema.prisma:524)。★NULL は予定外のタスク★(予定を持たない実在の清掃。ユーザー回答 2026-10-01。CLAUDE.md §4.7)で、★埋まる予定は無い(NULL の行は常にある)★。旧: 「TeamWorks が今後埋める前提」(指示書AQ 決定5)— 誤り」。★続く :426-429(NULL が1つのグループにまとまる)は今も正しいので残す★ |
| C2 | lib/fixtures/clean-task-reports.ts:24 |
「★CSV では189行すべて NULL★(今後 TeamWorks が埋める前提。決定5)」 | 「★CSV では189行すべて NULL★。★NULL は予定外のタスク★(予定のある清掃には id が入る。CLAUDE.md §4.7。旧: 「今後 TeamWorks が埋める前提」— 誤り)」 |
| C3 | lib/db/report-mapping.ts:245-256(:249 を含む段落) |
「clean_timetables.started_at は常に予定時刻と同値でシードされており…稼働率と出発成功率は同じ executed を分子に使う」(★clean_timetables.started_at は存在しない列★) |
★段階3-2 の1. で段落ごと書き直す★。時刻の記述は「clean_task_reports.started_at は、予定のある清掃では予定の start_at と同じ値、予定外のタスクでは実際の開始時刻が入る(ユーザー回答 2026-10-05。CLAUDE.md §4.7)。★出発成功率は時刻を見ない(P-6=A)★」 |
| C4 | lib/db/report-mapping.ts:278-280(errorCount の注意) |
「clean_error が 2(セキュリティ有効)/ 3(D-S制御盤異常)の清掃は robot_error_reports の行が作られないため…『エラー発生率』は実質『ロボット異常の発生率』」(★いまは読んでいない clean_error 列が前提★) |
「★清掃の結果は clean_task_reports だけから読み、clean_error 列は読まない★(D-151)。★制御盤・セキュリティのエラー、清掃を開始できなかったエラーも robot_error_reports に入り★(第11回 P-8・P-10)、★clean_timetable_id も入る★(P-9=A)。★本清掃の予定の id が入った行は、区分を問わずこの件数に入る★(どの予定の id が入るかは無回答)。★区分(ロボット/制御盤/セキュリティ・清掃開始失敗)の見分けと D-Security アラートの取得元の切り替えは次フェーズ★(D-158 当方の対応5)。旧: 第8回 A6-1「clean_error 2/3 の清掃は行が作られない」— 第11回で変わった」 |
| C5 | ★status 6 の説明3か所(§11 Q4)★: lib/config/index.ts:368-369(CLEAN_TASK_STATUS_LABELS の docstring)・lib/fixtures/clean-task-reports.ts:25(表の status の行)・lib/format/clean-result.ts:14 |
「意味は未受領。第11回で確認」/「★6 は未受領★」 | 「★6 は Pudu の値で、先方も意味が分からない(第11回 P-4。D-158)★。分かれば先方がデータを入れる。★数字のまま表示する★」。★:369 の続き「「その他」「不明」に潰さないこと」は残す★。★cleanTaskStatusLabel() の中身・CLEAN_TASK_STATUS_LABELS の値は変えない★ |
npx tsc --noEmit -p . — エラー0件npm run lint — 指摘0件(重複キー・$queryRaw・any が無いこと)npm test — ★全件通過★(表1・表2・表3 を含む)USE_FIXTURES=true で npm run build★ — 成功(PowerShell なら $env:USE_FIXTURES='true'; npm run build)USE_FIXTURES=true)★: .claude/launch.json の ★d-watch-fixtures(ポート 3100)★ で起動する(Claude Code なら preview_start の d-watch-fixtures)。★確かめ終わったら、自分で起動した dev サーバーは必ず止める★
task_area = 0 で実施した行が無く(lib/db/fixture-clean-area.ts:20-25)、レポートの KPI は作り値(lib/fixtures/reports.ts)なので、★詳細ログ・エリア別詳細・総清掃面積・レポートの数字は変わらないのが正しい★。指示書AS 段階7-5 の境界値(施設2 = 90% ◎ / 施設3 = 90% ○ / 施設5 = 70% ○ / 施設8 = 10% △ / 施設9 = 10% × / 施設10 = 0% ×、エリア別詳細の施設7・1日前が全体 81% ○)がそのまま出ることdwatch_local。USE_FIXTURES=false)のレポート当期で「稼働率 ≤ 出発成功率」になっていることを見てよい(★ステージングには向けない★)grep -rnE "status ?===? ?4([^0-9]|$)|定刻出発|清掃実施回数 ÷ 清掃予定|÷ 清掃実施回数" app lib components d-watch-api.yaml --include=*.ts --include=*.tsx --include=*.yaml | grep -v lib/generated grep -rn "t(\"屋号\|t(\"全屋号\|\"選べる屋号\|\"屋号を選ぶ\|選べる屋号がありません" app lib components --include=*.ts --include=*.tsx
grep -rn "屋号" app lib components --include=*.ts --include=*.tsx。テストを除き約140件)| 分類 | 場所 | 扱い |
|---|---|---|
| ★画面に出る文字列(i18n のキー・既定の見出し語)★ | lib/i18n.ts:54 / :56 / :358-360、lib/masters/options.ts:46、components/features/clean-area/CleanAreaScreen.tsx:66 |
★直す★(段階4) |
★画面に出る文字列の呼び出し(t("…"))★ |
aria-label 6件(AlertsScreen.tsx:392 / CleanAreaScreen.tsx:238 / DetailLogScreen.tsx:370 / DsAlertsScreen.tsx:181 / DsLogScreen.tsx:346 / ReportsScreen.tsx:376)、ReportsScreen.tsx:509 / :522 / :530 |
★直す★ |
| ★見出し語そのものを説明するコメント★ | lib/i18n.ts:44-52 / :364 / :375、lib/masters/options.ts:33、CleanAreaScreen.tsx:61 / :374 |
★直す★ |
★API 定義のうち見出し語・customers の単位を述べる所★ |
d-watch-api.yaml:51 / :172-177 / :905 / :1680 |
★直す★ |
データ・絞り込み条件の説明(「屋号(customers.id)で絞り込み」など) |
lib/*/query.ts(clean-area:58 / clean-logs:31 / ds-alerts:25 / ds-devices:21 / facilities:28 / prechecks:32 / reports:120 / schedules:53)、lib/api/master-id.ts:89、lib/types/index.ts:180 / :196 / :954 / :985 / :1299 / :1308-1310、d-watch-api.yaml:1519-1534 / :2086 / :2100-2101 / :2287 |
★直す★(段階4 の 4-3。★列挙した行だけ。一括置換しない。§11 Q2★) |
| 処理の理由・経緯を述べるコメント(「この屋号の昨夜の成績」「屋号が0件のときは出さない」など) | components/features/*/*.tsx の JSX コメント、lib/hooks/use-classification-filter.ts、lib/masters/options.ts(:2-26 / :105-190)、app/api/**/route.ts、lib/db/*.ts、lib/facilities/*.ts、lib/clean-area/aggregate.ts、lib/logger/events.ts:218、lib/judge/kpi.ts:51 |
★残す★ |
| fixtures の説明 | lib/fixtures/customers.ts / groups.ts / facilities.ts / reports.ts:203-212 |
★残す★(顧客名の値もそのまま) |
| テスト | app/api/**/__tests__ / lib/**/__tests__(約120件) |
★残す★(t() のキーを文字列で比べているテストは無い。2026-10-05 確認) |
| モック | d-watch-mock.jsx(「全会社」) |
★触らない★(自前の辞書を持ち、アプリの i18n に依存しない) |
| ファイル | 内容 | 段階 |
|---|---|---|
lib/judge/__tests__/run-completion-rate.test.ts |
表1 R9 差し替え・R12 追加 | 1 |
lib/judge/__tests__/kpi.test.ts |
3つの率の分母・errorRate 上限なし・isCompletedTask() |
1 |
lib/db/__tests__/report-mapping.test.ts |
表2 K1〜K8・稼働率 ≤ 出発成功率/既存の completed・status の追加/w11(表3)/kpiFromCleanStats のエラー発生率 |
1 / 2 / 3 |
lib/db/__tests__/clean-log-mapping.test.ts |
task_area = 0 → 0/不変条件が両向き |
2 |
lib/db/__tests__/consecutive-source.test.ts |
Q9・テスト内の再実装を消す | 2 |
lib/db/__tests__/clean-area-source.test.ts |
F5(表3) | 2 |
lib/db/__tests__/fixture-clean-area.test.ts |
:145 |
2 |
lib/judge/__tests__/rescue.test.ts / lib/db/__tests__/rescue-mapping.test.ts |
ラベルだけ(期待値は変えない) | 2 |
app/api/reports/__tests__/route.test.ts |
当期のエラー発生率 50 | 3 |
lib/fixtures/__tests__/reports.test.ts |
★作り値の全行で 稼働率 ≤ 出発成功率(value / prev)★(§11 Q5) |
3 |
lib/db/__tests__/timetable-source.test.ts(新規)ほか 3b-6 の一覧 |
T1〜T8・既存スタブに cleanTimetableHistory |
3b |
robotErrorReport を読む経路のテスト |
スタブに robot_id: null の行を混ぜても落ちない(段階0 の 4) |
0 |
CLAUDE.md / docs/decisions.md(監督が直す)prisma/schema.prisma / lib/generated/prisma/**(★DB の定義は TeamWorks の領域。CLAUDE.md §7★。P-8 の DDL 変更の取り込み(db pull)も本書ではやらない)docs/code-map.md(監督が直す)control_error_histories)★ — robot_error_reports への切り替え(P-10)は ★次フェーズ★(D-158 当方の対応5)robot_error_reports の3区分(ロボット/制御盤/セキュリティ・清掃開始失敗)の見分け★ — ★次フェーズ★。error_type を推測で分類しない(CLAUDE.md §4.8)status / comment / responded_at / resolved_at。指示書AT)kpiFromSummaryRatios() / SummaryRatios / periodOfSummaryRow()(lib/db/report-mapping.ts:99 付近・:218-241)meanCleanRatio() の中身・judgeGrade() / displayRate() / GRADE_THRESHOLDS / RUN_COMPLETION_RATE の値latestReportByTimetableId() / notExecutedFromReport() / isFutureSchedule() の中身(lib/db/clean-log-mapping.ts)launchFailedDaysInRun() / foldRescueDays() の中身(D3)scripts/seed-local-db.ts の ★接続先とガード★(lib/db/local-guard.ts を含む)d-watch-mock.jsx| # | 論点 | 決定 |
|---|---|---|
| Q1 | 表3 を正にするか | ★正として固定する★ |
| Q2 | 「屋号(customers.id)」というデータの説明 |
★「顧客」にそろえる★(P-15 で customers は法人と確定したので、「屋号」は誤りになった)。経緯を書いた文(「旧: 屋号」等)は残す。★対象の行は段階4 の 4-3★ |
| Q3 | 複数顧客の KPI 合算 | ★変えない★(指示書AK の方針のまま。本書は表の記述を直すだけ) |
| Q4 | 「status 6 は未受領・第11回で確認」のコメント | ★直す★: 「6 は Pudu の値で先方も意味不明(第11回 P-4)。分かれば先方がデータを入れる。数字のまま表示」 |
| Q5 | lib/fixtures/reports.ts:256 の稼働率 > 出発成功率 |
★直す★。★出発成功率の側を上げる(65.0 → 75.0 / 前期 68.0 → 71.0)★。不変条件のテストを1件足す(段階3-4 の表の下)。★改訂(2026-10-05)★: 当初は「稼働率側を下げる(72.4 → 60.5)」としたが、稼働率の昇順を守るテスト(lib/fixtures/__tests__/reports.test.ts:212)が落ち、並べ替えれば画面のワースト1位が変わるため取り下げた |
| Q6 | robot_id が DDL では NULL 可・Prisma では NOT NULL |
★段階0 に足す: robotErrorReport の読み取りはすべて select で必要な列だけにし、robot_id・robot リレーションを読まない★(NULL の行が入っても読み取りで落ちないように)。★prisma db pull は監督がステージングに接続できるようになってから行う★(本書ではスキーマを変えない) |
| Q7 | EN の大文字小文字 | ★"All Customers" / "Customer"★(既存の "All Holdings" にそろえる。英訳はユーザーが後でまとめて見直す) |
| Q8 | 稼働率の式が変わり、施設ステータス(閾値 good 90 / warning 75。FACILITY_STATUS_THRESHOLDS。★訂正 2026-10-06: 当初「90/80」は誤り★)と稼働率ワースト順が以前より悪く出る |
★閾値は据え置く★(変えるならユーザー判断。監督からユーザーに伝える) |
| 範囲を広げた3点 | 完了率の「暫定」→「確定」の記述 / シードの error_count の分母 / runCompletionRate() の戻り値を number に |
★3点とも採る★ |
段階ごとに分ける(段階0 の 4 / 段階1 / 段階2 / 段階3 / 段階3b / 段階4 / 段階5)。★git add はファイルパスを明示する★(git add -A 禁止)。 メッセージには ★何を変えたか★ と ★なぜ(D-158。TeamWorks 第11回 P-5 / P-6 / P-15)★ を書く。★段階1 のコミットは「テストだけ(この時点では落ちる)」と明記する★。 ★分割 PR の作成とマージは daichi がレビューしてから行う★(D-154)。