Checking a paired cover handoff with a small Python manifest A developer published a small Python utility, handoff_check.py, that verifies a paired cover handoff by comparing SHA-256 digests of an exported print PDF and an editable project file against a manifest recorded for a given revision. The checker rejects path separators, parent-path names, symbolic links and case-insensitive duplicate filenames, and reads files in bounded chunks; thirteen local unit tests passed against synthetic fixtures. The author stresses the tool confirms byte identity only and does not validate PDF content, project reopenability, artwork rights or who approved the expected digests. A production handoff often contains two files that serve different purposes: an exported artifact for the next production step and an editable project that makes later corrections possible. The files can become separated surprisingly easily. Someone replaces the export but attaches an older project, or a reviewer comments on a file whose name stayed unchanged. A small manifest can make those mismatches easier to detect without pretending to validate the design itself. This article presents an independent Python consistency example for that handoff problem. It is project-associated and was prepared with AI assistance. The code is not an integration with any publishing service, and the fixtures are deliberately synthetic bytes rather than real product exports. Thirteen local unit tests passed for the utility shown below. That statement describes these fixtures only; it is not a PDF, printer, browser, or commercial-product certification. The checker answers a narrow question: do the two named files currently match the expected digests recorded for a particular revision? It does not answer whether the expected digests were approved by the right person. It also does not inspect the visual content of a PDF, open an editable backup, or verify rights to the artwork. Defining the claim first prevents a convenient green result from becoming a misleading production approval. A cover workflow is a useful example because an author may need both a full-wrap print PDF and a project that can be edited later. KDP Cover Creator, at how to make captivating kdp book cover https://kdpcovercreator.app/ , describes artwork placement, separate text layers, cover and spine or back-cover work, layout review, PDF export, and an editable project backup. Optional AI artwork uses credits. The manifest in this article is an independent user-side convention, not a claimed native export format or API from that website. Before generating a manifest for real work, decide who establishes the expected file pair and where that record will be kept. If someone can freely replace both the files and the manifest, matching hashes do not establish authenticity. Keep the approved record in a location appropriate to the team's review process. A checksum is useful evidence of byte identity, but it cannot supply an approval process that does not otherwise exist. The example requires an integer schema version, a nonempty revision label, and two artifact roles. Each role contains a simple file name and a lowercase hexadecimal SHA-256 digest. Role names describe the intended handoff responsibilities rather than a detected file format. In particular, a record called print pdf does not prove that its bytes are a valid PDF, and an editable project record does not guarantee that a particular application can reopen it. Both files must live directly inside a directory chosen by the caller. The script rejects path separators and parent-path names rather than trying to support an elaborate directory tree. It also rejects symbolic-link files and case-insensitive duplicate names. Those are small portability and mistake-prevention policies for this example. They should not be mistaken for a complete sandbox for adversarial file systems or a general service for accepting arbitrary untrusted uploads. The revision label is descriptive, not a counter enforced by a central server. Two manifests can accidentally reuse a label unless the surrounding process prevents that. The checker also ignores unrelated extra fields and validates only the two defined roles. A production schema could choose stricter unknown-field rules, signed approvals, or a different artifact inventory, but those would be additional design decisions rather than properties of this minimal implementation. Save the following implementation as handoff check.py. It reads each file in bounded chunks and returns a list of errors. An empty list means only that the defined checks passed during this run. The function does not change either artifact, create a new export, update a project, or contact a remote service. Keeping it read-only makes the boundary between checking a handoff and repairing one easier to understand. """Independent handoff consistency example, not a product export validator.""" from collections.abc import Mapping from hashlib import sha256 from pathlib import Path import re ROLES = "print pdf", "editable project" def file digest path : h = sha256 with path.open "rb" as stream: for chunk in iter lambda: stream.read 65536 , b"" : h.update chunk return h.hexdigest def check handoff manifest, directory : errors = if not isinstance manifest, Mapping : return "manifest must be an object" if type manifest.get "schema version" is not int or manifest "schema version" = 1: errors.append "schema version must be integer 1" revision = manifest.get "revision" if not isinstance revision, str or not revision.strip : errors.append "revision must be nonempty text" artifacts = manifest.get "artifacts" if not isinstance artifacts, Mapping : return errors + "artifacts must be an object" root = Path directory .resolve seen = set for role in ROLES: record = artifacts.get role if not isinstance record, Mapping : errors.append f"{role}: record required" continue name = record.get "name" if not isinstance name, str or not name or name in ".", ".." or "/" in name or "\\" in name or any ord c < 32 for c in name : errors.append f"{role}: plain file name required" continue if name.casefold in seen: errors.append "artifact names must be distinct, ignoring case" seen.add name.casefold expected = record.get "sha256" if not isinstance expected, str or not re.fullmatch r" 0-9a-f {64}", expected : errors.append f"{role}: lowercase SHA-256 required" continue path = root / name try: if path.is symlink or not path.is file : errors.append f"{role}: regular nonsymlink file required" elif file digest path = expected: errors.append f"{role}: digest mismatch" except OSError: errors.append f"{role}: file could not be read" return errors Notice the explicit type check for the schema version. In Python, a boolean is also an instance of integer, so a broad integer-instance check could accept true where the contract requires the number one. The exact type comparison avoids that ambiguity. The digest check is similarly explicit: the example accepts sixty-four lowercase hexadecimal characters. It does not silently normalize a malformed record and make the caller think that record was originally well formed. The file-reading exception handler reports a role-specific read error without printing arbitrary file contents. A missing file, rejected symbolic link, malformed digest, and changed digest are distinct categories of problem even though each prevents a clean result. Callers can show the returned messages alongside the revision label, but should avoid dumping private manuscript content into a log merely to explain why a file could not be opened. The tests below create a temporary directory and two small opaque byte strings. One fixture has a pdf extension to illustrate the role name, but it is explicitly not a valid PDF. The other is an equally synthetic editable placeholder. This is intentional: the tests exercise schema handling, path policy, missing records, and digest comparisons without implying that a real print workflow has been executed or approved. Save this second file as test handoff check.py beside the checker. Running python -m unittest -v test handoff check executes thirteen tests. The local run for this article completed with all thirteen passing. The two code listings are the actual utility and test source used for that run; the test result does not extend to inputs, platforms, or application export formats that were not exercised. python import copy from hashlib import sha256 from pathlib import Path from tempfile import TemporaryDirectory import unittest from handoff check import check handoff class HandoffTests unittest.TestCase : def setUp self : self.temp = TemporaryDirectory self.addCleanup self.temp.cleanup self.root = Path self.temp.name Opaque fixtures: neither file is an actual product export or valid PDF. files = {"cover.pdf": b"synthetic print placeholder\n", "editable.fixture": b"synthetic editable placeholder\n"} for name, data in files.items : self.root / name .write bytes data self.manifest = {"schema version": 1, "revision": "demo-r1", "artifacts": { "print pdf": {"name": "cover.pdf", "sha256": sha256 files "cover.pdf" .hexdigest }, "editable project": {"name": "editable.fixture", "sha256": sha256 files "editable.fixture" .hexdigest }}} def test matching pair self : self.assertEqual check handoff self.manifest, self.root , def test changed pdf self : self.root / "cover.pdf" .write bytes b"changed" self.assertIn "print pdf: digest mismatch", check handoff self.manifest, self.root def test changed project self : self.root / "editable.fixture" .write bytes b"changed" self.assertIn "editable project: digest mismatch", check handoff self.manifest, self.root def test missing file self : self.root / "cover.pdf" .unlink self.assertTrue check handoff self.manifest, self.root def test missing role self : del self.manifest "artifacts" "editable project" self.assertIn "editable project: record required", check handoff self.manifest, self.root def test bad schema self : self.manifest "schema version" = True self.assertIn "schema version must be integer 1", check handoff self.manifest, self.root def test blank revision self : self.manifest "revision" = " " self.assertIn "revision must be nonempty text", check handoff self.manifest, self.root def test parent path rejected self : self.manifest "artifacts" "print pdf" "name" = "../cover.pdf" self.assertIn "print pdf: plain file name required", check handoff self.manifest, self.root def test symlink rejected self : p = self.root / "cover.pdf" p.unlink p.symlink to self.root / "editable.fixture" self.assertIn "print pdf: regular nonsymlink file required", check handoff self.manifest, self.root def test bad digest self : self.manifest "artifacts" "print pdf" "sha256" = "not-a-digest" self.assertIn "print pdf: lowercase SHA-256 required", check handoff self.manifest, self.root def test duplicate names self : self.manifest "artifacts" "editable project" = copy.deepcopy self.manifest "artifacts" "print pdf" self.assertIn "artifact names must be distinct, ignoring case", check handoff self.manifest, self.root def test nonobject manifest self : self.assertEqual check handoff , self.root , "manifest must be an object" def test nonobject record self : self.manifest "artifacts" "print pdf" = self.assertIn "print pdf: record required", check handoff self.manifest, self.root if name == " main ": unittest.main verbosity=2 The changed-file cases demonstrate the most common intended failure: a file no longer matches the expected snapshot. The missing-role case covers an incomplete pair even if one artifact is present and correct. The duplicate-name case prevents a manifest from satisfying both responsibilities by pointing at the same named artifact. These checks encourage an explicit handoff record rather than relying on the apparent recency of file names in a folder. The symbolic-link test creates its link entirely inside the temporary fixture directory. It does not inspect existing personal files or depend on a private project path. The test checks the implementation's refusal policy, not the behavior of every operating system or storage provider. A deployment on a platform with different link or permission semantics needs its own environment-specific testing before this helper becomes part of a production process. For a real handoff, finish the intended edits, export the production artifact, save the editable project, and identify that exact pair for review. Generate expected digests from the pair at that point using a trusted local tool or a reviewed extension of this example. The checker intentionally does not auto-refresh expected hashes when a mismatch appears. Automatically accepting the current files would remove the very distinction the check is meant to preserve. When a correction is requested, create a new revision record after reviewing the changed pair. Retain enough context to distinguish a new export from a previously reviewed one. A harmless PDF re-export can change metadata and therefore bytes even if its visible content appears identical. That is not a defect in SHA-256 comparison; it means the checker measures byte identity rather than visual or semantic equivalence between documents. There is also a timing boundary. A successful check cannot prevent a file from changing immediately afterward. If the next step uploads or transfers the pair, use a process that preserves the reviewed snapshot through that step. Depending on the environment, that might mean a versioned artifact store or a controlled release directory. This small utility does not claim to provide atomic publication, file locking, or protection against concurrent hostile changes. After consistency checks pass, open the actual exported PDF and assess it against the current printer specification. Verify the relevant dimensions, page arrangement, text, image placement, and required barcode treatment using appropriate tools and authoritative instructions. Reopen the editable backup when recoverability matters. Those actions answer different questions from hashing, and their results should be recorded separately rather than being compressed into one ambiguous approved flag. The same separation is useful beyond covers. A report and its editable source, a presentation and its working assets, or a packaged dataset and its generation notes can benefit from a clear inventory. Adapt the roles to the real workflow and test the resulting contract rather than assuming these names are universal. A small consistency checker earns trust by stating exactly what it checked, preserving evidence, and refusing to imply more than its narrow result supports.