# task-3029 — 인슈위키 유튜브 카드 품질 개선 (채널·게시일 노출 + 전사 첨부 + 요약 말투)

**레벨**: Lv.2 · **팀**: dev4-team · **회장 승인 완료** (2026-08-26)
**저장소**: `Jeon-Jonghyuk/InsuWiki` (`/home/jay/projects/insuwiki`, 기본 브랜치 **master**)

## ★ 회장 지적 (2026-08-26 원문)
> "유튜브 영상 요약해서 인슈위키에 업로드 된 카드 보니까 그 퀄리티가 마음에 안 든다.
>  1. 어떤 채널인지, 영상 업로드 날짜 확인 불가능
>  2. 전사 원문 첨부파일 확인 불가"
> "전사 텍스트 내용은 사람이 해당 카드에 첨부파일 업로드 한 것처럼 자동으로 올라가게 하면 좋겠어."

---

## ① 채널명 · 영상 게시일 노출

### ★★ 요약 프롬프트를 고치지 마라 — 값은 이미 손에 있다
회장이 "요약 프롬프트를 수정하면 되지 않나" 물었으나 **그럴 필요가 없고 오히려 위험하다.**
```
drive_uploader.py:138-140   이미 이렇게 쓰고 있다
    - **채널**: {channel_name}
    - **게시일**: {published_at[:10]}
firestore_writer.py:127     youtube_knowledge 에는 "companyName": channel_name 저장 중
youtube_api.py              YouTube API snippet 에서 받은 정확한 원본값
```
**그런데 `documents`(wiki 카드)에만 안 넣었다.** 이미 정확한 값을 갖고 있으니 그대로 저장하면 된다.

★ 프롬프트로 시키면 안 되는 이유: 요약 프롬프트에 **"자막에 없는 내용은 절대 추가하지 않습니다"**
규칙이 있다. 채널명·게시일은 자막에 없으므로 LLM 이 쓸 수 없고, 억지로 시키면 **지어낸다**.
정확한 값이 있는데 추측시키지 마라.

### 할 일
- `save_wiki_document` 가 **채널명 · 영상 게시일 · 원본 유튜브 링크**를 저장하도록 한다
- 저장 위치는 `properties` 를 쓴다(현재 `{}` 로 비어 있고 `DocumentProperties` 타입이 이미 있다).
  ★ 기존 소비자를 깨뜨리지 않는 방식인지 확인하고, 타입 확장이 필요하면 `nextapp/src/types/firestore.ts` 도 맞춰라
- **카드 화면 상단에 보이게** 한다. 저장만 하고 안 보이면 회장 지적이 해소되지 않는다
- 게시일은 **KST 기준 날짜**로 표시하라(파이프라인 값은 UTC ISO 문자열이다). 타임존 미표기 금지

---

## ② 전사 원문 첨부 — "사람이 올린 것처럼"

### 현재 상태 (ANU 실측)
```
Firestore 카드 8건 전부 attachments 1건씩 정상 저장돼 있다:
  fileId · name(2026-08-20_제목...) · url(/api/attachments/{fileId}) · type · uploadedAt
DocumentClient.tsx:875-883 에 첨부 목록 렌더 코드도 있다
```
**데이터도 있고 렌더 코드도 있는데 회장이 "확인 불가"라고 한다.** 원인을 먼저 특정하라.

### ★ 조사 먼저 (수정 금지 단계)
```
사람이 올릴 때 (api/upload/route.ts)   fileId · name · webViewLink
파이프라인이 넣는 것                    fileId · name · url · type · uploadedAt
화면이 그릴 때 쓰는 것                  fileId · name · url · type · uploadedAt
```
DocumentClient 주석: *"기존 Drive webViewLink 첨부(/api/ 로 시작하지 않는 url)는 그대로
`<a href>` 직행 — 하위호환 유지"* → **첨부 형태가 두 갈래로 공존한다.**

