- Image viewer controls (fit / 1:1 / rotate) now have handlers and reset per
case (were dead buttons).
- 'auto-entry deactivate' is scoped to the selected case's sourceSubmissionId
(was deactivating an arbitrary global entry).
- dismissCollectionCandidate persists via a real endpoint (was a local splice
that resurrected on the next refresh).
- setDecision has an in-flight guard; rerunSelectedEnrichment /
applyCoverageFilter get null guards and a best-effort refresh on partial
failure; deactivateCorrectionEntry skips already-inactive entries, tolerates
per-entry failures, and always refreshes (guarded).
- executeSuggestedQueries / runCandidateCollection commit only after success
so a failed run doesn't wipe the previous view; applyBootstrap clears a stale
error banner; renderCorrections guards derivedEntries.
- riskClass allowlists the band and case/similar/face-crop URLs route through
safeUrl (XSS defence-in-depth).
Backend (data-integrity / audit-trail):
- mark_evidence_status: make the read-modify-write + audit atomic under
_write_lock + _transaction (was 4 unlocked connections, last-writer-wins,
audit could diverge from DB state).
- promote_collection_candidates: acquire _write_lock, use a deterministic
_stable_id, wrap writes in _transaction, and guard already-promoted batches
so a retry/double-click cannot mint duplicate knowledge entries.
- risk_scoring: bucket web-detection entities by name so two distinct entities
in one image both count (was collapsed to one 'entity' bucket, under-scoring
high->medium). Identical entities still dedup.
Frontend (silent loss of operator actions):
- runManualSearch: in-flight guard; rerunHistoricalQuery voids the call,
preventing duplicate/racing search POSTs.
- deactivateCorrectionEntry: persist via the real knowledge-deactivate
endpoint instead of a local-only mutation + fake audit event.
- provider-retry button: report honestly (no backend endpoint) instead of
writing a fake 'Provider called' audit event.
Tests: +4 regression tests (mark_evidence_status rollback, batch-promote
idempotency, two distinct entities -> high, identical entity dedup).
Remaining Phase 1 item #6 (_auto_naver/_auto_google refactor) deferred.
Backend suite: 361 passed. app.js: node --check OK, 41 static tests pass.
Address commit security review: the same-origin branch of safeUrl accepted
//host and /\host, which browsers normalize to an external host (open
redirect). Allow only true same-origin paths.
Add safeUrl() to gate external search-result URLs into href/src (blocks
javascript:/data:), parse the response body before the ok check in apiJson
so non-JSON error bodies surface the real status, and hide broken evidence
preview images via onerror.
- Bundle Pretendard Variable woff2 locally (air-gapped safe, no CDN)
and switch UI/stamp font stacks to it; preload in index.html
- Replace the forensic-dossier paper theme with a flat neutral cool
palette: single teal accent, white cards, no noise texture, and
zero linear/radial gradients (per design contract)
- Restore the product-purpose top-bar block and its CSS, drop the
unused global search form, and strip the stray UTF-8 BOM
- Re-skin queue hover/selection, eyebrows, nav rail, chips, and
empty states to the neutral palette; tabular numerals for numbers
- Regenerate ui-overhaul final audit artifacts: zero horizontal
overflow across 8 views at 1440x900 and 390x844, Pretendard active
Design spec: docs/superpowers/specs/2026-06-11-operator-console-clean-review-ui-design.md
Plan: docs/plans/2026-06-11-001-feat-operator-console-clean-review-ui-plan.md
Tests: 358 passed (full suite incl. browser smoke)
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.