Pulp Engine Document Rendering
Get started
Release v0.76.1

Release v0.76.1 — audit remediation + post-closure CI firefight

Date: 2026-04-24 Tag: v0.76.1

Summary

First release to ship the three audit-remediation batches (docs credibility, hermetic local tests, polish + instrumentation) plus the five CI-firefight fixes that landed after the audit arc closed. No breaking product changes; no schema or CLI changes.

v0.76.0 was tagged without a preceding version-bump commit and was permanently burned at the check-version.mjs gate — all five release workflows failed in 3–4 seconds each, no artifacts published anywhere. Per tag-immutability policy, v0.76.0 is a dead tag; v0.76.1 is the first actually-shipping release on this line.

What landed

Batch 1 — docs credibility (commit bd06082)

  • docs/deployment-guide.md env tables gained an explicit Default column, pulled from the Description prose and matched against apps/api/src/config.ts. Previously the Example column was being misread as the default by buyers. Three defaults that had drifted were corrected: NODE_ENV = development (image: production), OIDC_REDIRECT_URI is Required-when-OIDC-enabled, OIDC_AUTO_PROVISION = true.
  • Go SDK consumer-install docs (docs/sdk-generation-guide.md row and packages/sdk-go/README.md banner) now describe the public mirror as “first-publish pending” with the exact Repository not found symptom, instead of promising a live go get path. Two bugs in the Go recipe fixed: packageName=pulp-enginepackageName=pulpengine (Go identifiers reject hyphens), and the stale rewriteGoModule function reference → the actual postProcess hook in generate-sdks.ts.
  • All four shipped SDK READMEs (TypeScript, Python, Go, .NET) gained a “Preview routes in production” subsection that explains the PREVIEW_ROUTES_ENABLED gate and points at GET /capabilities as runtime truth. The production-endpoint list was corrected from POST /render/pdf (doesn’t exist) to the real surface (POST /render + per-format routes).
  • Python SDK README’s bad repo link (github.com/anthropics/pulp-engine) fixed to github.com/TroyCoderBoy/pulp-engine.
  • .claude path leaks removed from 4 source docs that were publishing to the website and 404-ing in production. New content-gate in apps/website/scripts/sync-docs.mjs fails the website build on regression.

Batch 2 — hermetic local tests (commit 0620c59)

  • apps/api/src/__tests__/setup/env-isolation.setup.ts widened to strip REDIS_URL, RATE_LIMIT_STORE, RATE_LIMIT_FAIL_OPEN (prevents a populated dev REDIS_URL from flooding the API suite with 429s). Swapped the stale OIDC_ISSUER entry for the real enable flag OIDC_DISCOVERY_URL that’s actually read by config.ts.
  • New apps/api/README.md with honest local test-loop setup. Documents the actual dotenv -e ../../.env -- vitest run contract, uses the exact CI Docker shape for the throwaway Postgres container (postgres:16, POSTGRES_DB=pulp-engine), and explicitly calls out ephemeral per-run DB provisioning as a non-goal.
  • Editor test determinism: apps/editor/vitest.config.ts switched to pool: 'forks' (Vitest 4 shape matching apps/api/vitest.file.config.ts), plus a new apps/editor/src/test-setup.ts with a defensive afterEach that calls cleanup() gated on document presence and localStorage?.clear?.() / sessionStorage?.clear?.() with optional chaining so tests that stub storage with minimal objects don’t throw. Resolves the cross-file jsdom contamination that was producing getMultipleElementsFoundError in login-identity.test.tsx under the default threads pool.

Batch 3 — polish + instrumentation (commit d0905b9)

  • Licence copy alignment across README.md and three marketing pages (pricing.astro, features.astro, get-started.astro). Each mention of licence-key behaviour gains a short honest disclosure: the current gate is a presence check on PULP_LICENCE_KEY, cryptographic validation is on the roadmap, removing the watermark remains a licence breach regardless of technical means. EVALUATION-LICENCE.md untouched — the legal text is interpretable in a way that’s compatible with current code behaviour.
  • New docs/initiatives/signed-licence-v1.md — single anchor for the disclosures above, describing current enforcement, target enforcement, and why it’s deferred.
  • Windows installer smoke gained bootstrap diagnostics. installer/scripts/start-pulpengine.ps1 writes timestamped phase markers to %APPDATA%\PulpEngine\logs\bootstrap.log (entry, env-load, chromium-resolve, chromium-resolved, pre-spawn, spawned); resolved Chromium path is logged before the existence check. .github/workflows/ci.yml’s /health/ready timeout block appends Get-Process node / Get-NetTCPConnection / Get-CimInstance Win32_Process captures to the same log, defensively creating $LogDir if it’s missing. All of this rides the existing ci-windows-logs artifact upload. continue-on-error: true on the Start step is preserved — this batch adds visibility, not gating.
  • Editor bundle visualizer wired in behind VITE_BUNDLE_REPORT=1 env gate. Default-off. Initial measurement: bwip-js (1400 KB rendered / 258 KB gzip) and exceljs (1287 KB / 278 KB gzip) together account for ~85% of the vendor bucket; both have independent lazy boundaries and are candidates for a future named-chunk promotion.

