Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

feat(reporter): emit pnpm:summary at install end#355

Merged
zkochan merged 2 commits into
mainfrom
feat/reporter-summary
May 1, 2026
Merged

feat(reporter): emit pnpm:summary at install end#355
zkochan merged 2 commits into
mainfrom
feat/reporter-summary

Conversation

@zkochan

@zkochan zkochan commented Apr 30, 2026

Copy link
Copy Markdown
Member

Summary

Second channel from the backfill (#347). Adds the Summary variant to
LogEvent and emits it from Install::run after the existing
pnpm:stage importing_done.

Mirrors pnpm's emit at
installing/deps-installer/src/install/index.ts:1663.
The payload carries only prefix; pnpm's reporter combines this with
the accumulated pnpm:root events to render the final "+N -M" diff
block. pnpm:root is its own backfill item (still unchecked in #347),
so today the summary is emitted but the diff block stays empty — same
as pnpm's behavior on a no-op install.

Stacked on #354 (pnpm:context).

Convention compliance

Per the per-PR conventions in #347:

  • LogEvent::Summary mirrors the upstream payload field-for-field.
  • Code comment + commit message reference the upstream permalink at
    the pinned SHA (086c5e91e8).
  • Recording-fake DI test extended to cover the new event.
  • No throttle (one emit per install).
  • Verified the test catches the regression: commented out the
    emit, confirmed
    unexpected event sequence: [Context, ImportingStarted, ImportingDone],
    restored.
  • Tick the pnpm:summary box in chore(reporter): backfill missing log events in already-ported code #347 on merge.

Drive-by rename

Renamed the install integration test from
install_emits_context_and_stage_events to
install_emits_pnpm_event_sequence. The test now asserts four events
(context, importing_started, importing_done, summary) and will keep
growing as more channels land at the install boundary
(pnpm:package-manifest, pnpm:stats, etc.). A stable name avoids
churn in subsequent PRs.

Test plan

  • cargo nextest run -p pacquet-reporter — 6 tests, including the
    new summary_event_matches_pnpm_wire_shape.
  • cargo nextest run -p pacquet-package-manager install_emits_pnpm_event_sequence
    — passes; full sequence and summary's prefix spot-checked.
  • just ready — 255 tests pass, lint clean.
  • Smoke check: pacquet install --reporter=ndjson emits a
    pnpm:summary line after the closing pnpm:stage line.

References

Summary by CodeRabbit

  • New Features

    • Added pnpm summary logging to display package management summaries ("+N -M" blocks) in correct order.
  • Tests

    • Updated test coverage for summary event serialization and event ordering verification.

@codecov

codecov Bot commented Apr 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 88.56%. Comparing base (5999435) to head (baaeb0b).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
crates/package-manager/src/install.rs 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #355      +/-   ##
==========================================
- Coverage   88.57%   88.56%   -0.01%     
==========================================
  Files          65       65              
  Lines        5784     5790       +6     
==========================================
+ Hits         5123     5128       +5     
- Misses        661      662       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Apr 30, 2026

Copy link
Copy Markdown

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.01     14.9±0.31ms   290.4 KB/sec    1.00     14.8±0.59ms   292.8 KB/sec

@github-actions

github-actions Bot commented Apr 30, 2026

Copy link
Copy Markdown

Integrated-Benchmark Report (Linux)

Scenario: Frozen Lockfile

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.723 ± 0.067 2.633 2.852 1.00 ± 0.04
pacquet@main 2.714 ± 0.077 2.629 2.836 1.00
pnpm 6.618 ± 0.069 6.476 6.741 2.44 ± 0.07
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.7227958476,
      "stddev": 0.06703708249889809,
      "median": 2.7284134709999996,
      "user": 2.4098531800000003,
      "system": 3.456330659999999,
      "min": 2.633259897,
      "max": 2.851789528,
      "times": [
        2.851789528,
        2.786657424,
        2.761441812,
        2.687807104,
        2.645548513,
        2.633259897,
        2.72937372,
        2.7348904700000003,
        2.727453222,
        2.669736786
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.7135279850000003,
      "stddev": 0.07690225338281903,
      "median": 2.7084330795000002,
      "user": 2.43763428,
      "system": 3.420420059999999,
      "min": 2.629276455,
      "max": 2.835715241,
      "times": [
        2.719719038,
        2.835715241,
        2.657987537,
        2.765786562,
        2.8320093920000002,
        2.629276455,
        2.716581591,
        2.638705617,
        2.639213849,
        2.7002845680000003
      ]
    },
    {
      "command": "pnpm",
      "mean": 6.6178745444,
      "stddev": 0.06925407582807729,
      "median": 6.606608444500001,
      "user": 9.178740079999999,
      "system": 4.524236859999999,
      "min": 6.475539525,
      "max": 6.7409299570000005,
      "times": [
        6.635538212,
        6.587693888,
        6.684639064000001,
        6.612004158,
        6.475539525,
        6.5947488320000005,
        6.647497704,
        6.7409299570000005,
        6.601212731,
        6.598941373000001
      ]
    }
  ]
}

