POSA_Copyrighter/docs/reviews/2026-07-11-remediation-checklist.md
changukyu 2c607e0df6 docs: 2026-07-11 multi-agent review report, remediation checklist, offline extras
- Add the 2026-07-11 multi-agent project-review report and the remediation
  checklist (per-item status, with deferred items and their rationale).
- offline-install: document Ollama model and Playwright Chromium transfer, a
  hash-verified lock, --only-binary, and correct the egress note (image
  comparison fetches arbitrary SSRF-guarded public URLs, not only API hosts).
2026-07-11 16:08:04 +09:00

7.4 KiB

2026-07-11 리뷰 리메디에이션 체크리스트

기준 리뷰: docs/reviews/2026-07-11-project-review.md (HEAD 89c1fe4) 신규 HIGH 9 + 유닛 추가 HIGH 3(통합/프론트) + MEDIUM ~28 + LOW ~14. 배치는 risk-per-effort 순. 각 배치 후 pytest tests/rights_filter -q 통과 확인.

Batch 1 — 스코어링 파이프라인 복구 (최우선) ✅ 완료

직렬화 라운드트립 필드 손실 1개 패턴이 HIGH 3건을 만듦. 프로모터 3건은 배포 즉시 노출되므로 동일 배치.

  • H6 store_serialization.py — _evidence_payload에 promoted/promotionReason 추가, _domain_evidence_from_ui에서 복원
  • H7 store_serialization.py — entity/category 추가+복원
  • D1 store_serialization.py — 실제 EvidenceSource 영속화(domainSource), 키워드 휴리스틱은 레거시 폴백
  • M12 search_result_promoter.py — no-results 구조적 매칭, 마커 스캔에서 query 텍스트 제외
  • M13 search_result_promoter.py — 한국어 마커 추가, 단문 오탐 워드바운더리
  • M14 risk_scoring.py — promoted Naver 결과 query_signature 기준 dedup
  • 회귀 테스트 7건 (라운드트립 score>0, 2 distinct entities, skip 무점수, dedup, 프로모터)

