- add-popup-source.sh: slug validated against ^[a-z0-9-]+$ before nginx
interpolation; UPSTREAM_HOST derived unconditionally so the CSP
reminder fires in the no-proxy case — which is exactly when the host
must be added to connect-src (AUDIT §4.8)
- refreeze.sh: backs up the freeze and restores it on a failed resolve
instead of leaving the repo with no freeze file (§4.9)
- einops gets the policy-mandated upper bound and a comment naming its
consumer (nomic's remote modeling code) (§1.5)
- Makefile: pdftoppm failures warn instead of vanishing in the while
pipeline; .NOTPARALLEL guards deploy's clean->build->sign ordering
against -j invocations (§8.4)
- Atomic writers (embed, archive, the three sidecar extractors):
PID-unique temp names so concurrent runs can't interleave, cleanup on
failure everywhere, fsync where the artifact is not trivially
regenerable (§4.10)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- import-photo.sh: validate \$SLUG against ^[a-z0-9-]+\$ before
writing under content/photography/; rejects '../' and other
surprises early. Also fail loudly with a clear message if either
'magick' resize or 'magick mogrify -strip' returns non-zero
(prevents shipping a file that still carries EXIF when the strip
silently failed).
- compress-assets.sh: reject non-numeric MIN_SIZE up front (otherwise
the comparison fails later with a cryptic arithmetic error).
- extract-dimensions.py / extract-exif.py / extract-palette.py:
add traceback.print_exc() after the broad except so a corrupt
image produces a stack trace alongside the one-line summary.
- extract-exif.py: switch from Pillow's deprecated _getexif() to
the public getexif() API; pyproject allows Pillow up to 12 where
_getexif may be removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>