Add _score_font_line_pixel() which renders candidate text and compares
pixels against the actual page image using Dice coefficient overlap.
This captures glyph shape differences that the old word-width MAE
approach cannot distinguish (e.g. serif vs sans-serif).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Centralize 21 repeated color values into :root variables.
Makes theme changes trivial and improves readability.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Reorganize the monolithic 1,436-line frontend into 9 focused modules:
types, state, dom, canvas, viewport, associates, popover, solver, main.
No build step — browsers load ES modules natively. JSDoc @typedef
annotations provide type safety via @ts-check + jsconfig.json.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Without flex properties, #viewer-section collapsed to content
height (just the controls bar), giving the workspace 0 height
and causing zoom to compute as 0%.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Remove unused detect_redactions import from app.py
- Add de-duplication check in dblclick handler to prevent
creating duplicate redaction entries for the same dark region
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Shift+drag now adjusts gap width (was ctrl+shift+drag).
Manual redaction marking via shift+drag is removed;
users now double-click to spot-detect redactions.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Extract inline analysis logic from the analyze endpoint into a reusable
_run_analysis() helper function, then add a new /api/redaction/spot
endpoint that chains spot_redaction detection with analysis in one call.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Uses OpenCV connected components to find a dark region at a specific
click point, complementing the existing detect_redactions() which
auto-detects all redaction bars via morphological operations.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds green segment overlay, floating font toolbar, bottom text edit
bar, and backend offset guess to the redaction-centric UI.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Hold Shift and drag on the canvas to draw a custom redaction
rectangle. Creates an unanalyzed redaction entry that triggers
on-demand OCR when clicked.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace line list with redaction list, add canvas-native redaction
overlays with hit-testing, popover with on-demand analysis and
solver integration. Remove old font/segment/overlay controls.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
When a user clicks a redaction, this endpoint crops the surrounding line,
runs Tesseract OCR, detects the font, and returns text segments (before/after
the redaction), gap width, font info, and character-level bounding boxes.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace upfront OCR + font detection + overlay rendering with lightweight
OpenCV-based redaction detection. Upload now just rasterizes and detects
black rectangles, making it significantly faster. Remove the overlay
endpoint and update the data endpoint to return redaction bboxes.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Shift from upfront OCR to redaction-centric workflow with OpenCV
detection, canvas-native clickable overlays, on-demand analysis,
and per-redaction popover solver UI.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Fetches from 3 data sources (HuggingFace parquet, rhowardstone entities,
Epstein Exposed API) plus 8 court-verified addresses. Merges, deduplicates,
validates, and writes 644 unique emails to unredact/data/emails.txt.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Victim names are stored as a flat set of lowercased name variants
with no person details — the V badge appears but is not clickable,
protecting victim identities. A result can show both T1/T2/T3 and V
badges simultaneously.
- 15 known victims from public court records → 43 name variants
- Enabler/perpetrator categories promoted to T2
- Purple V badge with pointer-events disabled
- Victim matching uses prefix/suffix combination like associate matching
Co-Authored-By: Claude Opus 4.6 <[email protected]>
When matching solver results against associates, now tries:
- gap text alone ("oe")
- prefix + gap ("joe" if prefix="j")
- gap + suffix
- prefix + gap + suffix
Composite matches (prefix+gap) get a +3 score boost since the
surrounding context confirms the match. Deduplicates by person_id,
keeping the highest-scoring match.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Badge is now a button — clicking it opens a popup listing all
matching associates with their tier description (flight logs /
inner circle / named in files), category, and match type.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Sort results strictly by tier (T1 > T2 > T3 > none), then by score
within the same tier. Previously a T3 full-name match could outrank
a T1 first-name match.
- Boost associate score by +2 when the person's name matches the
user's filter prefix/suffix, surfacing likely candidates higher.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Lazy-loads associates.json from data dir and serves it at /api/associates,
with fallback to empty dicts if file is missing.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
7 tasks covering build script, API endpoint, frontend matching/sorting/badges,
and end-to-end testing. TDD approach with exact file paths and code.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Defines tiered prioritization of known Epstein associates in solver
results using rhowardstone/Epstein-research-data as the data source.
Associates are matched by full name, first/last, nicknames, and aliases
with frontend-side sorting and badge display.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Measures a known word's width in font context, then verifies the solver
recovers that word from its width. Proves the width table and solver
work correctly end-to-end.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add a solve panel UI that lets users attempt to recover redacted text
by finding strings whose rendered width matches the redaction gap.
Includes charset selection, length bounds, tolerance slider, and
dictionary/enumerate/both mode controls. Results stream via SSE and
can be clicked to insert into the gap.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add POST /api/solve endpoint that streams results via Server-Sent Events,
supporting both enumerate (brute-force) and dictionary solve modes. Add
dictionary CRUD endpoints (POST/GET/DELETE /api/dictionary) and solve
cancellation (DELETE /api/solve/{id}). Move static files mount to end of
app.py so API routes take priority.
Co-Authored-By: Claude Opus 4.6 <[email protected]>