Fix beta preset selection and improve test plan builder UI

This commit is contained in:
2026-09-17 21:51:25 -04:00
parent a50eae9d21
commit 4237371360
4 changed files with 256 additions and 60 deletions
+37
View File
@@ -0,0 +1,37 @@
import type { BetaPlan, BetaRequirement } from './beta-plan.js';
const count = (n: number, word: string) => `${n} ${word}${n === 1 ? '' : 's'}`;
const duration = (minutes: number) => minutes >= 60 && minutes % 60 === 0 ? count(minutes / 60, 'hour') : count(minutes, 'minute');
export const presetDescriptions: Record<string, string> = {
'Quick smoke test': 'A quick check that the server starts and stays healthy.',
'Gameplay validation': 'Prove the build through real matches and populated playtime.',
'Long soak': 'Exercise stability and participation over a longer test.'
};
export function requirementSummary(r: BetaRequirement): string {
const players = r.minPlayers > 1 ? ` with at least ${r.minPlayers} players` : ' with players present';
switch (r.kind) {
case 'round': return `Reach round ${r.target}${players}`;
case 'matches': return `Complete ${count(r.target, 'match').replace('matchs', 'matches')}${r.minRound ? ` reaching round ${r.minRound}` : ''}${r.minPlayers > 1 ? players : ''}${r.minMinutes ? ` lasting at least ${duration(r.minMinutes)} each` : ''}`;
case 'populated-minutes': return `Accumulate ${duration(r.target)}${players}`;
case 'player-hours': return `Accumulate ${r.target} player-hours${r.minPlayers > 1 ? players : ''}`;
case 'population': return `Reach ${count(r.target, 'player')} online`;
case 'sustained-population': return `Keep at least ${count(r.minPlayers, 'player')} online for ${duration(r.target)}`;
case 'healthy-minutes': return `Stay continuously healthy for ${duration(r.target)}`;
case 'failure-budget': return r.target === 0 ? 'Allow no health outages' : `Allow at most ${count(r.target, 'health outage')}`;
case 'restart-budget': return r.target === 0 ? 'Allow no unexpected restarts' : `Allow at most ${count(r.target, 'unexpected restart')}`;
case 'clean-logs': return r.target === 0 ? 'Allow no detected script errors' : `Allow at most ${count(r.target, 'detected script error')}`;
case 'recovery': return `Repeat the checks after ${count(r.target, 'recovery restart')}`;
case 'feature': return `Observe ${r.event || 'a named feature event'} ${count(r.target, 'time')}${players}${r.minRound ? ` at round ${r.minRound} or later` : ''}`;
case 'manual': return r.label;
}
}
export function coverageSummary(plan: BetaPlan): string {
return plan.scope === 'all' ? 'Every selected server' : plan.scope === 'quorum' ? `At least ${count(plan.quorum, 'selected server')}`
: plan.scope === 'map' ? 'One server per selected map' : plan.scope === 'game' ? 'One server per selected game' : 'One server per game / map';
}
export function needsSessionTelemetry(r: BetaRequirement): boolean {
return ['round', 'feature', 'restart-budget'].includes(r.kind) || (r.kind === 'matches' && (r.minRound > 0 || r.minPlayers > 1));
}
export function requirementCategory(r: BetaRequirement): string {
return r.kind === 'manual' ? 'Tester sign-off' : ['healthy-minutes', 'failure-budget', 'restart-budget', 'clean-logs'].includes(r.kind) ? 'Continuous check' : 'Milestone';
}