아래 중 무엇인지 **실제로 확인해서 특정**하라. 추정으로 고치지 마라.
```
(a) 첨부 영역이 렌더되지 않는다 (조건·위치 문제)
(b) 렌더되지만 클릭 시 /api/attachments/{fileId} 인증 호출이 실패한다
(c) Drive 파일 자체가 열리지 않는다 (권한·파일 부재)
```
- (b) 검증법: 실제 로그인 토큰으로 `/api/attachments/{fileId}` 를 호출해 **HTTP 코드와 본문**을 보라.
  ANU 가 확인한 실제 fileId: `15S96mcYFq5ElylpvKMXtC3xSLVqWQ1jT` (카드 `youtube-5v6VeX4fk90`)
- `findAttachmentOwner` 가 `documents` 전체를 순회하는 구조다. 문서가 늘면 느려지거나 실패할 수 있다

### 할 일
특정된 원인만 고쳐서 **사람이 올린 첨부와 동일하게 보이고 동일하게 열리도록** 한다.
- 회장 표현: *"사람이 해당 카드에 첨부파일 업로드 한 것처럼"*
- 형태를 사람 업로드 쪽에 맞출지, 화면이 두 형태를 모두 처리하게 할지 **판단하고 근거를 남겨라**

---

## ③ 요약 서두의 LLM 말투 제거

### ANU 실측 — 카드마다 서두가 제각각이다
```
카드 A:  "# 보험 유튜브 영상 핵심 논지 재구성"  →  "## 1. 주제 한줄"
카드 B:  "자막 분석 결과입니다."                →  "**1. 주제 한줄**"
카드 C:  "라이나 생명 종신생활연금 자막을 분석했습니다.
          아래 결과물을 그대로 사용하시면 됩니다."  →  "**1. 주제 한줄**"
```
**"아래 결과물을 그대로 사용하시면 됩니다"** 는 독자가 아니라 지시자에게 하는 말이다.
제목 형식도 `## 1.` 과 `**1.**` 이 섞여 카드마다 모양이 다르다.

### 할 일
`YOUTUBE_SUMMARY_PROMPT` 에 **출력 형식 고정** 조항을 추가한다.
- 서두 인사말·메타 발화 **금지** (`~분석했습니다` · `~사용하시면 됩니다` · `아래는~` 류)
- 4단 제목 형식을 **하나로 고정**(예: `## 1. 주제 한줄`)
- 첫 줄부터 바로 본문이 시작되게 한다

### ★ 건드리지 말 것
- **요약 내용 규격은 회장 확정이다.** 1,500~2,000자 하한 보증 · 4단 구성 ·
  "자막에 없는 내용 추가 금지" · "숫자·보장한도·기간·면책 축약 금지" · 마지막 줄 고지문
  → **형식만 고정하고 내용 규칙은 그대로 두라**
- 이건 "글자수 요약"이 아니라 **내용 기준 핵심논지 재구성**이다(회장 재확인 2026-08-26)

---

## ★ 하지 말 것
- 요약 **내용** 규격 변경 (분량·4단 구성·인용 규칙)
- `lastCrawledAt` 커서 가드 완화 (t3021 결과물, 라이브 발화 확인됨)
- fail-closed 완화 (전사 없으면 카드 생성 안 함)
- 1회 처리량 상한 로직 (**task-3028 이 동시 진행 중이다. `config.py`·`main.py` 충돌 주의**)
- 타이머 주기 변경 · systemd 유닛 수정
- 기존 카드 8건을 **일괄 삭제·재생성** 금지. 백필이 필요하면 **설계만 제안**하고 ANU 승인을 받아라

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "scripts/youtube-pipeline/youtube_pipeline/firestore_writer.py"
    - "scripts/youtube-pipeline/youtube_pipeline/summarizer.py"
    - "scripts/youtube-pipeline/tests/**"
    - "nextapp/src/app/docs/**"
    - "nextapp/src/app/api/attachments/**"
    - "nextapp/src/types/firestore.ts"
    - "memory/reports/task-3029.md"
  forbidden_paths:
    - "scripts/youtube-pipeline/youtube_pipeline/config.py"
    - "scripts/youtube-pipeline/youtube_pipeline/main.py"
    - "scripts/youtube-pipeline/youtube_pipeline/transcriber.py"
    - "scripts/youtube-pipeline/youtube_pipeline/drive_uploader.py"
    - ".github/workflows/**"
    - "functions/**"
  commands: ["bash", "python3", "pytest", "npm", "npx", "gh"]
  merge_policy: "tiered"
  ttl_hours: 24
