Skip to content

feat: report lockfile verification progress#11712

Merged
zkochan merged 6 commits into
mainfrom
lockfile-verify-report
May 18, 2026
Merged

feat: report lockfile verification progress#11712
zkochan merged 6 commits into
mainfrom
lockfile-verify-report

Conversation

@zkochan

@zkochan zkochan commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

The lockfile resolution verifier added in #11705 runs an unbounded registry round-trip on cache miss and was previously silent — on a cold registry cache the user sees nothing for several seconds, then either install resumes or an error appears. This wires user-visible progress around that pass.

  • New pnpm:lockfile-verification log (@pnpm/core-loggers) with status: 'started' | 'done', an entry count, and elapsed ms on done.
  • Verifier emits started/done around the actual fan-out in verifyLockfileResolutions. Emission happens only on the path that does real work; the cache hit, empty-verifiers, and empty-lockfile branches stay silent — no noise when nothing is happening.
  • New reportLockfileVerification in @pnpm/cli.default-reporter. One inner observable so the done message overwrites the transient started line in ansi-diff mode; in appendOnly (CI) both lines print.

Rendered output:

? Verifying lockfile (234 entries)...
✓ Lockfile verified (234 entries in 1.2s)

(Singular form 1 entry when there's only one.)

Pacquet parity

Not ported — pacquet doesn't carry the resolution-policy lockfile verifier yet (see the parity note on #11705). When pacquet ports the verifier, the equivalent log event will travel with it.

Test plan

  • pnpm --filter @pnpm/core-loggers run compile — clean
  • pnpm --filter @pnpm/cli.default-reporter run compile — clean
  • pnpm --filter @pnpm/installing.deps-installer run compile — clean
  • pnpm --filter pnpm run compile — bundle rebuilds cleanly
  • Manually exercised toOutput$ with synthetic started + done events; confirmed both messages render correctly with plural and singular entry counts
  • Added unit test cli/default-reporter/test/reportingLockfileVerification.ts — could not be executed in this environment because every test in the package errors out with the pre-existing Jest ESM module is already linked error (reproduced against unrelated existing tests on Node 22.22 and 24.15). Test will run in CI on the supported Node version.

Written by an agent (Claude Code, claude-opus-4-7).

Summary by CodeRabbit

  • New Features

    • Lockfile verification emits a transient "Verifying lockfile..." progress line, a completion message with entry count and elapsed time, and a brief failure line; cached no-op verifications remain silent. Messages pluralize correctly and include workspace-relative path only when helpful.
  • Refactor

    • Verification now deduplicates distinct lockfile entries before checking to avoid redundant work.
  • Tests

    • Coverage expanded for progress display, pluralization, elapsed-time formatting, path handling (including trailing-separator cases), and failure output.

Review Change Stack

The lockfile resolution verifier introduced in #11705 runs an unbounded
registry round-trip on cache miss and was previously silent — on a cold
registry cache users saw nothing for several seconds. Emit pnpm:lockfile-verification
log events (started/done) around the actual verification pass and render
them in the default reporter as a transient progress line that collapses
into a final "verified" summary with entry count and elapsed time. The
cached short-circuit stays silent.
Copilot AI review requested due to automatic review settings May 18, 2026 08:19
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c9adf793-b524-4fbd-8cb1-5d30f34bf066

📥 Commits

Reviewing files that changed from the base of the PR and between 66ef137 and 49a6633.

📒 Files selected for processing (1)
  • .changeset/lockfile-verification-progress-logs.md

📝 Walkthrough

Walkthrough

Adds a typed pnpm:lockfile-verification logger, emits started/done/failed progress events during lockfile verification using a deduplicated candidate set, routes those events through the default reporter with optional lockfile-path and elapsed-time formatting, and tests the rendered output.

Changes

Lockfile Verification Progress Logging

Layer / File(s) Summary
Logger type definitions
core/core-loggers/src/lockfileVerificationLogger.ts, core/core-loggers/src/all.ts, core/core-loggers/src/index.ts
Introduces lockfileVerificationLogger and typed message contracts for started (entries), done (entries, elapsedMs) and failed (entries, elapsedMs), and re-exports the types.
Reporter integration and rendering
cli/default-reporter/src/index.ts, cli/default-reporter/src/reporterForClient/index.ts, cli/default-reporter/src/reporterForClient/reportLockfileVerification.ts
Adds a lockfileVerification Subject/observable, implements reportLockfileVerification with optional at <relative-path> suffix and pretty-ms elapsed formatting, and wires it into reporterForClient.
Reporter output tests
cli/default-reporter/test/reportingLockfileVerification.ts
Tests started/done/failed frames, singular/plural wording, elapsed-time formatting, lockfile path inclusion/omission scenarios, and trailing-separator workspaceDir behavior.
Verification logging and candidate pipeline
installing/deps-installer/src/install/verifyLockfileResolutions.ts
Collects a deduplicated candidate Map via collectCandidates, emits started/done/failed debug logs with candidate counts and elapsedMs, skips verification when no candidates (cache fast path), and refactors iterateLockfileViolations to accept the candidate map; buildVerificationError now returns an error instance.
Changeset documentation
.changeset/lockfile-verification-progress-logs.md
Documents the new progress log events, default reporter transient rendering, and a Pacquet parity note.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • pnpm/pnpm#11583: Modifies the lockfile verification flow in verifyLockfileResolutions.ts; related to the candidate-based verifier changes.

Poem

🐰 I hopped through logs with nimble paws,

Started, then done — I counted the rows,
Entries tallied, time neatly shown,
A fleeting line to let users know,
Lockfile checks finished — tap, tap, toes!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: report lockfile verification progress' directly and accurately summarizes the main change: adding user-visible progress reporting for lockfile verification.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lockfile-verify-report

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds user-visible progress messages around the lockfile resolution verifier (introduced in #11705). The verifier emits started / done events on the path that actually performs the registry round-trip, and the default reporter renders them as a transient progress line.

Changes:

  • New pnpm:lockfile-verification log type in @pnpm/core-loggers with started / done variants (plus entry count and elapsed ms).
  • verifyLockfileResolutions factors out collectCandidates and emits started before the fan-out and done after a violation-free pass; cached/empty branches stay silent.
  • @pnpm/cli.default-reporter wires a new reportLockfileVerification reporter and a matching push stream in toOutput$, with unit tests for plural/singular rendering.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
core/core-loggers/src/lockfileVerificationLogger.ts New logger and message type definitions for verification progress.
core/core-loggers/src/index.ts Adds LockfileVerificationLog to the union Log.
core/core-loggers/src/all.ts Re-exports the new logger module.
installing/deps-installer/src/install/verifyLockfileResolutions.ts Extracts collectCandidates, emits started/done around the verification pass.
cli/default-reporter/src/reporterForClient/reportLockfileVerification.ts New reporter that maps verification events to one inner observable.
cli/default-reporter/src/reporterForClient/index.ts Wires the new reporter into the client reporter list.
cli/default-reporter/src/index.ts Adds the new push stream and pnpm:lockfile-verification dispatch.
cli/default-reporter/test/reportingLockfileVerification.ts Unit tests for plural/singular and done rendering.
.changeset/lockfile-verification-progress-logs.md Changeset describing the new logs and reporter behavior.
Comments suppressed due to low confidence (1)

installing/deps-installer/src/install/verifyLockfileResolutions.ts:175

  • When iterateLockfileViolations returns a non-empty violations list, the function throws without ever emitting a terminating lockfile-verification event. In ansi-diff mode the transient "? Verifying lockfile (N entries)..." line stays as the last rendered frame for this reporter just before the error is printed, which is misleading (it suggests verification is still in progress while the error is being shown). Consider emitting a terminal event (e.g. status: 'done' or a new status: 'failed') on the throw path so the reporter can overwrite/clear the transient line before the error surfaces.
  lockfileVerificationLogger.debug({ status: 'started', entries: candidates.size })
  const violations = await iterateLockfileViolations(candidates, verifiers, options?.concurrency)

  if (violations.length === 0) {
    lockfileVerificationLogger.debug({
      status: 'done',
      entries: candidates.size,
      elapsedMs: Date.now() - startedAt,
    })
    // Persist the success so the next install can stat-only the lockfile.
    if (cache) {
      recordVerification(cache.cacheDir, {
        lockfilePath: cache.lockfilePath,
        verifiers,
        hashLockfile,
      }, cachePrecomputed)
    }
    return
  }

  // Stable order so the error output is deterministic.
  violations.sort((a, b) => `${a.name}@${a.version}`.localeCompare(`${b.name}@${b.version}`))
  // Pick the throw code: a single-code batch keeps the per-policy code
  // (so existing handlers / docs / search keywords still route correctly);
  // a mixed batch (e.g. minimumReleaseAge + trust-downgrade on the same
  // lockfile) escalates to the generic `LOCKFILE_RESOLUTION_VERIFICATION`
  // and the per-entry code goes into the breakdown so the user can see
  // which policy each entry tripped.
  const distinctCodes = new Set(violations.map((v) => v.code))
  const isMixed = distinctCodes.size > 1
  const errorCode = isMixed ? 'LOCKFILE_RESOLUTION_VERIFICATION' : violations[0].code
  const visible = violations.slice(0, MAX_VIOLATIONS_TO_PRINT)
  const omitted = violations.length - visible.length
  const formatEntry = isMixed
    ? (v: ResolutionPolicyViolation): string => `  ${v.name}@${v.version} [${v.code}] ${v.reason}`
    : (v: ResolutionPolicyViolation): string => `  ${v.name}@${v.version} ${v.reason}`
  const breakdown = visible.map(formatEntry).join('\n')
  const details = omitted > 0
    ? `${breakdown}\n  …and ${omitted} more`
    : breakdown
  throw new PnpmError(
    errorCode,
    `${violations.length} lockfile entries failed verification:\n${details}`,
    {
      hint: 'The lockfile contains entries that the active policies reject. ' +
        'This can mean the lockfile is stale, or that someone committed a ' +
        'lockfile that bypassed the policy locally — inspect recent changes ' +
        'to pnpm-lock.yaml before trusting it. If the changes look expected, ' +
        'run "pnpm clean --lockfile" and then "pnpm install" to rebuild from ' +
        'a fresh resolution. Alternatively, relax the policy that flagged ' +
        'them.',
    }
  )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread installing/deps-installer/src/install/verifyLockfileResolutions.ts
zkochan added 2 commits May 18, 2026 10:27
…tandard

Add `lockfilePath` to the `pnpm:lockfile-verification` event payload so
consumers always know which lockfile a `started`/`done` pair refers to.
In the default reporter, render the path in the message only when the
lockfile lives outside the workspace root (or, for non-workspace
installs, outside cwd) — the common case stays uncluttered, while
custom `lockfileDir` setups now surface in the verification line.
…ered message

"Verifying lockfile" was opaque about *what* was being verified. Reword
the rendered messages to explicitly name the check ("supply-chain
policies"), so users on a cold-cache pause understand what's happening
instead of just seeing the pause.
Copilot AI review requested due to automatic review settings May 18, 2026 08:32
A non-empty lockfile.packages whose snapshots all fail name/version
extraction would still emit a "Verifying lockfile (0 entries)" line even
though no verifier work runs. Bail before emission when the candidate
map is empty so the no-op branch stays silent, matching the contract
for the other no-op branches (empty verifiers, no lockfile.packages).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comment thread installing/deps-installer/src/install/verifyLockfileResolutions.ts
Comment thread cli/default-reporter/src/reporterForClient/reportLockfileVerification.ts Outdated
Address two Copilot review points on #11712:

1. The verifier emitted `started` but no terminal event when violations
   were found or when the registry fan-out threw, leaving "Verifying
   lockfile…" as the last frame for that block in ansi-diff mode (and
   an unmatched line in CI logs). Add a `failed` status to the logger,
   wrap the fan-out in try/finally so a terminal event is emitted on
   every exit path that emitted `started`, and render a brief failure
   line so the spinner-style frame is replaced before the PnpmError
   block prints.

2. The path-suppression heuristic used strict `===` between
   path.dirname(lockfilePath) and expectedDir, which broke on trailing
   separators and slash-direction differences. Switch to a
   path.relative-based check so a workspaceDir like `/repo/` or a
   Windows path with mixed slashes still correctly suppresses the
   redundant "at <path>" suffix.
@zkochan zkochan added the area: supply chain security Issues related to minimumReleaseAge, blockExoticSubdeps, build script safety, and trust policies. label May 18, 2026
The lockfile verifier now emits log events during the registry round-trip pass, improving user visibility into the process.
Copilot AI review requested due to automatic review settings May 18, 2026 09:38
@zkochan zkochan merged commit 4a79336 into main May 18, 2026
11 of 12 checks passed
@zkochan zkochan deleted the lockfile-verify-report branch May 18, 2026 09:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

KSXGitHub pushed a commit that referenced this pull request May 18, 2026
origin/main advanced with two PRs:

- #11712 (feat: report lockfile verification progress) — TS only.
  Adds a new `lockfile_verification` logger channel and renders its
  progress in `cli/default-reporter`. No pacquet code touched.
- #11713 (test(pacquet): do not tolerate the lacking of tools) —
  hardens `git-fetcher/src/fetcher/tests.rs` so that missing host
  tools fail the test instead of being silently skipped, plus a
  paragraph in `pacquet/AGENTS.md` and a checkbox in
  `pacquet/plans/TEST_PORTING.md`.

Both auto-merged cleanly with this branch — only one touched a file
this branch also changed (`fetcher/tests.rs`, where rc.14 renamed
two closure params), and git's merge driver resolved it without
manual intervention.

`cargo check --workspace --tests --locked`, `cargo dylint --all --
--all-targets --workspace`, and `cargo fmt --check` all clean
post-merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli/dlx area: lockfile area: supply chain security Issues related to minimumReleaseAge, blockExoticSubdeps, build script safety, and trust policies.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants