Skip to content

feat(dm001): deprecated-only findings, graduated severity, and release-age context - #926

Merged
sonukapoor merged 12 commits into
mainfrom
feature/issue-732-dm001-scoring-staleness
Aug 6, 2026
Merged

feat(dm001): deprecated-only findings, graduated severity, and release-age context#926
sonukapoor merged 12 commits into
mainfrom
feature/issue-732-dm001-scoring-staleness

Conversation

@sonukapoor

Copy link
Copy Markdown
Collaborator

DM001 (--check-maintenance) grows from a single constraint-drag signal into a small maintenance-risk model.

  • Deprecated npm packages now surface as their own finding (medium), not just an annotation on a drag finding, so an abandoned direct dependency is flagged even when it is not blocking a CVE fix.
  • Severity is graduated: constraint drag stays high (it blocks a security fix); a deprecation is advisory medium.
  • A Last release line is shown for packages that have not published in years, as context to judge abandonment. Release age never drives severity on its own - a stable, feature-complete package can be old and perfectly fine.
  • Staleness rides through to the JSON, HTML, and SARIF outputs alongside the full npm deprecation message and URL (the terminal keeps its cell compact and shows a Deprecated flag).

Deprecation and release-age detection fetch one npm packument per direct dependency (bounded concurrency, cached, online-only); constraint-drag detection still works offline.

Note for users: on a project with deprecated direct dependencies, --check-maintenance will now surface those as new medium findings. It is opt-in and advisory (medium does not fail CI unless you set --fail-on medium).

Closes #732
Closes #835

@sonukapoor
sonukapoor force-pushed the feature/issue-732-dm001-scoring-staleness branch 2 times, most recently from 6a216d1 to e140055 Compare August 3, 2026 22:01
Adds a directDependencies parameter to detectDM001 and a new pass,
after the existing drag loop, that checks each direct dependency not
already covered by a drag finding for npm-level deprecation on its
latest published version. Deprecated-only findings are scored via
scoreMaintenanceFinding({ drag: false, deprecated: true, stale }),
bounded by runWithConcurrency (limit 10), and skipped entirely when
offline. index.ts and multi-folder-scan.ts pass [] for now (wired up
in task 5).
… not time.modified

npm bumps packument time.modified on any mutation, including npm deprecate.
That made a package deprecated recently but last released years ago read as
fresh, so it never amplified deprecated (medium) severity to high. Derive
lastPublish from time[dist-tags.latest] instead, matching the convention
already used in src/remediation/npm-registry.ts.
getFullYear() reads the local timezone, so a .../T00:00:00Z timestamp renders
one year early in any UTC-negative timezone (e.g. US Eastern). Use
getUTCFullYear() so the displayed year matches the ISO date's actual year.
… the URL

A raw npm deprecation message truncates to a useless "https://gi…" in the
width-capped maintenance box cell. Render a bare "Deprecated" flag instead,
keeping any "use X instead" replacement guidance when the message carries it.
The full message and URL are still emitted in the HTML/JSON/SARIF outputs.
A long drag detail line was chopped to 'upgrade to 1…', hiding the exact
upgrade target - the most actionable part. Word-wrap the details cell onto
continuation rows so the full guidance survives, and size the column to the
wrapped content.
Calendar age since last release is a weak proxy for abandonment - a stable,
complete package can be years old and perfectly fine. Severity now comes only
from explicit maintainer signals: drag (high) and npm-deprecation (medium).
Staleness is surfaced purely as a 'Last release: ...' context line, and
computeStaleness now returns a signal only when the package is genuinely old
(>= STALE_YEARS), so fresh packages no longer show a '0 years ago' line.
…ntext

Update the maintenance-risk docs and README for DM001 v2: split severity
(drag = high, deprecated = medium), document the deprecated-only firing path,
describe release age as display-only context (not a severity signal), correct
the packument-fetch cost (one per direct dependency, not just drag candidates),
and add a Maintenance risk README section + comparison-table row.
@sonukapoor
sonukapoor force-pushed the feature/issue-732-dm001-scoring-staleness branch from 4ad278e to aad135d Compare August 6, 2026 12:13
@sonukapoor
sonukapoor merged commit df71ee2 into main Aug 6, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant