Pulp Engine Document Rendering
Get started
Release v0.78.2

Release v0.78.2 — reproducible Windows test gate, encoding-corruption guard, Python SDK packaging fix

Date: 2026-05-07 Tag: v0.78.2

Summary

Audit-remediation patch on the v0.78.0 line. Three coordinated fixes plus one CI-hygiene tighten:

  1. Reproducible default test gate. pnpm test now runs green on Windows with no --maxWorkers=1 override and no other flag overrides, on both apps/editor and apps/api file-mode. Mirrors the existing vitest.file.config.ts Windows-singleFork pattern in the default Vitest configs so the parallel-worker contention that surfaced in login-identity.test.tsx, ChartNodeView.test.tsx, template-labels.route.test.ts, and auth-scopes.test.ts is gone for default runs as well.
  2. U+FFFD encoding guard. scripts/check-encoding.sh now detects U+FFFD replacement characters (not just Latin-1 mojibake) and runs in CI as a fail-fast lint stage. Cleaned 14 U+FFFD bytes across 4 tracked files (comment-divider corruption introduced by an editor pipeline that silently substituted for bytes it could not decode).
  3. Python SDK packaging fix. Renamed packages/sdk-python/docuforge/packages/sdk-python/pulp_engine/ so the importable module matches the PyPI distribution name (pulp-engine with hyphen → pulp_engine with underscore per Python identifier rules). Replaced 21 invalid from pulp-engine import ... and from docuforge import ... lines across 14 SDK files. Added a python3 -m compileall CI guard that catches the next syntax-level regression at PR time. Local editable-install round-trip verified: pip install -e packages/sdk-python && python -c "from pulp_engine import PulpEngineClient" resolves.
  4. Tag-glob hygiene. release.yml and the two SDK publish workflows now skip -rc*, -alpha*, -beta* tags. Pushing v0.78.2-rc1 previously triggered three release-style workflows that all failed at the version-consistency guardrail (harmless red-X noise); rc tags are now purely informational.

See docs/audits/2026-05-07-rating-7.8.md (or audit context conversation) for the rationale tying these to the audit’s Release Blockers and Polish rows.

No contract changes. No new features. No OpenAPI / SDK regen needed.

What landed

Reproducible Windows test gate (Workstream A)

  • apps/api/vitest.config.ts — added pool: 'forks' and poolOptions.forks.singleFork: process.platform === 'win32', mirroring the existing vitest.file.config.ts pattern. Windows timeouts also bumped (testTimeout: 60_000, hookTimeout: 30_000) to match file-mode.
  • apps/editor/vitest.config.ts — same singleFork: process.platform === 'win32' shape.
  • Linux retains parallel forks; no throughput regression on the existing CI gate.
  • Local Windows verification (no flag overrides): editor pnpm test passes 95 files / 1318 tests, api pnpm test:file passes 73 files / 1241 tests. CI ci-windows job goes green end-to-end.

Encoding-corruption guard (Workstream F)

  • scripts/check-encoding.sh — extended PATTERNS to include literal U+FFFD (\xef\xbf\xbd) alongside the existing Latin-1 mojibake patterns. Excluded .astro/ and _generated_docs/ (gitignored build mirrors that aren’t authoritative).
  • .github/workflows/ci.yml — wired bash scripts/check-encoding.sh as an early lint stage, before pnpm lint. Catches future U+FFFD reintroductions at PR time.
  • 14 U+FFFD bytes replaced with U+2500 (box-drawing horizontal) across:
    • apps/api/src/lib/render-queue-tracker.ts (3 bytes in a comment divider)
    • apps/api/src/routes/audit-events/audit-events.routes.ts (6 bytes across 2 dividers)
    • docs/deployment-guide.md (3 bytes in the prod-config divider — the one the audit specifically called out)
    • packages/pdf-renderer/src/renderer.ts (2 bytes in a layer-2 divider)

