- PDF chunking Phase 3 (issue #1961): chunked parsing now uses **overlap windows** so structure spanning a chunk boundary survives. `BaseChunkedParser` (`opencontractserver/pipeline/base/chunked_parser.py`) splits each chunk over an overlap-extended parse range via `calculate_page_chunks_with_overlap(..., overlap=chunk_overlap)` (new `chunk_overlap` knob, default `DEFAULT_CHUNK_OVERLAP=2` in `opencontractserver/constants/document_processing.py`; `DoclingParser` exposes it as the `DOCLING_CHUNK_OVERLAP` pipeline setting). Each chunk's reassembly offset is its parse-range `start` (so local page `i` maps to global page `start+i`), superseding the Phase-1 placeholder note that suggested `core_start`. `ChunkReassembler` (`opencontractserver/pipeline/base/chunk_reassembler.py`) now dedupes overlap pages by global index (keep-first), dedupes annotations by a chunk-independent content signature (label + global page geometry), and **re-links** cross-boundary relationship endpoints and `parent_id` references onto the surviving canonical IDs — replacing the previous `c{idx}_`-prefix severing that orphaned cross-chunk references. Residual orphans (a reference spanning more pages than the configured overlap) are logged + metered (`metric=chunk_reassembly_orphan_refs`) but never fatal. Covered by a service-level golden-equivalence gate (`opencontractserver/tests/test_chunked_parser.py::TestChunkedOverlapGoldenEquivalence`) proving a chunked-with-overlap parse reproduces the single-shot PAWLs, annotations, and relationships, plus reassembler-level dedup/re-link tests in `test_chunk_reassembler.py`. Hardening: `ChunkReassembler.finalize()` is now guarded against a second call (the in-place id-remap is single-use); the annotation dedup signature normalizes `rawText` whitespace so the same span surviving in two chunks still collapses; `_dedupe_pages` logs (`metric=chunk_reassembly_page_missing_index`) when a PAWLs page lacks an `index`; and the `overlap >= max_pages_per_chunk` error in `calculate_page_chunks_with_overlap` (plus a `BaseChunkedParser` docstring note) now tells subclasses with a small `max_pages_per_chunk` to pin `chunk_overlap = 0`.