Scenario: Frozen Lockfile (Hot Cache)

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 741.8 ± 42.5 698.8 806.5 1.00
pacquet@main 743.3 ± 61.3 690.6 869.2 1.00 ± 0.10
pnpm 2681.0 ± 82.2 2569.0 2831.3 3.61 ± 0.23
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.74184535672,
      "stddev": 0.042510642054007876,
      "median": 0.7263425535200001,
      "user": 0.24491543999999998,
      "system": 1.40026908,
      "min": 0.69881924502,
      "max": 0.80652972302,
      "times": [
        0.80236694302,
        0.80652972302,
        0.79442062502,
        0.70256237802,
        0.69881924502,
        0.72185363702,
        0.73083147002,
        0.73302961702,
        0.7065464020200001,
        0.72149352702
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.7432855968200001,
      "stddev": 0.061260900529532904,
      "median": 0.71844345302,
      "user": 0.25330324000000004,
      "system": 1.3618994799999997,
      "min": 0.69056219502,
      "max": 0.8692366880200001,
      "times": [
        0.8692366880200001,
        0.6930406920200001,
        0.83963177002,
        0.71643845102,
        0.69056219502,
        0.71410422202,
        0.72044845502,
        0.73650278502,
        0.7440302980200001,
        0.70886041202
      ]
    },
    {
      "command": "pnpm",
      "mean": 2.68102461442,
      "stddev": 0.08217258816340818,
      "median": 2.6661718920200004,
      "user": 3.266750739999999,
      "system": 2.2401537799999995,
      "min": 2.56902871402,
      "max": 2.83127277202,
      "times": [
        2.76526763402,
        2.56902871402,
        2.83127277202,
        2.67055849302,
        2.6063318510199998,
        2.66178529102,
        2.61411665702,
        2.7583545270200003,
        2.63817687402,
        2.69535333102
      ]
    }
  ]
}

@zkochan zkochan force-pushed the feat/reporter-context branch from a6a2ab4 to f8a4e47 Compare May 1, 2026 20:27
@zkochan zkochan force-pushed the feat/reporter-summary branch from bbd6d3e to 682bc70 Compare May 1, 2026 20:34
@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 084026b4-89ec-4912-9a15-42e1e85d0cc4

📥 Commits

Reviewing files that changed from the base of the PR and between 5999435 and baaeb0b.

📒 Files selected for processing (3)
  • crates/package-manager/src/install.rs
  • crates/reporter/src/lib.rs
  • crates/reporter/src/tests.rs

📝 Walkthrough

Walkthrough

The changes extend the logging event schema by introducing a new LogEvent::Summary variant and corresponding SummaryLog struct. The installer now emits this summary event after the import stage completes, ensuring proper sequencing of the "+N -M" summary block in reporter output. Test coverage verifies event ordering and payload serialization.

