Skipping DropShadows→Current entirely made flush_and_submit very
slow due to Skia ops-task ordering, but doing that empty blit on
every shape was wasted GPU work. Touch it once per tile when
shadows are skipped, and drop the redundant DropShadows clear.
Marking intermediate surfaces dirty after clearing them on tile
context switch made the first stack composite blit empty
Fills/Strokes/shadows into Current. Dirty means content to
composite, so clear the flags after the clear instead.
Partial frames only flushed the Backbuffer, so tile GPU commands
queued until present_frame's flush_and_submit and stalled the
browser on large files. Submit the context each partial frame
without presenting Target or re-composing the tile atlas.
Remove the guard in stop-devenv that refused to stop ws0 while any
ws1+ instance was running. Each workspace is now fully independent
and can be started/stopped in any order. Shared infra shuts down
only when no instances remain running.
Updated docs (devenv.md, agentic-devenv.md) and devenv memory to
reflect the new behavior.
AI-assisted-by: mimo-v2.5-pro
Never pipe test output directly to filters (head, tail, grep).
Always redirect to a file first to prevent hiding test failures.
AI-assisted-by: mimo-v2.5
Move Dockerfile.frontend, .backend, .exporter, .mcp and .storybook
under docker/images/ from ubuntu:26.04 / nginx-unprivileged / a
manual Node tarball install to Docker Hardened Images (Debian 13,
or Alpine for storybook). storybook and mcp get a true non-dev
runtime; frontend, backend and exporter keep the -dev tag as their
final image, since each needs a shell and/or package manager at
container runtime (nginx templating, fontforge/python3, and a
headless-browser stack, respectively).
Move docker/imagemagick/Dockerfile and docker/devenv/Dockerfile from
ubuntu:26.04 to Docker Hardened Images (Debian 13 / trixie).
imagemagick gets a true non-dev runtime with its shared libraries
vendored via ldd; devenv keeps the -dev tag as its final image since
it's an interactive development container, not a production
artifact.
MCP tokens now use a separate JWT issuer claim (`urn:penpot:mcp-token`) instead of `access-token`, preventing them from being validated as API access tokens.
Fixes#10960
AI-assisted-by: qwen3.7-plus
Production crash where @(get bounds id) threw
"No protocol method IDeref.-deref defined for type null"
when a shape ID had no corresponding entry in the bounds map
during layout calculations.
Added defensive nil guards (when-let / when) to all unprotected
bounds dereference sites:
- flex_layout/bounds.cljc: layout-content-points (parent + child)
and layout-content-bounds
- grid_layout/bounds.cljc: layout-content-points and
layout-content-bounds
- min_size_layout.cljc: child-min-width grid branch (3 sites) and
child-min-height grid branch
Added 7 new tests in geom_bounds_layout_nil_test.cljc covering all
nil-bounds edge cases for flex, grid, and min-size layout paths.
Registered in runner.cljc.
Closes#10843
AI-assisted-by: qwen3.7-plus
* 🐛 Fix main menu is covered by the toolbar
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of workspace context menu
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of tokens context menu
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of old context menu
* 📎 PR improvements