Repository navigation
fix(releases): grade a release over working projects first; an affected release for an active pin always surfaces - #988
Merged
Conversation
…ed release for an active pin always surfaces release_grade::concerned_pins picked the largest gap across EVERY project, and the stack-change stream and the Brief dropped scratch/dormant projects only afterwards. A scratch tree a major behind made the release "major" for the scratch tree alone; the filter then removed it, and the active project a minor behind heard nothing (a malicious release included). ReleaseGrade::retain_projects narrows the pins before the class and the concerned set are computed. The stack-change stream grades active_grade(..) and checks advisories against its direct pins for every release an active project is behind on; an Affected release is a Security change whatever its size (a malicious patch inside a caret range is what a refresh installs first). The Brief narrows before its Breaking/Yanked test. The scorer (pipeline_v2) and knowledge gaps / release_changelog do not call retain_projects: their grades and scores are unchanged, so PIPELINE_VERSION needs no bump. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
…it; rank by its grade (#988 review) B1: the sites (and the coverage copies) of an AFFECTED release are every active direct pin behind it (behind_pins), not the largest-gap set: with 4.2.1, A on 4.1.0 and B on 4.2.0, a malicious 4.2.1 named A alone, and an advisory hitting 4.2.1 and A's copy counted as covered and dropped B's warning. S2: a non-malicious affected release ranks and takes its urgency from its grade (rank_change; a patch ranks with the minors), so it never outranks a yanked pin or loses a major's Medium; malware stays High and first. S3: its version line reads "pkg X (affected)", no installed -> announced arrow that would read as the fix. S4: the Brief's narrowing is `upgrade_grade`, tested so that reverting it fails; the transitive-only test (green on the old code) is dropped. Nits: active_grade computed once per release (release_change_active); "newest stable release per package". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
runyourempire
force-pushed
the
fix/release-grade-active-pins
branch
from
October 18, 2026 12:39
e750f8e to
d808741
Compare
runyourempire
enabled auto-merge
October 18, 2026 12:39
runyourempire
added a commit
that referenced
this pull request
Oct 18, 2026
…ge of #988 and #992) #988 landed a stack_change test that builds an AdvisoryWindow literal before #992 added the cwe_ids field, so the merge-queue build failed with E0063. Same fixture, empty CWE list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
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.
Summary
This follow-up to #983 fixes a gap in
release_grade::concerned_pinsthat existed before #983.The bug: the grade picked the largest version gap across every project, and the stack-change stream and the Brief only dropped scratch and dormant projects afterwards. So a scratch tree that was a major version behind made the release "major" for the scratch tree alone. The filter then removed the scratch tree, and the active project that was only a minor behind got no announcement, even when the release was malicious.
The fix:
ReleaseGrade::retain_projects: narrows a grade to the chosen projects before the class and the concerned projects are computed.stack_change_releases.rs):active_grade(..)once per release.security(an id the frontend already reads) and has no Run action.behind_pins), not just the largest-gap set. Coverage by the advisory lane is judged on those same copies (review B1). With release 4.2.1, project A on 4.1.0 and project B on 4.2.0:rank_change, a patch counts as a minor), so a runtime major stays Medium and a yanked pin still outranks it.npm · pkg 4.2.1 (affected), with no "installed → announced" arrow that could be mistaken for the advisory lane's "installed → fix".brief_facts_build.rs): a newupgrade_gradenarrows to working projects before the Breaking/Yanked test. A release that only a scratch tree is behind on therefore never takes the package's single upgrade slot.stack_change.rs(claimed by #986): only the version-line and rank/urgency lines inrelease_citationsandrelease_itemchange. Those hunks are away from #986's edit tosecurity_item.Effect on the consumers of
release_grade(before and after on fixtures)npm update left-padderpipeline_v2), knowledge gaps,release_changelogScores do not change. Only the stack-change stream and the Brief call
retain_projects;grade_registry_releaseandgrade_pinsare untouched. The scorer's pins already leave out dormant projects before grading, and keep scratch projects as a label by design. PIPELINE_VERSION needs no bump, so this does not interact with #986. Cost, as measured in review: about 49 lookups per pass, roughly 0.2 s, cached.Follow-ups (not in this PR)
change_labelandrelease_actionarms that combineMinor | Securitypredate this PR. Rust needs an arm for every variant, and an affected release never reaches them because the advisory's title and advice replace them.Tests
cargo test --lib -- scoring:: evidence:: brief_facts ace_commands osv:: briefing knowledge_gaps release_changelog: 1823 passed, 0 failed (35 ignored). After makingrelease_changetest-only to fix a clippy dead-code error,stack_changepasses 30/30 and clippy is clean. The pre-push gate passed after rebasing onto fix(temporal): find a pin by the matcher's folded name (PEP 503, Cargo -/_), not only exact or lowercase #989.(affected), and a yanked pin outranks it;upgrade_grade: a scratch-only release is no candidate, and a scratch yanked pin does not mask a breaking upgrade. Reverting the narrowing makes this test fail;release_grade: the before and after of narrowing.cargo fmt: clean.cargo clippy --lib -- -D warnings: clean.🤖 Generated with Claude Code
https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7