mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(state): preserve additive column order (#121062)
Keep fresh shared-state table definitions aligned with SQLite ADD COLUMN ordering so current-version upgraded databases pass canonical schema validation.\n\nRefs #121061
This commit is contained in:
committed by
GitHub
parent
cb50289e28
commit
0b4c8a9fc9
@@ -1956,39 +1956,50 @@ INSERT INTO macos_port_guardian_records VALUES (4242, 18789, '/usr/bin/ssh', 're
|
||||
).toEqual([{ task_id: "task-index-repair" }]);
|
||||
});
|
||||
|
||||
it("repairs the same-version worktree cleanup column with physical index drift", () => {
|
||||
const stateDir = createTempStateDir();
|
||||
const env = { OPENCLAW_STATE_DIR: stateDir };
|
||||
const databasePath = materializeCurrentStateDatabase(stateDir);
|
||||
it.each([
|
||||
{ columnName: "run_end_cleanup_json", tableName: "worktrees" },
|
||||
{ columnName: "shared_host", tableName: "worker_environments" },
|
||||
])(
|
||||
"appends same-version $columnName to $tableName before schema validation",
|
||||
({ columnName, tableName }) => {
|
||||
const stateDir = createTempStateDir();
|
||||
const env = { OPENCLAW_STATE_DIR: stateDir };
|
||||
const databasePath = materializeCurrentStateDatabase(stateDir);
|
||||
|
||||
const { DatabaseSync } = requireNodeSqlite();
|
||||
const shippedSchema = new DatabaseSync(databasePath);
|
||||
try {
|
||||
shippedSchema.exec("ALTER TABLE worktrees DROP COLUMN run_end_cleanup_json;");
|
||||
expect(readSqliteNumberPragma(shippedSchema, "user_version")).toBe(
|
||||
OPENCLAW_STATE_SCHEMA_VERSION,
|
||||
);
|
||||
} finally {
|
||||
shippedSchema.close();
|
||||
}
|
||||
createTaskRunStatusIndexPhysicalDrift(databasePath);
|
||||
const { DatabaseSync } = requireNodeSqlite();
|
||||
const shippedSchema = new DatabaseSync(databasePath);
|
||||
let canonicalColumnOrder: string[];
|
||||
try {
|
||||
canonicalColumnOrder = (
|
||||
shippedSchema.prepare(`PRAGMA table_info(${tableName})`).all() as Array<{ name: string }>
|
||||
).map((column) => column.name);
|
||||
shippedSchema.exec(`ALTER TABLE ${tableName} DROP COLUMN ${columnName};`);
|
||||
expect(readSqliteNumberPragma(shippedSchema, "user_version")).toBe(
|
||||
OPENCLAW_STATE_SCHEMA_VERSION,
|
||||
);
|
||||
} finally {
|
||||
shippedSchema.close();
|
||||
}
|
||||
createTaskRunStatusIndexPhysicalDrift(databasePath);
|
||||
|
||||
const reopened = openOpenClawStateDatabase({ env });
|
||||
const columns = reopened.db.prepare("PRAGMA table_info(worktrees)").all() as Array<{
|
||||
name: string;
|
||||
}>;
|
||||
expect(columns.map((column) => column.name)).toContain("run_end_cleanup_json");
|
||||
expect(reopened.db.prepare("PRAGMA integrity_check").get()).toEqual({
|
||||
integrity_check: "ok",
|
||||
});
|
||||
expect(
|
||||
reopened.db
|
||||
.prepare(
|
||||
"SELECT task_id FROM task_runs INDEXED BY idx_task_runs_status WHERE status = 'running'",
|
||||
)
|
||||
.all(),
|
||||
).toEqual([{ task_id: "task-index-repair" }]);
|
||||
});
|
||||
const reopened = openOpenClawStateDatabase({ env });
|
||||
const columns = reopened.db.prepare(`PRAGMA table_info(${tableName})`).all() as Array<{
|
||||
name: string;
|
||||
}>;
|
||||
expect(columns.map((column) => column.name)).toEqual(canonicalColumnOrder);
|
||||
expect(canonicalColumnOrder.at(-1)).toBe(columnName);
|
||||
expect(reopened.db.prepare("PRAGMA integrity_check").get()).toEqual({
|
||||
integrity_check: "ok",
|
||||
});
|
||||
expect(
|
||||
reopened.db
|
||||
.prepare(
|
||||
"SELECT task_id FROM task_runs INDEXED BY idx_task_runs_status WHERE status = 'running'",
|
||||
)
|
||||
.all(),
|
||||
).toEqual([{ task_id: "task-index-repair" }]);
|
||||
},
|
||||
);
|
||||
|
||||
it("does not add Claw bootstrap columns before rejecting unrelated index corruption", () => {
|
||||
const stateDir = createTempStateDir();
|
||||
|
||||
@@ -1801,10 +1801,10 @@ CREATE TABLE IF NOT EXISTS worktrees (
|
||||
owner_id TEXT,
|
||||
snapshot_ref TEXT,
|
||||
provisioned_paths_json TEXT,
|
||||
run_end_cleanup_json TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
last_active_at INTEGER NOT NULL,
|
||||
removed_at INTEGER
|
||||
removed_at INTEGER,
|
||||
run_end_cleanup_json TEXT
|
||||
) STRICT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_worktrees_repo_fingerprint
|
||||
@@ -1846,7 +1846,6 @@ CREATE TABLE IF NOT EXISTS worker_environments (
|
||||
profile_snapshot_json TEXT NOT NULL,
|
||||
provision_operation_id TEXT NOT NULL UNIQUE,
|
||||
lease_id TEXT,
|
||||
shared_host INTEGER CHECK (shared_host IN (0, 1)),
|
||||
ssh_host TEXT,
|
||||
ssh_port INTEGER CHECK (ssh_port IS NULL OR (ssh_port >= 1 AND ssh_port <= 65535)),
|
||||
ssh_user TEXT,
|
||||
@@ -1878,7 +1877,8 @@ CREATE TABLE IF NOT EXISTS worker_environments (
|
||||
state_changed_at_ms INTEGER NOT NULL,
|
||||
idle_since_at_ms INTEGER,
|
||||
destroy_requested_at_ms INTEGER,
|
||||
last_error TEXT
|
||||
last_error TEXT,
|
||||
shared_host INTEGER CHECK (shared_host IN (0, 1))
|
||||
) STRICT;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_worker_environments_provider_lease
|
||||
|
||||
Reference in New Issue
Block a user