fix(PD002): false positives on workspace roots — member-declared dependencies reported as transitive-only phantoms
@alamb-hex is already working on this.
Since Aug 11, 2026.
- Dominant language
- TypeScript
- Stars
- 715
- Forks
- 145
- Avg merge
- 21h 39m
- Merged PRs (30d)
- 66
Description
Summary
When scanning a monorepo root, PD002 reports dependencies that are declared directly in a workspace member's package.json as transitive-only phantoms. Declaration appears to be resolved against the root manifest only, while imports are collected from the whole tree — so every workspace-member dependency that is imported in that member's source is flagged.
Version: 1.28.0 · Package manager: pnpm (workspace via pnpm-workspace.yaml)
Minimal reproduction
repro/
├── package.json { "name": "pd002-repro", "private": true, "version": "1.0.0" }
├── pnpm-workspace.yaml packages: ["apps/*"]
└── apps/web/
├── package.json { "name": "@repro/web", "dependencies": { "js-yaml": "^4.1.0" } }
└── src/index.ts import yaml from 'js-yaml';
pnpm install
cve-lite . overrides --json
Actual
PD002 medium js-yaml
js-yaml is imported in source but only present as a transitive dependency - declare it explicitly
details: Imported in: apps/web/src/index.ts. If the parent package drops or changes this
dependency, your code will break without warning. Run: pnpm add js-yaml
Expected
No finding. js-yaml is a declared direct dependency of @repro/web, which is the package that imports it.
The suggested remediation (pnpm add js-yaml) would add a redundant second declaration at the root.
The detail line points at the fix
The finding already reports Imported in: apps/web/src/index.ts. So the import's owning workspace is known at the point the finding is produced — it just isn't used to pick which manifest to resolve the declaration against. Resolving against the nearest enclosing workspace member's package.json (falling back to the root) should close this.
Corroborating: scanning the member directly is clean.
cve-lite ./apps/web overrides --json # 0 findings
cve-lite . overrides --json # 1 PD002 finding
Real-world impact
On a real 2-app pnpm monorepo (root manifest declares one devDependency; apps/web declares the rest), a root scan produces 11 PD002 findings, all false — next, react, vitest, tailwindcss, @tanstack/react-query, lucide-react, clsx, tailwind-merge, @testing-library/react, @testing-library/jest-dom, @vitejs/plugin-react.
For a dashboard aggregating findings across many repos, that one project dominates the view with noise, which is what led us to filter PD001/PD002 out of our integration entirely rather than lose the signal from the OA rules.
Notes
- The scan notes already say "Monorepo workspace boundaries are only partially modeled in this version" — this is a concrete instance.
- I verified PD002 only. PD001 (override-only phantom) plausibly shares the same declaration-resolution path, but I have not confirmed it.
- Possibly related in spirit: #943, #947, #949 corrected workspace attribution for dev/prod classification. The PD rules may need the equivalent treatment.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.