53 lines
1.6 KiB
Markdown
53 lines
1.6 KiB
Markdown
|
|
# 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).
|