Preserve deleted server history

Retain historical server identities, results, and evidence after deletion. Mark archived entries as Deleted and prevent old work from targeting servers that reuse the same name.

Fixes #16.
This commit is contained in:
2026-09-27 21:48:55 -04:00
parent 53b29f726c
commit 981fb27c1c
61 changed files with 929 additions and 223 deletions
+7 -6
View File
@@ -25,7 +25,7 @@ const setStage = () =>
restarted_at = CASE WHEN ? = 'awaiting-health' OR ? = 'ready' THEN COALESCE(restarted_at, ?) ELSE restarted_at END,
healthy_at = CASE WHEN ? = 'awaiting-match' OR (? = 'ready' AND healthy_at IS NULL) THEN COALESCE(healthy_at, ?) ELSE healthy_at END,
match_seen_at = CASE WHEN ? = 'ready' AND match_seen_at IS NULL THEN ? ELSE match_seen_at END
WHERE beta_id = ? AND server = ?`
WHERE beta_id = ? AND server = ? AND server_deleted_at IS NULL`
);
function transition(
@@ -35,7 +35,7 @@ function transition(
error: string | null = null
): void {
const t = nowIso();
setStage().run(
const result = setStage().run(
stage,
error,
t,
@@ -50,17 +50,17 @@ function transition(
betaId,
server
);
emit({ type: 'beta-server-stage', betaId, server, stage, error });
if (result.changes) emit({ type: 'beta-server-stage', betaId, server, stage, error });
}
// Bump beta.state to ready-promote when every one of its beta_servers is ready.
// A single failed row is enough to keep the beta in 'running' (operator retries).
function reconcileBetaState(betaId: number): void {
const rows = db()
.prepare(`SELECT stage FROM beta_servers WHERE beta_id = ?`)
.all(betaId) as Array<{ stage: BetaStage }>;
.prepare(`SELECT stage, server_deleted_at FROM beta_servers WHERE beta_id = ?`)
.all(betaId) as Array<{ stage: BetaStage; server_deleted_at: string | null }>;
if (rows.length === 0) return;
if (rows.every((r) => r.stage === 'ready')) {
if (rows.every((r) => r.stage === 'ready' && !r.server_deleted_at)) {
const upd = db()
.prepare(`UPDATE betas SET state = 'ready-promote' WHERE id = ? AND state = 'running'`)
.run(betaId);
@@ -98,6 +98,7 @@ async function runBetaTick(): Promise<{ processed: number }> {
FROM beta_servers bs
JOIN betas b ON b.id = bs.beta_id
WHERE b.state = 'running'
AND bs.server_deleted_at IS NULL
AND NOT EXISTS (SELECT 1 FROM beta_test_plans p WHERE p.beta_id = b.id)
AND bs.stage IN ('awaiting-empty','restarting','awaiting-health','awaiting-match')
ORDER BY b.id, bs.server`