63 lines
3.9 KiB
TypeScript
63 lines
3.9 KiB
TypeScript
import type { BetaRequirement, BetaTestView } from './beta-plan.js';
|
|
import { needsGameTelemetry } from './beta-plan-summary.js';
|
|
|
|
export function betaWaitingCondition(
|
|
requirement: BetaRequirement,
|
|
observation?: BetaTestView['servers'][number]['observation']
|
|
): string {
|
|
if (requirement.kind === 'manual')
|
|
return 'Waiting for a tester to record their name and observation.';
|
|
if (requirement.kind === 'recovery')
|
|
return 'The other checks must pass before the next restart when empty; each cycle needs fresh evidence.';
|
|
if (requirement.kind === 'healthy-minutes')
|
|
return observation?.healthy === true
|
|
? 'Collecting consecutive fresh healthy observations; an outage or monitoring gap resets this duration.'
|
|
: 'Waiting for fresh container and RCON health observations. Unhealthy or stale observations reset this duration.';
|
|
if (requirement.kind === 'failure-budget')
|
|
return 'An observed health outage exceeded the budget. Investigate before starting a fresh attempt.';
|
|
if (needsGameTelemetry(requirement)) {
|
|
if (!observation?.lastGameplayAt)
|
|
return 'No gameplay report received for this attempt. Check the game reporter and Telemetry API requests.';
|
|
if (observation.gameEnded) return 'Waiting for the next game and its qualifying reports.';
|
|
if (requirement.kind === 'population')
|
|
return `Waiting for a game report containing at least ${requirement.target} players.`;
|
|
const players = `at least ${requirement.minPlayers} player${requirement.minPlayers === 1 ? '' : 's'}`;
|
|
if ((observation.players ?? 0) < requirement.minPlayers)
|
|
return `The latest report has ${observation.players ?? 0} players; this check needs ${players}.`;
|
|
if (requirement.kind === 'matches')
|
|
return requirement.minMinutes && !observation.matchStarted
|
|
? 'This match has no game-start report, so its duration cannot qualify. Waiting for a new game start and game end.'
|
|
: `Waiting for game end${requirement.minRound ? ` after reaching round ${requirement.minRound}` : ''} with ${players}${requirement.minMinutes ? ` and at least ${requirement.minMinutes} minutes since game start` : ''}.`;
|
|
if (requirement.kind === 'round')
|
|
return `Waiting for a round change, heartbeat, or game end reporting round ${requirement.target} or higher with ${players}.`;
|
|
return `Time is credited when the next report arrives, with ${players} at both ends of the interval. It does not advance continuously between reports.`;
|
|
}
|
|
return 'Waiting for qualifying evidence.';
|
|
}
|
|
|
|
export function betaEvidenceSummary(event: BetaTestView['evidence'][number]): string {
|
|
let payload: Record<string, unknown>;
|
|
try {
|
|
payload = JSON.parse(event.payload);
|
|
} catch {
|
|
return event.kind.replaceAll('-', ' ').replaceAll('_', ' ');
|
|
}
|
|
if (!payload || typeof payload !== 'object') return event.kind;
|
|
if (['game_start', 'round_change', 'heartbeat', 'game_end'].includes(event.kind)) {
|
|
const label =
|
|
event.kind === 'game_start'
|
|
? 'Game started'
|
|
: event.kind === 'game_end'
|
|
? 'Game ended'
|
|
: event.kind === 'heartbeat'
|
|
? 'Heartbeat'
|
|
: 'Round changed';
|
|
return `${label}${typeof payload.round === 'number' ? ` at round ${payload.round}` : ''}${Array.isArray(payload.players) ? ` with ${payload.players.length} players` : ''}${typeof payload.map === 'string' ? ` on ${payload.map}` : ''}.`;
|
|
}
|
|
if (event.kind === 'manual-sign-off')
|
|
return `${payload.requirement ?? 'Checklist'}: ${payload.note ?? 'Signed off'}`;
|
|
if (event.kind === 'health' || event.kind === 'status-sample')
|
|
return `${payload.healthy ? 'Healthy observation' : 'Unhealthy observation'}${payload.reason ? `: ${payload.reason}` : '.'}`;
|
|
return event.kind.replaceAll('-', ' ').replaceAll('_', ' ');
|
|
}
|