# task-930.4: Passive Feedback diff 감지 로직 구현 (한정위임)

## 배경
- 설계서 v1.2 Section 4-3에 정의된 Passive Feedback Loop 구현
- 제이회장님이 아웃풋을 수정하면, 그 diff가 최고 품질의 학습 데이터 (ground truth)
- 제이회장님 추가 작업 0, 기존 워크플로우 변경 없음

## 선행 산출물 (반드시 읽고 시작)
1. **설계서**: `/home/jay/workspace/memory/specs/skill-eval-self-learning-design.md` (v1.2, Section 4-3, 8-3)
2. **learnings 인프라**: `/home/jay/workspace/scripts/learnings_archiver.py`
3. **스킬 레지스트리**: `/home/jay/.claude/skills/shared/skill-registry.json`
4. **eval-axes**: `/home/jay/.claude/skills/shared/eval-axes.json`

## 작업 범위 (한정위임 — 끝까지 진행)

### Phase 1: diff 감지 엔진 구현

**파일**: `scripts/passive-feedback.py` (신규)

**핵심 로직:**
1. **스냅샷 저장**: 스킬이 아웃풋을 생성할 때, 원본을 스냅샷으로 저장
   - 경로: `memory/skill-feedback/{skill-name}/snapshots/{timestamp}.txt`
   - 메타데이터: skill_name, timestamp, task_id (있으면)

2. **diff 감지**: 제이회장님이 수정한 후의 파일과 스냅샷을 비교
   - `difflib.unified_diff` 사용
   - 의미 있는 변경만 추출 (공백/포맷 변경 제외)

3. **학습 추출**: diff에서 학습 포인트 도출
   - AI 호출: "이 diff에서 어떤 개선이 이뤄졌는지 분석해줘"
   - 결과를 learnings.jsonl에 `source: "jay-feedback"` 으로 저장
   - jay-feedback은 **immutable** (TTL 무관, 영구 보존)

**CLI 인터페이스:**
```
# 스냅샷 저장 (스킬 실행 시 호출)
python3 scripts/passive-feedback.py snapshot --skill <name> --file <path> [--task-id <id>]

# diff 감지 + 학습 추출 (수동 또는 자동 트리거)
python3 scripts/passive-feedback.py detect --skill <name> --original <snapshot_path> --modified <current_path>

# 특정 스킬의 피드백 이력 조회
python3 scripts/passive-feedback.py history --skill <name>
```

### Phase 2: passive-diffs.jsonl 구현

**경로**: `memory/skill-feedback/{skill-name}/passive-diffs.jsonl`

**스키마:**
```json
{
  "timestamp": "2026-03-25T12:00:00",
  "skill_name": "satori-cardnews",
  "task_id": "task-xxx",
  "snapshot_path": "memory/skill-feedback/satori-cardnews/snapshots/20260325_120000.txt",
  "diff_summary": "CTA 문구를 '상담 예약하기'에서 '지금 무료 상담'으로 변경",
  "diff_lines": [
    {"type": "remove", "line": "상담 예약하기"},
    {"type": "add", "line": "지금 무료 상담"}
  ],
  "learning_extracted": "CTA는 '예약' 대신 '무료' 키워드 포함 시 전환율 향상",
  "learning_id": "learn-xxx"
}
```

### Phase 3: learnings 연동

- diff에서 추출한 학습은 `learnings_archiver.py`의 `add_learning()` 함수로 저장
- source: "jay-feedback"
- skill_name 필드 필수 (스킬별 격리)
- expires_at: null (영구 보존)

### Phase 4: 테스트

**파일**: `scripts/tests/test_passive_feedback.py` (신규)

테스트 케이스:
1. snapshot 저장 → 파일 존재 확인
2. detect → diff 정상 추출
3. 공백만 변경 시 → 의미 있는 diff 없음 처리
4. learning 추출 → learnings.jsonl에 jay-feedback source로 저장 확인
5. history 조회 → passive-diffs.jsonl 정상 반환
6. AI 호출 모킹 (학습 추출 부분)
7. 스냅샷 경로 자동 생성

## 제약사항
- **신규 파일**: `scripts/passive-feedback.py`, `scripts/tests/test_passive_feedback.py`
- learnings.jsonl 쓰기는 반드시 learnings_archiver.py의 add_learning() 사용
- memory/skill-feedback/ 디렉토리는 task-930.2에서 이미 생성됨
- AI 호출: anthropic SDK, 모델 claude-sonnet-4-6, API 키는 환경변수 ANTHROPIC_API_KEY
- 모듈화: 200줄/파일 제한
- WORKSPACE_ROOT 환경변수 우선, 없으면 스크립트 위치 기준 추론

## 산출물
1. `scripts/passive-feedback.py`
2. `scripts/tests/test_passive_feedback.py`
3. 보고서: `memory/reports/task-930.4.md`