Skip to content

fix(scan): stop the false [UPDATE] nag for equal-or-older batch-ranked patches - #162

Open
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/false-update-nag-batch-ranking
Open

fix(scan): stop the false [UPDATE] nag for equal-or-older batch-ranked patches#162
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/false-update-nag-batch-ranking

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Problem

After vendoring a patch, re-running scan --mode vendored perpetually reports an [UPDATE] / updates[] entry pointing at a patch that is the SAME or OLDER than the one already vendored — a permanent false nag (confirmed in prod on pip + poetry legs for urllib3).

detect_updates (crates/socket-patch-cli/src/commands/scan/discovery.rs:248, pre-fix) flagged an update whenever the top-ranked batch candidate's UUID differed from the recorded one. The candidate is chosen by api::ranking::cmp_batch_infos, but batch endpoint responses omit publishedAt (see ranking.rs:176 and rank_batch_info at ranking.rs:143, which parse an absent date to epoch 0). With severity and merge-coverage tied and the date meaningless, ranking falls through to the arbitrary UUID tiebreak — so an equal-or-older sibling patch can be crowned "top candidate" and flagged as a newer update.

Fix

In detect_updates (crates/socket-patch-cli/src/commands/scan/discovery.rs):

  • (a) Same UUID as recorded → never an update (short-circuit, discovery.rs:249).
  • (b) When the recorded patch is still among the offered patches, only surface an update if the candidate GENUINELY supersedes it — new helper candidate_supersedes (discovery.rs:~271) requires a strictly-better MEANINGFUL axis: worse severity, greater merge coverage, or a real, strictly-greater publishedAt. A missing date parses to None (via the existing RFC-2822 api::date::parse_timestamp_secs) and is never treated as newer, so an equal-or-older patch is never surfaced.
  • If the recorded patch is no longer offered at all, ages are uncomparable, so the different currently-available candidate is still flagged (unchanged behavior; also the only thing a manifest-only record can produce).

Note: a strictly-newer sibling can only out-rank the applied patch when the batch actually supplies dates; with dates absent the newest is the applied one and apply (the richer by-package shape) keeps it, so detect_updates and apply stay consistent. Missed (not false) updates only until the endpoint emits publishedAt.

Test

crates/socket-patch-cli/src/commands/scan/discovery.rs — hermetic unit tests alongside the existing detect_updates tests:

  • detect_updates_no_nag_when_applied_patch_still_offered_and_batch_omits_dates — core regression: applied uuid-b re-listed with sibling uuid-a (sorts first), no dates → NO update. Verified RED before / GREEN after (temporarily disabling the guard makes it panic with "an equal-or-older sibling with no real date must not be an update").
  • detect_updates_still_flags_a_higher_severity_candidate_offered_alongside_applied — over-suppression guard: a CRITICAL sibling still flags.
  • detect_updates_flags_a_genuinely_newer_candidate_when_batch_supplies_dates — over-suppression guard: a strictly-newer sibling (real dates) still flags.

cargo test -p socket-patch-cli --lib discovery:: → 23 passed, 0 failed. cargo build -p socket-patch-cli and cargo clippy -p socket-patch-cli clean. All pre-existing detect_updates tests unchanged and green.

Scope

Single-file change to scan/discovery.rs. No API/type changes; reuses public api::ranking::{severity_order, merged_coverage} and api::date::parse_timestamp_secs. Kills sweep findings false-update-nag-older-uuid, false-update-flag-batch-ranking; touches K11. No cross-dependencies with the other parallel bug fixes.

🤖 Generated with Claude Code


Note

Low Risk
Scan update detection only; no API or manifest schema changes; guarded by focused unit tests.

Overview
detect_updates no longer treats every batch top-ranked candidate with a different UUID as an update. When the manifest’s applied patch is still in the batch response, an update is reported only if that candidate genuinely supersedes the applied patch via candidate_supersedes: strictly worse severity, broader merge coverage, or a real, strictly greater publishedAt (missing dates do not count).

This stops perpetual [UPDATE] / updates[] noise when batch responses omit dates and cmp_batch_infos picks a sibling on UUID tiebreak alone. If the recorded patch is no longer offered, behavior is unchanged—a different available UUID still flags an update.

Unit tests cover the no-nag regression, higher-severity updates, and genuinely newer siblings when dates are present.

Reviewed by Cursor Bugbot for commit 221d5d2. Configure here.

`detect_updates` flagged an `[UPDATE]` (and a JSON `updates[]` entry)
whenever the top-ranked batch candidate differed from the recorded patch.
Batch responses omit `publishedAt`, so `cmp_batch_infos` collapses to the
arbitrary uuid tiebreak and can crown an equal-or-older sibling as the
"top" candidate — perpetually nagging a vendored project with a patch no
newer than the one already committed.

Now, when the applied patch is still among the offered patches, only
surface an update if the candidate genuinely supersedes it on a meaningful
axis (severity, merge coverage, or a real strictly-greater publish date).
Missing dates parse to `None` and are never treated as newer, so an
equal-or-older patch is never surfaced. Recency parsing stays on the
existing RFC-2822-aware `api::date` helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant