The bash double-quoted BODY="...\n..." assignment never interpreted
\n as a newline, so Gitea rendered the literal backslash-n text
instead of a line break (visible on the 2.1.3 release). Build it
with printf instead, which does expand \n.
83 tests (94% coverage of src/py) covering the builder pipeline
(gallery sync, HTML/CSS generation, image processing, full site
build) and the Flask webui (routes, uploads, theme/font management).
Dockerfile gains a `test` stage (pytest) between the wheel builder
and the prod image, and pins the alpine base to a full patch tag so
Renovate can classify updates. CI workflow builds, smoke-tests, runs
the suite, scans with Trivy, and publishes/releases on merge to main,
following the same pipeline already running on adguard-cidre.