Skip to content

Prevent prepack builds from racing during recursive packing #973

Description

@dahlia

Background

The build-packages job is flaky because recursive packing starts overlapping builds that write to the same dist directories. The failures block npm package artifacts even though the test and initial build steps have passed.

Before packing, .github/workflows/main.yaml builds every non-example workspace package once with pnpm -r --filter='!./examples/**' run build:self. It then runs pnpm pack --recursive with enable-pre-post-scripts=true. Packing invokes each package's prepack script, and most packages implement prepack as pnpm build. Those build scripts use selectors such as @fedify/relay..., so each invocation rebuilds the package and its workspace dependencies. Several independent packing workers can therefore clean and regenerate the same dependency output at once.

Pack lifecycle scripts were enabled in c87db61 so that @fedify/fedify could materialize skills/fedify/SKILL.md before creating its tarball. Disabling every lifecycle script would bring that packaging bug back, so the fix needs to preserve the skill preparation without allowing concurrent builds to share output directories.

Evidence

The latest failure occurred in the build-packages job. While @fedify/relay was bundling src/mastodon.test.ts, tsdown could not resolve the @fedify/vocab-runtime workspace package:

[UNLOADABLE_DEPENDENCY] Could not load ../vocab-runtime/dist/mod.js
No such file or directory (os error 2)

The same log shows @fedify/vocab-runtime reporting Cleaning 92 files repeatedly during the pack step. One cleanup started at 09:11:52 UTC, and the relay build failed to read dist/mod.js at 09:11:55 UTC. The same error appeared in an earlier July 29 run and a July 26 run, while the identical command succeeded on July 27. The timing-dependent result makes this a build race rather than a consistently missing artifact.

This is related to #634, which fixed one manifestation by externalizing @fedify/fixture from test bundles. The new failure involves @fedify/vocab-runtime and shows that the underlying concurrent rebuild problem remains.

Reproduction

On a clean checkout with Node.js 22 and pnpm 10.28.0, run the same build and pack commands as CI:

mise deps
pnpm -r --filter='!./examples/**' run build:self
pnpm pack --recursive --filter='!./examples/**' \
  --config.enable-pre-post-scripts=true

The race does not occur on every run, so the pack command may need to be repeated.

Expected behavior

Recursive packing should produce all npm tarballs deterministically after the workspace has been built. It should not rebuild the same output directory from concurrent lifecycle scripts. The @fedify/fedify tarball must still contain skills/fedify/SKILL.md.

Possible direction

The packaging path should ensure that only one build writes each dist directory. We could serialize package packing, or separate the one-time workspace build and Fedify skill materialization from the lifecycle scripts used by pnpm pack. .github/workflows/main.yaml and .github/workflows/publish-pr.yaml should use the same race-free path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions