# Connector: PDF documents (`pdf`) **Purpose**: official documents that only exist as PDF and whose text matters — framework and standards documents (NIST CSF 2.0, SP 800-53), forms and instructions (SEC Form 10-K, IRS 1040, CRA guides), network rules (Visa Core Rules), licence agreements (Apple SLA), AI-lab policies (OpenAI Preparedness Framework). Only **stable URLs** qualify; dated file names (`statement_20250917.pdf`) belong to feed/HTML sensors, not here. **Sensor types**: FILE, PDF_INDEX. **Config**: `maxPages` (40 — extraction cost grows linearly; long documents are sampled from the start), `headers`, `timeoutMs`. **Extraction**: pdf.js through `unpdf` (pure JS, no native binary); page texts joined, whitespace normalized, then `canonicalizeText` (same scrubbing as HTML pages) → text diff. Metadata: title, author, producer, creation and modification dates (`publishedAt`). **Confidence**: < 40 chars extracted (scanned document) → confidence 0.2 — the pipeline then only reports changed/unchanged on the raw hash, never a text diff. **Failure handling**: HTML instead of PDF → `html_not_pdf`; body not starting with `%PDF-` → `bad_pdf`. Limit 40 MB. **Known quirks**: pdf.js prints `Warning: TT: undefined function` for some embedded fonts (harmless); very large documents (OpenAI framework 27 MB) take several seconds — tier D. **Tests**: covered live by the validator (`config/sources.d/35-documents-data.yaml`). **Verified**: 2026-09-08 on 10 PDFs.