Skip to content

v3.3.0 — Through the front door

Choose a tag to compare

@MarkusNeusinger MarkusNeusinger released this 26 Sep 22:15
· 573 commits to main since this release
3c696a6

1,028 merged PRs (#10812–#11850), 968 of them the catalog pipeline's own. The highlights — the full record is CHANGELOG.md, and each PR carries its own reasoning.

Added

  • 👍 / 👎 directly on the plot — rating an implementation is one tap on the static preview or the interactive surface, stored per library and language; one vote per image per session (#11827).
  • A shared-secret origin gate closes the direct *.run.app door, and the apex Worker's source moves into the repository — api/origin_gate.py refuses with 403 anything the Cloudflare edge did not stamp, so the bot challenge, WAF and cache can no longer be bypassed one URL away (#11208).
  • The API image is built and its container smoke-tested before merge, not after — the first build of a changed Dockerfile used to happen in Cloud Build after merge, which is how the deploy trigger sat red from 2026-08-30 with every PR check green (#11205).
  • IndexNow: changed pages are pushed to Bing, Yandex, Seznam, Naver and Yep instead of waiting for a crawl — every push touching plots/ submits the affected spec and implementation URLs (#11202).
  • The bot-serving monitor now raises an alarm instead of only turning a tab red, and derives what it asserts from the repo — a failing run opens an issue; it had sat red for ten consecutive nights unnoticed (#11209).

Changed

  • anyplot-api runs as a single instance: min 1, max 1, concurrency 40 — between 2026-08-29 and 09-10 Cloud Run started 464 extra instances, each cold start paid for by a live request; the frontend follows at max 1, concurrency 80 (#11828, #11829).
  • Search results for a plot now name its languages and its other libraries — hub titles read {title} in Python, R, Julia and JavaScript, implementation pages {title} in plotnine (Python) (#11844).
  • The frontend deploys through a candidate revision instead of straight onto live traffic — smoked on its tag URL, then promoted exactly; the API deploy got the same net (#11207, #10821).
  • The API image is built in two stages and loses more than half its weight — 1.62 GB to 693 MB; a .dockerignore that is actually read and shipped bytecode followed (#10821, #11211).
  • The site's typeface is MonoLisa 3.000: MonoLisa Code everywhere, MonoLisa Text registered for experiments — the webfont CSS is now generated, so the next font update is a re-run (#11836).
  • Every PR now adds a changelog.d/ fragment instead of a bullet in CHANGELOG.md — the shared [Unreleased] spot stops producing sibling-PR conflicts, and a CI gate enforces it (#11215).
  • The scheduled regen runs once a day instead of ten times — 02:17 UTC, re-enabled after the gap backfill (#11848).

Fixed

  • OG cards render MonoLisa's italic swashes in production again — the API image installs libraqm0; the guard added on the way had blocked every API deploy for two days (#10813, #10821).
  • Infrastructure failures no longer spend a pair's generation budget — the Claude outage of 2026-09-02 had burned all three attempts of 27 pairs in twenty minutes (#11199).
  • Implementation pages no longer share one meta description per spec — 4,254 plot pages had about 334 distinct descriptions (#11203).
  • Google had no clean image to show as a result's thumbnail — primaryImageOfPage now points at the render itself (#11844).
  • Google showed no icon for anyplot.ai — the bot HTML declares the icons and a real favicon.ico ships (#11838).
  • Coverage matrix on the stats page counted against 9 libraries instead of 15 — the denominator now comes from the registry (#11835).

Security

  • The site's own origin has a gate now, and it ships switched off — anyplot-app's nginx refuses what the edge did not stamp, armed by measurement rather than a leap (#11221).
  • script-src drops 'unsafe-inline' for a per-request nonce — Cloudflare copies the nonce onto its injected detection script, which no hash could ever cover (#11220).
  • The origin gate loses its last real exemption: the cache flush now carries the edge's header instead of being waved through (#11214).

Full Changelog: v3.2.0...v3.3.0