Print-ready editable voter-information booklet for the City of Chamblee 2026 Democratic primary.
  • Python 61.1%
  • TeX 38%
  • Makefile 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Clawlter Agent aab6f0b19b
All checks were successful
Booklet CI / Validate and build booklet PDFs (pull_request) Successful in 13m0s
Booklet CI / Validate and build booklet PDFs (push) Successful in 6m8s
ci: use current PDF management package
2026-07-13 10:52:59 +00:00
.forgejo/workflows ci: use current PDF management package 2026-07-13 10:52:59 +00:00
assets fix(booklet): pin reviewed media inputs 2026-07-12 17:23:38 +00:00
data fix(booklet): refresh media from source bytes 2026-07-12 20:24:51 +00:00
deliverables fix: correct deandre mathis qr code 2026-04-17 16:26:28 +00:00
qa-previews fix: simplify footer callout layout 2026-04-13 18:33:42 +00:00
scripts merge: add deterministic media inputs to accessible PDF 2026-07-12 21:56:38 +00:00
src merge: add deterministic media inputs to accessible PDF 2026-07-12 21:56:38 +00:00
tests merge: add deterministic media inputs to accessible PDF 2026-07-12 21:56:38 +00:00
.gitattributes chore: keep deliverable pdfs out of git lfs 2026-04-13 20:10:47 +00:00
.gitignore feat: add initial chamblee 2026 voter booklet draft 2026-04-13 17:39:13 +00:00
Makefile merge: add deterministic media inputs to accessible PDF 2026-07-12 21:56:38 +00:00
README.md merge: add deterministic media inputs to accessible PDF 2026-07-12 21:56:38 +00:00

Chamblee 2026 voter booklet

Editable-source + PDF project for the Chamblee 2026 Democratic primary voter booklet.

Active generation pipeline

  • Generator script: scripts/generate_booklet.py
  • Validation script: scripts/validate_booklet.py
  • Editable booklet pages: src/booklet-pages.tex
  • Editable imposed print layout: src/booklet-print.tex
  • Rendered booklet pages PDF: build/booklet-pages.pdf
  • Rendered imposed print PDF: build/booklet-print.pdf

Prerequisites

  • Python 3
  • ffmpeg / ffprobe for an explicit headshot refresh
  • LuaLaTeX and latexmk for PDF builds
  • qpdf and Poppler (pdfinfo, pdftotext) for digital PDF accessibility checks
  • Git LFS enabled before building from a fresh clone, so committed image assets are real images rather than pointer files

The included Makefile defaults to the Hermes TeX Live path when available (/opt/hermes-runtime/tools/texlive/2026/bin/x86_64-linux) and otherwise uses latexmk from PATH. Override with LATEXMK=/path/to/latexmk if needed.

Build and validation

git lfs pull              # fetch the reviewed, content-addressed media inputs
make generate             # offline: refresh data/render_data.json and src/*.tex
make validate             # check generated data, assets, and imposition order
make build                # build build/booklet-pages.pdf and build/booklet-print.pdf

Equivalent manual build commands:

python3 scripts/generate_booklet.py
python3 scripts/validate_booklet.py
export PATH=/opt/hermes-runtime/tools/texlive/2026/bin/x86_64-linux:$PATH
latexmk -lualatex -interaction=nonstopmode -halt-on-error -jobname=booklet-pages -output-directory=build src/booklet-pages.tex
latexmk -lualatex -interaction=nonstopmode -halt-on-error -jobname=booklet-print -output-directory=build src/booklet-print.tex

Sources and structure

  • Authoritative candidate list: data/sheet_raw.json
  • Cleaned/render-ready data: data/render_data.json
  • Reviewed media provenance: data/media-manifest.json
  • Content-addressed candidate QR codes: assets/media/qrs/
  • Content-addressed candidate headshots: assets/media/headshots/
  • Review images: qa-previews/
  • Project repository root: this directory

Binary file handling

This repo uses Git LFS for committed image formats listed in .gitattributes. Clone with Git LFS enabled to fetch preview images and static assets normally.

Current PDF deliverables in deliverables/ are committed as regular files; generated PDFs under build/ are ignored.

PDF accessibility policy

build/booklet-pages.pdf is the digital reading copy. Its build supplies document metadata and language, tagged headings and figures, neutral name-derived image alternatives, and clickable destinations matching the printed QR codes. Run make check-accessibility after building to inspect those behaviors with pdfinfo, qpdf, and pdftotext.

build/booklet-print.pdf is an imposed production artifact: its page sequence and two-up geometry are for folding and printing, not linear screen-reader reading. It is therefore not represented as a tagged accessible document. The digital pages PDF is the maintained accessible alternative for the same content.

Reviewed media policy

Ordinary generate, validate, and build commands are deterministic and do not contact campaign sites or the QR service. They resolve only committed media listed in data/media-manifest.json, verify each file's SHA-256 digest, and fail closed when an asset is missing, changed, or no longer matches its source URL or crop parameters.

Media refresh is a separate, deliberate review operation:

make refresh-media
git diff -- data/media-manifest.json assets/media/
make test generate validate build

The refresh command always reacquires remote source/service bytes, even when the URL, crop, and processor are unchanged. It records both source_sha256 and the reviewed rendered sha256, with source_provenance: fetched; unchanged source bytes reuse the digest-verified rendered asset without rerunning the headshot transform. Headshot source and rendered digests are normally distinct. For QR entries, source_sha256 hashes the QR service PNG response and equals sha256 because that response is the reviewed asset without another transform.

The initial reviewed assets predate raw-source retention. Their migration is explicit rather than inferred: headshots use a null source_sha256 with source_provenance: unavailable-historical-source, so the first explicit refresh must reacquire and transform source bytes. QR generation is an identity flow, so the reviewed QR bytes are recorded as both source and render digests with source_provenance: reviewed-identity-input. A successful refresh replaces either bootstrap marker with fetched provenance; no historical source digest is fabricated.

Changed inputs are written to new content-addressed paths and the manifest is replaced atomically only after a complete asset is available. Review the new image/QR bytes and manifest diff before committing them. Do not run media refresh in ordinary CI; network download policy is enforced by the downloader and maintained separately from this provenance/cache layer.

Imposition order

The print PDF follows the required 8-page booklet order:

  • Sheet A front: page 8 | page 1
  • Sheet A back: page 2 | page 7
  • Sheet B front: page 6 | page 3
  • Sheet B back: page 4 | page 5