fix: keep pnpm's package store out of the release builder's clean-source check
CI / verify (pull_request) Successful in 1m4s
CI / infrastructure-smoke (pull_request) Successful in 37s
CI / migration-smoke (pull_request) Successful in 1m54s
CI / package-release (pull_request) Successful in 32s
CI / image-build (pull_request) Successful in 30s
CI / deploy-smoke (same-origin) (pull_request) Successful in 50s
CI / deploy-smoke (split) (pull_request) Successful in 1m32s

The package-release job failed its clean-tree assertion in CI. Reproduced
as root in a container with a bind-mounted checkout, as the Gitea runner
does: after checkout the tree is clean; `pnpm install --frozen-lockfile`
then creates `.pnpm-store/` (17,272 untracked files) at the checkout's
root, because pnpm keeps its store on the node_modules file system and
the checkout is its own mount; `pnpm build` changes nothing. No tracked
file is ever modified.

- `.pnpm-store/` is ignored, like node_modules: a package cache, never
  source. The clean-commit requirement is unchanged for every tracked
  file and every untracked file Git does not ignore.
- The clean-tree failure now lists `git status --short` and
  `git diff --stat`.
- Nothing is built before the clean-source assertion: the gate no longer
  runs a global `pnpm build` first. The builder asserts a clean tree,
  builds, then fails if its build changed the tree, before packing. Core's
  verifier is built after both releases, for the consumer proof only.
- Every secondary offline install (the second worktree, the consumer
  module) uses the workspace install's own store explicitly, since pnpm
  picks a store per file system and those directories are on another.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-10-08 08:43:19 -05:00
co-authored by Claude Opus 5.5
parent 9debe4e891
commit 4f1b1d68c7
7 changed files with 80 additions and 17 deletions
+14 -7
View File
@@ -63,12 +63,18 @@ pnpm packages:release # writes .package-release/ekklesia-packages-<vers
`scripts/package-release.ts`:
1. **Refuses a modified source tree.** A release is built from a commit. `--allow-modified` exists
for local development only; its manifest then says `"modified": true`, and such a release must
never be published.
1. **Refuses a modified source tree, before it builds anything.** A release is built from a
commit. A tree is clean when `git status` shows no change to a tracked file and no untracked file
that Git does not ignore. Ignored files are build output and package-manager state:
`node_modules`, `dist`, `.turbo`, and pnpm's `.pnpm-store`, which pnpm creates at the checkout's
root when the checkout is its own mount (a CI runner's workspace volume). The failure lists every
change. `--allow-modified` exists for local development only; its manifest then says
`"modified": true`, and such a release must never be published.
2. **Checks the release set and versions** in the workspace.
3. **Rebuilds from clean output.** It removes each public package's `dist/` and rebuilds without the
build cache, so output from a deleted source file can never ship.
build cache, so output from a deleted source file can never ship. It then checks the source tree
again: a build that changed a tracked file, or wrote an untracked one Git does not ignore, fails
the release, because what is packed must be exactly the commit.
4. **Packs each package with `pnpm pack`.** Pack-only pnpm hooks (`scripts/lib/pack-hooks.cjs`)
apply, never the workspace's install settings ([Reproducibility](#reproducibility)).
5. **Inspects every tarball.** It checks:
@@ -127,11 +133,11 @@ depend only on the commit.
pnpm test:package-release # scripts/test-package-release.sh
```
1. **Builds the train** from this checkout.
1. **Builds the train** from this checkout. Nothing is built before it.
2. **Builds it again** from a second worktree of the same commit at another absolute path, and
requires both release directories to be byte-identical: every tarball, `SHA256SUMS`, and the
manifest.
3. **Runs the standalone consumer proof** (`scripts/test-standalone-module.sh --release <dir>`) on
3. **Builds Core's verifier**, then **runs the standalone consumer proof** (`scripts/test-standalone-module.sh --release <dir>`) on
that release:
- **The release is checked first.** Every artifact must match the manifest's size, SHA-256, and
integrity, and the release must not be built from a modified tree.
@@ -139,7 +145,8 @@ pnpm test:package-release # scripts/test-package-release.sh
`tests/fixtures/standalone-module`, copied outside the repository. Every `@ekklesia/*`
package, direct or transitive, resolves to its release tarball. There is no workspace link and
no Ekklesia source checkout. The install runs offline: third-party packages come from the
local pnpm store, so no registry is involved at all.
workspace install's own pnpm store, named explicitly because pnpm otherwise picks a store per
file system, so no registry is involved at all.
- **The lockfile matches the release.** It must record each artifact's own integrity. The module
then reinstalls from the lockfile alone with `--frozen-lockfile`.
- **The install has the right shape.** There is no `drizzle-orm`, and exactly one `react`, which