feat: match fleet to blueprint targets exactly

Add an optional exact blueprint mode with keep/create/remove previews, atomic queueing, cancellation of unstarted excess creations, and persistent dependencies for safe port reuse. Track removals alongside creations and preserve fill mode as the default.

Validation: type check, production build, and 103 deployment tests passed. The full suite has one telemetry assertion failure also reproduced on the previous commit.

Fixes #42
This commit is contained in:
2026-09-27 13:36:08 -04:00
parent 1aa7f15371
commit 0b0e5b5bdb
13 changed files with 517 additions and 83 deletions
+8
View File
@@ -249,6 +249,14 @@ export function db(): Database.Database {
migrateTable(handle, 'beta_scripts', BETA_SCRIPTS_COLUMNS);
migrateTable(handle, 'deployment_scripts', DEPLOYMENT_SCRIPTS_COLUMNS);
migrateTable(handle, 'deployments', DEPLOYMENTS_COLUMNS);
migrateTable(handle, 'server_launch_collections', [
{ name: 'mode', ddl: "ALTER TABLE server_launch_collections ADD COLUMN mode TEXT NOT NULL DEFAULT 'fill'" },
{ name: 'retained_servers', ddl: "ALTER TABLE server_launch_collections ADD COLUMN retained_servers TEXT NOT NULL DEFAULT '[]'" }
]);
migrateTable(handle, 'server_collection_previews', [
{ name: 'mode', ddl: "ALTER TABLE server_collection_previews ADD COLUMN mode TEXT NOT NULL DEFAULT 'fill'" },
{ name: 'fleet_snapshot', ddl: 'ALTER TABLE server_collection_previews ADD COLUMN fleet_snapshot TEXT' }
]);
migrateTable(handle, 'server_telemetry', [{ name: 'payload', ddl: 'ALTER TABLE server_telemetry ADD COLUMN payload TEXT' }]);
// Kind-referencing indexes: safe here because migrateTable above just
// ALTER'd the column into existence if it was missing.
+20 -1
View File
@@ -467,7 +467,9 @@ CREATE TABLE IF NOT EXISTS server_launch_recipes (
CREATE TABLE IF NOT EXISTS server_launch_collections (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_at TEXT NOT NULL
created_at TEXT NOT NULL,
mode TEXT NOT NULL DEFAULT 'fill',
retained_servers TEXT NOT NULL DEFAULT '[]'
);
CREATE TABLE IF NOT EXISTS server_collection_members (
@@ -483,9 +485,26 @@ CREATE TABLE IF NOT EXISTS server_collection_previews (
blueprint_name TEXT NOT NULL,
entries TEXT NOT NULL,
servers TEXT NOT NULL,
mode TEXT NOT NULL DEFAULT 'fill',
fleet_snapshot TEXT,
collection_id TEXT REFERENCES server_launch_collections(id) ON DELETE CASCADE
);
-- A pending removal can be shared by multiple reviewed collection requests.
CREATE TABLE IF NOT EXISTS server_collection_removals (
collection_id TEXT NOT NULL REFERENCES server_launch_collections(id) ON DELETE CASCADE,
deployment_id TEXT NOT NULL REFERENCES server_deployments(id) ON DELETE CASCADE,
position INTEGER NOT NULL,
PRIMARY KEY (collection_id, deployment_id)
);
-- Reusing a port is safe only after the reviewed removal has completed.
CREATE TABLE IF NOT EXISTS server_creation_dependencies (
deployment_id TEXT NOT NULL REFERENCES server_deployments(id) ON DELETE CASCADE,
removal_id TEXT NOT NULL REFERENCES server_deployments(id) ON DELETE CASCADE,
PRIMARY KEY (deployment_id, removal_id)
);
-- Persist state transitions atomically, including changes made by background workers.
-- Polls with unchanged status/error do not produce duplicate activity entries.
CREATE TABLE IF NOT EXISTS beta_events (