Pulp Engine v0.36.0 — Release Notes
This release fixes the version-history lazy boundary in the editor: the modal now mounts on-demand when the user opens it, eliminating hidden API traffic and adding an explicit loading state in place of the previous invisible fallback.
What changed
1. Version-history modal is now genuinely on-demand
Before: VersionHistoryModal was mounted into the React tree as soon as any
API-backed template was open (gated on isApiTemplate, not on the user actually
opening the history panel). Its data-fetch effect ran on every templateKey /
currentVersion change — even while the modal was closed — producing hidden API
calls that the user never requested.
After: The component only mounts when the user opens version history
(showHistory && template && isApiTemplate). The data-fetch effect also carries an
explicit open guard (if (!open) return) as a secondary safety for future
refactors.
Net effect: no version-list API calls until the user clicks History.
2. Explicit loading state instead of invisible Suspense fallback
The Suspense boundary for the lazy VersionHistoryModal chunk previously used
fallback={null}, so the first-time code-split download produced no visible
feedback.
After: The fallback renders an open dialog shell with a spinner and the title “Version History”, matching the style of the component that is about to appear.
The internal “Loading…” text shown while the version list is fetched now also
includes a spinner, consistent with the style used in PublishGateDialog.
3. Close/reopen behavior
Each open now triggers a fresh version-list fetch rather than reusing data pre-loaded while the modal was closed. This is the correct behavior — it ensures the list always reflects the current server state, including any saves made since the last open.
4. Documentation — auth/trust-model corrections in api-guide and runbook
A doc-truth audit found three drifted statements in the auth/trust-model sections:
-
docs/api-guide.md— renderConfig trust model, “These fields can be set via” Was:POST /templatesandPUT /templates/:key— requireadminscope Now:POST /templatesandPUT /templates/:key— requireeditororadminscope Justified by:apps/api/src/plugins/auth.plugin.ts:53—return ['admin', 'editor']for all non-DELETE, non-restore template routes. The old text contradicted both the code and the authorization matrix earlier in the same document. -
docs/api-guide.md— renderConfig table,customCsstrust level column Was:Trusted authors / preview callersNow:Template authors (\editor` or `admin`) / preview callersThe phrase "trusted authors" was ambiguous and could be read as admin-only. The code applies no scope restriction tocustomCssbeyond the route-level check atauth.plugin.ts:53`. -
docs/runbook.md— “Verify templates” section, GET examples Was:(admin key required)on theGET /templatesandGET /templates/:key/samplecurl examples. Now:(admin or editor key)The adjacentPOST /render/validateexample already correctly said “(editor or admin key)”; the GET comments were inconsistent. Justified byauth.plugin.ts:53.
No code changes. No migration required.
5. Accessibility — publish dialog accessible description
PublishGateDialog was missing a DialogDescription, causing Radix UI to emit a
console warning on every open of the publish/update flow.
After: A visually-hidden (sr-only) DialogDescription is now rendered inside the
dialog header, satisfying Radix’s accessibility requirement and giving screen readers a
static description of the dialog’s purpose. The visible UI is unchanged.
6. README — commercial positioning pass
Repositioned README.md for a developer product audience. No content was removed; sections were reordered to lead with value proposition, quick start, and API demo before deployment detail. Specific changes:
- Opening rewritten: removed “for internal engineering teams” framing; replaced with a plain developer-facing value proposition
- New “What’s included” section added after the opening
- New “How it works” paragraph added (editor → storage → render API story)
- Docker quick start and local quick start moved above storage/security detail
- API demo (“API at a glance”) moved up to follow “How it works”
- “Storage modes” section renamed to “Storage backends”
docs/runbook.mdH1 updated: “First Internal Deployment Runbook” → “Operator Runbook”
No code changes. No API changes. No migration required.
Upgrade
No server-side changes. Editor-only fix; no environment variables, no schema migrations.
docker pull ghcr.io/OWNER/pulp-engine:v0.36.0