Release note · August 6, 2026
A batch manifest should be generated, not hand-written
A privacy-safe batch report needs an explicit manifest because it cannot safely reveal or guess the source paths that connect documents across a handoff. But hand-authoring that manifest for hundreds of PDFs is a poor trade: people make mistakes, and the safest review workflow becomes too tedious to use.
PDFFence 1.26.0 adds pdffence batch-init, a deliberately narrow generator for the common case where a before and after tree preserve the same relative PDF paths.
Generate the private map locally
pdffence batch-init baseline/ candidate/ review.json
pdffence batch baseline/ candidate/ \
--manifest review.json --policy pdffence.yml --format sarif
The first command recursively walks two selected local directory trees and writes a strict JSON manifest. It pairs only same-relative-path PDFs and assigns deterministic opaque labels such as document-0001. A file present only in one tree remains a one-sided entry, so the existing batch workflow reports it as added or removed and PFP016 can fail CI if the declared set changed.
The generated manifest itself contains relative paths. It is not an artifact and it is not a public report: store it where those paths are allowed, do not commit it casually, and do not upload it to a CI artifact. The command requires an explicit destination, writes atomically, and produces no path-bearing standard output.
Why it does not “find” renames
Two files with different paths are not reliably the same document merely because they look similar, have a comparable byte size, or share a name fragment. Treating a heuristic as identity creates the exact sort of silent omission a review tool should avoid.
So batch-init does not infer a rename. It writes separate added and removed entries. When a reviewer knows that old/location.pdf became new/location.pdf, they edit the private manifest to place those two paths under one existing opaque ID. The resulting batch report can then compare the real pair without publishing either path.
A scan boundary, not a permissive file crawl
The generator has hard limits: at most 100,000 scanned tree entries, the existing 4,096-document manifest limit, and the 256 KiB manifest limit. It rejects any symbolic link in the scanned tree rather than following or silently skipping it, rejects PDF-named non-regular entries and unrepresentable path forms, and detects repeated directory identities. Non-PDF files are ignored.
Those checks make the generated manifest a local starting point that is compatible with the same source-boundary rules used by pdffence batch. They do not make an arbitrary directory trustworthy, and they do not turn a scan into an assertion that it found every document relevant to a business process.
Proved on a full paired corpus
PDFFence 1.26 passed 273 tests, Ruff, and bytecode compilation. The new coverage exercises deterministic pairing, explicit unmatched paths, strict manifest round-tripping, no-root leakage, private marker-bearing path errors, force behavior, symbolic links, invalid names, and scanner/document/manifest-size limits.
For independent integration evidence, a fresh two-tree projection of all 161 PDFCAB 1.24.1 pairs went through batch-init. The generated manifest contained 161 entries; its batch report recorded 161 changed documents with no policy findings. Every generator-routed entry's public snapshots, changes, and findings exactly matched the corresponding standalone pdffence diff --format json result.
The wheel and source archive built byte-for-byte reproducibly with a fixed timestamp, passed Twine checks, and passed clean Python 3.12/3.13 installations. The public GitHub wheel was re-downloaded, checksum-verified, installed from its published URL, and used to generate and review the 161-entry manifest again. A clean dependency audit found no known vulnerabilities.
What this is—and is not
batch-init reduces manifest setup work; it does not replace review judgment. It neither renders PDFs, compares visual appearance, validates PDF conformance, executes actions, follows URIs, extracts text, decrypts documents, searches for malware, nor validates signatures, certificates, trust, authorization, or safety. It deliberately does not guess a rename or claim a tree is a complete business document set.
The tagged batch-manifest contract, threat model, and validation record define the supported boundary.
python -m pip install https://github.com/SybilGambleyyu/pdffence/releases/download/v1.26.0/pdffence-1.26.0-py3-none-any.whl
PDFFence is MIT-licensed and available on GitHub. The release assets include SHA-256 checksums for the wheel and source archive.