# 指示書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`

**いま**:
```ts
 * ★`lib/judge/kpi.ts` は使わない★
 *   kpi.ts は週次/月次の**面積ベース**集計（CLAUDE.md §4.2）用で、
 *   ここでやりたい日次の**件数カウント**とは別物。混ぜると分母の意味が変わる。
```

**問題**: ★kpi.ts の完了率はもう面積ベースではない★（`clean_ratio` の単純平均。D-151）。★粒度も週・月・年の3つ★になった。

**直し方（例）**:
```ts
 * ★`lib/judge/kpi.ts` は使わない★
 *   kpi.ts は週次/月次/年次の集計期間の KPI（CLAUDE.md §4.2）用で、
 *   ここでやりたい日次の**件数カウント**とは別物。混ぜると分母の意味が変わる。
```
★「使わない」という結論と理由（日次の件数カウントとは別物）は正しいので残す★。★「面積ベース」という誤った説明だけを外す★。

### 1-2. `lib/judge/__tests__/advice.test.ts:66` のテスト名

**いま**:
```ts
  it("10.0%はR2ではない（10%未満が条件。D-020b）", () => {
```

**問題**: ★D-020b は「境界はすべて下のランクに落ちる」なので、それに従うと 10.0% は × になり、R2 に当たる★。★このテストが確かめていること（10.0% は R2 ではない）と逆の規則を根拠に挙げている★。正しい根拠は ★D-139（×の境界だけは「10%未満」のまま）★。

**直し方**:
```ts
  it("10.0%はR2ではない（×は10%未満。10.0は△。D-139）", () => {
```
★テストの中身（`expect` の3行）は変えないこと★。

### 1-3. `app/api/clean-logs/[id]/areas/route.ts:126`

**いま**（`judge.areas` ログを出す直前のコメント）:
```ts
    //   （行は `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`

**いま**:
```ts
   *   - ★全体率は面積ベース（`Σ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 の「❌ 間違い」の例）:
```ts
// ❌ 間違い（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だが判定は○」と同じケース）。

**直し方**:
```ts
// ❌ 間違い（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`）:
```ts
      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 は単純平均に更新済み）。残りの文はそのまま |
