Skip to content

feat(scoring): upstream time-decay, behind a default-off flag (#703)#731

Merged
JSONbored merged 1 commit into
mainfrom
feat/time-decay-scoring
Jun 14, 2026
Merged

feat(scoring): upstream time-decay, behind a default-off flag (#703)#731
JSONbored merged 1 commit into
mainfrom
feat/time-decay-scoring

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

What

Implements upstream gittensor's sigmoid time-decay in gittensory's score model (#703), default-off and owner-gated. The roadmap defers #703 "gated on owner review of a before/after diff" — so this changes nothing live until you set SCORING_TIME_DECAY_ENABLED.

Faithfulness

Ports the validator's calculate_time_decay (gittensor/validator/utils/datetime_utils.py) verbatim:

  • Hard 12h grace → multiplier exactly 1.0.
  • Then a logistic on days-since-merge: 1 / (1 + exp(0.4·(days − 10)))50% at 10 days.
  • Floored at the 0.05 minimum.

The 4 constants are now modeled in DEFAULT_SCORING_CONSTANTS (so they stop surfacing as unmodeled drift via #690).

Before / after (what enabling would do — for your review)

PR age multiplier
fresh (< 12h) 1.00
5 days ~0.88
10 days 0.50
20 days 0.05 (floor)
30 days 0.05 (floor)

A fresh PR is unaffected even when enabled, so a normal new-PR preview never changes — only an aged-PR projection decays.

Architecture note (why per-PR projection, not a historical-aggregate refactor)

I'd initially scoped "per-PR merge-age data spine." On investigation, gittensory's preview scores a single fresh planned PR and surfaces the contributor's upstream-API standing (already decayed upstream) — there's no raw historical per-PR aggregation in gittensory to decay, so re-applying there would double-count. The faithful, double-decay-safe model is per-PR: predicted score × calculateTimeDecay(prAgeHours), with prAgeHours an optional preview input and applyTimeDecay injected server-side from the env flag (not caller-controllable).

How to enable (after you review)

Set SCORING_TIME_DECAY_ENABLED=true. Then a score preview that supplies prAgeHours decays per the curve above.

Tests

calculateTimeDecay vs upstream (grace / 50%@10D / floor / monotonic), constants-now-modeled, the env gate, preview applied-vs-unapplied paths, and a before/after trajectory. Typecheck + UI lint + OpenAPI (regenerated) clean; 97% coverage held.

…f flag (#703)

Ports upstream gittensor's sigmoid time-decay (the validator's calculate_time_decay)
into gittensory's score model. DEFAULT-OFF + owner-gated: the roadmap defers #703
pending owner review of a before/after ranking diff, so this changes nothing live
until SCORING_TIME_DECAY_ENABLED is set.

- scoring/model.ts: model the 4 upstream constants (TIME_DECAY_GRACE_PERIOD_HOURS 12,
  SIGMOID_MIDPOINT 10, SIGMOID_STEEPNESS_SCALAR 0.4, MIN_MULTIPLIER 0.05) so they no
  longer surface as unmodeled drift (#690); + isTimeDecayEnabled gate (default off).
- scoring/preview.ts: calculateTimeDecay (verbatim port: hard 12h grace -> 1.0, then a
  logistic on days-since-merge, 50% at 10d, floored at 0.05) + a timeDecayMultiplier
  applied to estimatedMergedScore. A fresh PR (age < grace) is unaffected even when
  enabled, so a normal new-PR preview never changes.
- prAgeHours input + the owner-gated applyTimeDecay flag injected server-side at the
  routes + MCP score-preview entry points (not caller-controllable).

Why per-PR projection (not a historical-aggregate refactor): gittensory's preview
scores a single fresh planned PR and surfaces the contributor's upstream-API standing
(already decayed upstream); it has no raw historical per-PR aggregation to decay, so
re-applying there would double-count. The faithful model is per-PR (predicted score x
decay-by-age).

Decay curve (the before/after to review): fresh 100% -> 5d ~88% -> 10d 50% -> >=20d 5% floor.

Tests: calculateTimeDecay vs upstream (grace, 50%@10D, floor, monotonic), constants
now modeled, the env gate, the preview applied/unapplied paths, and a before/after
trajectory. 97% coverage held; OpenAPI regenerated.
@ghost

ghost commented Jun 14, 2026

Copy link
Copy Markdown

Note

Gittensory Gate skipped

PR closed before full evaluation. No late first comment was created.

Signal Result Evidence Action
Gate result ⚠️ Skipped #731 is no longer open. No action.

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

@ghost ghost added the gittensory:reviewed label Jun 14, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

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

@ghost

ghost commented Jun 14, 2026

Copy link
Copy Markdown

gittensory · advisory review

Reviewed 8 changed file(s) — two independent AI reviewers.

Suggested action: 🔍 Manual review. The changed route's preview could not be captured — review the rendered page manually before merging.

Reviewer A · gpt-oss-120b — recommends ✅ merge
This PR introduces an upstream time‑decay multiplier to scoring previews, adds a default‑off env‑gated flag, updates schemas, constants, and tests. The implementation is clean, type‑safe, and includes comprehensive unit tests.

Suggestions

  • Add a brief description for the new timeDecayMultiplier property in the OpenAPI spec for better documentation.
  • Consider adding an integration test for the API endpoint to verify the field appears in the JSON response when the flag is enabled.
  • Document the new SCORING_TIME_DECAY_ENABLED env var in the project's README or configuration guide.

Worth double-checking

  • Consumers of the scoring preview API must handle the additional timeDecayMultiplier field; ensure downstream code tolerates extra properties.
  • If the env flag is mistakenly enabled in production, aged PR scores will be reduced – verify operational monitoring reflects this change.

Reviewer B · nemotron-3-120b-a12b — recommends ✅ merge
The PR adds an optional upstream time-decay feature to score previews, controlled by a default-off environment variable (SCORING_TIME_DECAY_ENABLED). It introduces prAgeHours and applyTimeDecay inputs, a timeDecayMultiplier in results, and implements the decay logic via a sigmoid function with grace period. Changes are confined to scoring logic, API routes, MCP server, OpenAPI schemas, and tests. The feature is owner-gated and off by default, preserving the public/private boundary as it does not introduce forbidden terms in public output.

Suggestions

  • Consider adding a JSDoc comment to calculateTimeDecay explaining the sigmoid formula's parameters for future maintainers.
  • Verify that the OpenAPI spec updates (apps/gittensory-ui/public/openapi.json) are complete and consistent with the schema definitions in src/openapi/schemas.ts.
  • Ensure the environment variable documentation (in src/env.d.ts) note that the value is case-insensitive (already handled by regex).

Worth double-checking

  • When enabled, time decay will reduce estimated scores for aged PRs; owners must review the before/after impact as noted in the comment.
  • The calculateTimeDecay function uses constants from DEFAULT_SCORING_CONSTANTS; ensure these constants are not overridden unexpectedly in specific environments.
  • The OpenAPI spec updates are manual and error-prone; consider automating spec generation from schemas to avoid drift.

Warning

Could not capture a preview of the changed route(s) — review the rendered page manually before merging.

Before = production · After = this PR's preview deploy.

Route Viewport Before After
/ desktop before desktop after desktop
mobile before mobile after mobile

@ghost ghost added the gittensory-review label Jun 14, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
gittensory-ui 52dbcd9 Commit Preview URL

Branch Preview URL
Jun 14 2026, 04:55 PM

@JSONbored
JSONbored merged commit c217f17 into main Jun 14, 2026
12 checks passed
@JSONbored
JSONbored deleted the feat/time-decay-scoring branch June 14, 2026 16:57
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jun 14, 2026
@github-actions github-actions Bot mentioned this pull request Jun 14, 2026
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant