HIGH:
- face detection: guard OpenCV builds lacking CascadeClassifier and isolate
per-submission analysis failures in BatchAnalyzer, so a broken cv2 or one bad
image no longer takes down every seed/reload/import/upload/rerun with no HTTP
response
- risk scoring: gate Google custom image search (match=search_image) to 0
points so the persistence round-trip (result_url aliased to url) can no longer
flip the same evidence to +45 and inflate bands
- serialization: exclude SEARCH_SKIPPED/ENRICHMENT_FAILURE rows from the auto
search dedup signatures so a quota-skipped query stays retryable instead of
being treated as already done forever
- external_policy: add a daily-window reset + lock (mirrors SearchApiPolicy) so
Vision is not permanently disabled once the daily limit is hit
- image_store: skip a malformed manifest row (and coerce bad width/height)
instead of letting one ValueError paralyse loading/re-analysis for the queue
MEDIUM/LOW:
- enrichment: only count a face crop as transmitted when it actually left the
system, removing false usage debits and a false "personal image sent to
external provider" audit record; pick lastFailure from the failing item;
preserve the collection set when every search was quota-skipped; dedup
candidate counts; attribute Vision failures to the google provider badge
- store: search coverage requires a real result, not a failure row
- scoring: FACE_PERSON contributes once regardless of how many rows exist
- fingerprints: refuse near-matches on degenerate (near-uniform) average
hashes while keeping identical-hash matches
- preprocessing: apply EXIF orientation for external derivatives, face crops,
pHash and the PIL decode fallback
- promoter: scan title/description only, never the URL path/host tokens
- integrations: map Vision responses inside the adapter try; cap HTTPError
bodies; skip the connect probe when a proxy applies; reservation-style quota
accounting (try_reserve/release) to make the check-then-act atomic
- governance/admin: enforce the LLM-summary rule on the real persistence path;
reject unknown manual-entry fields; upsert the rejected_image knowledge entry
on repeat rejections; split policy skips out of the failures group
- env_file: strip a trailing inline comment from unquoted values
Environment drift fixed out-of-tree: removed the user-site OpenCV 5.0.0 that
shadowed the pinned opencv-python-headless==4.13.0.92.
Regression tests added; pytest tests/rights_filter is green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E6GD9gxUtfUiVB3JHejGpU
- Launcher guards Python 3.13 before importing the package and chdirs to the
repo root so cwd-relative default paths resolve consistently.
- main() logs the resolved .env path and warns on a missing static dir or a
short auth token; env_file reads utf-8-sig so a BOM doesn't drop the first
variable.
- .gitignore covers .claude/settings.local.json and .impeccable/.
Introduce a reusable browser-test harness under tests/operator_gui/:
- conftest.py: shared fixtures (operator_server, browser with graceful skip,
operator_page with screenshot-on-failure artifacts)
- pages/: OperatorWorkbench Page Object encapsulating selectors and actions
- refactor test_browser_smoke.py onto the fixtures + POM (drops duplicated
server/browser plumbing)
- test_decision_flow.py: approve/hold/reject E2E against the real server,
covering the reject-requires-memo guard and decision persistence
Pin playwright in requirements-dev.txt (Chromium bundled offline for the
air-gapped target) and ignore the artifacts/ screenshot dir.
Add requirements.txt (numpy/opencv-python-headless/pillow — the only
third-party runtime imports) and requirements-dev.txt, plus an offline
install runbook. Ignore .coverage and wheelhouse/.
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.