---
name: extraction-review
description: Review the Set-of-Mark table extraction visually. Use to eyeball quber's default (Set-of-Mark) engine — a before/after HTML (table image with its bounding box | final corrected markdown) and an annotated PDF with the Set-of-Mark bounding boxes drawn on each page. Also retains a legacy cross-version raw-camelot diff for camelot upgrades.
allowed-tools: Bash, Read
---

# Extraction Review Skill

Visual review of quber's default **Set-of-Mark** extraction engine (vision
locates each table and its region; Camelot fills it in-region; grounded
correction cleans structure). Two render modes, plus a legacy diff layer.

## Prerequisites

- Project venv active (`source .venv/bin/activate`); run from the repo root.
- `pdf2image` + poppler and PyMuPDF (`fitz`) — already project deps.
- A working LLM backend for the `after`/corrected output: `api` (with
  `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY` in `.env`) for real correction,
  or `mock` for a fast no-LLM render (shows raw Camelot grid markdown).
- PDFs to review live in `documents/` (or pass explicit paths; `s3://` works if
  you resolve it first — both scripts take local paths).

Both render modes run the Set-of-Mark engine live and draw the model's
`som_region` (the full-precision Set-of-Mark bounding box), so there is no
intermediate dump to capture first.

## Mode 1 - Before/after review HTML

One row per table, two columns: the page cropped around the table with its
Set-of-Mark bounding box drawn (`before`), and the final corrected markdown
(`after`). Responsive: columns stack on screens <=900px.

```bash
python .claude/skills/extraction-review/scripts/gen_html.py \
  documents/review.html api documents/BHE_991.pdf
```

Args: `<out.html> <backend> <pdf> [<pdf> ...]`.

## Mode 2 - Annotated PDF (bounding boxes drawn)

Renders each source PDF with the Set-of-Mark bounding boxes drawn on every
page (ordinal + title label), saved as `<out_dir>/<name>.boxed.pdf`.

```bash
python .claude/skills/extraction-review/scripts/boxed_pdf.py \
  output api documents/BHE_991.pdf
```

Args: `<out_dir> <backend> <pdf> [<pdf> ...]`.

## Legacy - Cross-version raw camelot diff

For camelot version bumps (e.g. the QUE-248 lattice/stream spike): dump raw
`camelot.read_pdf` output under the current version and an older baseline, then
diff counts, grid coverage, and numeric-cell fidelity. JSON dumps default to
`$REVIEW_DIR` (`.camelot-eval/`).

```bash
bash .claude/skills/extraction-review/scripts/run_all.sh   # v2_*.json (current) + v1_*.json (baseline)
python .claude/skills/extraction-review/scripts/diff.py    # count + coverage regressions
python .claude/skills/extraction-review/scripts/numdiff.py # numeric-fidelity regressions
```

`run_all.sh` honors `REVIEW_DIR` and `V2_EXTRA` (extra `read_pdf` kwargs on the
current run); `V1_CAMELOT` sets the baseline version (default `1.0.9`).

## Scripts

- `scripts/gen_html.py` - before/after review HTML (Set-of-Mark engine).
- `scripts/boxed_pdf.py` - annotated PDF with Set-of-Mark bounding boxes.
- `scripts/raw_extract.py` - camelot-only dump; runs under any camelot version.
- `scripts/run_all.sh` - drives both camelot versions across docs.
- `scripts/diff.py` - count + coverage regression report.
- `scripts/numdiff.py` - numeric-fidelity regression report.

## Notes

- Both render modes draw `ExtractedTable.som_region` (normalized 0..1, top-left,
  full-precision floats; never floored). Tables where Camelot found nothing in
  the region still carry their `som_region` and are shown.
- The legacy diff scripts treat empty grids and prose-page noise as non-data;
  they surface, never silently drop, anything they flag.
