Skip to content

fix(engine): floor freshness for missing or invalid issue timestamps#2853

Closed
glorydavid03023 wants to merge 1 commit into
JSONbored:mainfrom
glorydavid03023:fix/engine-freshness-stale-floor
Closed

fix(engine): floor freshness for missing or invalid issue timestamps#2853
glorydavid03023 wants to merge 1 commit into
JSONbored:mainfrom
glorydavid03023:fix/engine-freshness-stale-floor

Conversation

@glorydavid03023

Copy link
Copy Markdown
Contributor

What

computeOpportunityFreshness (the miner engine's local opportunity scorer) treated an open issue with a missing or unparseable timestamp as maximally fresh (issueAgeDays returned 0exp(0) → freshness 1), 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: issueAgeDays returns STALE_AGE_DAYS for a null/unparseable timestamp, which underflows through exp(-STALE_AGE_DAYS / 20) to the 0.05 freshness 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 to 0 (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" (expect 0.05)
  • opportunity-metadata-signals.test.ts"freshness … helpers stay pure with … safe inputs" (expect 0.05)
  • opportunity-branch-internals.test.ts

This change makes all of them green again.

Note: the scorer's docstring references opportunityFreshnessFactor in src/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 because pickTimestamp only yields a parseable string or null) is v8 ignore-annotated, matching the file's existing convention.

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.
@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 4, 2026
@loopover-orb

loopover-orb Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Caution

🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥

🛑 Gittensory review result - reject/close recommended

Review updated: 2026-07-04 00:09:20 UTC

1 file · 1 AI reviewer · 1 blocker · readiness 73/100 · CI green · blocked

🛑 Suggested Action - Reject/Close

  • Maintainer test expectations unmet — Add or update tests, or attach passing validation output that satisfies the maintainer's test expectations.

Review summary
The change restores stale flooring for open issues whose selected timestamp is absent or invalid by returning STALE_AGE_DAYS from issueAgeDays, and computeOpportunityFreshness then clamps the decayed score to 0.05. The visible path is coherent: pickTimestamp still prefers valid updatedAt/createdAt strings and otherwise returns null, so malformed metadata no longer receives maximum freshness. No breaking defect is visible in the provided file.

Nits — 4 non-blocking
  • nit: packages/gittensory-engine/src/opportunity-freshness.ts:58 says this mirrors another freshness helper, but the changed missing/invalid timestamp behavior is intentionally different and should be called out there to prevent a future accidental re-sync.
  • packages/gittensory-engine/src/opportunity-freshness.ts:58: update the computeOpportunityFreshness docstring to explicitly state that missing or unparseable timestamps are floored to stale in this engine helper.
  • Code changes lack test evidence — Add focused regression tests or explain why existing coverage is sufficient.
  • Readiness score is below the configured threshold — Use the readiness panel as advisory maintainer context; the score does not block this PR.

Why this is blocked

  • Maintainer test expectations unmet — Add or update tests, or attach passing validation output that satisfies the maintainer's test expectations.
Signal Result Evidence
Code review ❌ 1 blocker 1 reviewer
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (no linked issue context).
Validation posture ❌ 5/25 Preflight is holding this PR: the review lane is unavailable, so it is not ready for automated review.
Contributor workload ✅ 10/10 Author activity: 255 registered-repo PR(s), 160 merged, 12 issue(s).
Contributor context ✅ Confirmed Gittensor contributor glorydavid03023; Gittensor profile; 255 PR(s), 12 issue(s).
Gate result ❌ Blocking Repo-configured hard blocker found.
Review context
  • Author: glorydavid03023
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: Python, JavaScript, TypeScript, Rust, C++, Kotlin, MDX, Ruby
  • Official Gittensor activity: 255 PR(s), 12 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Explain no-issue PR.
  • Await review-lane availability.
  • Refresh registry data or choose a registered active repo.
  • Link the issue being solved, or explicitly explain why this is a no-issue PR.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

🟩 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.

  • Re-run Gittensory review

@glorydavid03023

Copy link
Copy Markdown
Contributor Author

Superseded by #2858, which lands the identical fix on main (restoring the stale sentinel for missing/invalid issue timestamps, via Number.POSITIVE_INFINITY where this PR used a large finite STALE_AGE_DAYS). Same root cause (the #2780 revert of #2806's flooring) and same behavioral result (→ 0.05 floor). Closing as redundant now that main is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant