Defer server file changes until guarded restart activation

Persist beta, promotion, drift, and rollback payloads until occupancy and restart-capacity checks pass. Preserve rollback snapshots and campaign ordering, and allow held rollback campaigns to resume safely.

Fixes #28

Validation: 805 tests passed, Svelte checks clean, production build passed.
This commit is contained in:
2026-09-27 23:06:16 -04:00
parent eb2a852fdc
commit fb48f64de1
36 changed files with 1634 additions and 421 deletions
+32 -2
View File
@@ -343,6 +343,35 @@ CREATE TABLE IF NOT EXISTS deployment_files (
CREATE INDEX IF NOT EXISTS idx_deployment_files_dep ON deployment_files(deployment_id);
-- File payloads stay in SQLite until Provisioning has admitted their restart.
-- Existing campaigns/betas without rows here already wrote their files in the
-- previous release; they remain restart-only work during upgrade.
CREATE TABLE IF NOT EXISTS staged_file_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_kind TEXT NOT NULL CHECK (source_kind IN ('campaign','beta')),
source_id TEXT NOT NULL,
server TEXT NOT NULL,
kind TEXT NOT NULL,
rel_path TEXT NOT NULL,
content BLOB,
script_version_id INTEGER,
inventory_source TEXT NOT NULL,
deployment_file_id INTEGER REFERENCES deployment_files(id) ON DELETE CASCADE,
preserve_before_image INTEGER NOT NULL DEFAULT 0,
check_before INTEGER NOT NULL DEFAULT 0,
expected_before_sha TEXT,
state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','applying','applied','cancelled')),
applied_at TEXT,
UNIQUE (source_kind, source_id, server, kind, rel_path)
);
CREATE INDEX IF NOT EXISTS idx_staged_files_source ON staged_file_changes(source_kind, source_id, server);
CREATE TRIGGER IF NOT EXISTS staged_files_campaign_delete AFTER DELETE ON deployments BEGIN
DELETE FROM staged_file_changes WHERE source_kind = 'campaign' AND source_id = OLD.id;
END;
CREATE TRIGGER IF NOT EXISTS staged_files_beta_delete AFTER DELETE ON betas BEGIN
DELETE FROM staged_file_changes WHERE source_kind = 'beta' AND source_id = CAST(OLD.id AS TEXT);
END;
-- Per-script rows on aggregate promote/rollback deployments. For legacy
-- single-script deployments this may also be backfilled from the deprecated
-- deployments.script_id / script_version_id / prior_version_id columns.
@@ -550,10 +579,11 @@ CREATE TABLE IF NOT EXISTS campaign_events (
message TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_campaign_events ON campaign_events(deployment_id, id);
CREATE TRIGGER IF NOT EXISTS campaign_activity_file AFTER INSERT ON deployment_files
DROP TRIGGER IF EXISTS campaign_activity_file;
CREATE TRIGGER campaign_activity_file AFTER INSERT ON deployment_files
BEGIN
INSERT INTO campaign_events (deployment_id, message)
VALUES (NEW.deployment_id, NEW.server || ': ' || NEW.verb || ' ' || NEW.rel_path);
VALUES (NEW.deployment_id, NEW.server || ': recorded file change — ' || NEW.verb || ' ' || NEW.rel_path);
END;
CREATE TRIGGER IF NOT EXISTS campaign_activity_open AFTER INSERT ON deployments
BEGIN