Context
Found by the v13.2 release rehearsal: the operator asked on 2026-10-06 to double-check the release scripts before the cut. publish.mjs ends with gh release create, and that release event runs .github/workflows/npm-publish.yml: npm ci, then npm publish, on a fresh checkout of the tag.
The Problem
On dev at 94ae5deb00, a clean worktree ran exactly the workflow's steps: npm ci, then npm pack, which runs the same prepack/prepare lifecycle as npm publish. The results:
- The tarball holds 0
dist/ files (5,985 files, 23.3 MB).
- A scratch consumer installed from it fails on
import('neo.mjs/buildScripts/util/templateBuildProcessor.mjs') with ERR_MODULE_NOT_FOUND … node_modules/neo.mjs/dist/parse5.mjs.
npm run check-package-contents on that tree exits 1 with "13 required entr(ies) missing from the npm tarball".
Control on the same tree, after npm run bundle-browser-deps (5.8 s):
- the guard passes, "all 13 required entr(ies) present";
- the tarball carries
dist/{parse5,marked,mermaid}.mjs, dist/highlight/ and dist/monaco/;
- the consumer import links.
The published 13.1.0 tarball also holds 0 dist/ files, but the re-includes landed after it (#17957, 2026-08-31). That makes 13.2.0 the first release meant to carry the bundles, and its notes say so in 📦 An Engine package a consumer can build. Published as the workflow stands, 13.2.0 breaks the dist/esm build of every consumer that installs it, along with any module that imports parse5 or marked at module scope. An npm version cannot be republished, so the fix would be a 13.2.1.
The Architectural Reality
- Design authority:
.npmignore, the authoritative header since #19223: "src/functional/util/HtmlTemplateProcessor.mjs imports this bundle by relative path, and buildScripts/util/templateBuildProcessor.mjs imports it at module scope — so an installed engine needs it to RUN the dist/esm build". REQUIRED_ENTRIES in buildScripts/util/check-package-contents.mjs lists the same 13 entries (#17943, closed by #17957).
dist/ is gitignored. A checkout holds no bundles until npm run bundle-browser-deps runs: bundle-parse5, bundle-marked, bundle-mermaid, bundle-monaco, build-highlightjs.
- Both PR-time checks run that step before they pack:
check-package-contents.yml and consumer-runtime-build.yml. npm-publish.yml does not. The checks therefore measure a package the publisher never builds.
- The premise that hid this is on record. #17957's session (
56bc214a-5b55-41a2-848a-cdfa372abbcd) added the bundle step to the check because "npm publish runs build-all (which bundles parse5) first". Only publish.mjs runs build-all, in the operator's checkout. npm publishes from CI's fresh checkout.
The Fix
.github/workflows/npm-publish.yml, between npm ci and npm publish:
- run: npm run bundle-browser-deps
- run: npm run check-package-contentsThe guard runs the real npm pack and fails on any missing required entry. A later drift then fails the publish before npm's immutable version is spent. A unit arm beside the guard's own spec (test/playwright/unit/buildScripts/checkPackageContents.spec.mjs) reads the workflow with js-yaml, following check-guard-ci-parity.spec.mjs, and pins both steps before npm publish in that job.
Acceptance Criteria
Out of Scope
- Which bundles the package declares: that is #18823's decision. This ticket makes the publisher produce whatever
.npmignore and REQUIRED_ENTRIES declare.
publish.mjs itself, and republishing 13.1.0.
Related
#17943 / #17957 (the re-includes), #18814, #19223 (prepack composition), #18872 (consumer-runtime check), #18823 (bundle-size decision), #14800 (13.2 notes; cut list).
Live latest-open sweep: checked the latest 20 open issues at 2026-10-06T11:07:47Z; no equivalent found.
A2A claim sweep: last 30 messages (all read-states); no overlapping claim.
MC sweep: "npm-publish.yml npm publish package missing dist parse5 bundle, bundle-browser-deps not run before publish, published tarball lacks bundles", 6 results; prior decision #17957 rested on the false premise quoted above; #18823 open and out of scope.
Own-assignment sweep: 3 open (#19413, #15000, #14800), none overlapping.
Origin Session ID: 40a3c119-6419-4e87-9248-002c686708fe
Retrieval Hint: "release rehearsal npm-publish dist bundles parse5 13.2"
Context
Found by the v13.2 release rehearsal: the operator asked on 2026-10-06 to double-check the release scripts before the cut.
publish.mjsends withgh release create, and that release event runs.github/workflows/npm-publish.yml:npm ci, thennpm publish, on a fresh checkout of the tag.The Problem
On
devat94ae5deb00, a clean worktree ran exactly the workflow's steps:npm ci, thennpm pack, which runs the sameprepack/preparelifecycle asnpm publish. The results:dist/files (5,985 files, 23.3 MB).import('neo.mjs/buildScripts/util/templateBuildProcessor.mjs')withERR_MODULE_NOT_FOUND … node_modules/neo.mjs/dist/parse5.mjs.npm run check-package-contentson that tree exits 1 with "13 required entr(ies) missing from the npm tarball".Control on the same tree, after
npm run bundle-browser-deps(5.8 s):dist/{parse5,marked,mermaid}.mjs,dist/highlight/anddist/monaco/;The published
13.1.0tarball also holds 0dist/files, but the re-includes landed after it (#17957, 2026-08-31). That makes 13.2.0 the first release meant to carry the bundles, and its notes say so in 📦 An Engine package a consumer can build. Published as the workflow stands, 13.2.0 breaks thedist/esmbuild of every consumer that installs it, along with any module that importsparse5ormarkedat module scope. An npm version cannot be republished, so the fix would be a 13.2.1.The Architectural Reality
.npmignore, the authoritative header since #19223: "src/functional/util/HtmlTemplateProcessor.mjsimports this bundle by relative path, andbuildScripts/util/templateBuildProcessor.mjsimports it at module scope — so an installed engine needs it to RUN the dist/esm build".REQUIRED_ENTRIESinbuildScripts/util/check-package-contents.mjslists the same 13 entries (#17943, closed by #17957).dist/is gitignored. A checkout holds no bundles untilnpm run bundle-browser-depsruns:bundle-parse5,bundle-marked,bundle-mermaid,bundle-monaco,build-highlightjs.check-package-contents.ymlandconsumer-runtime-build.yml.npm-publish.ymldoes not. The checks therefore measure a package the publisher never builds.56bc214a-5b55-41a2-848a-cdfa372abbcd) added the bundle step to the check because "npm publishrunsbuild-all(which bundles parse5) first". Onlypublish.mjsrunsbuild-all, in the operator's checkout. npm publishes from CI's fresh checkout.The Fix
.github/workflows/npm-publish.yml, betweennpm ciandnpm publish:- run: npm run bundle-browser-deps - run: npm run check-package-contentsThe guard runs the real
npm packand fails on any missing required entry. A later drift then fails the publish before npm's immutable version is spent. A unit arm beside the guard's own spec (test/playwright/unit/buildScripts/checkPackageContents.spec.mjs) reads the workflow withjs-yaml, followingcheck-guard-ci-parity.spec.mjs, and pins both steps beforenpm publishin that job.Acceptance Criteria
npm-publish.ymlrunsnpm run bundle-browser-depsand thennpm run check-package-contentsbeforenpm publish. Thereleaseandworkflow_dispatchtriggers share that one job.npm publish. The PR shows the red by mutation.neo.mjs@13.2.0listsdist/parse5.mjs.Out of Scope
.npmignoreandREQUIRED_ENTRIESdeclare.publish.mjsitself, and republishing 13.1.0.Related
#17943 / #17957 (the re-includes), #18814, #19223 (
prepackcomposition), #18872 (consumer-runtime check), #18823 (bundle-size decision), #14800 (13.2 notes; cut list).Live latest-open sweep: checked the latest 20 open issues at 2026-10-06T11:07:47Z; no equivalent found. A2A claim sweep: last 30 messages (all read-states); no overlapping claim. MC sweep: "npm-publish.yml npm publish package missing dist parse5 bundle, bundle-browser-deps not run before publish, published tarball lacks bundles", 6 results; prior decision #17957 rested on the false premise quoted above; #18823 open and out of scope. Own-assignment sweep: 3 open (#19413, #15000, #14800), none overlapping.
Origin Session ID: 40a3c119-6419-4e87-9248-002c686708fe
Retrieval Hint: "release rehearsal npm-publish dist bundles parse5 13.2"