feat(pnpm-policy): accept several inventories and merge them - #116
Merged
Conversation
`inventory` took a single reference, so a workspace that needed the union
of two inventories could not express it. The only way to combine them was
to build a flattened copy and commit it next to the config — which is a
second place the whole list lives, goes stale on its own, and has to be
reviewed by hand.
It now takes a path, a package, or a list of either, merged before the
policy resolves:
inventory:
- "@acme/pnpm-policy"
- "@acme/pnpm-policy-upstream"
Why a list rather than more maintainers in one export: trusting an
upstream account is a decision one workspace may have made and others
have not. Adding that account to the inventory everyone installs extends
the exemption to every workspace by default. Separate published packages
let each workspace opt into exactly what it trusts.
Merging is a union — an inventory only says what is exempt, so combining
can widen the set and never narrow it. `generatedAt` reports the oldest
input, because the merged view is only as fresh as its stalest source;
reporting the newest would overstate it.
`pnpm-policy inventory` writes one file, so with several configured there
is no single default to overwrite and it now asks for `--out` instead of
guessing.
A bare string still works and is unchanged for every existing config.
83 tests pass, 10 of them new: union, dedupe, oldest timestamp,
single-inventory passthrough, empty-list rejection, sharedScopes
handling, end-to-end generate across two inventories, intersection still
applied to the merged result, and the single-string path.
This was referenced Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
So a workspace can consume two published inventories over npm instead of keeping a flattened copy of both checked in.
The problem
inventorytook a single reference. A workspace needing the union of two had no way to say so, so the only option was to build a combined export and commit it beside the config. That is the whole list living in a second place: it goes stale independently, and it has to be reviewed by hand on every refresh.Today
constructiveis the only repo in the org carrying its ownpnpm-policy.inventory.json— 1024 entries — purely because it needs@constructive-io/pnpm-policyplus one upstream account. Every other repo consumes the published package and commits nothing.The change
inventorynow takes a path, an installed package, or a list of either, merged before the policy resolves:A bare string behaves exactly as before.
Why a list, rather than just more maintainers in one export
That was my first instinct and it is the wrong shape. Trusting an upstream account is a decision one workspace may have made and others have not. Folding it into the inventory everyone installs extends the exemption to every workspace by default — silently, since
intersectonly hides it until some repo happens to resolve one of those packages.Separate published packages keep the trust boundary where the decision was made: each workspace lists what it actually trusts.
Semantics
generatedAtis the oldest input. The merged view is only as fresh as its stalest source; reporting the newest would overstate it.sharedScopesis preserved when any input has it, so a scope another account also publishes into stays visible as such.pnpm-policy inventorywith several configuredThat command writes one file, and with a list there is no single default to overwrite. It now stops and asks for
--outrather than guessing which entry it owns.Verification
New tests cover: union, dedupe of a name both inventories claim, oldest-timestamp rule, single-inventory passthrough, empty-list rejection,
sharedScopesmerge and omission, matching names contributed by either source, end-to-endgenerateacross two inventories, intersection still applied to the merged result, and the single-string path still working.Note for running the suite locally:
pnpm installcurrently fails in this repo becausepnpm-workspace.yamlcarries pnpm's auto-injectedallowBuildsplaceholders (set this to true or false), andyamlize/nested-objneed building first. I resolved those locally to run the tests and reverted; none of it is in this diff. Worth fixing separately — it is the same gap the rollout issue notes, that dev-utils publishes the tool and has no policy of its own.Follows constructive-io/constructive-planning#1464. Once this is published I will send the
constructivePR that switches it to the list form and deletes its local inventory.🤖 Generated with Claude Code
https://claude.ai/code/session_01CEswUi4ANuB58rva48aHge