Newer
Older
client_dwatch / docs / handoff / 指示書AR_古い記述とエリア完了率ログの修正_20261001.md

指示書AR — 古くなった記述の修正と、エリア完了率ログの項目の差し替え

日付: 2026-10-01 / 担当: Cursor / 前提: D-139 / D-151 / 指示書AQ / CLAUDE.md §4.1・§4.2・§4.3

★渡す時期: 第10回の回答が来てから、4カラム UPDATE の指示書と一緒に渡す★(ユーザー指示 2026-10-01。D-153 項3)


0. 何をするか(1行)

D-139(判定の境界変更)と D-151(完了率を clean_ratio の単純平均に変更)のあと、★いまの仕様と逆のことを書いたまま残っている記述★を直す。 あわせて、★検算の役に立たなくなったログの項目★(段階4)を差し替える。

★段階1〜3と5はコメント・テスト名・文書だけで、動作は変わらない★。★段階4だけはログに出す項目が変わる★。


1. 背景 — なぜ直すのか

いつ 何が変わったか
2026-09-16(D-139) ★判定の境界を「上のランクに入る」に変えた★(90.0→◎、70.0→○)。★×の境界だけは「10%未満」のまま★(10.0→△)。★D-020b(境界はすべて下のランクに落ちる)は破棄★
2026-09-30(D-151) ★清掃完了率を clean_ratio の単純平均(清掃1回=1票)に変えた★。★面積比(Σclean_area ÷ Σtask_area)は廃止★。★全画面で同じ定義★(レポートKPI / 総清掃面積 / ★エリア別完了率モーダルの全体率★ / 要レスキュー R-3)

★実装は変更済みで、テストも通っている★(98ファイル / 2,297件)。★残っているのは「説明」が古いまま、という状態★。 ★読んだ人が古い説明を信じて実装を戻すと、事故になる★(例: 「全体率は面積ベースという意図した非対称」と書いてあれば、面積比に戻すのが正しいと読める)。

★発見の経緯★: 別セッションが2件を指摘(段階1-1 / 1-2)。監督が実物で確かめ、★同じ種類の古い記述をリポジトリ全体から探して、さらに5件を足した★(段階1-3〜1-5 と 段階4)。


2. ★直さないもの(必ず読むこと)★

★「旧:」「以前は」「廃止」「破棄」と経緯として書いている記述は正しい★。★消さないこと★。例:

ファイル:行 記述 直さない理由
lib/judge/grade.ts:15 「D-020b(…)は破棄」 経緯。正しい
lib/judge/__tests__/advice.test.ts:150 「D-139。旧 D-020b では出ていた」 経緯。正しい
lib/clean-logs/areas.ts:94 「以前は全体だけ面積ベース…だった」 経緯。正しい
lib/fixtures/areas.ts:116 「旧定義の面積ベース 802/1200 = 66.83…%」 ★面積比に戻っていないことを確かめるための比較値★。正しい
lib/fixtures/__tests__/areas.test.ts:38, 49 「面積ベースと単純平均で判定が割れる」 同上

★見分け方★: その記述が★いまの仕様★として書かれているか(=直す)、★昔の仕様★として書かれているか(=直さない)。


3. 段階1 — ソースのコメントとテスト名(動作は変えない)

1-1. lib/dashboard/aggregate.ts:6-8

いま:

 * ★`lib/judge/kpi.ts` は使わない★
 *   kpi.ts は週次/月次の**面積ベース**集計(CLAUDE.md §4.2)用で、
 *   ここでやりたい日次の**件数カウント**とは別物。混ぜると分母の意味が変わる。

問題: ★kpi.ts の完了率はもう面積ベースではない★(clean_ratio の単純平均。D-151)。★粒度も週・月・年の3つ★になった。

直し方(例):

 * ★`lib/judge/kpi.ts` は使わない★
 *   kpi.ts は週次/月次/年次の集計期間の KPI(CLAUDE.md §4.2)用で、
 *   ここでやりたい日次の**件数カウント**とは別物。混ぜると分母の意味が変わる。

