claude/probability-config-review-1tdolw #119
2 changed files with 25 additions and 9 deletions
|
|
@ -69,6 +69,25 @@ interface ActionData {
|
|||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Engine knobs that a simulator (or the shared input-policy resolver) actually
|
||||
* reads from config. The structured Engine fields are limited to these so the UI
|
||||
* never shows a control that silently does nothing — bespoke per-sim constants
|
||||
* (e.g. homeFieldElo, eloDivisor, srsEloScale, raceNoise) that live in a profile
|
||||
* but are not read from config stay editable only via the raw-JSON escape hatch.
|
||||
*/
|
||||
const HONORED_ENGINE_KNOBS = new Set([
|
||||
"iterations",
|
||||
"parityFactor",
|
||||
"seasonGames",
|
||||
"overtimeRate",
|
||||
"matchParityFactor",
|
||||
"averageOpponentElo",
|
||||
"baseDrawRate",
|
||||
"drawDecay",
|
||||
"ratingScaleFactor",
|
||||
]);
|
||||
|
||||
function parseOptionalNumber(value: string | undefined): number | null {
|
||||
if (value === undefined || value.trim() === "") return null;
|
||||
const parsed = Number(value);
|
||||
|
|
@ -335,7 +354,7 @@ export default function AdminSportsSeasonSimulator({ loaderData }: Route.Compone
|
|||
// nested object edited in its own section). Driving the fields from the merged
|
||||
// config means each simulator shows exactly the knobs it actually reads.
|
||||
const engineEntries = Object.entries(config.config)
|
||||
.filter(([key, value]) => key !== "inputPolicy" && typeof value === "number")
|
||||
.filter(([key, value]) => HONORED_ENGINE_KNOBS.has(key) && typeof value === "number")
|
||||
.map(([key, value]) => [key, value as unknown as number] as [string, number]);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -254,14 +254,11 @@ export function resolveSourceElos(
|
|||
);
|
||||
}
|
||||
if (oddsInputs.length >= 2) {
|
||||
// Map onto the configured Elo band so the policy's floor/ceiling set the
|
||||
// odds-derived *spread* (the real flattening dial), not just a post-hoc clamp.
|
||||
const converted = convertFuturesToElo(oddsInputs, "american", {
|
||||
exponent: 0.33,
|
||||
eloMin: policy.eloMin,
|
||||
eloMax: policy.eloMax,
|
||||
});
|
||||
for (const [participantId, elo] of converted) {
|
||||
// Odds map onto the calibrated band (probability-engine DEFAULT_CALIBRATION);
|
||||
// the policy's eloMin/eloMax then clamp the result via clampDerived below, so
|
||||
// a season's Elo floor/ceiling still narrows the odds-derived spread without
|
||||
// widening it (and without clamping a high directly-entered base Elo's blend).
|
||||
for (const [participantId, elo] of convertFuturesToElo(oddsInputs)) {
|
||||
oddsElo.set(participantId, elo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue