Bundle the remaining imaging hardening and the host/CI fixes from the
"Doe alles" pass into one release.
Furniture:
- Resolve the local bundle extension from FURNI_BUNDLE_EXT (".hab" default,
".nitro" for a stock Nitro client). The configured extension is written by
imports/repairs and preferred on lookup; the other stays a legacy fallback.
Imaging:
- Avatar proxy sends s-maxage=86400 + stale-while-revalidate (300/3600 for the
fallback path) so the edge can hold a render a day.
- Cloudflare cache rule now covers /api/imaging/ (verified MISS->HIT live).
- Document that bare /imaging is shadowed by the edge proxy to the renderer.
Ops/CI:
- docker-update.sh skips a CI-managed host (exit 0) instead of failing cron.
- ci-deploy.sh runs the cross-browser imaging gate (chromium+firefox+webkit)
against the candidate before cutover; DEPLOY_SKIP_CROSS_BROWSER=1 as escape.
- scripts/imager-health-alert.sh alerts (Discord) on imager up/down transitions;
runs from cron every 5 minutes.
Tests:
- Furniture bundle-ext resolver + FURNI_BUNDLE_EXT wiring.
- Imaging performance budget (bytes + warm latency).
- classifyDdos: /api/imaging/* stays in the api bucket.
Environment-independent contract tests (cache headers + source, CORS, OPTIONS
preflight, negative figure/badge tables, concurrency burst) run in both the
deploy gate and the cross-browser job.
CMS-only /imaging assertions (webp/avif transcode, animated-APNG passthrough,
s-maxage edge caching) live in cms-imaging.spec.ts and are skipped behind the
edge proxy; the public topology has its own public-routing.spec.ts smoke that
fails if the edge ever stops fronting the imager or starts shadowing the CMS
endpoints. A committed per-engine visual baseline pins the static render.
The cross-browser imaging job is now blocking (IMAGING_EDGE=1), so avatar
imaging on chromium/firefox/webkit is a required signal.
In production the edge proxy fronts /imaging to the imager container, so the
CMS route only answers when reached directly. Asserting it in the shared spec
failed against the public site in all three engines. Its behaviour is covered
by src/lib/imaging-route.test.ts; the e2e spec now only checks the endpoints
that are identical in both topologies (/api/imaging/avatar and the badge).
The deploy gate only installs chromium, so imaging had no browser-level
coverage. Add two Playwright specs:
- e2e/imaging/avatar-endpoint.spec.ts: HTTP contract for the avatar
(/api/imaging/avatar), default (/imaging) and badge endpoints — animated
APNG for a figure with an effect, the trailing-`.0` regression figure,
ETag/304 revalidation, and a 400 for a malformed figure. Runs in the
deploy gate automatically via the default Playwright config.
- e2e/imaging/avatar-render.spec.ts: loads the avatar in a real browser and
asserts it decodes at a non-zero size and animates. Navigates to the image
URL directly so production CSP `upgrade-insecure-requests` cannot rewrite
the request over a plain-HTTP host.
Add playwright.imaging.config.ts running both across chromium, firefox and
webkit, a `test:imaging` script, and a non-blocking CI job that installs all
three engines and checks the live site.