Summary
The score-preview time-decay resolver does not coerce a repo's scoring.time_decay.grace_period_hours override to an integer, so a fractionally-configured grace period diverges from what the upstream gittensor validator awards. The preview reports a higher score than the validator for a PR aged between trunc(grace) and grace.
Area
Registry sync
Expected behavior
Upstream resolve_time_decay (gittensor/validator/utils/load_weights.py) coerces the grace period — and only the grace period — to an integer:
return ResolvedTimeDecay(
grace_period_hours=int(pick(cfg.grace_period_hours, TIME_DECAY_GRACE_PERIOD_HOURS)), # int() — truncates
sigmoid_midpoint_days=float(pick(cfg.sigmoid_midpoint_days, TIME_DECAY_SIGMOID_MIDPOINT)),
sigmoid_steepness=float(pick(cfg.sigmoid_steepness, TIME_DECAY_SIGMOID_STEEPNESS_SCALAR)),
min_multiplier=float(pick(cfg.min_multiplier, TIME_DECAY_MIN_MULTIPLIER)),
)
Upstream's range check permits 0 <= grace_period_hours <= 168, so a maintainer can legally configure a fractional value (e.g. 13.9); upstream then truncates it to 13. gittensory's resolveTimeDecay (src/scoring/preview.ts) advertises that it "Mirrors upstream's resolve_time_decay" and should match this integer coercion.
Actual behavior
resolveTimeDecay passes the raw override through unchanged:
gracePeriodHours: pickOverride(overrides?.gracePeriodHours, constant(constants, "TIME_DECAY_GRACE_PERIOD_HOURS")),
and parseTimeDecayOverrides (src/registry/normalize.ts) reads grace_period_hours straight through with no truncation. calculateTimeDecay then compares prAgeHours < gracePeriodHours against the un-truncated float.
With scoring.time_decay.grace_period_hours = 13.9 and time-decay enabled (SCORING_TIME_DECAY_ENABLED), a PR aged 13.5h:
- Upstream: grace =
13 -> 13.5 >= 13 -> out of grace -> decay multiplier < 1, score reduced.
- gittensory preview: grace =
13.9 -> 13.5 < 13.9 -> treated as fresh -> multiplier 1.0, no decay.
The preview silently over-states the score relative to the validator — the same class of upstream-parity drift addressed in #806/#807/#808/#812.
Reproduction
With a repo registry config of scoring.time_decay.grace_period_hours: 13.9 and applyTimeDecay on, calculateTimeDecay(13.5, constants, { gracePeriodHours: 13.9 }) returns 1 (no decay) instead of a value < 1.
Validation
Fix is local to resolveTimeDecay; covered by test/unit/scoring.test.ts (resolveTimeDecay overlays per-repo overrides…, calculateTimeDecay …). A regression test pins both the truncation and the boundary-decay behavior. Full local gate (npm run test:ci) is green.
Summary
The score-preview time-decay resolver does not coerce a repo's
scoring.time_decay.grace_period_hoursoverride to an integer, so a fractionally-configured grace period diverges from what the upstream gittensor validator awards. The preview reports a higher score than the validator for a PR aged betweentrunc(grace)andgrace.Area
Registry sync
Expected behavior
Upstream
resolve_time_decay(gittensor/validator/utils/load_weights.py) coerces the grace period — and only the grace period — to an integer:Upstream's range check permits
0 <= grace_period_hours <= 168, so a maintainer can legally configure a fractional value (e.g.13.9); upstream then truncates it to13.gittensory'sresolveTimeDecay(src/scoring/preview.ts) advertises that it "Mirrors upstream'sresolve_time_decay" and should match this integer coercion.Actual behavior
resolveTimeDecaypasses the raw override through unchanged:and
parseTimeDecayOverrides(src/registry/normalize.ts) readsgrace_period_hoursstraight through with no truncation.calculateTimeDecaythen comparesprAgeHours < gracePeriodHoursagainst the un-truncated float.With
scoring.time_decay.grace_period_hours = 13.9and time-decay enabled (SCORING_TIME_DECAY_ENABLED), a PR aged 13.5h:13->13.5 >= 13-> out of grace -> decay multiplier< 1, score reduced.13.9->13.5 < 13.9-> treated as fresh -> multiplier1.0, no decay.The preview silently over-states the score relative to the validator — the same class of upstream-parity drift addressed in #806/#807/#808/#812.
Reproduction
With a repo registry config of
scoring.time_decay.grace_period_hours: 13.9andapplyTimeDecayon,calculateTimeDecay(13.5, constants, { gracePeriodHours: 13.9 })returns1(no decay) instead of a value< 1.Validation
Fix is local to
resolveTimeDecay; covered bytest/unit/scoring.test.ts(resolveTimeDecay overlays per-repo overrides…,calculateTimeDecay …). A regression test pins both the truncation and the boundary-decay behavior. Full local gate (npm run test:ci) is green.