Skip to content

Repository files navigation

BatchSeal

Catch missing, swapped, leaked, duplicated, or unfinished personalized documents after generation and before delivery.

CI License: MIT Python 3.11+

BatchSeal is an offline CLI that compares a recipient CSV with a folder of final PDF, DOCX, TXT, and EML artifacts. It proves that every recipient has one expected file, checks required markers, catches another recipient's isolation marker, finds leftover template tokens, and blocks duplicated output. It does not generate or send mail.

The failure it catches

A merge job can exit successfully while attaching Bob's letter to Alice, omitting a file, leaving {{ amount_due }} in a document, or emitting the same statement for hundreds of recipients. Template-unit tests do not inspect the final batch as a set. BatchSeal does.

recipient CSV + generated folder
              |
              v
      completeness + isolation + residue checks
              |
        +-----+-----+
        |           |
      PASS(0)     FAIL(1)
                    |
             JSON + CSV + HTML

Try it in two commands

uv sync --frozen --all-extras
uv run batchseal audit --manifest examples/good/recipients.csv --input examples/good/output --report-dir reports/good

Expected result:

BatchSeal PASS: 4 recipients, 4 artifacts, 0 errors
Reports: reports/good

Now run the deliberately broken batch:

uv run batchseal audit --manifest examples/bad/recipients.csv --input examples/bad/output --report-dir reports/bad

It exits 1 and demonstrates every v0.1.0 finding from BS001 through BS009. The sample contains only synthetic names and .test email addresses.

Install

From the tagged source:

pipx install git+https://github.com/KanadeK/batchseal.git@v0.1.0
batchseal version

Or download the wheel from the latest GitHub Release:

pipx install batchseal-0.1.0-py3-none-any.whl

BatchSeal requires Python 3.11 or newer; CI tests Python 3.11 through 3.14 across Windows, macOS, and Linux.

Recipient CSV

recipient_id,expected_file,name,email,required_terms,isolation_terms
alice,letters/alice.pdf,Alice,alice@example.test,Alice|ID-A,ID-A|alice@example.test
bob,letters/bob.docx,Bob,bob@example.test,Bob|ID-B,ID-B|bob@example.test
Column Required Meaning
recipient_id yes Unique row key serialized in reports; default required and isolation marker.
expected_file yes Relative .pdf, .docx, .txt, or .eml path below --input.
name no Display name retained in the manifest only.
email no Added to default isolation markers when explicit markers are absent.
required_terms no `
isolation_terms no `

Use stable, unique customer or case IDs as isolation markers. Names such as John are usually too common. Matching is Unicode-aware and case-insensitive.

Findings

Code Meaning
BS001 Expected artifact is missing.
BS002 Supported artifact is not assigned in the manifest.
BS003 Multiple recipients map to one artifact.
BS004 Artifact cannot be parsed.
BS005 Artifact has no extractable text.
BS006 Required recipient term is missing.
BS007 Another recipient's isolation term appears.
BS008 An unresolved {{...}}, <<...>>, or named placeholder remains.
BS009 Distinct assigned artifacts have identical SHA-256 content.

See the repair guide for the exact recovery path for each code.

Reports and exit contract

Every audit writes:

  • batchseal-report.json — versioned machine contract (schema);
  • batchseal-findings.csv — spreadsheet-friendly remediation queue;
  • batchseal-report.html — self-contained human review page with no JavaScript.

Reports contain recipient IDs, relative paths, counts, stable codes, and artifact digests, but never document excerpts or matched recipient terms. Use opaque IDs and filenames if reports will be shared beyond the delivery team.

Exit Meaning
0 Audit completed and no errors were found.
1 Audit completed and the batch is not safe to deliver.
2 Manifest, input, command, or report configuration is invalid.

Limitations

  • PDF inspection uses the text layer. Image-only scans need OCR before BatchSeal.
  • Password-protected PDFs are rejected.
  • DOCX body, header, and footer text are inspected; macros and embedded active content are never executed.
  • EML recipient/subject headers, plain-text bodies, and supported PDF/DOCX/TXT attachments are inspected; HTML-only message bodies are outside v0.1.0.
  • Each expected artifact and inspected DOCX XML member is limited to 25 MiB.
  • A pass is a targeted batch QA result, not malware, DLP, or regulatory certification.

All processing is local. BatchSeal has no network code, telemetry, cache, mail sender, or mutation path for input documents. Read the threat model and security policy before regulated use.

Acceptance and repair

Run the same release gate used by CI:

uv run python scripts/release_check.py

It runs lint, format, typing, coverage, dependency audit, wheel/sdist build, clean-wheel installation, and both example batches. If it stops, fix the first reported command and rerun the gate; do not skip or weaken the failing check. For audit failures, follow docs/repair-guide.md, regenerate, and rerun the original audit.

Development

uv sync --frozen --all-extras
uv run pytest -q
uv run ruff check .
uv run ruff format --check .
uv run mypy src tests scripts
uv build

Architecture and scope live in SPEC.md. The selection research and explicit non-goals are in docs/research.md. Contributions are described in CONTRIBUTING.md.

MIT © 2026 KanadeK

About

Offline pre-delivery QA for personalized PDF, DOCX, TXT, and EML batches

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages