Skip to content

fix(engine): inject nowMs for deterministic PR staleness classification - #8952

Closed
jeffrey701 wants to merge 1 commit into
JSONbored:mainfrom
jeffrey701:fix-8872-classify-pr-staleness-nowms
Closed

fix(engine): inject nowMs for deterministic PR staleness classification#8952
jeffrey701 wants to merge 1 commit into
JSONbored:mainfrom
jeffrey701:fix-8872-classify-pr-staleness-nowms

Conversation

@jeffrey701

Copy link
Copy Markdown
Contributor

What

pending-pr-scenarios.ts's daysSince called Date.now() directly, so
classifyOpenPullRequest's 14-day staleness split (merge_ready vs stale_likely_close) was
non-deterministic — identical PR records classified differently purely based on when the function
ran, and the boundary was untestable without live time. The file's own header claims "pure
classification/detection logic," and its sibling modules (opportunity-freshness.ts /
opportunity-metadata.ts) already inject nowMs "so the miner engine stays pure and testable."

Change

Add an optional nowMs to daysSince (defaulting to Date.now() only at that call boundary) and
thread it through classifyOpenPullRequest's args. When a caller omits it, behavior is unchanged
(the default fires); a caller can now inject a fixed clock for deterministic classification.

Validation

  • New frozen-time test in test/unit/pending-pr-scenarios.test.ts (imports the engine source, so
    Codecov grades it): with an injected nowMs, an approved/passing PR at exactly 14 days old
    classifies stale_likely_close, and one millisecond short of 14 days classifies merge_ready
    pinning the exact boundary.
  • npx vitest run test/unit/pending-pr-scenarios.test.ts → 19/19 pass; 100% line+branch coverage on
    every changed line (both sides of the nowMs = Date.now() default).

Closes #8872

@jeffrey701
jeffrey701 requested a review from JSONbored as a code owner July 26, 2026 14:11
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
21906 1 21905 21
View the top 1 failed test(s) by shortest run time
test/unit/miner-worktree-allocator-collisions.test.ts > loopover-miner worktree allocator collisions (#4298) > returns distinct worktree paths when multiple processes acquire simultaneously
Stack Traces | 0.439s run time
AssertionError: expected 4 to be 5 // Object.is equality

- Expected
+ Received

- 5
+ 4

 ❯ test/unit/miner-worktree-allocator-collisions.test.ts:148:41

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 26, 2026
@loopover-orb

loopover-orb Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Caution

🛑 LoopOver review result - fixes required

Review updated: 2026-07-26 14:35:18 UTC

2 files · 1 AI reviewer · no blockers · CI failing · blocked

🛑 Suggested Action - Fix Blockers

Review summary
Adds an optional nowMs parameter to daysSince/classifyOpenPullRequest, defaulting to Date.now() only at the call boundary, so PR staleness classification becomes deterministic and testable at exact boundaries. The change is correct: default behavior is preserved for all existing callers, the new frozen-time test pins both sides of the 14-day boundary (13d23h59m59.999s vs 14d exactly), and it matches the existing nowMs-injection pattern already used in sibling modules (opportunity-freshness.ts). This is a narrow, low-risk pure-function change with real coverage of the new branch.

Nits — 4 non-blocking

CI checks failing

  • validate
  • validate-tests

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8872
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 (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 80 registered-repo PR(s), 36 merged, 18 issue(s).
Contributor context ✅ Confirmed Gittensor contributor jeffrey701; Gittensor profile; 80 PR(s), 18 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: minor
Linked issue satisfaction

Addressed
The diff adds an optional nowMs parameter to daysSince and threads it through classifyOpenPullRequest's args, defaulting to Date.now() only at the call boundary, exactly matching the sibling-module pattern requested. It also adds a frozen-time test pinning the exact 14-day boundary (merge_ready vs stale_likely_close) using injected nowMs rather than live Date.now(), satisfying both deliverables.

Review context
  • Author: jeffrey701
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Rust, TypeScript, Clojure, JavaScript
  • Official Gittensor activity: 80 PR(s), 18 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Triage stale or unlinked PRs.
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.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb

loopover-orb Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

LoopOver is closing this pull request on the maintainer's behalf (CI is failing (validate, validate-tests)). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed.

@loopover-orb loopover-orb Bot closed this Jul 26, 2026
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.

fix(engine): classifyOpenPullRequest's staleness check reads the wall clock, breaking the module's own "pure/deterministic" contract

1 participant