# Achievement Report Mastery Hit Rate Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Rename the achievement-report metric from `真题生词命中率` to `试卷掌握度命中率`, and derive its displayed value from `试卷熟词提升 ÷ 词汇量提升`, rounded to 1 decimal place as a percentage, with `0%` when `词汇量提升 = 0`.

**Architecture:** Keep the existing report DTO/placeholder shape intact and change only the application-layer mapping logic plus presentation text. Compute the percentage inside `AchievementReportContentMapper` from the existing delta fields so infrastructure rendering continues to consume the same `unknownWordHitRateText` placeholders without contract changes.

**Tech Stack:** Java, Maven, JUnit 5, AssertJ, HTML template rendering.

---

### Task 1: Replace payload-driven metric with derived mastery hit rate

**Files:**
- Modify: `abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/AchievementReportContentMapper.java`
- Test: `abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/AchievementReportContentMapperTest.java`
- Test: `abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.java`

**Step 1: Write the failing tests**

- Update mapper/service expectations so the metric is derived from `TestPaperImprovedWordCount ÷ StudentImproveWordCount` instead of `PaperMasteryHitRate`.
- Use the existing sample payload to expect `4 ÷ 19 = 21.1%`.
- Add a zero-denominator case expecting `0%` when `StudentImproveWordCount = 0`.
- Make at least one test keep `PaperMasteryHitRate` at a deliberately mismatched value so RED proves the old field is no longer the source.

**Step 2: Run tests to verify they fail**

Run:

```bash
mvn -pl abilities/exam-sprint/application -am -Dtest=AchievementReportContentMapperTest,ExamSprintReportApplicationServiceTest test
```

Expected: FAIL because the mapper still uses `PaperMasteryHitRate` and formats `1.93%` instead of `21.1%` / `0%`.

**Step 3: Write the minimal implementation**

- Add a small helper in `AchievementReportContentMapper` that:
  - reads `payload.testPaperImprovedWordCount()` as numerator
  - reads `payload.studentImproveWordCount()` as denominator
  - returns `"0%"` when denominator is zero
  - otherwise computes `(numerator / denominator) * 100`
  - rounds half up to 1 decimal place
  - formats non-zero denominator results with exactly 1 decimal place so `20%` becomes `20.0%` while `21.1%` stays `21.1%`
- Reuse the computed string for both `summaryMetrics.unknownWordHitRateText` and `examUnknownWordsHitStatus.unknownWordHitRateText`.

**Step 4: Run tests to verify they pass**

Run:

```bash
mvn -pl abilities/exam-sprint/application -am -Dtest=AchievementReportContentMapperTest,ExamSprintReportApplicationServiceTest test
```

Expected: PASS.

**Step 5: Do not commit**

- Leave changes uncommitted unless the user explicitly asks for a commit.

### Task 2: Rename the displayed metric label everywhere in achievement report outputs

**Files:**
- Modify: `abilities/exam-sprint/infrastructure/src/main/resources/templates/achievement-exam-sprint-report-template.html`
- Test: `abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/rendering/achievement/ClasspathAchievementExamSprintReportRendererTest.java`
- Test: `abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/pdf/PlaywrightExamSprintReportPdfGeneratorTest.java`

**Step 1: Write the failing tests**

- Update assertions from `真题生词命中率` to `试卷掌握度命中率`.
- Update rendered value expectations from `1.93%` to `21.1%` based on the shared sample payload.

**Step 2: Run tests to verify they fail**

Run:

```bash
mvn -pl abilities/exam-sprint/infrastructure -am -Dtest=ClasspathAchievementExamSprintReportRendererTest,PlaywrightExamSprintReportPdfGeneratorTest test
```

Expected: FAIL because the template still shows the old label and existing fixture-derived values still render `1.93%`.

**Step 3: Write the minimal implementation**

- Change the two achievement-template labels from `真题生词命中率` to `试卷掌握度命中率`.
- Keep placeholder names unchanged.

**Step 4: Run tests to verify they pass**

Run:

```bash
mvn -pl abilities/exam-sprint/infrastructure -am -Dtest=ClasspathAchievementExamSprintReportRendererTest,PlaywrightExamSprintReportPdfGeneratorTest test
```

Expected: PASS.

**Step 5: Do not commit**

- Leave changes uncommitted unless the user explicitly asks for a commit.

### Task 3: End-to-end verification of the final achievement report behavior

**Files:**
- Verify only: no new files expected

**Step 1: Run the combined verification suite**

Run:

```bash
mvn -pl abilities/exam-sprint/infrastructure,abilities/exam-sprint/application -am -Dtest=AchievementReportContentMapperTest,ExamSprintReportApplicationServiceTest,ClasspathAchievementExamSprintReportRendererTest,PlaywrightExamSprintReportPdfGeneratorTest test
```

Expected: PASS with zero failures.

**Step 2: Inspect the final diff**

Run:

```bash
git diff -- abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/AchievementReportContentMapper.java abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/AchievementReportContentMapperTest.java abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.java abilities/exam-sprint/infrastructure/src/main/resources/templates/achievement-exam-sprint-report-template.html abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/rendering/achievement/ClasspathAchievementExamSprintReportRendererTest.java abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/pdf/PlaywrightExamSprintReportPdfGeneratorTest.java
```

Expected: Only the derived-metric logic, renamed labels, and directly related test updates appear.

**Step 3: Do not commit**

- Stop after reporting verification evidence unless the user explicitly asks for a commit.