Batch 2 — 동시성 / _write_lock 규율 ✅ (M4/#12 제외)

무락 RMW 1개 패턴이 HIGH 3 + MEDIUM 5.

  • H1 sqlite_store.py — record_decision _write_lock
  • H2 store_persistence.py — _apply_provider_usage_delta 델타 병합(stale payload 되쓰기 금지)
  • H3 store_enrichment.py — _sync_provider_payloads 저장된 enabled 보존(operatorDisabled 플래그로 연결성/운영자 구분)
  • H4 store_operations.py — manual_search 네트워크 락 밖, RMW 재읽기 후 락 안
  • M1 store_operations.py — collect_keyword_candidates 후보 메모리 누적→락 안 clear+insert
  • M2 sqlite_store.py — set_provider_enabled/emergency_disable 락+트랜잭션
  • M3 store_enrichment.py — _sync_submission_provider_state 락
  • 회귀 테스트 2건 (operator-disable 재시드 생존, usage delta가 in-flight disable 안 되돌림)
  • #12 rerun_enrichment/run_auto_search 락 — 연기(메가함수 내 네트워크+RMW 교차, 락 유지 시 가용성 회귀; 연기된 HIGH#6 리팩터와 함께)
  • M4 seed 락 협소화 — 연기(동일 이유, 가용성 최적화)

Batch 3 — 시드/저장소 견고성 ✅

  • H5 sqlite_store.py — 빈 analysis run 시 'failed' 밴드+감사+continue + 테스트
  • #13 store_queue.py — ensure_queue WHERE 키를 기존 행 id로 + 테스트
  • M6 store_queue.py — 큐 활성/레거시 이관 시 감사 이벤트(스팸 방지 조건부)
  • M5 http_app.py — 업로드 TOCTOU: 배타 생성(open xb) 재시도 루프
  • [~] M8 image_store.py — 되돌림: stem-충돌 접미어가 id를 형제-의존으로 만들어 판정된 submission 중복 부활 회귀(diff 리뷰 HIGH) → id=path.stem 복귀. 올바른 수정은 시드 단계 incumbent-id 보존 + 자산경로 마이그레이션 필요(연기)
  • M7 store_schema.py — 제약 재구축 위반 행 coerce/격리 (미착수 — 마이그레이션 위험)
  • M9 store_queue.py — 레거시 이관 파일 존재 검증 (연기 — 오이관 위험, 신중 설계)

Batch 4 — 통합/아웃바운드 ✅

  • HIGH cloud_vision_web_detection.py — per-image error → HttpJsonError + 테스트 2건
  • HIGH search_policy.py — daily_limit 날짜 윈도우 리셋 + Lock
  • M google_custom_search.py — map 응답을 try 안으로
  • #9 http_json.py — 응답 크기 캡 + decode/read 예외 계약
  • #10 API 키 URL→헤더 — Vision만 X-goog-api-key(검증됨+테스트). customsearch는 헤더 미검증(미지원 시 검색 조용히 실패)이라 key= 쿼리 유지(diff 리뷰 MEDIUM)
  • #15 store_enrichment.py — lastFailure 첫 실패 아이템 (3곳)
  • LOW store_remote_fetch.py — SSRF not is_global(CGNAT 등 특수대역 차단)
  • LOW env_clients.py — NAVER display 3종 클램프(1~100)
  • M env_clients.py — daily-limit malformed → 보수적 100(fail-open 제거) + 테스트 갱신
  • M naver_search.py — 멀티페이지 쿼터 실제 요청 수 (미착수)
  • M store_remote_fetch.py — SSRF DNS-rebinding TOCTOU (미착수 — 커스텀 opener 필요)
  • LOW: EUC-KR 스니핑, dead code 삭제(레이아웃 테스트가 고정 → 유지)

Batch 5 — HTTP 보안 ✅ (M10/M11/#6)

  • M10 음수/비정수 Content-Length 거부 + 테스트
  • M11 핸들러 timeout=30
  • #6 앱셸 CSP/X-Frame-Options/nosniff + 테스트
  • #8(부분) 토큰 길이<32 경고 + static 부재 경고(__main__)
  • #7 쿠키 분리+Secure (연기 — Secure는 localhost HTTP서 쿠키 미전송→인증 붕괴; HTTPS 전제 필요)
  • #8 rate limit (미착수)
  • #10 Origin/Referer CSRF 폴백 (미착수)

Batch 6 — 프론트엔드 ✅

  • H8 이미지 뷰어 버튼 구현 + 케이스별 리셋
  • H9 dismiss 서버 영속화(신규 엔드포인트) + 테스트
  • HIGH '자동 항목 비활성' 선택 케이스 스코프
  • M16 deactivate 루프 멱등화(활성만, per-entry 실패 무시, finally refresh)
  • #17 setDecision in-flight 가드 + rerunSelected/applyCoverage null 가드
  • M18 addKnowledgeEntry 수집탭 초기화 부작용 제거
  • M19 executeSuggestedQueries refreshFromApi try/catch
  • M20 runCandidateCollection 선-클리어→성공 후로
  • M22 apiError 배너 applyBootstrap에서 clear
  • M23 renderCorrections derivedEntries 가드
  • #11(부분) riskClass 밴드 allowlist, case-image src safeUrl
  • #11 잔여 sinks(similar-strip/face-crop safeUrl, innerHTML label) (미착수)
  • #24 window.prompt → 인라인 (미착수 — 규모 큼)
  • M21 8개 delegated mutation 공용 in-flight 가드 (미착수)

Batch 7 — env/config/docs ✅

  • env_file.py UTF-8-sig BOM
  • env_clients.py daily-limit fail-open 제거
  • __main__/launcher 경로 ROOT chdir + python 3.13 가드 + static/token 경고
  • offline-install.md — Ollama/Playwright/lock 해시/egress 정정/--only-binary
  • .gitignore — .claude/settings.local.json, .impeccable/
  • env_clients.py LLM assistant OLLAMA 게이팅 (연기 — env={} llm 테스트 다수 의존)
  • package.json 정리 (미착수)

Batch 8 — 에러핸들링/기타 ✅ (부분)

  • #14 _sync_face_crops 무음 예외 로깅 + preprocessing EXIF 폴백 경고(#19)
  • #16 skip 사유 reasons 오염 제거 + 테스트
  • #18 dedup 핫패스 타깃 쿼리(2곳)
  • #14 잔여 무음 swallow(page scrape 등) (미착수)
  • #20 ScoreResult.reasons tuple (연기 — 테스트 다수 == [] 단언 충돌)

Batch 7 — env/config/docs

  • env_file.py:12 — UTF-8-sig BOM
  • daily-limit fail-open → 보수적 기본
  • env_clients.py:239 — LLM assistant OLLAMA_* 게이팅
  • __main__.py — 경로 ROOT 앵커링 + static 부재 경고
  • offline-install.md — Ollama/Playwright/lock 해시
  • python 3.13 가드, .gitignore, package.json 정리

Batch 8 — 에러핸들링/기타 백로그

  • #14 무음 예외 로깅
  • #16 skip 사유 reasons 오염
  • #19 EXIF/GPS PIL 폴백 경고
  • #20 ScoreResult.reasons tuple
  • #18 dedup 핫패스 타깃 쿼리