Ops ticket (commit 41ef7c6)

  • docs/initiatives/go-mirror-first-publish.md — one-time operator prerequisites to un-404 github.com/TroyCoderBoy/pulp-engine-go. Sync script and workflow were already built; only the public mirror repo + PULP_ENGINE_GO_MIRROR_TOKEN Actions secret are pending. Fully actionable without reopening any code.

Post-closure CI firefights (commits 6bb4b01 · 68d6638 · 2ce51da · d9009e7)

  • Prisma 6.19.3 upstream packaging regression — the CLI shipped with a 7.x Wasm engines bundle, which rejected the datasource { url = env("DATABASE_URL") } form our schema uses. Every CI job with a clean pnpm install --frozen-lockfile failed at the apps/api postinstall hook with Prisma CLI Version : 7.8.0 (the 6.x CLI loading the 7.x engine). Pinned both prisma and @prisma/client to exact 6.18.0; re-resolved lockfile has matching @prisma/engines-version@6.18.0-8.34b5a692.... The db:generate / db:migrate / db:deploy scripts also gained a pnpm exec prefix to force workspace-local binary resolution regardless of shell PATH.
  • Website test Response helpers in the playground suite were wrapping bodies in new Blob([...]) which tripped a jsdom/undici/Node-Blob realm mismatch on CI Linux (TypeError: object.stream is not a function). Switched to string bodies with explicit Content-Type headers; the Fetch spec guarantees response.blob().type comes from Content-Type so assertions remained valid.
  • plugin-storage-activation.test.ts briefly un-parked during Batch 3 diagnostic pass (3× green local runs), then re-parked after CI Windows reproduced the failure on the next run. CI gave us the concrete diagnostic the earlier “cross-file state pollution” hypothesis missed — the test’s fake plugin calls ctx.templateStore.list() inside its activation function at line 188, which plugin-system.plugin.ts:293’s assertStoreReady explicitly forbids. Timing-sensitive, not deterministically broken; GH Actions Windows’ slower disk I/O races reliably into the failure window. Parked until the test plugin is fixed; tracked in docs/initiatives/file-mode-wip-followups.md.

Operational posture

  • v0.76.0 is burned. Tag exists on origin pointing at d9009e7, which still has 0.75.8 in all package.json files. All 5 release workflows (Release, Publish {TypeScript, Python, Go, .NET} SDK) failed at the check-version.mjs gate in 3–4 seconds. No GitHub Release exists for v0.76.0; no npm, PyPI, NuGet, or GHCR artifacts published. The tag is permanent per the repo’s tag-immutability policy.
  • Cloudflare Pages (pulpengine.dev) auto-deploys from main and reflects every commit above — the Batch 3 licence-copy disclosure (“cryptographic validation”, roadmap link) is live on the pricing page.
  • v0.76.1 is the first tag to ship installer artifacts since v0.75.8. Go SDK publish will fail at the mirror-sync step until the Go-mirror ops ticket is executed; all other publishes are unblocked.

Verified before tagging

  • node scripts/check-version.mjs — all 9 version surfaces aligned at 0.76.1, tag matches, CHANGELOG section + link present, docs/release-v0.76.1.md exists.
  • pnpm --filter @pulp-engine/api typecheck — green.
  • pnpm --filter @pulp-engine/editor typecheck — green.
  • pnpm --filter @pulp-engine/website build — 110 pages, postbuild clean, .claude gate green.
  • pnpm --filter @pulp-engine/api test:file (with plugin-storage-activation.test.ts re-parked) — 73 passed, 8 skipped (81 files) · 1225 passed, 97 skipped (1322 tests). Matches pre-Batch-3 baseline.
  • pnpm --filter @pulp-engine/editor test — 5 consecutive runs in default parallel mode: all green (95 files, 1311 passed, 2 skipped, 0 failed).
  • pnpm --filter @pulp-engine/website test — 8 files, 60 tests, 0 failed.
  • pnpm sdk:generate — green; .NET csproj and sdk-go/version.go regenerated to 0.76.1.

Known residual (tracked, not blocking)

  • Go public mirror 404 until the ops runbook (docs/initiatives/go-mirror-first-publish.md) is executed.
  • plugin-storage-activation.test.ts parked in WIP_TESTS; tracked in file-mode-wip-followups.md with the concrete ctx.templateStore.list()-during-activation diagnostic.
  • Editor vendor chunk promotion for bwip-js and exceljs deferred; measurement infrastructure is in place to inform the split decision.