POSA_Copyrighter/docs/plans/2026-05-25-002-feat-image-rights-review-enrichment-plan.md
유창욱 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

570 lines
32 KiB
Markdown

---
title: "feat: Add Image Rights Review Enrichment"
type: feat
status: completed
date: 2026-05-25
origin: docs/brainstorms/2026-05-25-image-rights-review-enrichment-requirements.md
---
# feat: Add Image Rights Review Enrichment
## Summary
Extend the existing portable `rights_filter` core with search-enriched evidence, internal LLM-assisted query and summary boundaries, and a detailed operator review view model. Because this workspace has no real web admin app or database, the plan delivers backend contracts and tests that a target admin UI can render without re-deciding product behavior.
---
## Problem Frame
The current filter can analyze images, score risk, and expose a basic operator summary. Operators still need a single detailed review surface where internal evidence, Korean search evidence, provider evidence, LLM summaries, failures, and final manual actions are grouped coherently.
---
## Requirements
- R1. Provide a detailed operator review representation containing image reference, 0-100 score, band, top reasons, evidence groups, provider status, analysis failures, and manual decision actions. (Origin R1-R5, F2, AE7)
- R2. Add Naver search evidence as official text-query evidence only; do not upload images or automate/scrape Naver web UI. (Origin R6-R10, R20, AE1, AE2)
- R3. Add internal LLM assistance for query generation, search-result structuring, contradiction/deduplication, and operator summaries only. (Origin R11-R14, AE3)
- R4. Ensure LLM output is never a standalone scoring source or final decision authority. (Origin R12-R13, AE3)
- R5. Integrate enrichment failures and skipped providers as operator-visible reasons without reducing existing high-risk evidence. (Origin R5, R21, R23, AE4)
- R6. Keep approval, hold, and rejection as explicit operator actions; automated analysis must not change status. (Origin R15, AE5)
- R7. Preserve applicant isolation: applicants cannot see scores, search evidence, LLM summaries, provider details, or analysis failure reasons. (Origin R19, AE7)
- R8. Support rejection-derived knowledge accumulation and correction/deactivation paths that prevent bad decisions from poisoning future matching. (Origin R16-R18, F3, F4, AE5, AE6)
- R9. Keep existing Google Web Detection compliance gates and no-scraping boundaries intact. (Origin R20-R22)
**Origin actors:** A1 신청자, A2 운영자, A3 권리 리스크 필터, A4 내부 LLM, A5 Naver 검색 API, A6 Google Cloud Vision Web Detection
**Origin flows:** F1 검색 보강 분석, F2 상세 검토, F3 판정 기반 기준 DB 누적, F4 정정 및 오염 방지
**Origin acceptance examples:** AE1, AE2, AE3, AE4, AE5, AE6, AE7
---
## Scope Boundaries
- No real web admin frontend is built in this workspace. The deliverable is a backend review view model and integration contract that a target app can render.
- No Naver image-upload reverse search.
- No Google Image Search, Google Lens, Naver web UI automation, or scraping.
- No external LLM integration in this iteration.
- No LLM-based legal judgment, score calculation, automatic approval, or automatic rejection.
- No applicant-facing explanation, rights-evidence upload, or appeal UI.
- No dedicated brand/logo/trademark/stock-image detector; strong incidental evidence can still appear as operator evidence.
- No face recognition, celebrity identification from faces, face embeddings, or biometric template storage.
### Deferred to Follow-Up Work
- Target admin UI implementation: wire the detailed view model into the actual application once the app framework, routes, auth, and database exist.
- Full criteria database management screen: keep only the backend hooks needed for review feedback and contamination control here.
- Search-quality calibration: run pilot samples and tune query generation, result promotion, and scoring weights after the adapters exist.
---
## Context & Research
### Relevant Code and Patterns
- `src/rights_filter/domain/records.py` defines immutable-ish evidence records, analysis runs, knowledge-base entries, review statuses, data classes, and the in-memory repository.
- `src/rights_filter/jobs/batch_analyzer.py` orchestrates internal analysis, external derivative creation, Cloud Vision evidence, scoring, and run persistence.
- `src/rights_filter/integrations/cloud_vision_web_detection.py` uses a fake client boundary and maps provider results into `Evidence` records.
- `src/rights_filter/integrations/external_policy.py` provides a simple policy gate with disabled/compliance/metadata/online/quota checks.
- `src/rights_filter/admin/review_handlers.py` already separates operator-visible summaries from applicant summaries and creates automatic rejected-image entries on rejection.
- `src/rights_filter/analysis/risk_scoring.py` scores by evidence source and keeps failures from acting as exculpatory evidence.
- `tests/rights_filter/test_public_module_layout.py` protects the public module boundary; new planned modules should be added there.
### Institutional Learnings
- No `docs/solutions/` directory or prior institutional learning notes are present.
- There is no `STRATEGY.md`, `AGENTS.md`, or `CLAUDE.md` file in the workspace root; the active instructions are from the conversation context.
### External References
- Naver image search API is a REST API that accepts search terms and conditions as query-string data, not image uploads. It documents image search result fields such as title, link, thumbnail, size, and daily Search API quota. https://developers.naver.com/docs/serviceapi/search/image/image.md
- Naver Search API product page lists web, news, blog, image, encyclopedia, and other search surfaces, with a 25,000/day processing limit. https://developers.naver.com/products/service-api/search/search.md
- Naver API terms state API use is subject to provided conditions, allowed counts, client ID management, and policy compliance. https://developers.naver.com/products/terms
- Google Cloud Vision Data Usage FAQ explains the data-handling distinction that must remain part of the external enablement checklist. https://docs.cloud.google.com/vision/docs/data-usage
- Google Cloud Vision Web Detection can return web entities, matching images, visually similar images, pages with matching images, and best guess labels. https://docs.cloud.google.com/vision/docs/detecting-web
---
## Key Technical Decisions
- Backend view model first: since no admin app exists locally, implement the detailed review surface as structured presenter output rather than a web page.
- Evidence-source expansion over special-case strings: represent Naver search, LLM summaries, and enrichment skipped/failure states as first-class evidence sources so grouping, scoring, and presentation remain explicit.
- Text-only Naver adapter: mirror the existing fake-client adapter pattern, but accept only query text and provider options; image payload types must not be part of the Naver adapter interface.
- LLM as evidence organizer: use an internal LLM boundary that emits candidate queries and summaries tied to source evidence IDs or source URLs; never let LLM output feed scoring directly.
- Search-result promotion is conservative: Naver evidence contributes meaningful risk only when linked to named persons, works, characters, broadcasts, webtoons, games, official pages, or repeated matching-image sources.
- Enrichment orchestration is separate from the existing batch analyzer until the flow is proven: keep a focused enrichment job that can be called after or within batch analysis without destabilizing the internal-only path.
- Correction is provenance-driven: automatic rejection-derived entries must stay distinguishable from manual entries and deactivatable from the source decision path.
---
## Open Questions
### Resolved During Planning
- Detailed review screen form: implement a backend presenter/view model now; defer a real web admin screen because no app shell exists in this workspace.
- Naver role: use official text-query search only, with fake-client tests; do not perform image upload reverse search.
- LLM role: query generation, result structuring, and operator summary only; no score or final status authority.
- Rejection feedback default: create explicit automatic entries or candidates with provenance, and require correction/deactivation mechanics in the same iteration.
### Deferred to Implementation
- Exact Naver request tuning: final display count, sort order, and query variants should be validated with pilot samples and quota behavior.
- Internal LLM runtime: choose the actual local/internal model, prompt storage, logging policy, and deployment boundary in the target environment.
- Real admin app integration: map the review view model to framework routes, components, auth, and storage once the target app exists.
- Final score weights: tune Naver evidence contribution after sample outcomes are collected; start conservative.
---
## Output Structure
src/
rights_filter/
analysis/
evidence_enrichment.py
llm_assistance.py
search_result_promoter.py
admin/
detailed_review_presenter.py
knowledge_base_handlers.py
correction_handlers.py
integrations/
naver_search.py
search_policy.py
jobs/
review_enrichment_job.py
tests/
rights_filter/
analysis/
admin/
integrations/
jobs/
docs/
operations/
The tree shows proposed additions. The implementer may adjust names to fit the target application, but should preserve the same boundaries.
---
## High-Level Technical Design
> *This illustrates the intended approach and is directional guidance for review, not implementation specification. The implementing agent should treat it as context, not code to reproduce.*
```mermaid
flowchart TB
Run[Existing analysis run] --> Query[Internal LLM query generation]
Query --> NaverGate{Naver policy allows?}
NaverGate -->|yes| Naver[Naver text-query search]
NaverGate -->|no| SearchSkipped[Search skipped evidence]
Naver --> Promote[Search result promotion]
Promote --> Ledger[Evidence ledger]
SearchSkipped --> Ledger
Run --> Ledger
Ledger --> Summary[Internal LLM evidence summary]
Summary --> Review[Detailed operator review view model]
Review --> Decision[Manual approve / hold / reject]
Decision --> Knowledge[Knowledge-base feedback]
Knowledge --> Correction[Correction / deactivation]
```
---
## Implementation Units
```mermaid
flowchart TB
U1[U1 Evidence model extensions]
U2[U2 Naver search adapter]
U3[U3 Internal LLM assistance]
U4[U4 Enrichment orchestration]
U5[U5 Scoring and reason promotion]
U6[U6 Detailed review presenter]
U7[U7 Decision feedback and correction]
U8[U8 Governance docs and module layout]
U1 --> U2
U1 --> U3
U2 --> U4
U3 --> U4
U4 --> U5
U5 --> U6
U6 --> U7
U1 --> U8
U7 --> U8
```
### U1. Evidence Model Extensions
**Goal:** Extend the domain records so search evidence, LLM summaries, provider skips, and source-linked summaries can be represented without stringly-typed workarounds.
**Requirements:** R1, R2, R3, R4, R5, R7
**Dependencies:** Existing domain model
**Files:**
- Modify: `src/rights_filter/domain/records.py`
- Modify: `src/rights_filter/governance/policies.py`
- Test: `tests/rights_filter/domain/test_records.py`
- Test: `tests/rights_filter/governance/test_policies.py`
**Approach:**
- Add evidence source categories for Naver search, LLM summary, search skipped, and enrichment failure while keeping existing source names stable.
- Add data-class coverage for search evidence and LLM summary output so governance policies can distinguish them from provider metadata and operator notes.
- Preserve the simple `Evidence` shape, but standardize expected `data` keys by source in tests and presenters.
- Keep the repository in-memory for this workspace; do not invent a database layer.
**Execution note:** Write tests first for the privacy and governance boundary: LLM summary records must point back to source evidence, and Naver records must not contain uploaded-image payloads.
**Patterns to follow:**
- Follow the enum/dataclass style in `src/rights_filter/domain/records.py`.
- Follow policy mapping style in `src/rights_filter/governance/policies.py`.
**Test scenarios:**
- Happy path: a Naver search evidence record stores query, result URL, image URL, thumbnail URL, title, rank, and retrieved timestamp.
- Happy path: an LLM summary evidence record references source evidence IDs or source URLs and is classified as operator-only data.
- Edge case: Naver evidence data does not accept original-image or derivative-image payload markers.
- Error path: governance validation rejects LLM summary data that claims standalone authority without source references.
- Regression: existing fingerprint, face/person, web detection, external skipped, and failure evidence remain importable and scoreable.
**Verification:**
- The domain layer can represent every enrichment requirement without exposing applicant-visible fields or storing biometric artifacts.
### U2. Naver Text-Query Search Adapter
**Goal:** Add a Naver integration boundary that performs official text-query search through a fake-client contract in tests and records provider outcomes as evidence candidates.
**Requirements:** R2, R5, R9
**Dependencies:** U1
**Files:**
- Create: `src/rights_filter/integrations/search_policy.py`
- Create: `src/rights_filter/integrations/naver_search.py`
- Test: `tests/rights_filter/integrations/test_naver_search.py`
- Test: `tests/rights_filter/integrations/test_search_policy.py`
**Approach:**
- Model a search policy with disabled state, compliance approval, daily quota, calls made, and allowed provider names.
- Implement a fake-client adapter pattern similar to `CloudVisionWebDetectionAdapter`.
- Accept only text query requests and search parameters; keep image payload types out of the public method boundary.
- Map Naver result items into evidence records with source, query, rank, result URLs, thumbnail, title/description, and provider status.
- Record skipped, quota-exhausted, and provider-error states as operator-visible evidence.
**Execution note:** Start with adapter contract tests using a fake Naver client; do not add real credentials or live outbound calls.
**Patterns to follow:**
- `src/rights_filter/integrations/cloud_vision_web_detection.py` fake client and response mapper.
- `src/rights_filter/integrations/external_policy.py` simple policy-gate style.
**Test scenarios:**
- Happy path: approved text query returns multiple Naver result evidence records with query and rank preserved.
- Edge case: empty result set creates a low-confidence "no results" evidence record instead of disappearing.
- Error path: disabled policy, quota exhaustion, or provider exception records a skipped/failure evidence item and makes no client call when policy blocks it.
- Policy: passing an image payload-shaped input to the Naver adapter boundary is rejected before any provider call.
- Integration: Naver evidence can be stored on an analysis run alongside fingerprint and Google Web Detection evidence.
**Verification:**
- No test path sends original images or derivatives to Naver, and skipped search still appears in operator review data.
### U3. Internal LLM Query and Summary Assistance
**Goal:** Add an internal LLM boundary that can generate Korean search queries and summarize evidence for operators while remaining source-linked and non-authoritative.
**Requirements:** R3, R4, R5, R7
**Dependencies:** U1
**Files:**
- Create: `src/rights_filter/analysis/llm_assistance.py`
- Create: `src/rights_filter/analysis/search_query_generation.py`
- Test: `tests/rights_filter/analysis/test_llm_assistance.py`
- Test: `tests/rights_filter/analysis/test_search_query_generation.py`
**Approach:**
- Define an internal assistant interface with deterministic fake implementation for tests.
- Generate query candidates from existing evidence, OCR/label placeholders when present, knowledge-base names/aliases, and Google Web Detection entities.
- Structure assistant summaries as evidence records that cite source evidence IDs or URLs.
- Add guardrails that mark ungrounded assistant claims as notes, not risk reasons.
- Keep all assistant outputs operator-only and exclude them from applicant summaries.
**Execution note:** Test first that LLM output without citations cannot become a score reason.
**Patterns to follow:**
- Existing analysis service classes under `src/rights_filter/analysis/`.
- Existing applicant/operator separation in `src/rights_filter/admin/review_handlers.py`.
**Test scenarios:**
- Happy path: web entity "아이유" and alias "IU" produce Korean query candidates that include person/work context without duplicates.
- Happy path: LLM summary cites Naver and Google evidence URLs and appears in the operator review model.
- Edge case: duplicate or contradictory search results are summarized as uncertainty, not collapsed into one definitive claim.
- Error path: LLM provider failure records an enrichment failure evidence item and does not block existing analysis.
- Policy: source-less LLM claims are excluded from scoring reasons and applicant summaries.
**Verification:**
- Internal LLM assistance reduces operator reading work while remaining auditable and non-authoritative.
### U4. Review Enrichment Orchestration
**Goal:** Orchestrate query generation, Naver search, result promotion, LLM summary creation, and evidence persistence around existing analysis runs.
**Requirements:** R1, R2, R3, R5
**Dependencies:** U1, U2, U3
**Files:**
- Create: `src/rights_filter/analysis/evidence_enrichment.py`
- Create: `src/rights_filter/jobs/review_enrichment_job.py`
- Modify: `src/rights_filter/jobs/batch_analyzer.py`
- Test: `tests/rights_filter/analysis/test_evidence_enrichment.py`
- Test: `tests/rights_filter/jobs/test_review_enrichment_job.py`
- Test: `tests/rights_filter/jobs/test_batch_analyzer.py`
**Approach:**
- Keep enrichment idempotent by analysis version and provider/query signature.
- Allow the batch analyzer to remain useful in internal-only mode; enrichment should be callable after a run is created or disabled entirely.
- Store each query and provider outcome as evidence so the detailed review surface can explain missing or skipped evidence.
- Preserve partial success: one failed query or provider should not invalidate other evidence.
- Record operational counters for generated queries, executed searches, skipped searches, provider failures, and summary failures.
**Patterns to follow:**
- `src/rights_filter/jobs/batch_analyzer.py` summary counters and idempotency check.
- Evidence append flow through `AnalysisRun.add_evidence`.
**Test scenarios:**
- Happy path: an analysis run with Google entity evidence generates Naver queries, stores Naver evidence, stores an LLM summary, and recomputes a score.
- Happy path: rerunning enrichment with the same analysis version and same query signature does not duplicate evidence.
- Edge case: Naver disabled still records search-skipped evidence and creates an LLM summary from internal/Google evidence when possible.
- Error path: corrupt or missing analysis run returns a failure summary without creating a misleading low-risk result.
- Integration: batch analysis can run without enrichment, and enrichment can run later against stored runs.
**Verification:**
- Search enrichment can be enabled, disabled, retried, and audited independently of the internal-only baseline.
### U5. Search Result Promotion, Scoring, and Reasons
**Goal:** Convert promoted search evidence into conservative score contributions and operator-readable reasons while preventing LLM output from directly affecting the score.
**Requirements:** R1, R2, R3, R4, R5
**Dependencies:** U1, U2, U3, U4
**Files:**
- Create: `src/rights_filter/analysis/search_result_promoter.py`
- Modify: `src/rights_filter/analysis/risk_scoring.py`
- Modify: `src/rights_filter/analysis/reason_builder.py`
- Test: `tests/rights_filter/analysis/test_search_result_promoter.py`
- Test: `tests/rights_filter/analysis/test_risk_scoring.py`
- Test: `tests/rights_filter/analysis/test_reason_builder.py`
**Approach:**
- Promote Naver results only when they connect the query/result to named people, works, characters, broadcasts, webtoons, games, official sources, or repeated matching-image sources.
- Treat low-confidence Naver evidence as operator context, not high-risk proof.
- Ensure LLM summary evidence is visible but contributes zero direct score points.
- Keep failures and skips visible; failures add uncertainty where appropriate but never reduce stronger high-risk evidence.
- Preserve historical score behavior for existing fingerprint, face/person, and Google evidence.
**Execution note:** Add regression tests that face/person evidence alone and LLM-only evidence do not produce high risk.
**Patterns to follow:**
- `src/rights_filter/analysis/risk_scoring.py` source-based scoring and unique reason handling.
**Test scenarios:**
- Happy path: Naver evidence linking a Korean celebrity name and repeated image sources contributes medium or high review risk with clear reasons.
- Happy path: Naver evidence for a known character/work plus Google matching-image evidence reaches high risk.
- Edge case: generic image results with no named person/work/character remain context-only and do not create high risk.
- Error path: LLM summary claiming a celebrity match without source references contributes no score reason.
- Regression: external provider failure does not lower a prior rejected-image similarity score.
**Verification:**
- Operators see why search evidence mattered, and scores remain explainable without trusting LLM prose.
### U6. Detailed Operator Review Presenter
**Goal:** Build the backend representation of the detailed review screen, grouping evidence and actions so a future web admin UI can render it directly.
**Requirements:** R1, R6, R7
**Dependencies:** U1, U5
**Files:**
- Create: `src/rights_filter/admin/detailed_review_presenter.py`
- Modify: `src/rights_filter/admin/review_handlers.py`
- Modify: `src/rights_filter/admin/review_presenters.py`
- Test: `tests/rights_filter/admin/test_detailed_review_presenter.py`
- Test: `tests/rights_filter/admin/test_review_handlers.py`
**Approach:**
- Produce a detailed review dictionary or dataclass containing submission ID, image reference, score, band, top reasons, grouped evidence, provider statuses, LLM summaries, failures, and allowed manual actions.
- Group evidence into internal, Naver, Google, LLM, failure/skipped, and knowledge-base sections.
- Keep applicant summaries minimal and unchanged except for explicit regression coverage.
- Surface missing analysis as a review state rather than hiding the submission.
- Keep action affordances separate from automated recommendation data.
**Patterns to follow:**
- Existing `operator_summary_for` and `applicant_summary_for` behavior in `src/rights_filter/admin/review_handlers.py`.
- Existing tests in `tests/rights_filter/admin/test_review_handlers.py`.
**Test scenarios:**
- Happy path: detailed review output includes image reference, score, band, top reasons, Naver evidence group, Google evidence group, and LLM summary group.
- Happy path: high-risk analysis appears to operators but does not change review status automatically.
- Edge case: missing analysis returns a review model with analysis unavailable and manual actions still controlled by the host workflow.
- Error path: failed Naver, failed LLM, or disabled Google evidence appears under provider status/failure groups.
- Security: applicant summary excludes score, reasons, evidence, LLM summaries, provider status, and failure details.
**Verification:**
- A real admin UI can be built from the presenter output without exposing internal evidence to applicants.
### U7. Decision Feedback and Contamination Control
**Goal:** Strengthen rejection-derived knowledge accumulation and correction flows so automatic entries are useful but reversible.
**Requirements:** R6, R8
**Dependencies:** U1, U6
**Files:**
- Create: `src/rights_filter/admin/knowledge_base_handlers.py`
- Create: `src/rights_filter/admin/correction_handlers.py`
- Modify: `src/rights_filter/admin/decision_feedback.py`
- Modify: `src/rights_filter/domain/knowledge_base.py`
- Test: `tests/rights_filter/admin/test_knowledge_base_handlers.py`
- Test: `tests/rights_filter/admin/test_correction_handlers.py`
- Test: `tests/rights_filter/domain/test_knowledge_base.py`
**Approach:**
- Keep automatic rejection-derived entries distinct from manual operator registrations and search-result candidates.
- Add correction handling that deactivates entries derived from a corrected decision while preserving audit history.
- Allow manual entity registration with names, aliases, related keywords, policy memo, exception notes, and sample fingerprints.
- For this workspace, implement repository-level behavior only; defer role-based UI and persistent audit tables to target app integration.
**Execution note:** Test first around stale automatic entries: a corrected rejection must stop influencing future matching.
**Patterns to follow:**
- `InMemoryRightsFilterRepository.create_rejected_image_entry`.
- `KnowledgeBaseEntry` provenance and active/deactivation fields in `src/rights_filter/domain/records.py`.
**Test scenarios:**
- Happy path: rejecting a submission creates an automatic rejected-image entry with source decision provenance.
- Happy path: manually registering a celebrity or character entry creates a manual entry with aliases and policy memo.
- Edge case: automatic and manual entries with similar names remain separate and independently deactivatable.
- Error path: correcting a rejection deactivates derived automatic entries but leaves manual entries untouched.
- Privacy: attempts to register face embeddings or biometric templates are rejected by governance validation.
**Verification:**
- The knowledge base can grow from real operator decisions without making false positives permanent.
### U8. Governance, Operations, and Public Module Layout
**Goal:** Update operations guidance, public module tests, and governance policies so the new enrichment modes remain discoverable and safe to operate.
**Requirements:** R2, R3, R4, R5, R7, R9
**Dependencies:** U1, U7
**Files:**
- Modify: `docs/operations/image-rights-risk-filter.md`
- Modify: `tests/rights_filter/test_public_module_layout.py`
- Modify: `src/rights_filter/integrations/__init__.py`
- Modify: `src/rights_filter/analysis/__init__.py`
- Modify: `src/rights_filter/admin/__init__.py`
- Test: `tests/rights_filter/governance/test_policies.py`
**Approach:**
- Document search-enriched mode and LLM-assisted mode with explicit disable guidance.
- Add public module imports for planned modules so missing boundaries fail fast.
- Update governance tests for Naver text-only evidence, LLM source-linking, applicant isolation, and no-scraping boundaries.
- Keep external API enablement documentation explicit: Naver credentials and Google credentials are separate provider risks.
**Patterns to follow:**
- Existing operations doc structure in `docs/operations/image-rights-risk-filter.md`.
- Existing public module import test in `tests/rights_filter/test_public_module_layout.py`.
**Test scenarios:**
- Happy path: all new public modules import successfully.
- Policy: operations guidance states Naver uses text queries only and LLM summaries are reading aids.
- Security: governance tests cover applicant non-exposure for Naver evidence and LLM summaries.
- Regression: existing Cloud Vision compliance-gated mode remains documented and tested.
**Verification:**
- A deployer can identify how to enable, disable, audit, and explain search and LLM enrichment without weakening existing safety boundaries.
---
## System-Wide Impact
- **Interaction graph:** The enrichment flow touches analysis runs, evidence source typing, provider adapters, scoring, operator presenters, decision feedback, and governance policies.
- **Error propagation:** Naver, LLM, and Google failures become evidence/failure groups for operators, not silent success and not low-risk proof.
- **State lifecycle risks:** Enrichment must be idempotent by run/provider/query to avoid duplicate evidence; rejection-derived knowledge entries must be deactivatable when decisions are corrected.
- **API surface parity:** Operator-only surfaces gain richer evidence; applicant-facing summaries must stay intentionally sparse.
- **Integration coverage:** End-to-end tests should cover analysis run -> enrichment -> score -> detailed review -> rejection -> knowledge entry -> correction.
- **Unchanged invariants:** The filter never changes review status automatically, never exposes provider evidence to applicants, and never uses face identity recognition.
---
## Risks & Dependencies
| Risk | Mitigation |
|------|------------|
| Naver API is mistaken for reverse image search | Keep adapter text-query only, reject image payload inputs, and document the official API limitation. |
| LLM hallucination pollutes scores | Require source references for summaries and assign zero direct scoring weight to LLM evidence. |
| Search results create false positives | Promote only strongly linked person/work/character evidence, keep context-only results visible but low impact, and preserve operator judgment. |
| External provider cost or quota spikes | Add provider policies, daily limits, skipped evidence, and operational counters. |
| Detailed presenter leaks to applicants | Keep separate operator and applicant presenters with explicit regression tests. |
| Automatic rejection entries poison future matching | Preserve provenance, add correction/deactivation flows, and test stale-entry removal from active matching. |
| Real app integration differs from portable core | Keep this plan focused on backend contracts; defer routes, UI components, auth, and persistence wiring to target app integration. |
---
## Alternative Approaches Considered
- Build the real web admin screen now: rejected because this workspace contains no admin app, frontend stack, routes, auth, or database.
- Search-enrichment-only implementation: rejected because operators need a detailed surface to judge evidence quality.
- LLM-first scoring: rejected because source-less LLM output is not reliable enough for rights-risk decisions and conflicts with the origin safety boundary.
- Naver scraping or browser automation: rejected because official APIs are available for text-query search and UI automation would create unnecessary legal and operational risk.
---
## Phased Delivery
### Phase 1: Evidence and provider foundation
- Land U1 and U2 so Naver search evidence has a safe, typed, text-only path.
### Phase 2: LLM and enrichment pipeline
- Land U3 and U4 so query generation, search execution, summaries, and provider failure handling can run around existing analysis.
### Phase 3: Scoring and operator review
- Land U5 and U6 so promoted evidence affects risk conservatively and operators can inspect grouped evidence in one view model.
### Phase 4: Feedback, correction, and operations
- Land U7 and U8 so decisions improve future matching without permanent false-positive contamination.
---
## Documentation / Operational Notes
- Update the operations doc with Naver credential handling, query-only usage, provider quotas, and emergency disable mode.
- Document that LLM summaries are reading aids and must cite source evidence.
- Document how to interpret search-skipped, no-results, provider-failure, and LLM-failure states.
- Document correction flow for rejection-derived knowledge entries.
---
## Sources & References
- **Origin document:** [docs/brainstorms/2026-05-25-image-rights-review-enrichment-requirements.md](docs/brainstorms/2026-05-25-image-rights-review-enrichment-requirements.md)
- **Base plan:** [docs/plans/2026-05-25-001-feat-image-rights-risk-filter-plan.md](docs/plans/2026-05-25-001-feat-image-rights-risk-filter-plan.md)
- **Operations doc:** [docs/operations/image-rights-risk-filter.md](docs/operations/image-rights-risk-filter.md)
- Related code: [src/rights_filter/domain/records.py](src/rights_filter/domain/records.py)
- Related code: [src/rights_filter/admin/review_handlers.py](src/rights_filter/admin/review_handlers.py)
- Related code: [src/rights_filter/jobs/batch_analyzer.py](src/rights_filter/jobs/batch_analyzer.py)
- Related code: [src/rights_filter/integrations/cloud_vision_web_detection.py](src/rights_filter/integrations/cloud_vision_web_detection.py)
- Related tests: [tests/rights_filter/admin/test_review_handlers.py](tests/rights_filter/admin/test_review_handlers.py)
- Naver Image Search API: https://developers.naver.com/docs/serviceapi/search/image/image.md
- Naver Search API product page: https://developers.naver.com/products/service-api/search/search.md
- Naver API terms: https://developers.naver.com/products/terms
- Google Cloud Vision Data Usage FAQ: https://docs.cloud.google.com/vision/docs/data-usage
- Google Cloud Vision Web Detection: https://docs.cloud.google.com/vision/docs/detecting-web