Commit graph

2 commits

Author SHA1 Message Date
changukyu
5a9fcc0bea feat: 출처 신호 2종 (EXIF/IPTC 권리 표기 + 방송캡처 포렌식), 0점 라벨
두 신호를 하나의 EvidenceSource.PROVENANCE 와 하나의 GUI 그룹으로 묶는다.
운영자 관점에서 둘 다 같은 질문("이 이미지가 어디서 왔나")에 답하고, 새
EvidenceSource 는 배관 12곳을 요구하므로 둘을 합쳐 한 번만 지불한다.

## EXIF/IPTC 권리 표기

저작권자가 파일에 직접 써 넣은 값을 지금까지 100% 버리고 있었다.
build_external_derivative 가 raw 픽셀로 재구성하며 메타를 전량 파기하는데,
그 전에 읽는 코드가 없었다. 추출 훅은 원본 바이트가 아직 살아 있는
InternalAnalyzer.analyze 진입부에 둔다.

읽는 것은 EXIF Copyright/Artist 와 IPTC CopyrightNotice/Credit/Source/By-line
뿐이다. 화이트리스트가 프라이버시 경계이므로 상수로 두고 테스트로 고정한다 —
GPS, 바디 시리얼, Make/Model 은 같은 EXIF 블록에 나란히 있어도 읽지 않는다.

메타데이터는 위조가 쉬우므로 reason 에 "자기신고" 를 명시한다. 이것이
클리어런스 증명으로 읽히면 안 된다.

XMP/C2PA 는 이번 범위에서 뺀다 — Pillow 의 getxmp() 는 defusedxml 이 없으면
경고와 함께 빈 dict 를 반환하고, defusedxml 은 requirements.txt 에 없다.
폐쇄망 타깃에서 조용히 no-op 이 되므로 별도 반입 심사 안건이다.

## 방송캡처 포렌식

결정적 영상처리만 사용한다(레터박스, 자막 밴드 엣지 밀도, 방송 프레임 크기).
모델 0, 신규 의존성 0.

레터박스와 방송 프레임 크기는 하나의 카테고리(geometry)로 묶는다. 레터박스된
1280x720 은 한 관측을 두 번 말한 것이고, 따로 세면 시네마틱 크롭 하나로
라벨이 붙는다. 서로 독립인 카테고리가 2개 이상일 때만 발화한다.

## 0점

둘 다 점수 0으로 출시한다(사용자 결정). 캘리브레이션 데이터가 없는 상태에서
정당화할 수 있는 가중치가 없다 — decision_stats 의 밴드x판정 교차표로 실제
반려와의 상관을 본 뒤 부여한다. reason 은 노출하므로 0점이어도 운영자가
바로 활용할 수 있다.

## 실측

실제 제출 이미지 6장: 캡처 오탐 0건, 권리 메타 히트 0건. 정밀도는 확인됐고
가치는 이 코퍼스에서 아직 입증되지 않았다 — 메신저/SNS 를 거친 이미지는 메타가
이미 제거돼 있어 히트율이 낮을 것이라는 사전 지적과 일치한다.

자막 밴드 절대 밀도 하한은 0.02 -> 0.01. 비율(밴드/프레임 = 2.5배)이 판별자이고
절대 하한은 "밴드에 뭔가 있긴 한가" 게이트일 뿐이며, 하한이 높으면 실제 한
줄짜리 자막이 걸러진다. 합성 픽스처 기반이므로 실제 캡처 이미지 확보 시
재확인이 필요하다.

pytest 531 passed.
2026-07-25 23:59:00 +09:00
유창욱
3f7b3a9cf2 chore: initial commit of copyrighter (rights_filter)
Image rights / copyright detection system: SQLite store, HTTP app,
search integrations (Naver, Google Custom Search, Google Cloud Vision
web detection), image analysis (fingerprints, face/person detection,
evidence enrichment, risk scoring), an admin/review layer, governance
and retention policies, batch jobs, and a browser-based operator GUI.

This baseline incorporates a full code-review remediation pass
(46 fixes; 358 tests passing). Highlights:

CRITICAL
- Prevent evidence cascade-delete during the schema-constraint
  migration by disabling FK enforcement around the table rebuild.

Security
- Sandbox served media (neutralize stored XSS from uploaded/collected
  SVGs) via CSP + nosniff on the untrusted media routes.
- Strip embedded EXIF/GPS from external image derivatives before they
  are sent to third-party APIs.
- Return a clean 404 (not an uncaught StopIteration) for PATCH on an
  unknown provider.

Correctness
- LLM-summary failures no longer add +30 to the risk score.
- Decode only explicit JS escapes so Korean image URLs are not mangled.
- Consume search quota only after a successful request.
- Naver/Google adapters map responses inside the failure boundary, so a
  malformed response degrades to evidence instead of crashing enrichment.
- Domain-aware provider attribution; face-box IoU de-duplication; count
  searches (not result items); per-box crop isolation; clamp evidence
  confidence and Google CSE num; real submittedEpoch; and more.

Robustness
- Offline LLM connect fast-fails (short connect timeout) so seed/reload
  requests are not stalled; full read timeout preserved for generation.
- Malformed numeric env vars fall back to defaults instead of crashing
  startup.

Performance
- Per-submission evidence reads (no full-table scan per rescore),
  audit-log LIMIT, lazy active-store lookup, hoisted timestamps.

Tests
- ~24 regression tests added pinning the above fixes.

Runtime data (data/, outputs/, *.sqlite3, *.log), secrets (.env), and
node_modules are gitignored.
2026-06-09 09:50:31 +09:00