★「使わない」という結論と理由(日次の件数カウントとは別物)は正しいので残す★。★「面積ベース」という誤った説明だけを外す★。

1-2. lib/judge/__tests__/advice.test.ts:66 のテスト名

いま:

  it("10.0%はR2ではない(10%未満が条件。D-020b)", () => {

問題: ★D-020b は「境界はすべて下のランクに落ちる」なので、それに従うと 10.0% は × になり、R2 に当たる★。★このテストが確かめていること(10.0% は R2 ではない)と逆の規則を根拠に挙げている★。正しい根拠は ★D-139(×の境界だけは「10%未満」のまま)★。

直し方:

  it("10.0%はR2ではない(×は10%未満。10.0は△。D-139)", () => {

★テストの中身(expect の3行)は変えないこと★。

1-3. app/api/clean-logs/[id]/areas/route.ts:126

いま(judge.areas ログを出す直前のコメント):

    //   (行は `clean_ratio` の生値、全体は面積ベースという意図した非対称。指示書Z 決定7)

問題: ★全体率も clean_ratio の単純平均に揃えた★(指示書AQ §5-5)。★「意図した非対称」はもう存在しない★。

直し方: 段階4でこのログの項目を差し替えるので、★そのときにコメントも書き直す★(段階4-2 を参照)。

1-4. components/features/detail-log/AreaModal.tsx:39

いま: 「★全体率(ヘッダの「全体」)は面積ベース、行の完了率は clean_ratio の生値なので、…」で始まる docstring。

問題: 1-3 と同じ。★全体率も clean_ratio の単純平均★(未実施の行は分母に入れない)。

直し方: ★前後の文を読み、「全体率は面積ベース」を前提に書かれている説明をすべて、単純平均の説明に書き直す★。 ★「全体率は行の完了率の単純平均なので、行を足し合わせて割れば一致する」★という趣旨になるはず(★未実施=完了率が null の行は除く★)。 ★画面の動きを変えないこと★(コメントだけ)。

1-5. lib/db/index.ts:1023

いま:

   *   - ★全体率は面積ベース(`Σclean_area ÷ Σtask_area × 100`。`CLAUDE.md` §4.2)★ —

(areaCompletions() の docstring の中。続く行も読むこと)

問題: 1-3 と同じ。★CLAUDE.md §4.2 も 2026-09-30 に単純平均へ書き換え済み★。

直し方: ★全体率は clean_ratio の単純平均で、計算しているのはルート側の buildAreaCompletions()(lib/clean-logs/areas.ts)★という趣旨に直す。★このデータ層は面積を運んでいるが、それは表示用★であることを書く。


4. 段階2 — CLAUDE.md §4.3 のコード例(文書)

いま(CLAUDE.md §4.3 の「❌ 間違い」の例):

// ❌ 間違い(90.4%が丸めで90%になり、◎判定が消える)
const rounded = Math.round(rawRate);
const grade = judgeGrade(rounded);

問題: ★D-139 で 90.0% は ◎ になった★。★90.4% を丸めて 90% にしても ◎ のまま★で、「◎判定が消える」は★もう起きない★。 ★いま起きる事故は逆向き★ — ★89.5% を丸めて 90% にすると、本当は ○ なのに ◎ が出る★(CLAUDE.md §0-2 と §9.4 の「89.5 → 表示90だが判定は○」と同じケース)。

直し方:

// ❌ 間違い(89.5%が丸めで90%になり、本当は○なのに◎になる)
const rounded = Math.round(rawRate);
const grade = judgeGrade(rounded);

★「生値で判定する」という原則と、✅ 正しい の例は変えないこと★。★変えるのはコメントの1行だけ★。


5. 段階3 — /d-watch スキルの数値(文書)

ファイル: .claude/commands/d-watch.md

★数値が 2026-09-30〜10-01 の作業で古くなった★。2026-10-01 の実測値:

行の目安 いま 正しい値(2026-10-01 実測)
:41 D-149 まで(137件) ★D-151 まで(139件)★
:42 追記58 まで ★追記59 まで★
:66 最終決定番号 D-149 ★D-151★
:67 最新の追記 追記58 ★追記59★
:68 main..develop 394コミット ★411コミット★(git fetch 後の origin/main..origin/develop)
:70 テスト 97ファイル / 2,161件 全パス ★98ファイル / 2,297件 全パス★
:71 指示書 38本(次は AQ) ★40本(次は AS)★(★本書 AR を含む★)
:134 97ファイル / 2,161件 / D-149 ★98ファイル / 2,297件 / D-151★

★作業時点で数値がさらに変わっていたら、その時点の実測値を入れること★(grep -c '^### D-[0-9]' docs/decisions.md / npm test / ls docs/handoff/指示書*.md | wc -l)。

★PR #6 の行(:69)★は「open・CI緑・マージ可能・レビュー待ち」のままで正しいが、★「レビュー担当が未指定(レビュー依頼0件)」★を足すこと(2026-10-01 確認。gh pr view 6)。

★数値以外の記述(外部待ちの章など)は本書の範囲外★。触らないこと。


6. 段階4 — エリア完了率ログ(judge.areas)の項目を差し替える ★動作が変わる★

4-0. 何が問題か

GET /clean-logs/{id}/areas は、全体率を出したあとに judge.areas ログを出す。 このログが ★分子・分母を残している理由★は、lib/logger/events.ts:160-164 のとおり ★「あとで『全体率が行の平均と違う』と言われたときに、ログだけで検算できるようにする」★ため。

★ところがいま書き出しているのは面積の合計★(app/api/clean-logs/[id]/areas/route.ts:136-137):

      overall_clean_area: selected.reduce((sum, r) => sum + r.clean_area, 0),
      overall_task_area: selected.reduce((sum, r) => sum + r.task_area, 0),

★全体率は clean_ratio の単純平均に変わった★ので、★面積の合計からは全体率を検算できない★。★ログを残す目的が果たせていない★。

4-1. 直し方

  1. ★lib/logger/events.ts の JudgeAreasLogEvent★:

    • overall_clean_area / overall_task_area を ★削除★し、代わりに次の2つを足す:
      • overall_clean_ratio_sum: number — ★全体率の分子★。完了率が null でない行の clean_ratio(=行の completion_rate)の合計
      • overall_clean_ratio_count: number — ★全体率の分母★。完了率が null でない行の数
    • ★raw_overall_completion_rate === overall_clean_ratio_sum / overall_clean_ratio_count(分母0なら null)が成り立つこと★を docstring に書く
    • docstring の「★全体率は面積ベース★」「★意図した非対称★」の記述(:160-164)を、★単純平均の説明★に書き直す
  2. ★app/api/clean-logs/[id]/areas/route.ts:126-137★:

    • コメント(:126)を直す(段階1-3)
    • 上の2項目を出す。★値は buildAreaCompletions() が全体率を出すのに使ったのと同じ行・同じ規則で数えること★。 ★自前で別の数え方をしないこと★ — ★ログと画面の全体率が食い違う原因になる★。 lib/clean-logs/areas.ts が分子・分母を返していないなら、★buildAreaCompletions() の戻り値に分子・分母を足すのではなく★、 ★lib/judge/kpi.ts の meanCleanRatio() に渡しているのと同じ材料(合計と件数)をルート側で同じ規則で数える★か、 ★あるいは lib/clean-logs/areas.ts に「全体率の材料を返す純粋関数」を1つ足して、buildAreaCompletions() とルートの両方がそれを使う★形にする(★推奨は後者★。規則を1箇所に置くため)
  3. ★テストを足す★(app/api/clean-logs/[id]/__tests__/route.test.ts):

    • ★judge.areas ログの raw_overall_completion_rate が overall_clean_ratio_sum / overall_clean_ratio_count と一致する★こと
    • ★未実施(完了率 null)の行が分子にも分母にも入らない★こと
    • ★overall_clean_area / overall_task_area がログに出ないこと★

4-2. 影響

  • ★このログを集計・監視している仕組みは無い★(出力先は標準出力のみ。lib/logger/index.ts。2026-10-01 確認)。★項目を差し替えても壊れるものは無い★
  • ★画面とAPIのレスポンスは変わらない★(変わるのはログの項目だけ)
  • docs/decisions.md:7699 / :7730(指示書Z の記録)は★当時の経緯★なので直さない

7. 段階5 — 確認

  1. npx tsc --noEmit -p . — エラー0件
  2. npx eslint . — 指摘0件
  3. npm test — ★全件通過★(本書の前は 98ファイル / 2,297件。段階4のテストで増える)
  4. ★次の grep で、いまの仕様として「面積ベース」「D-020b」を書いている箇所が0件★(「旧:」「以前は」「破棄」と経緯として書いているもの、§2 の表のものは残ってよい):
    grep -rn "面積ベース\|D-020b\|overall_clean_area\|overall_task_area" lib app components --include=*.ts --include=*.tsx

8. 禁止事項(このプロジェクト共通。CLAUDE.md §7)

  • ★git add -A を使わない★。★ファイルパスを明示する★
  • ★§2 の「直さないもの」を消さない★
  • ★段階1〜3と5で動作を変えない★(コメント・テスト名・文書だけ)
  • any を使わない

9. コミット

段階ごとに分けてよい(例: 段階1〜3で1つ、段階4で1つ)。 メッセージには ★「何が古かったか」「なぜ直すか(D-139 / D-151)」★を書くこと。


追補(2026-10-01。D-152)

★段階3(/d-watch スキル)に1件追加★。数値に加えて、次の記述も直すこと。

行の目安 いま 正しい内容
:52 付近 「133.125.238.144 / clean_watch は本番DBそのもの(D-148)」 ★「133.125.238.144 / clean_watch はステージング。本番DBは別にある(D-152。D-148 は破棄)」★
:57 付近 「過去の文書の『テストDB』『テスト環境』という呼称は誤り」 ★削除★(D-152 で、呼称のほうが正しかったと確定)
ほか 「本番DBへは書き込まない」の趣旨の記述があれば ★「ステージングには4カラムの UPDATE を書き込んでよい(D-152)。それ以外は禁止」★

★CLAUDE.md §3 は監督が直し済み★(触らなくてよい。§4.3 の段階2 は予定どおり行うこと)。


追補2(2026-10-01。別エージェントの査読で見つかった分)

★追補の「ほか」を行で特定した★。あわせて、★段階1(コメント)に1件追加★。

ファイル 行の目安 いま 正しい内容
.claude/commands/d-watch.md :50 見出し「接続先は本番DBです」 ★「接続先はステージングです」★
同 :54 「書き込み禁止。UPDATE 権限はあるが実行しない」 ★「4カラム(status / comment / responded_at / resolved_at)の UPDATE は書き込んでよい(D-152)。それ以外は禁止」★
同 :55 「いまは当方のダミー1,787行が入っている」 ★「2026-09-30〜10-01 に先方が実データ(ドン・キホーテ実店舗10件+本社)を入れた。当方のダミーは消えている」★
同 :85 「本番DBに触れない」 ★「ステージングに触れない」★
同 :110 「本番DBに書き込まない」 ★:54 と同じ内容にする★
同 :109 「DATETIME は JST の壁時計値(素で読むと9時間進む)」 ★文意は正しい(アダプタが UTC と誤認するのを fromDbJst() で戻す)ので残す★。★「生の値に9時間を足さない。例外に見える2列は TeamWorks 回答待ち(CLAUDE.md §3)」を1行足す★
lib/judge/kpi.ts :12-14 「CLAUDE.md §4.2 の式は旧定義のまま残っているが、」 ★この句を削る★(§4.2 は単純平均に更新済み)。残りの文はそのまま