Changes

Cohort / File(s) Summary
Reporter Schema Extension
crates/reporter/src/lib.rs
Added LogEvent::Summary variant (serializes to "pnpm:summary") and new SummaryLog struct with level and prefix fields for downstream summary rendering.
Install Summary Emission
crates/package-manager/src/install.rs
Modified Install::run to emit LogEvent::Summary immediately after Stage::ImportingDone, using cloned prefix to preserve availability for summary emission. Event-ordering test updated with renamed test case and new expected LogEvent::Summary event.
Test Coverage
crates/reporter/src/tests.rs
Added test validating serialization of LogEvent::Summary into bunyan-style envelope format, verifying name as "pnpm:summary", level as "debug", and prefix flattening.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Poem

A summary log hops into view,
After imports finish what they do,
With prefix paired and level set,
The reporter's dance is not done yet—
Order matters, as I learned, it's true! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding and emitting a new pnpm:summary event at the end of the install process, which is the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reporter-summary

Review rate limit: 8/10 reviews remaining, refill in 10 minutes and 53 seconds.

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

@zkochan zkochan requested a review from Copilot May 1, 2026 20:35
Base automatically changed from feat/reporter-context to main May 1, 2026 20:36

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 the pnpm:summary reporting channel to the reporter wire format and emits it at the end of Install::run, aligning pacquet’s install lifecycle events more closely with pnpm so downstream pnpm-compatible reporters can render end-of-install summaries.

Changes:

  • Added LogEvent::Summary / SummaryLog to pacquet-reporter with pnpm:summary serde tagging.
  • Emitted pnpm:summary after pnpm:stage importing_done in Install::run.
  • Extended reporter/unit tests and renamed/extended the package-manager integration test to assert the new 4-event sequence.

Reviewed changes

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

File Description
crates/reporter/src/lib.rs Adds pnpm:summary event variant + payload type for serialization.
crates/reporter/src/tests.rs Adds a wire-shape test for the new summary event.
crates/package-manager/src/install.rs Emits pnpm:summary at install end and updates the integration test to assert the full event sequence.

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

Comment thread crates/reporter/src/tests.rs Outdated
Comment thread crates/reporter/src/lib.rs Outdated
zkochan added a commit that referenced this pull request May 1, 2026
Adds the `PackageImportMethod` variant to `LogEvent` and emits it from
`Install::run` after `pnpm:context`, before `pnpm:stage importing_started`.
Mirrors pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/fs/indexed-pkg-importer/src/index.ts#L32.

The wire-format enum has only `clone | hardlink | copy`; pacquet's
`Npmrc::package_import_method` adds `Auto` and `CloneOrCopy`. Both
collapse to `clone` because that's the optimistic path the upstream
auto-importer attempts first. For the explicit `Hardlink` / `Copy` /
`Clone` settings the wire value matches reality. A TODO at the emit
site notes that the value should be re-derived after the first
successful import once the fallback signal is surfaced past the
per-package import path.

While auditing this channel, also deferred `pnpm:stage
resolution_started/done`: pacquet's no-lockfile flow interleaves
resolution and import per dependency, so emitting `resolution_done`
after import work has already happened would break the JS reporter's
per-package state. Pick this back up once pacquet's no-lockfile flow
gains a separate resolution pass. Frozen-lockfile installs (pacquet's
primary path today) don't need these events anyway — pnpm itself skips
them in `deps-restorer`. The deferral is recorded under #347.

Tests:
- New `package_import_method_event_matches_pnpm_wire_shape` in the
  reporter crate asserts every wire value renders correctly.
- The install integration test grows to assert the five-event success
  sequence (Context, PackageImportMethod, ImportingStarted,
  ImportingDone, Summary) and spot-checks the wire mapping for the
  default `Auto` config (collapses to `Clone`).
