# task-924.1 완료 보고서: InfoKeyword 키워드 우선순위 평가 기능 추가

## SCQA

**S**: InfoKeyword에서 5개 키워드를 동시 평가하면 결과가 입력 순서대로 나열되어, 어떤 키워드가 더 가치 있는지 직접 비교해야 한다.

**C**: 정보성 키워드와 비정보성 키워드가 섞여 있을 때 우선순위 판단에 시간이 소요되며, 검색량이나 정보성 비율 등 핵심 지표를 수동 비교해야 한다.

**Q**: Worker 응답에 우선순위 정렬 로직을 추가하여 프론트엔드에서 자동으로 가치 순으로 표시할 수 있는가?

**A**: `prioritize_results()` 함수를 추가하여 (1) INFORMATIONAL 키워드를 검색량 높은 순으로, (2) NOT_INFORMATIONAL을 informational_count 높은 순으로 정렬. 각 결과에 priority(1~)와 priority_reason 필드를 추가. 프론트엔드에서 우선순위 번호 배지 + 사유 텍스트 표시. pytest 28건 전체 통과, pyright 신규 에러 0건.

## 수정 파일 목록

- `/home/jay/projects/InfoKeyword/worker/pipeline/analyzer.py` — `prioritize_results()` 함수 추가, `analyze_keywords()` 반환값 정렬
- `/home/jay/projects/InfoKeyword/tests/test_pipeline_steps.py` — `TestPrioritizeResults` 클래스 추가 (11개 테스트)
- `/home/jay/projects/InfoKeyword/src/types/index.ts` — `KeywordResult`에 `priority?`, `priority_reason?` 필드 추가
- `/home/jay/projects/InfoKeyword/src/app/report/[id]/page.tsx` — `KeywordResultCard`에 우선순위 번호 배지 + 사유 텍스트 표시

## 구현 상세

### 백엔드: `prioritize_results()`
- 정렬 키: `(그룹, -검색량 또는 -informational_count, -검색량)`
  - 그룹 0: INFORMATIONAL (검색량 내림차순)
  - 그룹 1: NOT_INFORMATIONAL (informational_count 내림차순, 동일 시 검색량 내림차순)
- 각 결과에 `priority: int` (1부터)와 `priority_reason: str` 추가
- 7단계 분석 로직 및 step5 threshold(50%) 미변경

### 프론트엔드
- `KeywordResult` 타입에 optional 필드 추가 (하위 호환성 유지)
- 리포트 페이지 `KeywordResultCard`에 indigo 색상 원형 번호 배지 + 사유 텍스트

## 테스트 결과

- **pytest**: 28 passed (기존 17 + 신규 11) / 0.21s
- **pyright**: 기존 `reportMissingImports` 16건만 존재, 신규 에러 0건
- **black + isort**: 적용 완료
- **TypeScript tsc**: 신규 에러 0건 (기존 테스트 환경 문제만 존재)

## 검증 기준 충족 확인

1. 정보성 키워드가 있는 경우: 검색량 높은 순 정렬됨 ✅ (test_informational_sorted_by_volume_desc)
2. 정보성 키워드가 없는 경우: informational_count 높은 순 정렬됨 ✅ (test_no_informational_sorted_by_informational_count_desc)
3. 각 키워드에 정보성/홍보성 라벨이 표시됨 ✅ (기존 verdict 배지 유지 + priority_reason 추가)
4. 기존 분석 결과에 영향 없음 ✅ (7단계 로직 미변경, 기존 17개 테스트 모두 통과)
5. pyright/black/isort 통과 ✅

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **black/isort 포매팅 미적용** — 불칸이 포매팅 적용했으나 일부 불일치 남음 → 팀장이 `black + isort` 재실행하여 해결
2. **priority_reason에 total_blogs 참조** — step5 결과에 `total_blogs`가 없을 수 있음 → `.get("total_blogs", 0)` 기본값 처리로 안전하게 구현됨
3. **프론트엔드 priority=0 falsy 문제** — `result.priority && ...` 조건에서 priority=0이면 표시 안 됨 → priority는 1부터 시작하므로 실제 문제 없음 (0은 존재하지 않는 값)

## QC 자동 검증
(아래에서 실행)
