Skip to content

Commit dfe470a

Browse files
Merge fast Rust mode H2: durable host runner record (context.db v97)
Co-authored-by: Alfonso <alfonso-magic-context@users.noreply.github.com>
2 parents 0d04f53 + be86361 commit dfe470a

11 files changed

Lines changed: 1104 additions & 8 deletions

‎packages/plugin/src/features/magic-context/migrations-armed-replay.test.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,29 @@ function populateForVersion(db: DatabaseType, version: number, state: ReplayStat
764764
).toEqual({ served_capture_id: 1 });
765765
populateModuleOwnedRows(db, version, state);
766766
return;
767+
case 97:
768+
if (!state.armed) throw new Error(`migration v${version} reached an unarmed store`);
769+
expect(
770+
db
771+
.prepare(
772+
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'host_runner_%' ORDER BY name",
773+
)
774+
.all(),
775+
).toEqual([
776+
{ name: "host_runner_entries" },
777+
{ name: "host_runner_ids" },
778+
{ name: "host_runner_state" },
779+
{ name: "host_runner_views" },
780+
]);
781+
db.prepare(`INSERT INTO host_runner_ids (session_id, harness, lineage_id, message_id, ordinal)
782+
VALUES ('armed-v97', 'opencode', 'lineage', 'marker', NULL)`).run();
783+
expect(
784+
db
785+
.prepare("SELECT ordinal FROM host_runner_ids WHERE session_id='armed-v97'")
786+
.get(),
787+
).toEqual({ ordinal: null });
788+
populateModuleOwnedRows(db, version, state);
789+
return;
767790
default:
768791
throw new Error(`populateForVersion has no arm for migration v${version}`);
769792
}

