Follow-up to #11583. The post-resolution gate added there re-hits the
registry on every install for every locked (name, version) pair, which
is expensive on warm/repeat installs where the lockfile hasn't moved.
If we are going to keep this gate on, I have the following requirements
to maximize performance.
1. Global per-lockfile cache of verified results
Store one record per lockfile path at
<cacheDir>/minimum-release-age-verified.json:
{
"/absolute/path/to/pnpm-lock.yaml": {
"lockfileHash": "<sha256 of pnpm-lock.yaml>",
"minimumReleaseAge": 1440,
"verifiedAt": "2026-05-14T...",
"lockfileFileSize": 154,
"lockfileMtimeNs": "1736245123000000000",
"lockfileInode": 12345
}
}
On install:
- Look up the record by lockfile absolute path. If there is no record,
run the gate.
- Stat the lockfile. If size, mtime and inode all match the cached
values, trust it and skip the hash. Zero registry calls.
- If size differs, guaranteed miss, run the gate.
- Otherwise (size matches but mtime/inode differ - typical after a
fresh CI checkout where the cache was restored), hash the file. If
the hash matches lockfileHash and current minimumReleaseAge <= cached minimumReleaseAge, skip the gate and refresh the stat
fields on the record so future installs hit the fast path.
- Otherwise run the gate and record the new hash + stat fields.
lockfileMtimeNs and lockfileInode are only meaningful on the same
machine; CI runners reset them on every checkout. That is fine: in CI
we fall back to the hash check, which is portable. The stat-cache
layer is the local-dev fast path; the hash is the source of truth.
We should recommend uploading this file as part of the CI cache.
File format / concurrency
Use JSON Lines (newline-delimited) rather than a single JSON object,
so new records can be appended without parsing and rewriting the whole
file. Appends of a single line on POSIX/NTFS are atomic, so concurrent
pnpm processes (parallel monorepo installs, CI matrices sharing a
cache) can write without locking - on read, the latest record per
lockfile path wins.
Cap the file at e.g. ~1000 entries; when adding a record past the cap,
rewrite the file keeping the N most recently verified.
If we are going to add this, we might as well do other lockfile-state
checks through the same cache when it makes sense.
2. Try the attestation endpoint before fetching full metadata
When verifying dates, if there is no package document in the local
cache, first request the attestation from the registry
(e.g. https://registry.npmjs.org/-/npm/v1/attestations/pnpm@11.1.1).
This is a much smaller payload than the full metadata document, but
it requires Sigstore signature verification and is only available for
packages published with provenance, so fall back to fetching full
metadata for unattested packages.
Caveat
Public benchmarks will show pnpm significantly slower in the
cold-cache, up-to-date-lockfile scenario. There is no way around
per-package round trips on a fresh CI runner with no restored cache;
the optimizations above target steady-state, not cold start.
Written by an agent (Claude Code, claude-opus-4-7).
Follow-up to #11583. The post-resolution gate added there re-hits the
registry on every install for every locked (name, version) pair, which
is expensive on warm/repeat installs where the lockfile hasn't moved.
If we are going to keep this gate on, I have the following requirements
to maximize performance.
1. Global per-lockfile cache of verified results
Store one record per lockfile path at
<cacheDir>/minimum-release-age-verified.json:{ "/absolute/path/to/pnpm-lock.yaml": { "lockfileHash": "<sha256 of pnpm-lock.yaml>", "minimumReleaseAge": 1440, "verifiedAt": "2026-05-14T...", "lockfileFileSize": 154, "lockfileMtimeNs": "1736245123000000000", "lockfileInode": 12345 } }On install:
run the gate.
values, trust it and skip the hash. Zero registry calls.
fresh CI checkout where the cache was restored), hash the file. If
the hash matches
lockfileHashand currentminimumReleaseAge <= cached minimumReleaseAge, skip the gate and refresh the statfields on the record so future installs hit the fast path.
lockfileMtimeNsandlockfileInodeare only meaningful on the samemachine; CI runners reset them on every checkout. That is fine: in CI
we fall back to the hash check, which is portable. The stat-cache
layer is the local-dev fast path; the hash is the source of truth.
We should recommend uploading this file as part of the CI cache.
File format / concurrency
Use JSON Lines (newline-delimited) rather than a single JSON object,
so new records can be appended without parsing and rewriting the whole
file. Appends of a single line on POSIX/NTFS are atomic, so concurrent
pnpm processes (parallel monorepo installs, CI matrices sharing a
cache) can write without locking - on read, the latest record per
lockfile path wins.
Cap the file at e.g. ~1000 entries; when adding a record past the cap,
rewrite the file keeping the N most recently verified.
If we are going to add this, we might as well do other lockfile-state
checks through the same cache when it makes sense.
2. Try the attestation endpoint before fetching full metadata
When verifying dates, if there is no package document in the local
cache, first request the attestation from the registry
(e.g.
https://registry.npmjs.org/-/npm/v1/attestations/pnpm@11.1.1).This is a much smaller payload than the full metadata document, but
it requires Sigstore signature verification and is only available for
packages published with provenance, so fall back to fetching full
metadata for unattested packages.
Caveat
Public benchmarks will show pnpm significantly slower in the
cold-cache, up-to-date-lockfile scenario. There is no way around
per-package round trips on a fresh CI runner with no restored cache;
the optimizations above target steady-state, not cold start.
Written by an agent (Claude Code, claude-opus-4-7).