From ac20fe9ef7eda5fd61cf67eed45dcfbb06be289c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 08:45:10 +0000 Subject: [PATCH] feat: add candidateScoreNonWinnerQMGMGap to cast explanation (80808080) https://claude.ai/code/session_01VKBFeSfC62NKttk4spVHsB --- src/aggregator.ts | 3 +- ...-cast-explain-non-winner-qm-gm-gap.test.ts | 263 ++++++++++++++++++ 2 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 test/80808080-cast-explain-non-winner-qm-gm-gap.test.ts diff --git a/src/aggregator.ts b/src/aggregator.ts index 425104f..7bb2cca 100644 --- a/src/aggregator.ts +++ b/src/aggregator.ts @@ -405,6 +405,7 @@ export class Aggregator { 'explanation also includes candidateScoreNonWinnerQMHMRatio: number — the ratio of the non-winner quadratic mean to the non-winner harmonic mean: candidateScoreNonWinnerQuadraticMean / candidateScoreNonWinnerHarmonicMean. Present when >= 3 candidates and all non-winner scores are positive (same conditions as candidateScoreNonWinnerHarmonicMean). Absent on cast:no_match, fewer than 3 candidates, or when any non-winner score is zero. Always >= 1: the quadratic mean is always >= the harmonic mean (QM >= AM >= GM >= HM by the Power Mean inequality chain). Equals 1 exactly when all non-winner scores are equal (tied non-winner pool). For n=3: equals sqrt((runnerUpScore^2 + thirdCandidateScore^2) / 2) * (runnerUpScore + thirdCandidateScore) / (2 * runnerUpScore * thirdCandidateScore). Product decomposition: candidateScoreNonWinnerQMHMRatio === candidateScoreNonWinnerQMToAMRatio * candidateScoreNonWinnerAMHMRatio — the QM-to-HM ratio factors exactly into the QM-to-AM ratio and the AM-to-HM ratio. Always >= candidateScoreNonWinnerAMHMRatio: since QM >= AM, QM/HM >= AM/HM. Identity: candidateScoreNonWinnerQMHMRatio * candidateScoreNonWinnerHarmonicMean === candidateScoreNonWinnerQuadraticMean always holds when both are present. Provides the broadest single-ratio view of the non-winner Power Mean spread, spanning the entire HM-to-QM range and combining both the AM-to-HM inequality inequality and the QM-to-AM excess in a single multiplicative measure. ' + 'explanation also includes candidateScoreNonWinnerQMGMRatio: number — the ratio of the non-winner quadratic mean to the non-winner geometric mean: candidateScoreNonWinnerQuadraticMean / candidateScoreNonWinnerGeometricMean. Present when >= 3 candidates and all non-winner scores are positive (same conditions as candidateScoreNonWinnerGeometricMean). Absent on cast:no_match, fewer than 3 candidates, or when any non-winner score is zero. Always >= 1: the quadratic mean is always >= the geometric mean (QM >= AM >= GM by the Power Mean inequality chain). Equals 1 exactly when all non-winner scores are equal (tied non-winner pool). For n=3: equals sqrt((runnerUpScore^2 + thirdCandidateScore^2) / 2) / sqrt(runnerUpScore * thirdCandidateScore), which simplifies to sqrt((runnerUpScore^2 + thirdCandidateScore^2) / (2 * runnerUpScore * thirdCandidateScore)). Product decomposition: candidateScoreNonWinnerQMGMRatio === candidateScoreNonWinnerQMToAMRatio * candidateScoreNonWinnerAMGMRatio — the QM-to-GM ratio factors exactly into the QM-to-AM ratio and the AM-to-GM ratio, since QM/GM = (QM/AM) * (AM/GM). Always >= candidateScoreNonWinnerQMToAMRatio: since GM <= AM, QM/GM >= QM/AM. Always >= candidateScoreNonWinnerAMGMRatio: since QM >= AM, QM/GM >= AM/GM. Identity: candidateScoreNonWinnerQMGMRatio * candidateScoreNonWinnerGeometricMean === candidateScoreNonWinnerQuadraticMean always holds when both are present. Together with candidateScoreNonWinnerAMGMRatio, candidateScoreNonWinnerGMHMRatio, candidateScoreNonWinnerQMToAMRatio, candidateScoreNonWinnerQMHMRatio, and candidateScoreNonWinnerAMHMRatio, completes the full set of pairwise ratios between the four classical Pythagorean means (HM, GM, AM, QM) for the non-winner pool. ' + 'explanation also includes candidateScoreNonWinnerQMHMGap: number — the absolute gap between the non-winner quadratic mean and the non-winner harmonic mean: candidateScoreNonWinnerQuadraticMean - candidateScoreNonWinnerHarmonicMean. Present when >= 3 candidates and all non-winner scores are positive (same conditions as candidateScoreNonWinnerHarmonicMean). Absent on cast:no_match, fewer than 3 candidates, or when any non-winner score is zero. Always >= 0: the quadratic mean is always >= the harmonic mean (QM >= HM). Zero exactly when all non-winner scores are equal (tied non-winner pool). For n=3: equals sqrt((runnerUpScore^2 + thirdCandidateScore^2) / 2) - 2 * runnerUpScore * thirdCandidateScore / (runnerUpScore + thirdCandidateScore). Additive decomposition: candidateScoreNonWinnerQMHMGap === candidateScoreNonWinnerQMGap + candidateScoreNonWinnerAMGMGap + candidateScoreNonWinnerGMHMGap — the QM-to-HM gap is exactly the sum of the three consecutive step gaps: (QM-AM) + (AM-GM) + (GM-HM), because QM - HM = (QM - AM) + (AM - GM) + (GM - HM). Always >= candidateScoreNonWinnerAMHMGap: since QM >= AM, QM - HM >= AM - HM. Always >= candidateScoreNonWinnerQMGap: since HM <= AM, QM - HM >= QM - AM. Identity: candidateScoreNonWinnerQMHMGap + candidateScoreNonWinnerHarmonicMean === candidateScoreNonWinnerQuadraticMean always holds when both are present. Provides the widest single additive measure of non-winner Power Mean spread, spanning the entire HM-to-QM range; complements candidateScoreNonWinnerQMHMRatio by expressing the same QM-to-HM distance in absolute rather than multiplicative terms. ' + + 'explanation also includes candidateScoreNonWinnerQMGMGap: number — the absolute gap between the non-winner quadratic mean and the non-winner geometric mean: candidateScoreNonWinnerQuadraticMean - candidateScoreNonWinnerGeometricMean. Present when >= 3 candidates and all non-winner scores are positive (same conditions as candidateScoreNonWinnerGeometricMean). Absent on cast:no_match, fewer than 3 candidates, or when any non-winner score is zero. Always >= 0: the quadratic mean is always >= the geometric mean (QM >= GM). Zero exactly when all non-winner scores are equal (tied non-winner pool). For n=3: equals sqrt((runnerUpScore^2 + thirdCandidateScore^2) / 2) - sqrt(runnerUpScore * thirdCandidateScore). Additive decomposition: candidateScoreNonWinnerQMGMGap === candidateScoreNonWinnerQMGap + candidateScoreNonWinnerAMGMGap — the QM-to-GM gap is exactly the sum of the QM-to-AM gap and the AM-to-GM gap: (QM - GM) = (QM - AM) + (AM - GM). Always >= candidateScoreNonWinnerQMGap (candidateScoreNonWinnerQMGap = QM - AM): since GM <= AM, QM - GM >= QM - AM. Always >= candidateScoreNonWinnerAMGMGap (candidateScoreNonWinnerAMGMGap = AM - GM): since QM >= AM, QM - GM >= AM - GM. Always <= candidateScoreNonWinnerQMHMGap: since GM >= HM, QM - GM <= QM - HM. Identity: candidateScoreNonWinnerQMGMGap + candidateScoreNonWinnerGeometricMean === candidateScoreNonWinnerQuadraticMean always holds when both are present. Complements candidateScoreNonWinnerQMGMRatio by expressing the QM-to-GM relationship additively rather than multiplicatively; together with candidateScoreNonWinnerAMGMGap and candidateScoreNonWinnerQMGap, allows a two-step additive decomposition of the QM-to-AM and AM-to-GM contributions. ' + 'explanation also includes winnerThirdGapToSpreadRatio: number — the winner-to-3rd gap as a fraction of the full candidate score spread: (winnerScore - thirdCandidateScore) / candidateScoreSpread. Present when >= 3 candidates exist and candidateScoreSpread > 0. Absent on cast:no_match, fewer than 3 candidates, or when spread is 0. Always in [0, 1]: winnerThirdGap <= spread (since thirdCandidateScore >= lowestCandidateScore). Additive decomposition: winnerThirdGapToSpreadRatio === winnerRunnerUpGapToSpreadRatio + runnerUpThirdGapToSpreadRatio — the winner-to-3rd ratio is exactly the sum of the winner-to-runner-up ratio and the runner-up-to-3rd ratio (the spread fractions add because their gaps partition the winner-to-3rd interval). For n=3: winnerThirdGapToSpreadRatio === 1, because thirdCandidateScore === lowestCandidateScore, so winner - third = winner - lowest = spread. Always >= winnerRunnerUpGapToSpreadRatio: winnerThirdGap >= winnerRunnerUpGap (same divisor). Provides a single normalised view of how far the top 3 candidates span the full score range, complementing the two-part decomposition into winnerRunnerUpGapToSpreadRatio and runnerUpThirdGapToSpreadRatio. Identity: winnerThirdGapToSpreadRatio * candidateScoreSpread === winnerThirdGap always holds when both are present. ' + 'explanation also includes winnerThirdGap: number — the absolute score gap between the winner (1st-ranked) and the 3rd-ranked candidate: winnerScore - thirdCandidateScore. Present when >= 3 candidates exist. Absent on cast:no_match or when fewer than 3 candidates exist. Always >= 0: winnerScore >= thirdCandidateScore by ranking. Always >= winnerRunnerUpGap: the winner-to-3rd gap spans at least as far as the winner-to-runner-up gap because thirdCandidateScore <= runnerUpScore. Always <= candidateScoreSpread: thirdCandidateScore >= lowestCandidateScore, so winner - third <= winner - lowest = spread. For n=3: winnerThirdGap === candidateScoreSpread (because thirdCandidateScore === lowestCandidateScore when n=3, so winner - third = winner - lowest = spread). Additive decomposition: winnerThirdGap === winnerRunnerUpGap + runnerUpThirdGap — the winner-to-3rd gap is exactly the sum of the winner-to-runner-up gap and the runner-up-to-3rd gap. This decomposition makes explicit how each step contributes to the overall winner-to-3rd distance. Identity: winnerThirdGap === winnerScore - thirdCandidateScore always holds when both are present. ' + 'explanation also includes runnerUpThirdGapToSpreadRatio: number — the runner-up-to-3rd gap as a fraction of the full candidate score spread: (runnerUpScore - thirdCandidateScore) / candidateScoreSpread. Present when >= 3 candidates exist and candidateScoreSpread > 0. Absent on cast:no_match, fewer than 3 candidates, or when spread is 0 (all candidates tied). Always in [0, 1]: runnerUpThirdGap = runnerUp - third <= winner - lowest = spread (since third >= lowest), so the ratio is at most 1; and the gap is >= 0, so the ratio is at most 1. For n=3: runnerUpThirdGapToSpreadRatio equals runnerUpLowestGapToSpreadRatio (since thirdCandidateScore === lowestCandidateScore when n=3); and winnerRunnerUpGapToSpreadRatio + runnerUpThirdGapToSpreadRatio === 1 (the two gaps partition the full spread exactly when n=3, because winnerRunnerUpGap + runnerUpThirdGap = winner - third = winner - lowest = spread). Provides the second step of a two-step spread decomposition alongside winnerRunnerUpGapToSpreadRatio: the winner-to-runner-up fraction plus the runner-up-to-3rd fraction; for n > 3 their sum is < 1 (score mass remains below the 3rd candidate). Identity: runnerUpThirdGapToSpreadRatio * candidateScoreSpread === runnerUpThirdGap always holds when both are present. ' + @@ -2348,7 +2349,7 @@ function buildCastExplanation( ...(brainMs !== undefined ? { brainMs } : {}), candidateCount: scoredTools.length, ...(best !== undefined ? { winnerScore: best.score, winnerServer: best.namespacedName.split('/')[0], winnerCategory: best.category, topCandidatesMeanScore: topCandidates.reduce((s, c) => s + c.score, 0) / topCandidates.length, ...(candidateScoreEntropyTotal > 0 ? { scoreDominanceIndex: best.score / candidateScoreEntropyTotal } : {}), ...(scoredTools.length >= 2 && candidateScoreEntropyTotal > 0 ? { nonWinnerScoreHeavinessRatio: (candidateScoreEntropyTotal - best.score) / candidateScoreEntropyTotal } : {}) } : {}), - ...(topCandidates.length > 1 ? { runnerUpScore: topCandidates[1].score, runnerUpTool: topCandidates[1].tool, runnerUpServer: topCandidates[1].tool.split('/')[0], runnerUpCategory: scoredTools[1].category, candidateScoreSpread: scoredTools[0].score - scoredTools[scoredTools.length - 1].score, lowestCandidateScore: scoredTools[scoredTools.length - 1].score, ...(scoredTools.length >= 3 ? { thirdCandidateScore: scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > 0 ? { thirdCandidateScoreToWinnerRatio: scoredTools[2].score / scoredTools[0].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { winnerThirdGapToSpreadRatio: (scoredTools[0].score - scoredTools[2].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 ? { winnerThirdGap: scoredTools[0].score - scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { runnerUpThirdGapToSpreadRatio: (topCandidates[1].score - scoredTools[2].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 && candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { thirdCandidateScoreZScore: (scoredTools[2].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { lowestCandidateScoreZScore: (scoredTools[scoredTools.length - 1].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { candidateScoreStandardizedRange: (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) / candidateScoreStdDev } : {}), ...(scoredTools.length >= 3 ? { runnerUpThirdGap: topCandidates[1].score - scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && candidateScoreEntropyTotal > 0 ? { thirdCandidateScoreToMeanRatio: scoredTools[2].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 ? { thirdCandidateScoreToRunnerUpRatio: scoredTools[2].score / topCandidates[1].score } : {}), ...(candidateScoreEntropy !== undefined ? { candidateScoreEntropy } : {}), ...(candidateGiniCoefficient !== undefined ? { candidateGiniCoefficient } : {}), ...(candidateScoreSkewness !== undefined ? { candidateScoreSkewness } : {}), ...(candidateScoreKurtosis !== undefined ? { candidateScoreKurtosis } : {}), ...(candidateScoreVariance !== undefined ? { candidateScoreVariance } : {}), ...(candidateScoreStdDev !== undefined ? { candidateScoreStdDev } : {}), candidateScoreMean: candidateScoreEntropyTotal / scoredTools.length, ...(medianCandidateScore !== undefined ? { medianCandidateScore } : {}), ...(scoredTools[0].score > 0 ? { candidateScoreMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / scoredTools[0].score } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreCoefficientOfVariation: candidateScoreStdDev / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && candidateScoreEntropyTotal > 0 ? { medianToMeanRatio: medianCandidateScore / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { winnerToMedianRatio: scoredTools[0].score / medianCandidateScore } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { winnerScoreZScore: (scoredTools[0].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { runnerUpScoreZScore: (topCandidates[1].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { zScoreGap: (scoredTools[0].score - topCandidates[1].score) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { nonWinnerMeanZScore: ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreNormalizedRange: (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(scoredTools[0].score > 0 ? { lowestCandidateScoreRatio: scoredTools[scoredTools.length - 1].score / scoredTools[0].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreLowestToMeanRatio: scoredTools[scoredTools.length - 1].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreLowestToMedianRatio: scoredTools[scoredTools.length - 1].score / medianCandidateScore } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreLowestToGeometricMeanRatio: scoredTools[scoredTools.length - 1].score / candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreLowestToHarmonicMeanRatio: scoredTools[scoredTools.length - 1].score / candidateScoreHarmonicMean } : {}), ...(nonZeroCandidateFraction !== undefined ? { nonZeroCandidateFraction } : {}), ...(topHeavinessRatio !== undefined ? { topHeavinessRatio } : {}), ...(candidateScoreHerfindahlIndex !== undefined ? { candidateScoreHerfindahlIndex } : {}), ...(effectiveN !== undefined ? { effectiveN } : {}), ...(scoreEntropyNormalized !== undefined ? { scoreEntropyNormalized } : {}), ...(candidateScoreIQR !== undefined ? { candidateScoreIQR } : {}), ...(candidateScoreIQRRatio !== undefined ? { candidateScoreIQRRatio } : {}), ...(candidateScoreIQR !== undefined && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { candidateScoreIQRCoverage: candidateScoreIQR / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(candidateScoreEntropyTotal > 0 ? { top2HeavinessRatio: (scoredTools[0].score + topCandidates[1].score) / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && topCandidates[1].score > 0 ? { runnerUpScoreHeavinessRatio: topCandidates[1].score / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestCandidateScoreHeavinessRatio: scoredTools[scoredTools.length - 1].score / candidateScoreEntropyTotal } : {}), ...(scoredTools.length >= 3 && candidateScoreEntropyTotal > 0 && scoredTools[2].score > 0 ? { thirdCandidateScoreHeavinessRatio: scoredTools[2].score / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 ? { winnerToNonWinnerMassRatio: scoredTools[0].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 && topCandidates[1].score > 0 ? { runnerUpToNonWinnerMassRatio: topCandidates[1].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestToNonWinnerMassRatio: scoredTools[scoredTools.length - 1].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestToRunnerUpRatio: scoredTools[scoredTools.length - 1].score / topCandidates[1].score } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[2].score > 0 ? { thirdToRunnerUpRatio: scoredTools[2].score / topCandidates[1].score } : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? { candidateScoreNonWinnerGeometricMean: Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)) } : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? { candidateScoreNonWinnerHarmonicMean: (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0) } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { candidateScoreNonWinnerMidRange: (topCandidates[1].score + scoredTools[scoredTools.length - 1].score) / 2 } : {}), ...(scoredTools.length >= 3 ? { runnerUpToNonWinnerMeanGap: topCandidates[1].score - (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) } : {}), ...(scoredTools.length >= 3 ? { lowestToNonWinnerMeanGap: (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) - scoredTools[scoredTools.length - 1].score } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? (() => { const midRange = (topCandidates[1].score + scoredTools[scoredTools.length - 1].score) / 2; return { candidateScoreNonWinnerMeanToMidRangeRatio: ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) / midRange }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerAMGMGap: nwMean - nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerAMHMGap: nwMean - nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerGMHMGap: nwGM - nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerGMHMRatio: nwGM / nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerAMGMRatio: nwMean / nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerAMHMRatio: nwMean / nwHM }; })() : {}), ...(scoredTools.length >= 3 ? { candidateScoreNonWinnerQuadraticMean: Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)) } : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMToAMRatio: nwQM / nwMean }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMGap: nwQM - nwMean }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerQMHMRatio: nwQM / nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMGMRatio: nwQM / nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerQMHMGap: nwQM - nwHM }; })() : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreTop3HeavinessRatio: scoredTools.slice(0, 3).reduce((s, t) => s + t.score, 0) / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreTop4HeavinessRatio: scoredTools.slice(0, 4).reduce((s, t) => s + t.score, 0) / candidateScoreEntropyTotal } : {}), ...{ winnerMeanGap: scoredTools[0].score - candidateScoreEntropyTotal / scoredTools.length }, ...{ winnerRunnerUpGap: scoredTools[0].score - topCandidates[1].score }, ...(scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { winnerRunnerUpGapToSpreadRatio: (scoredTools[0].score - topCandidates[1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { runnerUpLowestGapToSpreadRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...{ runnerUpMeanGap: topCandidates[1].score - candidateScoreEntropyTotal / scoredTools.length }, ...(candidateScoreGeometricMean !== undefined ? { candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined ? { candidateScoreHarmonicMean } : {}), ...(candidateScoreP90 !== undefined ? { candidateScoreP90 } : {}), ...(candidateScoreP10 !== undefined ? { candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP10 !== undefined ? { candidateScoreP80Range: candidateScoreP90 - candidateScoreP10 } : {}), ...(candidateScoreMAD !== undefined ? { candidateScoreMAD } : {}), ...(candidateScoreMADRatio !== undefined ? { candidateScoreMADRatio } : {}), ...(candidateScoreRobustSkewness !== undefined ? { candidateScoreRobustSkewness } : {}), ...(candidateScoreQuantileSkewness !== undefined ? { candidateScoreQuantileSkewness } : {}), ...(candidateScoreWinsorizedMean !== undefined ? { candidateScoreWinsorizedMean } : {}), ...(candidateScoreJainFairnessIndex !== undefined ? { candidateScoreJainFairnessIndex } : {}), ...(candidateScoreP75 !== undefined ? { candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined ? { candidateScoreP25 } : {}), ...(candidateScoreP95 !== undefined ? { candidateScoreP95 } : {}), ...(candidateScoreP05 !== undefined ? { candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP05 !== undefined ? { candidateScoreP90Range: candidateScoreP95 - candidateScoreP05 } : {}), ...(candidateScoreTrimmedMean !== undefined ? { candidateScoreTrimmedMean } : {}), ...{ candidateScoreNonWinnerMean: (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) }, ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); return { candidateScoreNonWinnerStdDev: Math.sqrt(nwVariance) }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); return { candidateScoreNonWinnerCoefficientOfVariation: Math.sqrt(nwVariance) / nwMean }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev <= 0) return {}; return { winnerNonWinnerZScore: (scoredTools[0].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev < 1e-10) return {}; return { runnerUpNonWinnerZScore: (topCandidates[1].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev < 1e-10) return {}; return { lowestNonWinnerZScore: (scoredTools[scoredTools.length - 1].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? { candidateScoreNonWinnerSpread: topCandidates[1].score - scoredTools[scoredTools.length - 1].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { candidateScoreNonWinnerSpreadRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; return { candidateScoreNonWinnerSpreadToMeanRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / nwMean }; })() : {}), ...{ candidateScoreWinnerFieldGap: scoredTools[0].score - (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) }, ...(scoredTools[0].score > 0 ? { candidateScoreFieldStrengthRatio: (candidateScoreEntropyTotal - scoredTools[0].score) / ((scoredTools.length - 1) * scoredTools[0].score) } : {}), ...(topCandidates[1].score > 0 ? { winnerScoreToNonWinnerMeanRatio: scoredTools[0].score / ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) } : {}), ...(topCandidates[1].score > 0 ? { runnerUpScoreToNonWinnerMeanRatio: topCandidates[1].score / ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { winnerScoreToP95Ratio: scoredTools[0].score / candidateScoreP95 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { winnerScoreToP05Ratio: scoredTools[0].score / candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreTailAsymmetryRatio: candidateScoreP95 / candidateScoreP05 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP75P25Ratio: candidateScoreP75 / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreMedianToP90Ratio: medianCandidateScore / candidateScoreP90 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP90P10Ratio: candidateScoreP90 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { winnerScoreToP90Ratio: scoredTools[0].score / candidateScoreP90 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { winnerScoreToP10Ratio: scoredTools[0].score / candidateScoreP10 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { winnerScoreToP75Ratio: scoredTools[0].score / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { winnerScoreToP25Ratio: scoredTools[0].score / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreMedianToP10Ratio: medianCandidateScore / candidateScoreP10 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreMedianToP75Ratio: medianCandidateScore / candidateScoreP75 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreMedianToP25Ratio: medianCandidateScore / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreMedianToP05Ratio: medianCandidateScore / candidateScoreP05 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { candidateScoreMedianToP95Ratio: medianCandidateScore / candidateScoreP95 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreP95P75Ratio: candidateScoreP95 / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP25P05Ratio: candidateScoreP25 / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreP90P75Ratio: candidateScoreP90 / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP25P10Ratio: candidateScoreP25 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP90P25Ratio: candidateScoreP90 / candidateScoreP25 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP95P10Ratio: candidateScoreP95 / candidateScoreP10 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP95P25Ratio: candidateScoreP95 / candidateScoreP25 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP75P10Ratio: candidateScoreP75 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP90P05Ratio: candidateScoreP90 / candidateScoreP05 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP75P05Ratio: candidateScoreP75 / candidateScoreP05 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP10P05Ratio: candidateScoreP10 / candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreP95P90Ratio: candidateScoreP95 / candidateScoreP90 } : {}), ...(candidateScoreP90 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP90MedianRatio: candidateScoreP90 / medianCandidateScore } : {}), ...(candidateScoreP75 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP75MedianRatio: candidateScoreP75 / medianCandidateScore } : {}), ...(candidateScoreP95 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP95MedianRatio: candidateScoreP95 / medianCandidateScore } : {}), ...(candidateScoreP10 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP10MedianRatio: candidateScoreP10 / medianCandidateScore } : {}), ...(candidateScoreP25 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP25MedianRatio: candidateScoreP25 / medianCandidateScore } : {}), ...(candidateScoreP05 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP05MedianRatio: candidateScoreP05 / medianCandidateScore } : {}), ...(candidateScoreP90 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP90ToWinnerRatio: candidateScoreP90 / scoredTools[0].score } : {}), ...(candidateScoreP75 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP75ToWinnerRatio: candidateScoreP75 / scoredTools[0].score } : {}), ...(candidateScoreP95 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP95ToWinnerRatio: candidateScoreP95 / scoredTools[0].score } : {}), ...(candidateScoreP25 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP25ToWinnerRatio: candidateScoreP25 / scoredTools[0].score } : {}), ...(candidateScoreP10 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP10ToWinnerRatio: candidateScoreP10 / scoredTools[0].score } : {}), ...(candidateScoreP05 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP05ToWinnerRatio: candidateScoreP05 / scoredTools[0].score } : {}), ...(candidateScoreP90 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP90ToMeanRatio: candidateScoreP90 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP75 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP75ToMeanRatio: candidateScoreP75 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP95 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP95ToMeanRatio: candidateScoreP95 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP10 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP10ToMeanRatio: candidateScoreP10 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP25 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP25ToMeanRatio: candidateScoreP25 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP05 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP05ToMeanRatio: candidateScoreP05 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreMeanToP90Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP90 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreMeanToP75Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP75 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { candidateScoreMeanToP95Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP95 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreMeanToP10Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP10 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreMeanToP25Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP25 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreMeanToP05Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { runnerUpScoreToP90Ratio: topCandidates[1].score / candidateScoreP90 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { runnerUpScoreToP75Ratio: topCandidates[1].score / candidateScoreP75 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { runnerUpScoreToP95Ratio: topCandidates[1].score / candidateScoreP95 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { runnerUpScoreToP10Ratio: topCandidates[1].score / candidateScoreP10 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { runnerUpScoreToP25Ratio: topCandidates[1].score / candidateScoreP25 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { runnerUpScoreToP05Ratio: topCandidates[1].score / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP90ToRunnerUpRatio: candidateScoreP90 / topCandidates[1].score } : {}), ...(candidateScoreP75 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP75ToRunnerUpRatio: candidateScoreP75 / topCandidates[1].score } : {}), ...(candidateScoreP95 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP95ToRunnerUpRatio: candidateScoreP95 / topCandidates[1].score } : {}), ...(candidateScoreP10 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP10ToRunnerUpRatio: candidateScoreP10 / topCandidates[1].score } : {}), ...(candidateScoreP25 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP25ToRunnerUpRatio: candidateScoreP25 / topCandidates[1].score } : {}), ...(candidateScoreP05 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP05ToRunnerUpRatio: candidateScoreP05 / topCandidates[1].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { runnerUpScoreToMeanRatio: topCandidates[1].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(topCandidates[1].score > 0 ? { candidateScoreMeanToRunnerUpRatio: (candidateScoreEntropyTotal / scoredTools.length) / topCandidates[1].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { winnerScoreToMeanRatio: scoredTools[0].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { winnerScoreToGeometricMeanRatio: scoredTools[0].score / candidateScoreGeometricMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && scoredTools[0].score > 0 ? { candidateScoreGeometricMeanToWinnerRatio: candidateScoreGeometricMean / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { winnerScoreToHarmonicMeanRatio: scoredTools[0].score / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && scoredTools[0].score > 0 ? { candidateScoreHarmonicMeanToWinnerRatio: candidateScoreHarmonicMean / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { runnerUpScoreToHarmonicMeanRatio: topCandidates[1].score / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && topCandidates[1].score > 0 ? { candidateScoreHarmonicMeanToRunnerUpRatio: candidateScoreHarmonicMean / topCandidates[1].score } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { runnerUpScoreToGeometricMeanRatio: topCandidates[1].score / candidateScoreGeometricMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && topCandidates[1].score > 0 ? { candidateScoreGeometricMeanToRunnerUpRatio: candidateScoreGeometricMean / topCandidates[1].score } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreGeometricMeanToMeanRatio: candidateScoreGeometricMean / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreMeanToGeometricMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreGeometricMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { runnerUpScoreToMedianRatio: topCandidates[1].score / medianCandidateScore } : {}), ...(medianCandidateScore !== undefined && topCandidates[1].score > 0 ? { candidateScoreMedianToRunnerUpRatio: medianCandidateScore / topCandidates[1].score } : {}), ...(medianCandidateScore !== undefined && scoredTools[0].score > 0 ? { candidateScoreMedianToWinnerRatio: medianCandidateScore / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreEntropyTotal > 0 ? { candidateScoreHarmonicMeanToMeanRatio: candidateScoreHarmonicMean / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreMeanToHarmonicMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreHarmonicMeanToGeometricMeanRatio: candidateScoreHarmonicMean / candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreGeometricMeanToHarmonicMeanRatio: candidateScoreGeometricMean / candidateScoreHarmonicMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreMedianToGeometricMeanRatio: medianCandidateScore / candidateScoreGeometricMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreMedianToHarmonicMeanRatio: medianCandidateScore / candidateScoreHarmonicMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreGeometricMeanToMedianRatio: candidateScoreGeometricMean / medianCandidateScore } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreHarmonicMeanToMedianRatio: candidateScoreHarmonicMean / medianCandidateScore } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreEntropyTotal > 0 ? { candidateScoreMeanToMedianRatio: (candidateScoreEntropyTotal / scoredTools.length) / medianCandidateScore } : {}), ...(topCandidates[1].score > 0 ? { winnerScoreRatio: topCandidates[0].score / topCandidates[1].score } : {}), topCandidatesScoreVariance: (() => { const mean = topCandidates.reduce((s, c) => s + c.score, 0) / topCandidates.length; return topCandidates.reduce((s, c) => s + (c.score - mean) ** 2, 0) / topCandidates.length; })(), topCandidatesScoreStdDev: (() => { const mean = topCandidates.reduce((s, c) => s + c.score, 0) / topCandidates.length; return Math.sqrt(topCandidates.reduce((s, c) => s + (c.score - mean) ** 2, 0) / topCandidates.length); })(), ...(topCandidatesScoreSkewness !== undefined ? { topCandidatesScoreSkewness } : {}), ...(topCandidatesKurtosis !== undefined ? { topCandidatesKurtosis } : {}), ...(topCandidatesGiniCoefficient !== undefined ? { topCandidatesGiniCoefficient } : {}) } : {}), + ...(topCandidates.length > 1 ? { runnerUpScore: topCandidates[1].score, runnerUpTool: topCandidates[1].tool, runnerUpServer: topCandidates[1].tool.split('/')[0], runnerUpCategory: scoredTools[1].category, candidateScoreSpread: scoredTools[0].score - scoredTools[scoredTools.length - 1].score, lowestCandidateScore: scoredTools[scoredTools.length - 1].score, ...(scoredTools.length >= 3 ? { thirdCandidateScore: scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > 0 ? { thirdCandidateScoreToWinnerRatio: scoredTools[2].score / scoredTools[0].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { winnerThirdGapToSpreadRatio: (scoredTools[0].score - scoredTools[2].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 ? { winnerThirdGap: scoredTools[0].score - scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { runnerUpThirdGapToSpreadRatio: (topCandidates[1].score - scoredTools[2].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 && candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { thirdCandidateScoreZScore: (scoredTools[2].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { lowestCandidateScoreZScore: (scoredTools[scoredTools.length - 1].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { candidateScoreStandardizedRange: (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) / candidateScoreStdDev } : {}), ...(scoredTools.length >= 3 ? { runnerUpThirdGap: topCandidates[1].score - scoredTools[2].score } : {}), ...(scoredTools.length >= 3 && candidateScoreEntropyTotal > 0 ? { thirdCandidateScoreToMeanRatio: scoredTools[2].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 ? { thirdCandidateScoreToRunnerUpRatio: scoredTools[2].score / topCandidates[1].score } : {}), ...(candidateScoreEntropy !== undefined ? { candidateScoreEntropy } : {}), ...(candidateGiniCoefficient !== undefined ? { candidateGiniCoefficient } : {}), ...(candidateScoreSkewness !== undefined ? { candidateScoreSkewness } : {}), ...(candidateScoreKurtosis !== undefined ? { candidateScoreKurtosis } : {}), ...(candidateScoreVariance !== undefined ? { candidateScoreVariance } : {}), ...(candidateScoreStdDev !== undefined ? { candidateScoreStdDev } : {}), candidateScoreMean: candidateScoreEntropyTotal / scoredTools.length, ...(medianCandidateScore !== undefined ? { medianCandidateScore } : {}), ...(scoredTools[0].score > 0 ? { candidateScoreMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / scoredTools[0].score } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreCoefficientOfVariation: candidateScoreStdDev / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && candidateScoreEntropyTotal > 0 ? { medianToMeanRatio: medianCandidateScore / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { winnerToMedianRatio: scoredTools[0].score / medianCandidateScore } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { winnerScoreZScore: (scoredTools[0].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { runnerUpScoreZScore: (topCandidates[1].score - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { zScoreGap: (scoredTools[0].score - topCandidates[1].score) / candidateScoreStdDev } : {}), ...(candidateScoreStdDev !== undefined && candidateScoreStdDev > 0 ? { nonWinnerMeanZScore: ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) - candidateScoreEntropyTotal / scoredTools.length) / candidateScoreStdDev } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreNormalizedRange: (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(scoredTools[0].score > 0 ? { lowestCandidateScoreRatio: scoredTools[scoredTools.length - 1].score / scoredTools[0].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreLowestToMeanRatio: scoredTools[scoredTools.length - 1].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreLowestToMedianRatio: scoredTools[scoredTools.length - 1].score / medianCandidateScore } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreLowestToGeometricMeanRatio: scoredTools[scoredTools.length - 1].score / candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreLowestToHarmonicMeanRatio: scoredTools[scoredTools.length - 1].score / candidateScoreHarmonicMean } : {}), ...(nonZeroCandidateFraction !== undefined ? { nonZeroCandidateFraction } : {}), ...(topHeavinessRatio !== undefined ? { topHeavinessRatio } : {}), ...(candidateScoreHerfindahlIndex !== undefined ? { candidateScoreHerfindahlIndex } : {}), ...(effectiveN !== undefined ? { effectiveN } : {}), ...(scoreEntropyNormalized !== undefined ? { scoreEntropyNormalized } : {}), ...(candidateScoreIQR !== undefined ? { candidateScoreIQR } : {}), ...(candidateScoreIQRRatio !== undefined ? { candidateScoreIQRRatio } : {}), ...(candidateScoreIQR !== undefined && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { candidateScoreIQRCoverage: candidateScoreIQR / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(candidateScoreEntropyTotal > 0 ? { top2HeavinessRatio: (scoredTools[0].score + topCandidates[1].score) / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && topCandidates[1].score > 0 ? { runnerUpScoreHeavinessRatio: topCandidates[1].score / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestCandidateScoreHeavinessRatio: scoredTools[scoredTools.length - 1].score / candidateScoreEntropyTotal } : {}), ...(scoredTools.length >= 3 && candidateScoreEntropyTotal > 0 && scoredTools[2].score > 0 ? { thirdCandidateScoreHeavinessRatio: scoredTools[2].score / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 ? { winnerToNonWinnerMassRatio: scoredTools[0].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 && topCandidates[1].score > 0 ? { runnerUpToNonWinnerMassRatio: topCandidates[1].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(candidateScoreEntropyTotal > 0 && (candidateScoreEntropyTotal - scoredTools[0].score) > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestToNonWinnerMassRatio: scoredTools[scoredTools.length - 1].score / (candidateScoreEntropyTotal - scoredTools[0].score) } : {}), ...(topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { lowestToRunnerUpRatio: scoredTools[scoredTools.length - 1].score / topCandidates[1].score } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[2].score > 0 ? { thirdToRunnerUpRatio: scoredTools[2].score / topCandidates[1].score } : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? { candidateScoreNonWinnerGeometricMean: Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)) } : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? { candidateScoreNonWinnerHarmonicMean: (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0) } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? { candidateScoreNonWinnerMidRange: (topCandidates[1].score + scoredTools[scoredTools.length - 1].score) / 2 } : {}), ...(scoredTools.length >= 3 ? { runnerUpToNonWinnerMeanGap: topCandidates[1].score - (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) } : {}), ...(scoredTools.length >= 3 ? { lowestToNonWinnerMeanGap: (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) - scoredTools[scoredTools.length - 1].score } : {}), ...(scoredTools.length >= 3 && topCandidates[1].score > 0 && scoredTools[scoredTools.length - 1].score > 0 ? (() => { const midRange = (topCandidates[1].score + scoredTools[scoredTools.length - 1].score) / 2; return { candidateScoreNonWinnerMeanToMidRangeRatio: ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) / midRange }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerAMGMGap: nwMean - nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerAMHMGap: nwMean - nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerGMHMGap: nwGM - nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerGMHMRatio: nwGM / nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerAMGMRatio: nwMean / nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerAMHMRatio: nwMean / nwHM }; })() : {}), ...(scoredTools.length >= 3 ? { candidateScoreNonWinnerQuadraticMean: Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)) } : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMToAMRatio: nwQM / nwMean }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMGap: nwQM - nwMean }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerQMHMRatio: nwQM / nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMGMRatio: nwQM / nwGM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwHM = (scoredTools.length - 1) / scoredTools.slice(1).reduce((s, t) => s + 1 / t.score, 0); return { candidateScoreNonWinnerQMHMGap: nwQM - nwHM }; })() : {}), ...(scoredTools.length >= 3 && scoredTools.slice(1).every(t => t.score > 0) ? (() => { const nwQM = Math.sqrt(scoredTools.slice(1).reduce((s, t) => s + t.score ** 2, 0) / (scoredTools.length - 1)); const nwGM = Math.exp(scoredTools.slice(1).reduce((s, t) => s + Math.log(t.score), 0) / (scoredTools.length - 1)); return { candidateScoreNonWinnerQMGMGap: nwQM - nwGM }; })() : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreTop3HeavinessRatio: scoredTools.slice(0, 3).reduce((s, t) => s + t.score, 0) / candidateScoreEntropyTotal } : {}), ...(candidateScoreEntropyTotal > 0 ? { candidateScoreTop4HeavinessRatio: scoredTools.slice(0, 4).reduce((s, t) => s + t.score, 0) / candidateScoreEntropyTotal } : {}), ...{ winnerMeanGap: scoredTools[0].score - candidateScoreEntropyTotal / scoredTools.length }, ...{ winnerRunnerUpGap: scoredTools[0].score - topCandidates[1].score }, ...(scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { winnerRunnerUpGapToSpreadRatio: (scoredTools[0].score - topCandidates[1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { runnerUpLowestGapToSpreadRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...{ runnerUpMeanGap: topCandidates[1].score - candidateScoreEntropyTotal / scoredTools.length }, ...(candidateScoreGeometricMean !== undefined ? { candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined ? { candidateScoreHarmonicMean } : {}), ...(candidateScoreP90 !== undefined ? { candidateScoreP90 } : {}), ...(candidateScoreP10 !== undefined ? { candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP10 !== undefined ? { candidateScoreP80Range: candidateScoreP90 - candidateScoreP10 } : {}), ...(candidateScoreMAD !== undefined ? { candidateScoreMAD } : {}), ...(candidateScoreMADRatio !== undefined ? { candidateScoreMADRatio } : {}), ...(candidateScoreRobustSkewness !== undefined ? { candidateScoreRobustSkewness } : {}), ...(candidateScoreQuantileSkewness !== undefined ? { candidateScoreQuantileSkewness } : {}), ...(candidateScoreWinsorizedMean !== undefined ? { candidateScoreWinsorizedMean } : {}), ...(candidateScoreJainFairnessIndex !== undefined ? { candidateScoreJainFairnessIndex } : {}), ...(candidateScoreP75 !== undefined ? { candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined ? { candidateScoreP25 } : {}), ...(candidateScoreP95 !== undefined ? { candidateScoreP95 } : {}), ...(candidateScoreP05 !== undefined ? { candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP05 !== undefined ? { candidateScoreP90Range: candidateScoreP95 - candidateScoreP05 } : {}), ...(candidateScoreTrimmedMean !== undefined ? { candidateScoreTrimmedMean } : {}), ...{ candidateScoreNonWinnerMean: (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) }, ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); return { candidateScoreNonWinnerStdDev: Math.sqrt(nwVariance) }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); return { candidateScoreNonWinnerCoefficientOfVariation: Math.sqrt(nwVariance) / nwMean }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev <= 0) return {}; return { winnerNonWinnerZScore: (scoredTools[0].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev < 1e-10) return {}; return { runnerUpNonWinnerZScore: (topCandidates[1].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); const nwVariance = scoredTools.slice(1).reduce((s, t) => s + (t.score - nwMean) ** 2, 0) / (scoredTools.length - 1); const nwStdDev = Math.sqrt(nwVariance); if (nwStdDev < 1e-10) return {}; return { lowestNonWinnerZScore: (scoredTools[scoredTools.length - 1].score - nwMean) / nwStdDev }; })() : {}), ...(scoredTools.length >= 3 ? { candidateScoreNonWinnerSpread: topCandidates[1].score - scoredTools[scoredTools.length - 1].score } : {}), ...(scoredTools.length >= 3 && scoredTools[0].score > scoredTools[scoredTools.length - 1].score ? { candidateScoreNonWinnerSpreadRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / (scoredTools[0].score - scoredTools[scoredTools.length - 1].score) } : {}), ...(scoredTools.length >= 3 ? (() => { const nwMean = (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1); if (nwMean <= 0) return {}; return { candidateScoreNonWinnerSpreadToMeanRatio: (topCandidates[1].score - scoredTools[scoredTools.length - 1].score) / nwMean }; })() : {}), ...{ candidateScoreWinnerFieldGap: scoredTools[0].score - (candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1) }, ...(scoredTools[0].score > 0 ? { candidateScoreFieldStrengthRatio: (candidateScoreEntropyTotal - scoredTools[0].score) / ((scoredTools.length - 1) * scoredTools[0].score) } : {}), ...(topCandidates[1].score > 0 ? { winnerScoreToNonWinnerMeanRatio: scoredTools[0].score / ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) } : {}), ...(topCandidates[1].score > 0 ? { runnerUpScoreToNonWinnerMeanRatio: topCandidates[1].score / ((candidateScoreEntropyTotal - scoredTools[0].score) / (scoredTools.length - 1)) } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { winnerScoreToP95Ratio: scoredTools[0].score / candidateScoreP95 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { winnerScoreToP05Ratio: scoredTools[0].score / candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreTailAsymmetryRatio: candidateScoreP95 / candidateScoreP05 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP75P25Ratio: candidateScoreP75 / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreMedianToP90Ratio: medianCandidateScore / candidateScoreP90 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP90P10Ratio: candidateScoreP90 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { winnerScoreToP90Ratio: scoredTools[0].score / candidateScoreP90 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { winnerScoreToP10Ratio: scoredTools[0].score / candidateScoreP10 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { winnerScoreToP75Ratio: scoredTools[0].score / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { winnerScoreToP25Ratio: scoredTools[0].score / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreMedianToP10Ratio: medianCandidateScore / candidateScoreP10 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreMedianToP75Ratio: medianCandidateScore / candidateScoreP75 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreMedianToP25Ratio: medianCandidateScore / candidateScoreP25 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreMedianToP05Ratio: medianCandidateScore / candidateScoreP05 } : {}), ...(medianCandidateScore !== undefined && candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { candidateScoreMedianToP95Ratio: medianCandidateScore / candidateScoreP95 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreP95P75Ratio: candidateScoreP95 / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP25P05Ratio: candidateScoreP25 / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreP90P75Ratio: candidateScoreP90 / candidateScoreP75 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP25P10Ratio: candidateScoreP25 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP90P25Ratio: candidateScoreP90 / candidateScoreP25 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP95P10Ratio: candidateScoreP95 / candidateScoreP10 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreP95P25Ratio: candidateScoreP95 / candidateScoreP25 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreP75P10Ratio: candidateScoreP75 / candidateScoreP10 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP90P05Ratio: candidateScoreP90 / candidateScoreP05 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP75P05Ratio: candidateScoreP75 / candidateScoreP05 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreP10P05Ratio: candidateScoreP10 / candidateScoreP05 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreP95P90Ratio: candidateScoreP95 / candidateScoreP90 } : {}), ...(candidateScoreP90 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP90MedianRatio: candidateScoreP90 / medianCandidateScore } : {}), ...(candidateScoreP75 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP75MedianRatio: candidateScoreP75 / medianCandidateScore } : {}), ...(candidateScoreP95 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP95MedianRatio: candidateScoreP95 / medianCandidateScore } : {}), ...(candidateScoreP10 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP10MedianRatio: candidateScoreP10 / medianCandidateScore } : {}), ...(candidateScoreP25 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP25MedianRatio: candidateScoreP25 / medianCandidateScore } : {}), ...(candidateScoreP05 !== undefined && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreP05MedianRatio: candidateScoreP05 / medianCandidateScore } : {}), ...(candidateScoreP90 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP90ToWinnerRatio: candidateScoreP90 / scoredTools[0].score } : {}), ...(candidateScoreP75 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP75ToWinnerRatio: candidateScoreP75 / scoredTools[0].score } : {}), ...(candidateScoreP95 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP95ToWinnerRatio: candidateScoreP95 / scoredTools[0].score } : {}), ...(candidateScoreP25 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP25ToWinnerRatio: candidateScoreP25 / scoredTools[0].score } : {}), ...(candidateScoreP10 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP10ToWinnerRatio: candidateScoreP10 / scoredTools[0].score } : {}), ...(candidateScoreP05 !== undefined && scoredTools[0].score > 0 ? { candidateScoreP05ToWinnerRatio: candidateScoreP05 / scoredTools[0].score } : {}), ...(candidateScoreP90 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP90ToMeanRatio: candidateScoreP90 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP75 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP75ToMeanRatio: candidateScoreP75 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP95 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP95ToMeanRatio: candidateScoreP95 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP10 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP10ToMeanRatio: candidateScoreP10 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP25 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP25ToMeanRatio: candidateScoreP25 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP05 !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreP05ToMeanRatio: candidateScoreP05 / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { candidateScoreMeanToP90Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP90 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { candidateScoreMeanToP75Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP75 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { candidateScoreMeanToP95Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP95 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { candidateScoreMeanToP10Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP10 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { candidateScoreMeanToP25Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP25 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { candidateScoreMeanToP05Ratio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && candidateScoreP90 > 0 ? { runnerUpScoreToP90Ratio: topCandidates[1].score / candidateScoreP90 } : {}), ...(candidateScoreP75 !== undefined && candidateScoreP75 > 0 ? { runnerUpScoreToP75Ratio: topCandidates[1].score / candidateScoreP75 } : {}), ...(candidateScoreP95 !== undefined && candidateScoreP95 > 0 ? { runnerUpScoreToP95Ratio: topCandidates[1].score / candidateScoreP95 } : {}), ...(candidateScoreP10 !== undefined && candidateScoreP10 > 0 ? { runnerUpScoreToP10Ratio: topCandidates[1].score / candidateScoreP10 } : {}), ...(candidateScoreP25 !== undefined && candidateScoreP25 > 0 ? { runnerUpScoreToP25Ratio: topCandidates[1].score / candidateScoreP25 } : {}), ...(candidateScoreP05 !== undefined && candidateScoreP05 > 0 ? { runnerUpScoreToP05Ratio: topCandidates[1].score / candidateScoreP05 } : {}), ...(candidateScoreP90 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP90ToRunnerUpRatio: candidateScoreP90 / topCandidates[1].score } : {}), ...(candidateScoreP75 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP75ToRunnerUpRatio: candidateScoreP75 / topCandidates[1].score } : {}), ...(candidateScoreP95 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP95ToRunnerUpRatio: candidateScoreP95 / topCandidates[1].score } : {}), ...(candidateScoreP10 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP10ToRunnerUpRatio: candidateScoreP10 / topCandidates[1].score } : {}), ...(candidateScoreP25 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP25ToRunnerUpRatio: candidateScoreP25 / topCandidates[1].score } : {}), ...(candidateScoreP05 !== undefined && topCandidates[1].score > 0 ? { candidateScoreP05ToRunnerUpRatio: candidateScoreP05 / topCandidates[1].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { runnerUpScoreToMeanRatio: topCandidates[1].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(topCandidates[1].score > 0 ? { candidateScoreMeanToRunnerUpRatio: (candidateScoreEntropyTotal / scoredTools.length) / topCandidates[1].score } : {}), ...(candidateScoreEntropyTotal > 0 ? { winnerScoreToMeanRatio: scoredTools[0].score / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { winnerScoreToGeometricMeanRatio: scoredTools[0].score / candidateScoreGeometricMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && scoredTools[0].score > 0 ? { candidateScoreGeometricMeanToWinnerRatio: candidateScoreGeometricMean / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { winnerScoreToHarmonicMeanRatio: scoredTools[0].score / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && scoredTools[0].score > 0 ? { candidateScoreHarmonicMeanToWinnerRatio: candidateScoreHarmonicMean / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { runnerUpScoreToHarmonicMeanRatio: topCandidates[1].score / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && topCandidates[1].score > 0 ? { candidateScoreHarmonicMeanToRunnerUpRatio: candidateScoreHarmonicMean / topCandidates[1].score } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { runnerUpScoreToGeometricMeanRatio: topCandidates[1].score / candidateScoreGeometricMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && topCandidates[1].score > 0 ? { candidateScoreGeometricMeanToRunnerUpRatio: candidateScoreGeometricMean / topCandidates[1].score } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreEntropyTotal > 0 ? { candidateScoreGeometricMeanToMeanRatio: candidateScoreGeometricMean / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreMeanToGeometricMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreGeometricMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 ? { runnerUpScoreToMedianRatio: topCandidates[1].score / medianCandidateScore } : {}), ...(medianCandidateScore !== undefined && topCandidates[1].score > 0 ? { candidateScoreMedianToRunnerUpRatio: medianCandidateScore / topCandidates[1].score } : {}), ...(medianCandidateScore !== undefined && scoredTools[0].score > 0 ? { candidateScoreMedianToWinnerRatio: medianCandidateScore / scoredTools[0].score } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreEntropyTotal > 0 ? { candidateScoreHarmonicMeanToMeanRatio: candidateScoreHarmonicMean / (candidateScoreEntropyTotal / scoredTools.length) } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreMeanToHarmonicMeanRatio: (candidateScoreEntropyTotal / scoredTools.length) / candidateScoreHarmonicMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreHarmonicMeanToGeometricMeanRatio: candidateScoreHarmonicMean / candidateScoreGeometricMean } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreGeometricMeanToHarmonicMeanRatio: candidateScoreGeometricMean / candidateScoreHarmonicMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 ? { candidateScoreMedianToGeometricMeanRatio: medianCandidateScore / candidateScoreGeometricMean } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 ? { candidateScoreMedianToHarmonicMeanRatio: medianCandidateScore / candidateScoreHarmonicMean } : {}), ...(candidateScoreGeometricMean !== undefined && candidateScoreGeometricMean > 0 && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreGeometricMeanToMedianRatio: candidateScoreGeometricMean / medianCandidateScore } : {}), ...(candidateScoreHarmonicMean !== undefined && candidateScoreHarmonicMean > 0 && medianCandidateScore !== undefined && medianCandidateScore > 0 ? { candidateScoreHarmonicMeanToMedianRatio: candidateScoreHarmonicMean / medianCandidateScore } : {}), ...(medianCandidateScore !== undefined && medianCandidateScore > 0 && candidateScoreEntropyTotal > 0 ? { candidateScoreMeanToMedianRatio: (candidateScoreEntropyTotal / scoredTools.length) / medianCandidateScore } : {}), ...(topCandidates[1].score > 0 ? { winnerScoreRatio: topCandidates[0].score / topCandidates[1].score } : {}), topCandidatesScoreVariance: (() => { const mean = topCandidates.reduce((s, c) => s + c.score, 0) / topCandidates.length; return topCandidates.reduce((s, c) => s + (c.score - mean) ** 2, 0) / topCandidates.length; })(), topCandidatesScoreStdDev: (() => { const mean = topCandidates.reduce((s, c) => s + c.score, 0) / topCandidates.length; return Math.sqrt(topCandidates.reduce((s, c) => s + (c.score - mean) ** 2, 0) / topCandidates.length); })(), ...(topCandidatesScoreSkewness !== undefined ? { topCandidatesScoreSkewness } : {}), ...(topCandidatesKurtosis !== undefined ? { topCandidatesKurtosis } : {}), ...(topCandidatesGiniCoefficient !== undefined ? { topCandidatesGiniCoefficient } : {}) } : {}), ...(focusName && focus ? { focus: focusName, focusBoost, diff --git a/test/80808080-cast-explain-non-winner-qm-gm-gap.test.ts b/test/80808080-cast-explain-non-winner-qm-gm-gap.test.ts new file mode 100644 index 0000000..7b1734d --- /dev/null +++ b/test/80808080-cast-explain-non-winner-qm-gm-gap.test.ts @@ -0,0 +1,263 @@ +/** + * 80808080: explanation.candidateScoreNonWinnerQMGMGap in ch1tty/cast when explain:true. + * + * candidateScoreNonWinnerQMGMGap: number — gap between non-winner quadratic mean and geometric mean: + * candidateScoreNonWinnerQuadraticMean - candidateScoreNonWinnerGeometricMean. + * + * Present when: >= 3 candidates and all non-winner scores > 0. + * Absent when: no_match, < 3 candidates, or any non-winner score is zero. + * Always >= 0 (QM >= GM by Power Mean chain). + * Zero when all non-winners are tied. + * For n=3: equals sqrt((r^2+t^2)/2) - sqrt(r*t). + * Additive decomposition: QMGMGap === QMGap + AMGMGap (since QM-GM = (QM-AM) + (AM-GM)). + * Always >= candidateScoreNonWinnerQMGap (GM <= AM => QM-GM >= QM-AM). + * Always >= candidateScoreNonWinnerAMGMGap (QM >= AM => QM-GM >= AM-GM). + * Always <= candidateScoreNonWinnerQMHMGap (GM >= HM => QM-GM <= QM-HM). + * Identity: gap + GM === QM. + * + * Covered: + * 80808080-1: present when >= 3 candidates and all non-winner scores > 0 + * 80808080-2: always finite and >= 0 + * 80808080-3: identity — gap + GM === QM + * 80808080-4: for n=3 equals sqrt((r^2+t^2)/2) - sqrt(r*t) + * 80808080-5: absent on cast:no_match + * 80808080-6: absent when fewer than 3 candidates + * 80808080-7: additive decomposition — QMGMGap === QMGap + AMGMGap + * 80808080-8: tool description documents candidateScoreNonWinnerQMGMGap + */ +import assert from 'node:assert/strict'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import test from 'node:test'; +import { Aggregator } from '../src/aggregator.js'; +import { SessionCoordinator } from '../src/coordinator.js'; +import type { Backend, BackendStatus, ServerConfig, ToolCallResult, ToolEntry } from '../src/types.js'; + +function dlqPath(label: string): string { + return join(tmpdir(), `ch1tty-80808080-${label}-${Date.now()}.jsonl`); +} + +const STRIPE_CFG: ServerConfig = { + id: 'stripe', name: 'Stripe Payments', type: 'remote', access: 'readwrite', + category: 'ecosystem', endpoint: 'https://stripe.test/mcp', +}; +const NEON_CFG: ServerConfig = { + id: 'neon', name: 'Neon Database', type: 'remote', access: 'readwrite', + category: 'code', endpoint: 'https://neon.test/mcp', +}; +const LINEAR_CFG: ServerConfig = { + id: 'linear', name: 'Linear', type: 'remote', access: 'readwrite', + category: 'ecosystem', endpoint: 'https://linear.test/mcp', +}; + +function makeBackend(tools: ToolEntry[]): Backend { + return { + registerServer: () => {}, + isRegistered: () => true, + getStatus: (): BackendStatus => ({ connected: true, toolCount: tools.length, toolCacheAge: 0 }), + listTools: async () => tools, + callTool: async (): Promise => ({ content: [{ type: 'text', text: 'ok' }] }), + listResources: async () => ({ resources: [], templates: [] }), + readResource: async () => ({ contents: [] }), + listPrompts: async () => [], + getPrompt: async () => ({ messages: [] }), + shutdown: async () => {}, + }; +} + +class FallbackCoordinator extends SessionCoordinator { + constructor(dlq?: string) { super({}, { enabled: false }, dlq); } + override async routeIntent(): Promise { return null; } +} + +function buildAgg(label: string, configs: ServerConfig[], toolMap: Record): Aggregator { + const path = dlqPath(label); + return new Aggregator(configs, { + backendFactory: (cfg) => makeBackend(toolMap[cfg.id] ?? []), + focusProfiles: { profiles: {} }, + suggestionsCatalog: {}, + ledgerDlqPath: path, + coordinator: new FallbackCoordinator(path), + }); +} + +const stripeTools: ToolEntry[] = [ + { name: 'create_invoice', description: 'billing invoice payment charge', inputSchema: { type: 'object', properties: {} } }, +]; +const neonTools: ToolEntry[] = [ + { name: 'run_sql', description: 'billing sql query database', inputSchema: { type: 'object', properties: {} } }, +]; +const linearTools: ToolEntry[] = [ + { name: 'create_issue', description: 'billing issue tracking project', inputSchema: { type: 'object', properties: {} } }, +]; + +test('80808080-1: present when >= 3 candidates and all non-winner scores > 0', async () => { + const agg = buildAgg('ccc1', [STRIPE_CFG, NEON_CFG, LINEAR_CFG], { stripe: stripeTools, neon: neonTools, linear: linearTools }); + try { + const r = await agg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + assert.ok('explanation' in parsed, 'explanation absent'); + const { explanation } = parsed; + if (explanation.candidateCount >= 3 && explanation.lowestCandidateScore > 0) { + assert.ok('candidateScoreNonWinnerQMGMGap' in explanation, + `candidateScoreNonWinnerQMGMGap should be present; keys: ${Object.keys(explanation).join(', ')}`); + assert.equal(typeof explanation.candidateScoreNonWinnerQMGMGap, 'number', 'should be a number'); + } + } finally { + await agg.shutdown(); + } +}); + +test('80808080-2: always finite and >= 0', async () => { + const agg = buildAgg('ccc2', [STRIPE_CFG, NEON_CFG, LINEAR_CFG], { stripe: stripeTools, neon: neonTools, linear: linearTools }); + try { + const r = await agg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + const { explanation } = parsed; + if ('candidateScoreNonWinnerQMGMGap' in explanation) { + assert.ok( + Number.isFinite(explanation.candidateScoreNonWinnerQMGMGap), + `should be finite, got ${explanation.candidateScoreNonWinnerQMGMGap}`, + ); + assert.ok( + explanation.candidateScoreNonWinnerQMGMGap >= -1e-9, + `should be >= 0, got ${explanation.candidateScoreNonWinnerQMGMGap}`, + ); + } + } finally { + await agg.shutdown(); + } +}); + +test('80808080-3: identity — gap + GM === QM', async () => { + const agg = buildAgg('ccc3', [STRIPE_CFG, NEON_CFG, LINEAR_CFG], { stripe: stripeTools, neon: neonTools, linear: linearTools }); + try { + const r = await agg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + const { explanation } = parsed; + if ('candidateScoreNonWinnerQMGMGap' in explanation && + 'candidateScoreNonWinnerGeometricMean' in explanation && + 'candidateScoreNonWinnerQuadraticMean' in explanation) { + const sum = explanation.candidateScoreNonWinnerQMGMGap + explanation.candidateScoreNonWinnerGeometricMean; + assert.ok( + Math.abs(sum - explanation.candidateScoreNonWinnerQuadraticMean) < 1e-9, + `gap + GM (${sum}) should equal QM (${explanation.candidateScoreNonWinnerQuadraticMean})`, + ); + } + } finally { + await agg.shutdown(); + } +}); + +test('80808080-4: for n=3 equals sqrt((r^2+t^2)/2) - sqrt(r*t)', async () => { + const agg = buildAgg('ccc4', [STRIPE_CFG, NEON_CFG, LINEAR_CFG], { stripe: stripeTools, neon: neonTools, linear: linearTools }); + try { + const r = await agg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + const { explanation } = parsed; + if ('candidateScoreNonWinnerQMGMGap' in explanation && + 'runnerUpScore' in explanation && + 'thirdCandidateScore' in explanation && + explanation.candidateCount === 3 && + explanation.runnerUpScore > 0 && + explanation.thirdCandidateScore > 0) { + const ru = explanation.runnerUpScore; + const t = explanation.thirdCandidateScore; + const expected = Math.sqrt((ru ** 2 + t ** 2) / 2) - Math.sqrt(ru * t); + assert.ok( + Math.abs(explanation.candidateScoreNonWinnerQMGMGap - expected) < 1e-9, + `for n=3, QMGMGap (${explanation.candidateScoreNonWinnerQMGMGap}) should equal sqrt((r^2+t^2)/2)-sqrt(rt) (${expected})`, + ); + } + } finally { + await agg.shutdown(); + } +}); + +test('80808080-5: absent on cast:no_match', async () => { + const path = dlqPath('ccc5'); + const emptyAgg = new Aggregator([STRIPE_CFG], { + backendFactory: () => makeBackend([]), + focusProfiles: { profiles: {} }, + suggestionsCatalog: {}, + ledgerDlqPath: path, + coordinator: new FallbackCoordinator(path), + }); + try { + const r = await emptyAgg.callTool('ch1tty/cast', { intent: 'xyzzy-nonexistent', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + assert.equal(parsed.cast, 'no_match', `expected no_match, got ${parsed.cast}`); + assert.ok( + !('candidateScoreNonWinnerQMGMGap' in parsed.explanation), + `should be absent on no_match`, + ); + } finally { + await emptyAgg.shutdown(); + } +}); + +test('80808080-6: absent when fewer than 3 candidates', async () => { + const path = dlqPath('ccc6'); + const twoAgg = new Aggregator([STRIPE_CFG, NEON_CFG], { + backendFactory: (cfg) => makeBackend(cfg.id === 'stripe' ? stripeTools : neonTools), + focusProfiles: { profiles: {} }, + suggestionsCatalog: {}, + ledgerDlqPath: path, + coordinator: new FallbackCoordinator(path), + }); + try { + const r = await twoAgg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + const { explanation } = parsed; + if (explanation.candidateCount < 3) { + assert.ok( + !('candidateScoreNonWinnerQMGMGap' in explanation), + `should be absent with < 3 candidates`, + ); + } + } finally { + await twoAgg.shutdown(); + } +}); + +test('80808080-7: additive decomposition — QMGMGap === QMGap + AMGMGap', async () => { + const agg = buildAgg('ccc7', [STRIPE_CFG, NEON_CFG, LINEAR_CFG], { stripe: stripeTools, neon: neonTools, linear: linearTools }); + try { + const r = await agg.callTool('ch1tty/cast', { intent: 'billing invoice payment', explain: true }); + const parsed = JSON.parse((r.content[0] as { text: string }).text); + const { explanation } = parsed; + if ('candidateScoreNonWinnerQMGMGap' in explanation && + 'candidateScoreNonWinnerQMGap' in explanation && + 'candidateScoreNonWinnerAMGMGap' in explanation) { + const sum = explanation.candidateScoreNonWinnerQMGap + explanation.candidateScoreNonWinnerAMGMGap; + assert.ok( + Math.abs(explanation.candidateScoreNonWinnerQMGMGap - sum) < 1e-9, + `QMGMGap (${explanation.candidateScoreNonWinnerQMGMGap}) should equal QMGap+AMGMGap (${sum})`, + ); + } + } finally { + await agg.shutdown(); + } +}); + +test('80808080-8: tool description documents candidateScoreNonWinnerQMGMGap', async () => { + const path = dlqPath('ccc8'); + const agg = new Aggregator([STRIPE_CFG], { + backendFactory: () => makeBackend([]), + focusProfiles: { profiles: {} }, + suggestionsCatalog: {}, + ledgerDlqPath: path, + coordinator: new FallbackCoordinator(path), + }); + try { + const { tools } = await agg.listAllTools(); + const cast = tools.find((t) => t.name === 'ch1tty/cast'); + assert.ok(cast, 'ch1tty/cast tool not found'); + assert.ok( + cast.description?.includes('candidateScoreNonWinnerQMGMGap'), + `cast description should mention candidateScoreNonWinnerQMGMGap, got: ${cast.description?.slice(0, 600)}`, + ); + } finally { + await agg.shutdown(); + } +});