‎packages/plugin/src/features/magic-context/migrations-v96.test.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,9 @@ describe("migration 96", () => {
4747
expect(saveLkgSlotToDb(db, "legacy", slot)).toBe(true);
4848
const before = db.prepare("SELECT * FROM lkg_slot_chunks").all();
4949
runMigrations(db);
50-
expect(LATEST_SUPPORTED_VERSION).toBe(96);
51-
expect(LATEST_MIGRATION_VERSION).toBe(96);
50+
expect(LATEST_SUPPORTED_VERSION).toBe(LATEST_MIGRATION_VERSION);
5251
expect(db.prepare("SELECT MAX(version) AS v FROM schema_migrations").get()).toEqual({
53-
v: 96,
52+
v: LATEST_MIGRATION_VERSION,
5453
});
5554
expect(db.prepare("SELECT * FROM lkg_slot_chunks").all()).toEqual(before);
5655
expect(loadPersistedLkgSlot(db, "legacy")).toEqual(slot);
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { describe, expect, test } from "bun:test";
2+
import { rmSync } from "node:fs";
3+
import { tmpdir } from "node:os";
4+
import { join } from "node:path";
5+
import { Database } from "../../shared/sqlite";
6+
import { createTestTempDirFromPath } from "../../shared/test-temp-dir";
7+
import { LATEST_MIGRATION_VERSION, MIGRATIONS, runMigrations } from "./migrations";
8+
import {
9+
getSchemaFenceRejection,
10+
initializeDatabase,
11+
LATEST_SUPPORTED_VERSION,
12+
openDatabase,
13+
} from "./storage-db";
14+
import {
15+
commitHostRunnerPass,
16+
createHostRunnerState,
17+
loadHostRunnerRecord,
18+
} from "./storage-host-runner";
19+
import { SESSION_SCOPED_TABLES } from "./storage-session-tables";
20+
21+
const tables = ["host_runner_entries", "host_runner_ids", "host_runner_views", "host_runner_state"];
22+
23+
function schema(db: Database): unknown[] {
24+
return db
25+
.prepare(
26+
"SELECT name, sql FROM sqlite_master WHERE name LIKE 'host_runner_%' ORDER BY name",
27+
)
28+
.all();
29+
}
30+
31+
describe("migration 97", () => {
32+
test("populated v96 upgrades losslessly and converges with fresh schema, idempotently", () => {
33+
const db = new Database(":memory:");
34+
const fresh = new Database(":memory:");
35+
try {
36+
initializeDatabase(db);
37+
for (const table of tables) db.exec(`DROP TABLE ${table}`);
38+
db.exec(
39+
"CREATE TABLE schema_migrations(version INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL, description TEXT)",
40+
);
41+
for (const migration of MIGRATIONS.filter((m) => m.version <= 96)) {
42+
migration.up(db);
43+
db.prepare("INSERT INTO schema_migrations(version, applied_at) VALUES (?, 0)").run(
44+
migration.version,
45+
);
46+
}
47+
db.prepare(
48+
"INSERT INTO session_meta(session_id, harness, counter) VALUES ('legacy', 'opencode', 42)",
49+
).run();
50+
const before = db.prepare("SELECT * FROM session_meta WHERE session_id='legacy'").get();
51+
runMigrations(db);
52+
expect(
53+
db.prepare("SELECT * FROM session_meta WHERE session_id='legacy'").get(),
54+
).toEqual(before);
55+
expect(LATEST_SUPPORTED_VERSION).toBe(97);
56+
expect(LATEST_MIGRATION_VERSION).toBe(97);
57+
initializeDatabase(fresh);
58+
runMigrations(fresh);
59+
expect(schema(db)).toEqual(schema(fresh));
60+
const key = { session_id: "s", harness: "opencode2" };
61+
const state = {
62+
...createHostRunnerState("lineage"),
63+
ordinal_divergence: 2,
64+
bootstrap_refused_json: '{"code":"misconfigured","config":{"model":"x"}}',
65+
};
66+
commitHostRunnerPass(db, key, { state, elided: ["marker"] });
67+
const record = loadHostRunnerRecord(db, key);
68+
MIGRATIONS.find((m) => m.version === 97)!.up(db);
69+
runMigrations(db);
70+
expect(loadHostRunnerRecord(db, key)).toEqual(record);
71+
for (const table of tables) {
72+
expect(
73+
SESSION_SCOPED_TABLES.find((definition) => definition.table === table)
74+
?.harnessScoped,
75+
).toBe(true);
76+
}
77+
} finally {
78+
db.close();
79+
fresh.close();
80+
}
81+
});
82+
83+
test("startup heals missing race, divergence and bootstrap refusal columns", () => {
84+
const db = new Database(":memory:");
85+
try {
86+
initializeDatabase(db);
87+
db.exec(
88+
"ALTER TABLE host_runner_entries DROP COLUMN race; ALTER TABLE host_runner_state DROP COLUMN ordinal_divergence; ALTER TABLE host_runner_state DROP COLUMN bootstrap_refused_json",
89+
);
90+
initializeDatabase(db);
91+
const columns = (table: string) =>
92+
(db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[]).map(
93+
(c) => c.name,
94+
);
95+
expect(columns("host_runner_entries")).toContain("race");
96+
expect(columns("host_runner_state")).toContain("ordinal_divergence");
97+
expect(columns("host_runner_state")).toContain("bootstrap_refused_json");
98+
} finally {
99+
db.close();
100+
}
101+
});
102+
103+
test("a v96 host refuses the migrated runner store at the normal open fence without changing it", () => {
104+
const directory = createTestTempDirFromPath(join(tmpdir(), "host-runner-fence-"));
105+
const path = join(directory, "context.db");
106+
const db = new Database(path);
107+
try {
108+
initializeDatabase(db);
109+
runMigrations(db);
110+
const before = schema(db);
111+
expect(openDatabase({ dbPath: path, latestSupportedVersion: 96 })).toBeNull();
112+
expect(getSchemaFenceRejection()).toEqual({
113+
persistedVersion: 97,
114+
supportedVersion: 96,
115+
});
116+
expect(schema(db)).toEqual(before);
117+
} finally {
118+
db.close();
119+
rmSync(directory, { recursive: true, force: true });
120+
}
121+
});
122+
});

‎packages/plugin/src/features/magic-context/migrations.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { splitLkgSlotPrefixes, splitReplayDecisions } from "./migration-v94-writ
77
import { installV95PerfSchema } from "./migration-v95-perf-indexes";
88
import { repairOpenCode2HarnessLabels } from "./opencode2-relabel";
99
import { installCompartmentHistoryVersions } from "./storage-compartment-history-version";
10+
import { installHostRunnerSchema } from "./storage-host-runner";
1011
import { ensureColumn, healAllNullColumns } from "./storage-schema-helpers";
1112
import { bumpEpochsForWorkspaceMemberSet } from "./workspaces";
1213

@@ -91,6 +92,10 @@ export const V85_OPENCODE2_RELABEL_TABLES = [
9192
"transform_decisions",
9293
"recomp_compartments",
9394
"recomp_facts",
95+
"host_runner_entries",
96+
"host_runner_ids",
97+
"host_runner_views",
98+
"host_runner_state",
9499
] as const;
95100

96101
/**
@@ -3225,6 +3230,13 @@ export const MIGRATIONS: Migration[] = [
32253230
)`);
32263231
},
32273232
},
3233+
{
3234+
version: 97,
3235+
description: "durable append-only host runner entries, ids, views and pass state",
3236+
up(db: Database): void {
3237+
installHostRunnerSchema(db);
3238+
},
3239+
},
32283240
];
32293241

32303242
/**

‎packages/plugin/src/features/magic-context/schema-version-fence.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { formatSchemaFenceBootLog, LATEST_SUPPORTED_VERSION } from "./storage-db
1212
describe("schema version fence", () => {
1313
it("LATEST_SUPPORTED_VERSION equals the highest migration version", () => {
1414
expect(LATEST_SUPPORTED_VERSION).toBe(LATEST_MIGRATION_VERSION);
15-
expect(LATEST_SUPPORTED_VERSION).toBe(96);
15+
expect(LATEST_SUPPORTED_VERSION).toBe(97);
1616
});
1717

1818
it("keeps every upstream migration below the downstream floor", () => {

‎packages/plugin/src/features/magic-context/storage-db.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {
7272
runMigrations,
7373
} from "./migrations";
7474
import { installCompartmentHistoryVersions } from "./storage-compartment-history-version";
75+
import { installHostRunnerSchema } from "./storage-host-runner";
7576
import { ensureColumn, healAllNullColumns } from "./storage-schema-helpers";
7677
import {
7778
loadToolDefinitionMeasurements,
@@ -161,7 +162,7 @@ export function __resetSchemaFenceStateForTests(): void {
161162
lastUnconfirmedMigrationHolders = null;
162163
}
163164

164-
export const LATEST_SUPPORTED_VERSION = 96;
165+
export const LATEST_SUPPORTED_VERSION = 97;
165166

166167
/**
167168
* Every runtime backend receives the same finite wait before the first schema
@@ -1133,6 +1134,7 @@ export function initializeDatabase(
11331134
db.exec("PRAGMA foreign_keys=ON");
11341135
configureContextDatabasePragmas(db);
11351136
applySqliteTuningPragmas(db);
1137+
installHostRunnerSchema(db);
11361138
db.exec(`
11371139
CREATE TABLE IF NOT EXISTS tags (
11381140
id INTEGER PRIMARY KEY AUTOINCREMENT,

0 commit comments

Comments
 (0)