fix(engine): floor freshness for missing or invalid issue timestamps#2853
fix(engine): floor freshness for missing or invalid issue timestamps#2853glorydavid03023 wants to merge 1 commit into
Conversation
computeOpportunityFreshness treated an open issue with a missing or unparseable timestamp as maximally fresh (age 0 -> freshness 1) instead of stale, so a malformed metadata row could rank ahead of genuinely fresh opportunities in the local ranker. issueAgeDays now returns STALE_AGE_DAYS for a null/unparseable timestamp -- underflowing to the 0.05 freshness floor after the clamp -- restoring the flooring this scorer shipped with (JSONbored#2806, "invalid or missing issue timestamps floor freshness instead of ranking malformed metadata first") that a later change inadvertently reverted to 0. The scorer's own tests already assert this contract (missing/non-string timestamps -> 0.05); they were red on main until this fix.
|
Caution 🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥 🛑 Gittensory review result - reject/close recommendedReview updated: 2026-07-04 00:09:20 UTC
🛑 Suggested Action - Reject/Close
Review summary Nits — 4 non-blocking
Why this is blocked
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
|
Superseded by #2858, which lands the identical fix on |
What
computeOpportunityFreshness(the miner engine's local opportunity scorer) treated an open issue with a missing or unparseable timestamp as maximally fresh (issueAgeDaysreturned0→exp(0)→ freshness1), rather than stale. A malformed metadata row could therefore rank ahead of genuinely fresh opportunities in the local ranker.This restores the stale flooring the scorer originally shipped with:
issueAgeDaysreturnsSTALE_AGE_DAYSfor anull/unparseable timestamp, which underflows throughexp(-STALE_AGE_DAYS / 20)to the0.05freshness floor after the clamp.Why this is the right direction
When this scorer landed (#2806), its stale-flooring was a deliberate, documented choice — the commit message states: "Invalid or missing issue timestamps now floor freshness instead of ranking malformed metadata first." A subsequent change reverted
issueAgeDays's missing/invalid returns to0(fresh) without updating the scorer's tests, turning the mainline red.The intended contract is asserted by the scorer's own existing tests, which currently fail on
main:opportunity-freshness.test.ts→ "treats missing timestamps as stale" and "falls back cleanly when timestamps are absent or non-string" (expect0.05)opportunity-metadata-signals.test.ts→ "freshness … helpers stay pure with … safe inputs" (expect0.05)opportunity-branch-internals.test.tsThis change makes all of them green again.
Note: the scorer's docstring references
opportunityFreshnessFactorinsrc/signals/reward-risk.ts. That canonical intentionally normalizes invalid timestamps to fresh for the on-server reward signal; the engine copy deliberately diverges to stale for the local metadata ranker (so malformed rows don't rank first), exactly as #2806 introduced. This restores that intended divergence — the shared shape (exponential decay,[0.05, 1]clamp, injected clock) is unchanged.Test
No new test needed — the fix is proven by the scorer's existing tests, which fail on
main(missing/invalid timestamp →1) and pass with this change (→0.05). The now-defensive non-finite branch (unreachable becausepickTimestamponly yields a parseable string ornull) isv8 ignore-annotated, matching the file's existing convention.