# task-930.4 완료 보고서: Passive Feedback diff 감지 로직 구현

## SCQA

**S**: 설계서 v1.2 Section 4-3에 정의된 Passive Feedback Loop이 설계 확정 상태이며, learnings_archiver.py 인프라가 이미 구축되어 `jay-feedback` source의 영구 보존을 지원한다.

**C**: 제이회장님이 AI 아웃풋을 수정하면 그 diff가 최고 품질의 학습 데이터(ground truth)인데, 이를 자동 감지하고 학습으로 축적하는 엔진이 없어 수동 피드백에 의존해야 했다.

**Q**: 기존 워크플로우 변경 없이, 스냅샷 저장 → diff 감지 → 학습 추출 → learnings 연동까지의 자동화 파이프라인을 구현할 수 있는가?

**A**: `passive_feedback.py` (199줄)와 테스트 (178줄)를 TDD로 구현 완료. pytest 8/8 통과 (0.41초), pyright 0 에러, black/isort 준수. CLI 3개 서브커맨드(snapshot/detect/history)와 learnings_archiver 연동이 정상 작동한다.

## 생성/수정 파일

- `scripts/passive_feedback.py` (신규, 199줄) — diff 감지 엔진 + CLI
- `scripts/tests/test_passive_feedback.py` (신규, 178줄) — 테스트 8건

## 구현 상세

### Phase 1: diff 감지 엔진
- `save_snapshot()`: 원본 파일을 `memory/skill-feedback/{skill}/snapshots/{timestamp}.txt`에 저장
- `detect_diff()`: difflib.unified_diff로 비교, 공백/포맷 변경 제외, AI로 learning 추출
- `_compute_meaningful_diff()`: remove/add 라인 strip() 정렬 비교로 공백만 변경 필터링

### Phase 2: passive-diffs.jsonl
- 스키마 준수: timestamp, skill_name, task_id, snapshot_path, diff_summary, diff_lines, learning_extracted, learning_id
- `_save_diff_record()`로 append-only 기록

### Phase 3: learnings 연동
- `learnings_archiver.add_learning(source="jay-feedback", learnings_path=...)` 호출
- expires_at=null 영구 보존 확인 (테스트 TC4에서 검증)

### Phase 4: 테스트
- TDD RED→GREEN 순서 준수 (테스트 파일 먼저 생성)
- 7개 테스트 케이스 / 8개 메서드 전체 통과

## 테스트 결과

```
8 passed in 0.41s
```

- TestSnapshotSave: 스냅샷 저장 + 파일 존재 + 내용 일치 + 메타데이터 ✅
- TestDetectDiffNormal: diff 추출 + passive-diffs.jsonl 기록 ✅
- TestDetectWhitespaceOnly: 공백만 변경 → None 반환 ✅
- TestLearningExtraction: learnings.jsonl에 jay-feedback source + expires_at=null ✅
- TestHistory: passive-diffs.jsonl 정상 반환 ✅
- TestHistory(empty): 파일 없을 때 빈 리스트 ✅
- TestAiCallMocking: anthropic SDK 1회 호출 + model=claude-sonnet-4-6 확인 ✅
- TestSnapshotPathAutoCreation: 디렉토리 자동 생성 + task_id=None 처리 ✅

## 검증 증거

- pytest: 8/8 PASSED (0.41s)
- pyright: 0 errors, 0 warnings, 0 informations
- black/isort: 포맷 준수 (적용 후 재검증 완료)
- 줄 수: 구현 199줄, 테스트 178줄 (200줄 제한 준수)

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **파일명 hyphen vs underscore** — Python 모듈 임포트를 위해 `passive_feedback.py` (underscore) 사용. CLI 실행은 `python3 scripts/passive_feedback.py`로 동일 작동.
2. **black/isort 포맷 불일치** — 초기 생성 파일에 포맷 차이 발견, `black + isort` 적용 후 테스트 재통과 확인.
3. **anthropic mock 호환성** — `isinstance(block, TextBlock)` 대신 `getattr(block, "text", None)` 사용하여 mock 환경에서도 정상 작동하도록 처리.

## QC 검증 결과

- **Overall: PASS** (8 PASS, 4 SKIP)
- file_check: PASS (passive_feedback.py 7291B, test 7526B)
- data_integrity: PASS
- test_runner: PASS (8 passed in 0.40s)
- pyright_check: PASS (0 errors, 0 warnings)
- style_check: PASS (black OK, isort OK)
- critical_gap: PASS
- spec_compliance: PASS
- duplicate_check: PASS (최대 유사도 14.6%)
- api_health: SKIP (서버 작업 아님)
- tdd_check: SKIP (audit-trail 미탐지)
- schema_contract: SKIP (workers 없음)
- scope_check: SKIP