- Verified the test catches the regression by temporarily commenting
  out the new emit and confirming the failure shape, then restored.

Refs #347. Engine: #345. Previous channel: #355.
@zkochan zkochan changed the base branch from main to feat/reporter-context May 1, 2026 20:40
@zkochan zkochan changed the base branch from feat/reporter-context to main May 1, 2026 20:41
zkochan added 2 commits May 1, 2026 22:43
Adds the `Summary` variant to `LogEvent` and emits it from
`Install::run` immediately after `pnpm:stage importing_done`. Mirrors
pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/installing/deps-installer/src/install/index.ts#L1663.

The payload carries only `prefix`; the reporter combines this with the
accumulated `pnpm:root` events (still TODO under #347) to render the
final "+N -M" diff block.

Test: extends the install integration test (renamed to
`install_emits_pnpm_event_sequence` to match the growing scope) to
assert the four-event success sequence (`Context`, `ImportingStarted`,
`ImportingDone`, `Summary`) and spot-checks summary's `prefix`.
Verified the test catches the regression by temporarily commenting
out the emit and confirming it failed with a Summary-shaped gap.

Refs #347. Engine: #345. Previous channel: #354.
Per review feedback on #355: the original wording said the `pnpm:summary`
payload "is just `prefix`", which omitted the `level` field that's
also part of the serialized record. `level` is the bunyan-envelope
severity carried by every channel, not channel-specific to summary;
say so explicitly so a reader doesn't try to "fix" the struct based on
the comment.

Same fix applied to the wire-shape test's doc comment.
@zkochan zkochan force-pushed the feat/reporter-summary branch from 682bc70 to baaeb0b Compare May 1, 2026 20:46
zkochan added a commit that referenced this pull request May 1, 2026
Adds the `PackageImportMethod` variant to `LogEvent` and emits it from
`Install::run` after `pnpm:context`, before `pnpm:stage importing_started`.
Mirrors pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/fs/indexed-pkg-importer/src/index.ts#L32.

The wire-format enum has only `clone | hardlink | copy`; pacquet's
`Npmrc::package_import_method` adds `Auto` and `CloneOrCopy`. Both
collapse to `clone` because that's the optimistic path the upstream
auto-importer attempts first. For the explicit `Hardlink` / `Copy` /
`Clone` settings the wire value matches reality. A TODO at the emit
site notes that the value should be re-derived after the first
successful import once the fallback signal is surfaced past the
per-package import path.

While auditing this channel, also deferred `pnpm:stage
resolution_started/done`: pacquet's no-lockfile flow interleaves
resolution and import per dependency, so emitting `resolution_done`
after import work has already happened would break the JS reporter's
per-package state. Pick this back up once pacquet's no-lockfile flow
gains a separate resolution pass. Frozen-lockfile installs (pacquet's
primary path today) don't need these events anyway — pnpm itself skips
them in `deps-restorer`. The deferral is recorded under #347.

Tests:
- New `package_import_method_event_matches_pnpm_wire_shape` in the
  reporter crate asserts every wire value renders correctly.
- The install integration test grows to assert the five-event success
  sequence (Context, PackageImportMethod, ImportingStarted,
  ImportingDone, Summary) and spot-checks the wire mapping for the
  default `Auto` config (collapses to `Clone`).
- Verified the test catches the regression by temporarily commenting
  out the new emit and confirming the failure shape, then restored.

Refs #347. Engine: #345. Previous channel: #355.
@zkochan zkochan merged commit 403d38c into main May 1, 2026
14 of 15 checks passed
@zkochan zkochan deleted the feat/reporter-summary branch May 1, 2026 21:19
zkochan added a commit that referenced this pull request May 1, 2026
Adds the `PackageImportMethod` variant to `LogEvent` and emits it from
`Install::run` after `pnpm:context`, before `pnpm:stage importing_started`.
Mirrors pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/fs/indexed-pkg-importer/src/index.ts#L32.

The wire-format enum has only `clone | hardlink | copy`; pacquet's
`Npmrc::package_import_method` adds `Auto` and `CloneOrCopy`. Both
collapse to `clone` because that's the optimistic path the upstream
auto-importer attempts first. For the explicit `Hardlink` / `Copy` /
`Clone` settings the wire value matches reality. A TODO at the emit
site notes that the value should be re-derived after the first
successful import once the fallback signal is surfaced past the
per-package import path.

While auditing this channel, also deferred `pnpm:stage
resolution_started/done`: pacquet's no-lockfile flow interleaves
resolution and import per dependency, so emitting `resolution_done`
after import work has already happened would break the JS reporter's
per-package state. Pick this back up once pacquet's no-lockfile flow
gains a separate resolution pass. Frozen-lockfile installs (pacquet's
primary path today) don't need these events anyway — pnpm itself skips
them in `deps-restorer`. The deferral is recorded under #347.

Tests:
- New `package_import_method_event_matches_pnpm_wire_shape` in the
  reporter crate asserts every wire value renders correctly.
- The install integration test grows to assert the five-event success
  sequence (Context, PackageImportMethod, ImportingStarted,
  ImportingDone, Summary) and spot-checks the wire mapping for the
  default `Auto` config (collapses to `Clone`).
- Verified the test catches the regression by temporarily commenting
  out the new emit and confirming the failure shape, then restored.

Refs #347. Engine: #345. Previous channel: #355.
zkochan added a commit that referenced this pull request May 2, 2026
Closes #346.

Adds a "Reporter / log events" section to `CODE_STYLE_GUIDE.md`
covering the convention for porting reporter emissions:

- **Finding the upstream emit** — three call shapes to grep for in
  `pnpm/pnpm` (`globalLogger.<channel>.<level>(...)`,
  `logger.<level>({ name: 'pnpm:<channel>', ... })`, and direct
  `streamParser.write(...)` calls).
- **Channel mapping** — `crates/reporter/src/lib.rs`'s `LogEvent`
  enum is the canonical list, with each variant pinning
  `#[serde(rename = "pnpm:<channel>")]`. Includes the convention
  for adding a new channel (mirror the upstream TS shape
  field-for-field, add a wire-shape unit test).
- **Threading** — `<R: Reporter>` generic on every fn that emits,
  turbofish at the production entry point, install-scoped state
  via parameters where dedup matters (e.g. `link_file`'s
  `&AtomicU8`).
- **Where to put the emit** — match the upstream call site's
  position relative to side effects; cite the upstream permalink
  at a pinned SHA in the code comment.
- **Testing** — recording-fake DI per #339, a `static
  Mutex<Vec<LogEvent>>` per test, sequence assertion via
  `matches!`. Verify the test catches the regression.
- **What not to do** — don't reformat upstream messages, don't
  invent channels, don't change emit granularity in either
  direction.
- **Worked example** — `pnpm:summary` in `Install::run` (landed in
  #355): shows the upstream permalink, the pacquet emit, and the
  test that pins the sequence.

Adds a sixth bullet to `AGENTS.md`'s cardinal rule pointing at the
new section, so the "match pnpm" mandate explicitly covers log
emissions.
zkochan added a commit that referenced this pull request May 2, 2026
A style guide should let a porter read it linearly without
context-switching to GitHub. The four issue references (#345 for
the reporter origin, #347 for the channel-backfill audit, #339 for
the recording-fake pattern, #355 for the worked example's PR) were
project history, not convention — none of them carried information
the doc itself didn't already restate inline.

Replace each with the concrete fact the reader needs: the reporter
lives in `crates/reporter` (with its trait, enum, and sinks named
in place); to add a new channel, do X, Y, Z (instead of "the work
tracked under #347"); the recording-fake pattern is the unit-struct
+ static-mutex shape (described directly, no "from #339"); and the
worked example is just the code, no "added in #355".
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants