2026-05-14 23:17:45 +02:00
|
|
|
---
|
|
|
|
|
id: MKTF-WP-0002
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "PDF Read Adapter"
|
|
|
|
|
domain: markitect
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
owner: markitect-filter
|
|
|
|
|
topic_slug: markitect
|
2026-05-14 23:33:31 +02:00
|
|
|
planning_priority: complete
|
2026-05-14 23:17:45 +02:00
|
|
|
planning_order: 20
|
|
|
|
|
depends_on_workplans:
|
|
|
|
|
- MKTF-WP-0001
|
|
|
|
|
related_workplans:
|
|
|
|
|
- MKTT-WP-0018
|
|
|
|
|
created: "2026-05-14"
|
|
|
|
|
updated: "2026-05-14"
|
|
|
|
|
state_hub_workstream_id: "7445fe6b-f1a9-4383-8053-4337337dc095"
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# MKTF-WP-0002: PDF Read Adapter
|
|
|
|
|
|
|
|
|
|
## Purpose
|
|
|
|
|
|
|
|
|
|
Implement the second concrete `markitect-filter` source adapter:
|
|
|
|
|
`source.pdf`, a read-only PDF adapter that satisfies the `markitect-tool`
|
|
|
|
|
source adapter contract.
|
|
|
|
|
|
|
|
|
|
The contract dependency is cross-repo and is tracked as related work rather
|
|
|
|
|
than a same-repo State Hub dependency edge: `markitect-tool` `MKTT-WP-0018`.
|
|
|
|
|
|
|
|
|
|
The first PDF slice should target deterministic text extraction from
|
|
|
|
|
digitally-readable PDFs. It should preserve page-level provenance and make
|
|
|
|
|
extraction uncertainty visible through diagnostics and quality signals.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
## Implemented Scope
|
2026-05-14 23:17:45 +02:00
|
|
|
|
|
|
|
|
- Optional PDF dependency profile isolated behind a `pdf` extra.
|
|
|
|
|
- Entry point group registration:
|
|
|
|
|
`markitect_tool.source_adapters`.
|
|
|
|
|
- Lightweight `pdf_adapter_descriptor`.
|
|
|
|
|
- Adapter id `source.pdf` with media type `application/pdf` and extension
|
|
|
|
|
`.pdf`.
|
|
|
|
|
- Inspection for basic PDF metadata, page count, encryption status, and
|
|
|
|
|
extractability signals.
|
|
|
|
|
- Read-only page text extraction into ordered Markdown segments.
|
|
|
|
|
- Page-aware source provenance with source paths, page numbers, page labels
|
|
|
|
|
where available, and stable segment ids.
|
|
|
|
|
- Configurable first-slice options such as page range, page break markers, and
|
|
|
|
|
whitespace normalization policy.
|
|
|
|
|
- Structured diagnostics for malformed PDFs, encrypted PDFs, image-only or
|
|
|
|
|
scanned pages, empty extraction, partial page failures, unsupported embedded
|
|
|
|
|
media, and lossy layout/table handling.
|
|
|
|
|
- Quality metadata for confidence, lossiness, skipped pages, warning counts,
|
|
|
|
|
extraction backend, and page coverage.
|
|
|
|
|
- Tests for descriptor shape, matching, inspection, normalization, malformed
|
|
|
|
|
inputs, encrypted or non-extractable inputs where fixtures allow, Markitect
|
|
|
|
|
API registry use, and entry point shape.
|
|
|
|
|
|
|
|
|
|
## Non-Goals
|
|
|
|
|
|
|
|
|
|
- OCR or scanned-document recognition.
|
|
|
|
|
- Pixel-perfect layout preservation.
|
|
|
|
|
- Table reconstruction beyond plain text and diagnostics.
|
|
|
|
|
- Image, figure, annotation, form, signature, or attachment extraction beyond
|
|
|
|
|
future metadata/diagnostic hooks.
|
|
|
|
|
- PDF writing/export.
|
|
|
|
|
- Network fetching.
|
|
|
|
|
- External processes or native system services in the first slice.
|
|
|
|
|
- Making PDF dependencies mandatory for EPUB3 or other adapters.
|
|
|
|
|
|
|
|
|
|
## P2.1 - Pin PDF v1 dependency and extraction policy
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T001
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "2ce51bb9-9182-4927-90d1-4c08433b5ddb"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Choose the first PDF extraction backend and dependency profile.
|
|
|
|
|
|
|
|
|
|
The decision should document:
|
|
|
|
|
|
|
|
|
|
- pure-Python preference for the first slice
|
|
|
|
|
- optional dependency placement under the `pdf` extra
|
|
|
|
|
- supported inputs: local, digitally-readable PDFs
|
|
|
|
|
- unsupported inputs: scanned/image-only PDFs without OCR
|
|
|
|
|
- encrypted/permission-restricted PDF behavior
|
|
|
|
|
- how page range, page breaks, and whitespace normalization should behave
|
|
|
|
|
- fallback or future status for heavier layout/OCR backends
|
|
|
|
|
|
|
|
|
|
Output: dependency decision, option contract, and implementation notes.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: `docs/pdf-adapter.md`, `pyproject.toml`, and the descriptor
|
|
|
|
|
metadata document a stdlib first slice, a reserved `pdf` extra, local
|
|
|
|
|
digitally-readable PDF support, page range/page marker/whitespace options, and
|
|
|
|
|
deferred OCR/layout-heavy backends.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## P2.2 - Add descriptor and entry point registration
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T002
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "27d754a9-59ae-4419-946b-f1f847bd3b10"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Add a `pdf_adapter_descriptor` matching the existing EPUB3 descriptor pattern.
|
|
|
|
|
|
|
|
|
|
The descriptor should define:
|
|
|
|
|
|
|
|
|
|
- adapter id `source.pdf`
|
|
|
|
|
- version `1`
|
|
|
|
|
- media type `application/pdf`
|
|
|
|
|
- extension `.pdf`
|
|
|
|
|
- read operation only
|
|
|
|
|
- safety metadata with local reads only
|
|
|
|
|
- option schema for page range, page breaks, and whitespace normalization
|
|
|
|
|
- quality profile and dependency metadata
|
|
|
|
|
- lazy factory import for the PDF adapter implementation
|
|
|
|
|
|
|
|
|
|
Output: descriptor, entry point registration, and descriptor tests.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: `pdf_adapter_descriptor` is registered through
|
|
|
|
|
`markitect_tool.source_adapters`, exported from the package, and covered by
|
|
|
|
|
descriptor and discovery tests.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## P2.3 - Implement PDF inspection
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T003
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "33b594e6-d12a-46d5-bc50-6ec1aebaaf65"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Implement `inspect` for PDF assets.
|
|
|
|
|
|
|
|
|
|
Inspection should report:
|
|
|
|
|
|
|
|
|
|
- title, creators/authors, subject, keywords, producer, creation/modification
|
|
|
|
|
dates where available
|
|
|
|
|
- page count
|
|
|
|
|
- encryption or permission status
|
|
|
|
|
- basic extractability signals
|
|
|
|
|
- diagnostics for malformed, unreadable, encrypted, or unsupported PDFs
|
|
|
|
|
|
|
|
|
|
Output: inspection implementation and tests with small fixtures.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: `PdfReadAdapter.inspect` reports metadata, page count,
|
|
|
|
|
extractability signals, encryption status, quality metadata, and malformed or
|
|
|
|
|
encrypted diagnostics using deterministic generated fixtures.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## P2.4 - Normalize page text into Markitect Markdown
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T004
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "30c0c777-a4e4-43d1-ac24-6a0f84c7b761"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Implement `read` for digitally-readable PDFs.
|
|
|
|
|
|
|
|
|
|
Normalization should:
|
|
|
|
|
|
|
|
|
|
- iterate pages in deterministic order
|
|
|
|
|
- apply page range filtering
|
|
|
|
|
- convert extracted text into Markdown-safe segment text
|
|
|
|
|
- create one or more ordered segments with stable segment ids
|
|
|
|
|
- preserve page-level provenance on every segment
|
|
|
|
|
- optionally insert page break markers
|
|
|
|
|
- produce a stable document id and cache key through the Markitect source
|
|
|
|
|
contract helpers
|
|
|
|
|
|
|
|
|
|
Output: read implementation and normalization tests.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: `PdfReadAdapter.read` extracts ordered page text into stable
|
|
|
|
|
page segments, applies page ranges, supports optional page markers, preserves
|
|
|
|
|
page provenance, and uses the Markitect cache-key helpers.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## P2.5 - Add diagnostics and quality semantics
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T005
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "8b6a190a-350b-4c61-ac4f-1900673a8cd2"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Define PDF-specific diagnostics and quality metadata.
|
|
|
|
|
|
|
|
|
|
The adapter should distinguish:
|
|
|
|
|
|
|
|
|
|
- malformed PDF
|
|
|
|
|
- encrypted or permission-restricted PDF
|
|
|
|
|
- no extractable text
|
|
|
|
|
- partially failed pages
|
|
|
|
|
- scanned/image-only pages
|
|
|
|
|
- dropped layout, tables, figures, annotations, or forms
|
|
|
|
|
- unsupported embedded resources
|
|
|
|
|
|
|
|
|
|
Quality should include extraction backend, page coverage, warning count,
|
|
|
|
|
skipped pages, lossiness, and confidence.
|
|
|
|
|
|
|
|
|
|
Output: diagnostic helpers, quality rules, and tests.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: PDF diagnostics cover malformed files, unreadable files,
|
|
|
|
|
encrypted PDFs, invalid page ranges, missing/empty streams, image-only pages,
|
|
|
|
|
empty extraction, and stream decompression failures. Quality metadata records
|
|
|
|
|
backend, page count, selected pages, extracted pages, coverage, warnings, and
|
|
|
|
|
skipped pages.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## P2.6 - Add fixtures, docs, and validation
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: MKTF-WP-0002-T006
|
2026-05-14 23:33:31 +02:00
|
|
|
status: done
|
2026-05-14 23:17:45 +02:00
|
|
|
priority: medium
|
|
|
|
|
state_hub_task_id: "af597160-e189-42be-8479-c6e0f467d238"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Add small deterministic PDF fixtures and documentation.
|
|
|
|
|
|
|
|
|
|
Validation should cover:
|
|
|
|
|
|
|
|
|
|
- descriptor shape
|
|
|
|
|
- media type and extension matching
|
|
|
|
|
- metadata inspection
|
|
|
|
|
- page text normalization
|
|
|
|
|
- malformed or empty extraction behavior
|
|
|
|
|
- registry and entry point shape
|
|
|
|
|
- `markitect-tool` API use through `inspect_source` and `normalize_source`
|
|
|
|
|
|
|
|
|
|
Output: tests, README update, and validation command.
|
|
|
|
|
|
2026-05-14 23:33:31 +02:00
|
|
|
Implemented: generated PDF fixtures and tests cover descriptor shape, matching,
|
|
|
|
|
metadata inspection, normalization, page range markers, malformed PDFs,
|
|
|
|
|
encrypted PDFs, registry use, entry point discovery, README documentation, and
|
|
|
|
|
the validation command below.
|
|
|
|
|
|
2026-05-14 23:17:45 +02:00
|
|
|
## Validation
|
|
|
|
|
|
|
|
|
|
Run from `markitect-filter`:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
PYTHONPATH=src:/home/worsch/markitect-tool/src python3 -m pytest
|
|
|
|
|
```
|