```
★ `config.py`·`main.py` 는 **task-3028 이 쓰고 있다.** 필요하면 ANU 에 보고하고 조율하라.

## 검증 (실측 강제)
1. **실제 카드 1건 생성** — 파이프라인을 1회 돌려(짧은 영상 소수) 새 카드에
   채널명·게시일·원본링크가 **실제로 저장되고 화면에 보이는지** 확인. 스크린샷 필수
2. **첨부 원인 특정 근거** — (a)(b)(c) 중 무엇이었는지와 그 판정 근거
3. **첨부 열람 실증** — 실제 로그인 상태에서 전사 첨부를 **열어서** 내용이 나오는지 확인
4. **요약 서두 검사** — 새로 생성된 요약의 **첫 200자**를 그대로 제시하라.
   인사말·메타 발화가 없고 제목 형식이 고정됐는지
5. **기존 카드 영향 없음** — 기존 8건이 깨지지 않는지 확인
6. **봉인** — 서두 말투가 다시 새는 변이, 채널명 저장을 빼는 변이를 만들어 테스트가 FAIL 하는지
   확인·복원. 변이가 no-op 이 아님을 `assert` 로 먼저 증명하라
7. `pytest` · `npm test` 회귀 유지 (**base 재측정 기준선**)

## ★ 실행 시 주의 — 오늘 서버가 OOM 으로 죽었다
- 검증용 파이프라인 실행은 **짧은 영상·소수 건**. GPU·RAM 장시간 점유 금지
- 타이머가 **6시간 주기**로 살아 있다(다음 18:16 KST). 그 시간대와 겹치지 마라
- 실행 전 `free -h` 확인, 여유 4GB 미만이면 대기하라
- ★ **worktree 를 써라.** 메인 저장소(`/home/jay/projects/insuwiki`)는 systemd 러너가 직접 실행한다

## 완료 조건 (DoD)
**새로 생성된 wiki 카드에서 채널명·영상 게시일·원본 링크가 화면에 보이고,
전사 첨부가 사람이 올린 첨부와 동일하게 열리며, 요약 첫 줄부터 본문이 시작된다.**

## ★ 세션 조기 종료 대책
시작 즉시 브랜치 + 드래프트 PR 을 먼저 열어라. **단계마다 커밋하라**
(오늘 OOM 으로 죽은 4팀 중 2팀은 커밋 0이라 진척이 전부 사라졌다).
★ ANU 명세 전제가 틀렸다고 판단되면 구현하지 말고 **반증을 먼저 기록한 뒤 보고하라.**

## 운영 계약
- `origin/master`(=`5da890c`) 기준으로 시작
- ★ `gh` 호출 시 `GH_TOKEN="$BOT_GITHUB_TOKEN"` 주입 필수 (회장 개인 PAT 금지 — 감사기록 오염)
- 워크플로우 `/home/jay/workspace/prompts/DIRECT-WORKFLOW.md` · QC `/home/jay/workspace/teams/shared/QC-RULES.md`
- `WORKSPACE_ROOT=/home/jay/workspace` · `CHAT_ID=6937032012` · 수집자 key `ANU_KEY=c119085addb0f8b7`
- 완료 경로는 `finish-task.sh` 실행이 유일하다. 수동 `.done` 금지.
- ★ PR Check `validate` 는 이 저장소에서 **상시 적색**이다. 변경 파일과 교집합이 없으면
  선재로 판정하고 근거를 보고서에 적어라

## 보고
**PR 생성까지가 범위다. 머지는 ANU 가 한다. 자동 머지 금지.**
`memory/reports/task-3029.md` 작성 후 표준 완료 콜백 등록. 콜백 프롬프트 **UTF-8 3900 bytes 이하**.
★ 봉투 첫 줄에 **"채널·게시일 화면 노출 여부 + 첨부 원인 특정 결과"** 를 담아라.

## goal_assertions (auto-generated)
- `npm test`
