Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/components/prs/PRTimeDecayChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
buildDecaySubline,
type DecayParams,
type DecayProjection,
fitCurveThroughPoint,
resolveDecayParams,
} from './prTimeDecayModel';

Expand Down Expand Up @@ -252,14 +253,18 @@ function buildChartOption(
const fontFamily = echartsFontFamily(theme);
const mutedHex = alpha(theme.palette.common.white, TEXT_OPACITY.tertiary);
const marker = resolveNowMarker(projection);
const seriesData = injectNowPoint(buildDecayCurve(params), marker);
const curveParams =
projection.curveMismatch && marker
? fitCurveThroughPoint(params, marker.day, marker.multiplier)
: params;
const seriesData = injectNowPoint(buildDecayCurve(curveParams), marker);
return {
...echartsTransparentBackground(),
grid: { left: 44, right: 16, top: 28, bottom: 36 },
tooltip: buildTooltip(theme, projection.preDecayScore, mutedHex),
xAxis: buildXAxis(axis, fontFamily, params.lookbackDays),
xAxis: buildXAxis(axis, fontFamily, curveParams.lookbackDays),
yAxis: buildYAxis(axis),
series: [buildSeries(theme, axis, params, seriesData, marker)],
series: [buildSeries(theme, axis, curveParams, seriesData, marker)],
};
}

Expand Down
27 changes: 26 additions & 1 deletion src/components/prs/prTimeDecayModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,31 @@ export function resolveDecayParams(
};
}

/**
* Re-fit the sigmoid midpoint so the curve passes through the subnet-reported
* (day, multiplier) point. Repos can override decay hyperparameters without
* the API publishing them (`/repos/{name}` only exposes emission shares), so
* when the reported multiplier contradicts the resolved params the fitted
* curve is the closest available approximation of the repo's real schedule.
*/
export function fitCurveThroughPoint(
params: DecayParams,
day: number,
multiplier: number,
): DecayParams {
if (!(multiplier > params.floor) || !(multiplier < 1) || day <= 0) {
return params;
}
const midpoint = day - Math.log(1 / multiplier - 1) / params.steepness;
return {
...params,
midpoint,
// A reported multiplier below 1 means decay already started, so the
// grace period cannot extend past the merge age.
graceHours: Math.min(params.graceHours, day * 24),
};
}

function decayAt(days: number, params: DecayParams): number {
if (days <= params.graceHours / 24) return 1;
const sigmoid =
Expand Down Expand Up @@ -214,6 +239,6 @@ export function buildDecaySubline(projection: DecayProjection): string {
}
const base = `${projection.daysSinceMerge.toFixed(1)} day(s) since merge`;
return projection.curveMismatch
? `${base} · showing subnet-reported multiplier (curve is approximate)`
? `${base} · curve fitted to subnet-reported multiplier (repo overrides decay params)`
: base;
}
Loading