# T744 — product match merge primary arbitration

> Status: `done`  
> Milestone: `M4` · Phase C  
> Kind: `feat` · Est. change: `~200 lines`

## Goal

把 fit 結果合併進既有 Opportunity，穩定選 PrimaryProduct 並正確換算 intent fit 10 分。

## Depends on

- T732、T743

## Inputs

- `apps/backend/internal/module/radar/usecase/judge_persist.go`
- `../spec.md` §3.3、§4.2

## Outputs

| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/backend/internal/module/radar/usecase/product_match_merge.go` | add | merge decision、primary arbitration、score recompute |
| `apps/backend/internal/module/radar/usecase/judge_persist.go` | edit | new／existing／same-product branches |
| merge tests | add | first／higher／tie／manual override／same product |

## Behavior

- 首 eligible 為 primary；更高分自動替換；tie 使用 spec 穩定規則。
- 有人工 override 不自動替換。
- primary 變更只改 fit reason 與總分，不重跑其他四問。
- 同 Product 再命中只 merge watch／term，不重判不計費。

## Out of scope

- 人工 override API（T754）
- list filters（T753）

## Acceptance

- [x] spec #4–#6 的 usecase tests 通過。

```bash
cd apps/backend && go test ./internal/module/radar/usecase/... -count=1
```

Implementation result (2026-08-10): new and existing opportunities now carry
ProductMatch snapshots through persistence. Same-product hits only merge
watch／term sources; new eligible products arbitrate primary by score, band,
time, and ID, while human overrides are preserved. Primary changes recompute
only the existing fit reason and intent total (product fit 0–100 → fit 0–10).
