feat(reporter): emit pnpm:package-manifest, pnpm:root, pnpm:stats, and pnpm:request-retry#375
Conversation
…d pnpm:request-retry Wires the four remaining portable channels from #347 into pacquet's reporter pipeline. Each follows the convention documented in CODE_STYLE_GUIDE.md: a `LogEvent` variant + payload struct, a wire-shape unit test in `pacquet-reporter`, the emit at the matching upstream pnpm site (with a pinned permalink at SHA `086c5e91e8`), and a recording-fake test where the surrounding code makes one reachable. * `pnpm:package-manifest`: `Initial` from `Install::run` next to the existing `pnpm:context` emit; `Updated` from `Add::run` after the manifest is rewritten. Presence-tagged on `initial` / `updated` per pnpm's wire shape. * `pnpm:root`: `Added` per direct dependency in `SymlinkDirectDependencies::run`. Iterates per dependency group so each emit can label its `dependencyType`. Reuses the install root `requester` for the `prefix` field. * `pnpm:stats`: `Added` (snapshot count) and `Removed` (placeholder `0` until pruning lands) from `CreateVirtualStore::run`. Comment notes the upstream-divergence: pnpm reports the current/wanted diff, pacquet has no current-lockfile tracking yet so every install looks like a fresh install. * `pnpm:request-retry`: emitted from `fetch_and_extract_with_retry` before each backoff sleep. Maps `TarballError` onto pnpm's JS-shaped error object — `httpStatusCode` for HTTP failures, a placeholder `code` derived from the variant name for everything else, so the JS reporter's `?? `-chain dispatch picks up the right field.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds new pnpm-shaped reporter channels and payloads (package-manifest, root, stats, request-retry); emits those events from package-manager operations (add, install, create_virtual_store, symlink_direct_dependencies) and from tarball retry logic; includes serialization and behavioral tests. ChangesReporter core & tests
Package-manager instrumentation & tests
Tarball retry observability & tests
Sequence Diagram(s)sequenceDiagram
participant Installer
participant SymlinkWorker
participant Reporter
participant FS as FileSystem
participant Fetcher
Installer->>Reporter: emit pnpm:package-manifest (initial)
Installer->>SymlinkWorker: SymlinkDirectDependencies::run::<R>(requester, dependency_groups)
SymlinkWorker->>FS: create symlink for dep A
SymlinkWorker->>Reporter: emit pnpm:root added (prefix=requester, dependency_type)
SymlinkWorker->>FS: create symlink for dep B
SymlinkWorker->>Reporter: emit pnpm:root added (prefix=requester, dependency_type)
Installer->>Reporter: emit pnpm:stats (added/removed) [create_virtual_store]
Fetcher->>Fetcher: encounter transient error (e.g., 503)
Fetcher->>Reporter: emit pnpm:request-retry (attempt, error with httpStatusCode)
Fetcher->>Fetcher: retry and succeed
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 9/10 reviews remaining, refill in 6 minutes. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #375 +/- ##
==========================================
+ Coverage 81.03% 81.50% +0.46%
==========================================
Files 64 64
Lines 3517 3622 +105
==========================================
+ Hits 2850 2952 +102
- Misses 667 670 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
crates/reporter/src/tests.rs (1)
266-465: ⚡ Quick winAdd context logging before new non-
assert_eq!checks.The new tests add several
assert!key-presence assertions without logging the serialized payload/context first. Addeprintln!/dbg!immediately before those checks to keep failures diagnosable in CI.As per coding guidelines, "Follow test-logging guidance — log before non-assert_eq! assertions, dbg! complex structures, skip logging for simple scalar assert_eq!"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/reporter/src/tests.rs` around lines 266 - 465, Several tests add assert! presence checks without prior diagnostic logging; insert logging calls before those non-assert_eq! assertions to aid CI debugging. For each test function (package_manifest_event_matches_pnpm_wire_shape, root_event_matches_pnpm_wire_shape, stats_event_matches_pnpm_wire_shape, request_retry_event_matches_pnpm_wire_shape) add a dbg! or eprintln! of the serialized JSON (the local variable json produced from envelope.pipe_ref(...) -> serde_json::from_str) immediately before the assert! loops that check .get(...).is_none() (and before the for k in [...] { assert!(json["..."].get(k)... ) } blocks); prefer dbg!(json) for complex objects and eprintln! for short scalar checks, and do not add logging before existing assert_eq! scalar comparisons. Ensure you reference the json variable and place the logging right before the offending assert! so failures emit the payload.crates/package-manager/src/symlink_direct_dependencies/tests.rs (1)
80-85: ⚡ Quick winAdd context logging before non-
assert_eq!assertions in these tests.Please log relevant path/result context right before the
assert!checks (symlink existence andmatches!result) to align with the test diagnostics convention.As per coding guidelines, "Follow test-logging guidance — log before non-assert_eq! assertions, dbg! complex structures, skip logging for simple scalar assert_eq!"
Also applies to: 139-139
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/package-manager/src/symlink_direct_dependencies/tests.rs` around lines 80 - 85, Before the non-assert_eq! assertions, add context logging of the checked path and the call result: evaluate and store the result of is_symlink_or_junction(&modules_dir.join("fastify")) and log the path and the bool/Result (e.g., using dbg! or tracing::info!) immediately before the assert!; do the same for is_symlink_or_junction(&modules_dir.join("@pnpm.e2e/dev-dep")) and for the matches! expression referenced around the second location (line ~139), logging the value being matched and the subject path/structure; keep assert_eq! uses unchanged and only add logs immediately prior to the non-assert assertions so test diagnostics follow the project guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/package-manager/src/add.rs`:
- Around line 100-106: The current prefix derivation uses unwraps that can
panic: the expression around manifest.path().parent().map(...).unwrap() and
to_str().unwrap() should be made robust. Replace the chain that sets prefix (the
variable named prefix in add.rs derived from manifest.path()) with safe
handling: check manifest.path().parent() and provide a sensible fallback if None
(e.g., use the manifest path itself or "."), and convert the parent path to a
UTF-8-safe string using to_string_lossy() or OsString handling instead of
to_str().unwrap(), ensuring no panics occur on non-UTF-8 paths. Ensure the new
logic preserves the existing semantics of prefix when parent exists and
documents the fallback choice.
In `@crates/package-manager/src/symlink_direct_dependencies.rs`:
- Around line 74-90: The current parallel loop panics on symlink errors via
expect("symlink pkg"); change the loop to propagate errors by using
par_iter().try_for_each and make the closure return Result<(),
SymlinkDirectDependenciesError>, replacing expect(...) with
symlink_package(...)? and mapping the symlink error into
SymlinkDirectDependenciesError; ensure the surrounding function's
signature/return type supports returning Result so the propagated error from the
closure bubbles up instead of aborting a rayon worker (refer to symlink_package,
PkgNameVerPeer::new, and SymlinkDirectDependenciesError to locate and convert
the error).
- Around line 100-105: The match currently maps DependencyGroup::Peer to
dependency_type = None but the later emit/symlink path still processes it;
change the logic to skip peers entirely by adding an early guard: if group ==
DependencyGroup::Peer { continue; } (or equivalent) before computing
dependency_type so the code that emits "pnpm:root added" and creates the symlink
is not executed for peers; reference the DependencyGroup enum, the
dependency_type variable, and the code path that emits "pnpm:root added"/creates
the symlink to locate where to insert the guard.
---
Nitpick comments:
In `@crates/package-manager/src/symlink_direct_dependencies/tests.rs`:
- Around line 80-85: Before the non-assert_eq! assertions, add context logging
of the checked path and the call result: evaluate and store the result of
is_symlink_or_junction(&modules_dir.join("fastify")) and log the path and the
bool/Result (e.g., using dbg! or tracing::info!) immediately before the assert!;
do the same for is_symlink_or_junction(&modules_dir.join("@pnpm.e2e/dev-dep"))
and for the matches! expression referenced around the second location (line
~139), logging the value being matched and the subject path/structure; keep
assert_eq! uses unchanged and only add logs immediately prior to the non-assert
assertions so test diagnostics follow the project guideline.
In `@crates/reporter/src/tests.rs`:
- Around line 266-465: Several tests add assert! presence checks without prior
diagnostic logging; insert logging calls before those non-assert_eq! assertions
to aid CI debugging. For each test function
(package_manifest_event_matches_pnpm_wire_shape,
root_event_matches_pnpm_wire_shape, stats_event_matches_pnpm_wire_shape,
request_retry_event_matches_pnpm_wire_shape) add a dbg! or eprintln! of the
serialized JSON (the local variable json produced from envelope.pipe_ref(...) ->
serde_json::from_str) immediately before the assert! loops that check
.get(...).is_none() (and before the for k in [...] {
assert!(json["..."].get(k)... ) } blocks); prefer dbg!(json) for complex objects
and eprintln! for short scalar checks, and do not add logging before existing
assert_eq! scalar comparisons. Ensure you reference the json variable and place
the logging right before the offending assert! so failures emit the payload.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6777d7a5-26a8-4a07-a4a0-9d6e5df748f3
📒 Files selected for processing (11)
crates/package-manager/src/add.rscrates/package-manager/src/create_virtual_store.rscrates/package-manager/src/install.rscrates/package-manager/src/install/tests.rscrates/package-manager/src/install_frozen_lockfile.rscrates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rscrates/reporter/src/lib.rscrates/reporter/src/tests.rscrates/tarball/src/lib.rscrates/tarball/src/tests.rs
| entries.par_iter().for_each(|(name, spec, group)| { | ||
| // TODO: the code below is not optimal | ||
| let virtual_store_name = | ||
| PkgNameVerPeer::new(PkgName::clone(name), spec.version.clone()) | ||
| .to_virtual_store_name(); | ||
|
|
||
| let name_str = name.to_string(); | ||
| symlink_package( | ||
| &config | ||
| .virtual_store_dir | ||
| .join(virtual_store_name) | ||
| .join("node_modules") | ||
| .join(&name_str), | ||
| &config.modules_dir.join(&name_str), | ||
| ) | ||
| .expect("symlink pkg"); // TODO: properly propagate this error | ||
|
|
There was a problem hiding this comment.
Do not panic on symlink failures inside the parallel install path.
expect("symlink pkg") turns filesystem errors into panics, which can abort the install from a rayon worker. This should be propagated as SymlinkDirectDependenciesError instead.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/package-manager/src/symlink_direct_dependencies.rs` around lines 74 -
90, The current parallel loop panics on symlink errors via expect("symlink
pkg"); change the loop to propagate errors by using par_iter().try_for_each and
make the closure return Result<(), SymlinkDirectDependenciesError>, replacing
expect(...) with symlink_package(...)? and mapping the symlink error into
SymlinkDirectDependenciesError; ensure the surrounding function's
signature/return type supports returning Result so the propagated error from the
closure bubbles up instead of aborting a rayon worker (refer to symlink_package,
PkgNameVerPeer::new, and SymlinkDirectDependenciesError to locate and convert
the error).
Micro-Benchmark ResultsLinux |
There was a problem hiding this comment.
Pull request overview
This PR finishes wiring four remaining pnpm-compatible reporter channels into pacquet’s reporter pipeline, adding the corresponding LogEvent variants/payloads, emit sites, and wire-shape + recording-fake tests.
Changes:
- Add
pnpm:package-manifest,pnpm:root,pnpm:stats, andpnpm:request-retrytopacquet-reporter(types + wire-shape tests). - Emit the new events from the matching pacquet call sites (
install,add,create_virtual_store,symlink_direct_dependencies, tarball retry loop). - Extend/install new tests to pin event ordering and validate emitted payloads.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/tarball/src/lib.rs | Adds pnpm:request-retry emission and tarball-error → request-retry error mapping. |
| crates/tarball/src/tests.rs | Adds a recording-fake test asserting retry-event emission behavior. |
| crates/reporter/src/lib.rs | Introduces new LogEvent variants and payload structs/enums for the four channels. |
| crates/reporter/src/tests.rs | Adds wire-shape serialization tests for the new channels. |
| crates/package-manager/src/symlink_direct_dependencies.rs | Emits pnpm:root added per direct dependency and threads reporter/prefix through. |
| crates/package-manager/src/symlink_direct_dependencies/tests.rs | Adds unit tests for pnpm:root added emissions and error path. |
| crates/package-manager/src/install_frozen_lockfile.rs | Updates call to SymlinkDirectDependencies::run::<R>() and threads requester. |
| crates/package-manager/src/install.rs | Emits pnpm:package-manifest initial before pnpm:context. |
| crates/package-manager/src/install/tests.rs | Updates event-sequence test to include manifest + stats events. |
| crates/package-manager/src/create_virtual_store.rs | Emits pnpm:stats added and placeholder removed: 0. |
| crates/package-manager/src/add.rs | Emits pnpm:package-manifest updated after saving the manifest. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let name_str = name.to_string(); | ||
| symlink_package( | ||
| &config | ||
| .virtual_store_dir | ||
| .join(virtual_store_name) | ||
| .join("node_modules") | ||
| .join(&name_str), | ||
| &config.modules_dir.join(&name_str), | ||
| ) | ||
| .expect("symlink pkg"); // TODO: properly propagate this error | ||
|
|
Integrated-Benchmark Report (Linux)Scenario: Frozen Lockfile
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.71636527726,
"stddev": 0.10864183298024227,
"median": 2.69978219906,
"user": 2.3965814,
"system": 3.4038292999999995,
"min": 2.5616842810600002,
"max": 2.95949639506,
"times": [
2.95949639506,
2.70394325606,
2.69562114206,
2.83152112906,
2.70499957006,
2.71428283606,
2.68460344006,
2.66715555406,
2.64034516906,
2.5616842810600002
]
},
{
"command": "pacquet@main",
"mean": 2.67588145026,
"stddev": 0.04110673052971748,
"median": 2.6675257645599997,
"user": 2.4029591,
"system": 3.4002719,
"min": 2.62304205606,
"max": 2.75632350706,
"times": [
2.72298704006,
2.70252252206,
2.6536732610600002,
2.67206872606,
2.66298280306,
2.62304205606,
2.67372545406,
2.66188508706,
2.62960404606,
2.75632350706
]
},
{
"command": "pnpm",
"mean": 6.6546352542600005,
"stddev": 0.06626926471255074,
"median": 6.66331427456,
"user": 9.267293899999999,
"system": 4.4768636,
"min": 6.51945531806,
"max": 6.73954089606,
"times": [
6.63280439506,
6.73210386406,
6.665517797060001,
6.583899601060001,
6.51945531806,
6.73954089606,
6.66645312206,
6.644401951060001,
6.66111075206,
6.70106484606
]
}
]
}Scenario: Frozen Lockfile (Hot Cache)
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.72729329838,
"stddev": 0.0772296549321924,
"median": 0.69927623888,
"user": 0.25499908,
"system": 1.3530937999999997,
"min": 0.68984396788,
"max": 0.9432701078800001,
"times": [
0.9432701078800001,
0.70627327788,
0.69362938588,
0.70053741088,
0.68984396788,
0.69440140888,
0.69801506688,
0.7215840788800001,
0.7343929948800001,
0.69098528388
]
},
{
"command": "pacquet@main",
"mean": 0.7229295583800001,
"stddev": 0.028020547495824166,
"median": 0.71536819288,
"user": 0.2544656799999999,
"system": 1.3707614000000001,
"min": 0.69854225088,
"max": 0.79858005288,
"times": [
0.79858005288,
0.71567225288,
0.70804259888,
0.70647301588,
0.72764463288,
0.72141694288,
0.71506413288,
0.7124055258800001,
0.69854225088,
0.72545417788
]
},
{
"command": "pnpm",
"mean": 2.71114355728,
"stddev": 0.07658663724827394,
"median": 2.71034498888,
"user": 3.22762598,
"system": 2.1951493999999996,
"min": 2.57455196588,
"max": 2.85787179588,
"times": [
2.57455196588,
2.65017654588,
2.85787179588,
2.67907592188,
2.75555259588,
2.75009485788,
2.70421391688,
2.66538924088,
2.75803267088,
2.71647606088
]
}
]
} |
* `cargo doc` failed because `pacquet-reporter` cannot link to `pacquet-tarball` (the dependency runs the other way). Drop the intra-doc link to plain backticks. * `pacquet-package-manager symlink_direct_dependencies` test failed on Windows because junctions need their target directories to exist before `junction::create`. Pre-create the virtual-store target paths so the test stays cross-platform. * `Add::run`'s post-save `pnpm:package-manifest updated` emit derived its `prefix` via panic-prone `to_str().unwrap()` / `parent().unwrap()`. Switch to `to_string_lossy()` with a manifest-path fallback so non-UTF-8 paths and root-level `package.json`s don't crash the install. * `SymlinkDirectDependencies::run` filtered `DependencyGroup::Peer` to `dependency_type: None` while still proceeding to symlink and emit. `get_map_by_group(Peer)` returns `None` already so the emit can't actually fire, but the dead `Peer` arm in the match was misleading. Filter peers explicitly at the iteration source and replace the match arm with `unreachable!`. * Drop a stray `eprintln!` from the new `pnpm:root` test.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/package-manager/src/symlink_direct_dependencies.rs`:
- Around line 72-82: The entries vector currently collects package entries from
each dependency group (skipping DependencyGroup::Peer) which can include
duplicates and cause concurrent symlink races; update the construction of
entries (the let entries: Vec<(&PkgName, &_, DependencyGroup)> block that uses
dependency_groups and project_snapshot.get_map_by_group) to first merge/flatten
entries by package name and apply the same precedence rules used elsewhere for
direct-dependency flattening (so each package appears only once with the
highest-precedence group), then collect that deduplicated list before the
parallel loop (par_iter) so no duplicate symlink work or duplicate `pnpm:root
added` events occur.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0b3b2291-6fe6-4a7b-a011-61a066be7c69
📒 Files selected for processing (4)
crates/package-manager/src/add.rscrates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rscrates/reporter/src/lib.rs
✅ Files skipped from review due to trivial changes (1)
- crates/package-manager/src/symlink_direct_dependencies/tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/reporter/src/lib.rs
A malformed v9 lockfile that lists the same package across multiple importer sections (e.g. `dependencies` + `optionalDependencies`) used to race two `symlink_package` calls to the same `node_modules/<name>` and emit two `pnpm:root added` events. Pnpm's resolver normalises this upstream of `linkDirectDeps` (a package marked `optional: true` only lands in `optionalDependencies`), so by the time the symlink stage runs the input list is already unique. Pacquet ingests user-supplied lockfiles so the same guarantee doesn't carry — collapse with a first-wins `HashSet<PkgName>` pass before `par_iter` so the behavioural envelope matches pnpm. First-wins picks the highest-priority group from the caller's `dependency_groups` order. The CLI passes `[Prod, Dev, Optional]` so prod beats dev/optional, matching pnpm's dependencies-over-optional precedence. Adds a unit test pinning the collapse: same dep in `dependencies` and `optionalDependencies` must produce exactly one symlink and one `pnpm:root added` event with `dependencyType: prod`.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/package-manager/src/symlink_direct_dependencies/tests.rs`:
- Around line 95-96: Before the two assert! checks that call
is_symlink_or_junction on modules_dir.join("fastify") and
modules_dir.join("@pnpm.e2e/dev-dep"), add diagnostic logging that prints the
full path and the result of is_symlink_or_junction (or the error) so failures
show context; specifically, evaluate the path into a local variable (e.g.,
fastify_path / dev_dep_path), call is_symlink_or_junction and log the path and
the returned Result/boolean (using eprintln! or println!) immediately before the
assert!, and apply the same pattern to the other occurrence noted around line
239 so test failures include the checked path and result.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6fe7e66f-e7ce-4f9e-a97b-bd384bd17c2e
📒 Files selected for processing (2)
crates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/package-manager/src/symlink_direct_dependencies.rs
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| symlink_package( | ||
| &config | ||
| .virtual_store_dir | ||
| .join(virtual_store_name) | ||
| .join("node_modules") | ||
| .join(&name_str), | ||
| &config.modules_dir.join(&name_str), | ||
| ) | ||
| .expect("symlink pkg"); // TODO: properly propagate this error |
* `tarball_error_to_request_retry` doc claimed `code` was "derived from the variant name" — the implementation actually uses curated `ERR_PACQUET_*` constants per match arm. Update the comment so a future maintainer doesn't assume a `TarballError` rename propagates automatically (Copilot review). * `pnpm:root added` emit converted `name` to a `String` twice (`name_str` and again for `real_name`). Reuse the already-built string via clone — the registry name and alias key are the same value at this layer (Copilot review). * Test asserts that aren't `assert_eq!` now log their checked values first per CODE_STYLE_GUIDE.md (`eprintln!` for paths, `dbg!` for the `Result`) so failures surface diagnostic context (CodeRabbit review).
The merge in `d6e8400` brought in a new `pacquet-tarball` lib test from #375 that calls `fetch_and_extract_with_retry::<RecordingReporter>` without the `&AuthHeaders` argument this PR added to the function signature. Add `&AuthHeaders::default()` to the call site so the crate compiles.
Summary
Wires the four remaining portable channels from #347 into pacquet's reporter pipeline. Each follows the convention documented in
CODE_STYLE_GUIDE.md§ "Reporter / log events":LogEventvariant + payload struct inpacquet-reportercrates/reporter/src/tests.rs086c5e91e8Channels
pnpm:package-manifest— presence-tagged oninitial/updated.Initialfires fromInstall::runnext to the existingpnpm:contextemit so consumers have the on-disk manifest before the install header renders.Updatedfires fromAdd::runaftermanifest.save()so the audit pipeline can diff initial vs updated.pnpm:root—Addedper direct dependency fromSymlinkDirectDependencies::run. Iterates perDependencyGroupso each emit can label itsdependencyType(prod/dev/optional); peer deps aren't materialised here so they're skipped, matching pnpm.pnpm:stats—Added(snapshot count) andRemoved(placeholder0until pruning lands) fromCreateVirtualStore::run. The code comment notes the upstream-divergence: pnpm reports the current/wanted diff (newDepPathsSet.size), pacquet has no current-lockfile tracking yet so every install looks like a fresh install andaddedends up as the total snapshot count.pnpm:request-retry— emitted fromfetch_and_extract_with_retrybefore each backoff sleep, withattemptone-indexed (the failed attempt) andtimeoutmirroringRetryOpts::delay_forms. A newtarball_error_to_request_retryhelper mapsTarballErroronto pnpm's JS-shaped error object:httpStatusCodefor HTTP failures, a placeholdercodederived from the variant name for everything else, so the JS reporter's??-chain dispatch (httpStatusCode ?? status ?? errno ?? code) picks up the right field.Tests
crates/reporter/src/tests.rs— wire-shape tests for all four new channels, asserting the JSON shape@pnpm/cli.default-reporterconsumes (camelCase field names, presence-tagged dispatch, optional fields skipping rather than rendering asnull).crates/package-manager/src/install/tests.rs— extendsinstall_emits_pnpm_event_sequenceto pin the new[PackageManifest, Context, ImportingStarted, Stats(Added), Stats(Removed), ImportingDone, Summary]order.crates/package-manager/src/symlink_direct_dependencies/tests.rs— new unit tests provingpnpm:root addedfires once per direct dep with the rightdependencyTypeper group, and pinning the existingMissingRootImportererror path.crates/tarball/src/tests.rs—request_retry_event_fires_per_retried_attemptproves the retry-loop emits exactly once per failed-and-being-retried attempt withhttpStatusCode: "503"(no placeholdercodewhen the JS-side dispatch field is populated).Pure additive — no existing wire-shape changed.
Test plan
just ready(typos / fmt / check / test / lint, including the new wire-shape and recording-fake tests)cargo nextest run -p pacquet-reporter— 15/15 passingcargo nextest run -p pacquet-package-manager symlink_direct_dependencies install_emits_pnpm_event_sequence— passescargo nextest run -p pacquet-tarball request_retry— passesReferences
Summary by CodeRabbit
New Features
Tests