# T850 — candidate normalization prefilter

> Status: `done`（2026-08-11）
> Milestone: `M5`
> Est. change: `~190 lines`

## Goal

完成後候選會先經來源正規化、去重、硬排除、需求證據與產品證據前處理，reject 不進昂貴 AI。

## Depends on

- T841、T843

## Inputs

- `apps/backend/internal/module/radar/usecase/sweep_fetch.go`
- `apps/backend/internal/module/radar/domain/**`
- Spec §4.3、驗收 #8、#9、#15

## Outputs

### 程式變更（預期路徑）

| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/backend/internal/module/radar/domain/candidate.go` | edit/add | disposition、machine reason、evidence fields |
| `apps/backend/internal/module/radar/usecase/candidate_prefilter.go` | add | normalize、dedupe、exclude、pass/review/reject |
| `apps/backend/internal/module/radar/usecase/candidate_prefilter_test.go` | add | provider／公告／純名／口語 fixtures |

### 行為變更

- 同來源只留資訊最完整一筆；provider、廣告、公告、雜訊與產品硬排除為 reject。
- 無需求或產品證據降 review；不直接宣稱高順位。

### API / 契約（若有）

- 輸出 machine reason 與 pass/review/reject counts 給 Sweep。

## Out of scope

- 不做 AI judge、不做 priority score persistence。

## Acceptance

- [x] 純產品名、同業、公告不進 AI；真正求助可 pass。
- [x] URL／external ID 正規化去重穩定。
- [ ] 指令：

```bash
cd apps/backend && go test ./internal/module/radar/usecase -run 'Prefilter|Candidate' -count=1
```

## Notes

前處理不得推測作者敏感屬性；未知時間只保留風險。
