# T529 — five-question-judge-scorer

> Status: `done`  
> Milestone: `M2`  
> Kind: `feat`  
> Est. change: `~200 lines`

## Goal

完成後系統應：單筆貼文可產出 `intent_score`／`intent_band`／五條 `reasons[]`／`region_match` 三態／`freshness_hours`／`matched_service`，並判斷硬否決。

## Depends on

- T510、T528

## Inputs

- Spec：`../spec.md` §3.2（硬否決）、§3.3（權重與門檻）、§4.3、§9.2（OP-01～OP-05）
- 既有分類結果（`seeking_help`／`provider_offer`／…）與 AI provider：`apps/backend/internal/module/ai/**`

## Outputs

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

| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/backend/internal/module/radar/usecase/judge.go` | add | 組 prompt（貼文＋ServiceProfile＋觸發 term）、解析結構化輸出、算分 |
| `apps/backend/internal/module/radar/domain/scoring.go` | add | 權重常數（真實性 30／購買意圖 30／地區 15／時效 15／匹配度 10）、band 門檻 80／50、`freshness` 級距 |
| `apps/backend/internal/module/radar/domain/region.go` | add | 三態比對：命中服務地區→`match`；明確他縣市→`mismatch`；未提→`unknown`（**不猜測**） |

### 行為變更

- 硬否決（不計分直接 `rejected`＋`reject_reason`）：第一問「非真實需求」、分類為 `provider_offer`／`announcement`／`noise`、發布距今 > 14 天。
- `remote_ok=true` 時：`mismatch` 不觸發硬否決且地區維度給滿分（OP-05）。
- 時效：≤24h 滿分、24–72h 遞減、72h–14 天低分、>14 天硬否決。
- 五維度各一條人話理由；缺任一條視為判定失敗（不寫庫，交 T530 處理）。
- 計費：`ai_research` meter／`source=radar.judge`。

### 決策（收斂 spec §10 問題 4、5）

- 權重採上列數值為初版，**只調權重與 prompt，不動 band 門檻**。
- 縣市代碼表沿用 T510 的 domain 白名單；比對為代碼與常見別名精確比對，不做地理推論。

## Out of scope

- 入庫與去重（T530）
- 配額截斷（T531）

## Acceptance

- [x] OP-01～OP-05 各有 unit test（fake AI 回固定結構）
- [x] 未提地區的貼文得 `unknown` 且拿到部分分，回應中無縣市猜測
- [x] 指令：

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