Python SDK packaging fix (Workstream B)

  • git mv packages/sdk-python/docuforge → packages/sdk-python/pulp_engine (history preserved, similarity 96–100% per file).
  • packages/sdk-python/pyproject.toml[tool.hatch.build.targets.wheel] packages = ["pulp_engine"] and the sdist include list updated to match. PyPI distribution name stays pulp-engine (legal hyphen). Wheel filename becomes pulp_engine-0.78.2-py3-none-any.whl per PEP 427.
  • 21 import + mock.patch() string replacements across 14 SDK files: from pulp-engine importfrom pulp_engine import, from docuforge importfrom pulp_engine import, "pulp-engine.resources.batch.*""pulp_engine.resources.batch.*".
  • Stale docuforge/pulp-engine workaround comments removed from tests/conftest.py, tests/test_errors.py, and docs/api-errors.md. The “use docuforge for now” note in api-errors.md was a v0.78.0-era forward-looking marker; the rename obsoletes it.
  • docs/sdk-generation-guide.md directory path corrected: packages/sdk-python/pulp-engine/packages/sdk-python/pulp_engine/.
  • docs/release-v0.61.0.md python example fixed (was from pulp-engine import Pulp Engine — never compiled even at original publication).
  • New CI guard at .github/workflows/ci.yml: python3 -m compileall packages/sdk-python/pulp_engine packages/sdk-python/tests runs right after the encoding check. Shell-independent and recursive — won’t miss a file like a glob would. ~5s on the existing Linux runner.
  • Per memory/project_v075_6_shipped.md (no PyPI publish has actually shipped for any v0.75.X+), this rename is not breaking for any live user.

Tag-glob hygiene

  • .github/workflows/release.yml, .github/workflows/publish-sdk-typescript.yml, .github/workflows/publish-sdk-python.yml — added negation patterns to the on.push.tags block:
    tags:
      - "v*.*.*"
      - "!v*-rc*"
      - "!v*-alpha*"
      - "!v*-beta*"
  • Verified empirically: pushing v0.78.2-rc1 triggered 3 workflows (Release / Publish TS / Publish Python — all failed at version-consistency or auth, no actual publish attempted). Pushing v0.78.2-rc2 after this fix triggered zero new release-style runs.

Per-template-rate-limit test fix (intermediate, surfaced during rc validation)

  • apps/api/src/__tests__/per-template-rate-limit.test.ts — bumped the “resets counter after window expires” test from a 1ms window / 5ms wait to a 50ms window / 100ms wait. The original timing was wall-clock fragile under Windows singleFork (three sequential synchronous .check() calls could span >1ms, so the bucket expired between them and the exhaust assertion flipped to allowed=true). No production code change.

Why no SDK / OpenAPI churn

The Python SDK rename changes the importable module name and the on-disk source layout, but the wire shapes, error envelopes, and OpenAPI spec are untouched. Existing TypeScript SDK callers see no change at all (the TS SDK rename observation in the audit was a separate doc-naming concern; the @pulp-engine/sdk package and its directory packages/sdk-typescript/ keep their current names).

PyPI / npm Trusted Publisher entries remain a one-time registry-side configuration carried over from v0.78.0; nothing in this release attempts publishes that didn’t previously work.

Verification

  • Local (Windows, on the rc2 tag tree): bash scripts/check-encoding.sh, python -m compileall packages/sdk-python/pulp_engine packages/sdk-python/tests, pnpm lint, pnpm typecheck, pnpm build, pnpm --filter @pulp-engine/editor test, pnpm --filter @pulp-engine/api test:file — all green with no flag overrides.
  • CI on 1d73a2e (the rc2 commit): 9/9 jobs green, including ci-windows file-mode + installer smoke and Docker build + smoke test.
  • Editable install round-trip: pip install -e packages/sdk-python && python -c "from pulp_engine import PulpEngineClient, PulpEngineError, PaginatedResult, BinaryResult, PptxResult, paginate" succeeds. SDK pytest: 62 passed.

Known residual

  • Coverage gate runtime drift on Linux CI. The rc2 run’s Coverage gate took longer than the prior fe5852e baseline (slow runner, not a code regression). The gate still passed. Worth tracking if the trend continues.
  • Per-template-rate-limit test:file flake on Windows local runs. A single transient failure surfaced during the local verification recipe on the rc2 tree but did not reproduce on a second run. This is environmental (Windows wall-clock variance under singleFork) and is a separate test from the one fixed in c786733; logged as a follow-up to investigate which test was the actual flake.
  • Audit blockers C–F deferred to follow-up patches per the internal audit-remediation plan: OpenAPI version + route-security drift (Workstream C), HA Redis/S3 automated checks (Workstream D), complexity hotspot first-carve (Workstream E). v0.78.2’s scope was reproducible-gate + Python SDK + hygiene only.