Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,11 @@ test('production UDS admission commits one transcript before the root handoff',
});
assert.equal(started.disposition, 'turn_started');
if (started.disposition !== 'turn_started') return;
const active = await client.queryTurn({ sessionId: fixture.sessionId, turnId: started.turnId });
await client.stopTurn({
const active = await client.request('turn.query', {
sessionId: fixture.sessionId,
turnId: started.turnId,
});
await client.request('turn.stop', {
sessionId: fixture.sessionId,
turnId: started.turnId,
runId: active.runId,
Expand All @@ -268,7 +271,7 @@ test('a Host crash after queue admission recovers the durable successor once', a
const firstHost = await fixture.startHost();
const first = await connectClient(fixture.root);
const started = requireStartedTurn(
await first.startTurn({
await first.request('turn.start', {
sessionId: fixture.sessionId,
turnId: randomUUID(),
content: { text: FAKE_ASK_USER_QUESTION_PROMPT },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ const ownerChildEntrypoint = fileURLToPath(
test('rejects a second authority for the same storage root in another process', async (t) => {
const storageRoot = await mkdtemp(join(tmpdir(), 'maka-dependency-owner-process-'));
const child = spawn(process.execPath, [ownerChildEntrypoint], {
env: { ...process.env, MAKA_DEPENDENCY_OWNER_ROOT: storageRoot },
env: {
...process.env,
NODE_NO_WARNINGS: '1',
MAKA_DEPENDENCY_OWNER_ROOT: storageRoot,
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,73 @@ import {
import { SQLITE_AGENT_GRAPH_CONTROL_TABLES } from '../sqlite-session-metadata-schema.js';

describe('SqliteSessionMetadataStore', () => {
test('repairs both v30 schema variants after a migration version collision', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-session-metadata-v30-collision-'));
try {
for (const missing of ['message-admissions', 'coordination-index'] as const) {
const path = join(root, `${missing}.sqlite`);
const setup = createSqliteSessionMetadataStore(path);
setup.close();

const legacy = new DatabaseSync(path);
try {
if (missing === 'message-admissions') {
legacy.exec(`
DROP TABLE IF EXISTS message_admissions;
DROP TABLE IF EXISTS cancelled_message_admissions;
`);
} else {
legacy.exec('DROP INDEX IF EXISTS session_metadata_one_workhub_coordination_session');
}
legacy
.prepare(
"UPDATE session_metadata_schema SET version = 30 WHERE scope = 'session_metadata'",
)
.run();
} finally {
legacy.close();
}

const migrated = createSqliteSessionMetadataStore(path);
try {
assert.equal(migrated.schemaVersion(), SQLITE_SESSION_METADATA_SCHEMA_VERSION);
} finally {
migrated.close();
}

const schema = new DatabaseSync(path, { readOnly: true });
try {
assert.deepEqual(
schema
.prepare(`
SELECT name, type
FROM sqlite_schema
WHERE name IN (
'message_admissions',
'cancelled_message_admissions',
'message_admissions_by_session_order',
'session_metadata_one_workhub_coordination_session'
)
ORDER BY name
`)
.all()
.map((row) => ({ ...row })),
[
{ name: 'cancelled_message_admissions', type: 'table' },
{ name: 'message_admissions', type: 'table' },
{ name: 'message_admissions_by_session_order', type: 'index' },
{ name: 'session_metadata_one_workhub_coordination_session', type: 'index' },
],
);
} finally {
schema.close();
}
}
} finally {
await rm(root, { recursive: true, force: true });
}
});

test('migrates v27 metadata to the current schema without backfilling external origin', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-session-metadata-v27-'));
const path = join(root, 'state.sqlite');
Expand Down
37 changes: 34 additions & 3 deletions packages/storage/src/sqlite-session-metadata-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import type { DatabaseSync } from 'node:sqlite';

export const SQLITE_SESSION_METADATA_SCHEMA_VERSION = 30;
export const SQLITE_SESSION_METADATA_SCHEMA_VERSION = 31;
export const SQLITE_SESSION_MESSAGE_CHUNK_BYTES = 64 * 1024;
export const SQLITE_SESSION_MESSAGE_CHUNK_MARKER = '{"$maka":"session-message-chunks-v1"}';

Expand Down Expand Up @@ -1156,9 +1156,40 @@ const MIGRATIONS: ReadonlyMap<number, string> = new Map([
`,
],
[
30,
31,
`
CREATE UNIQUE INDEX session_metadata_one_workhub_coordination_session
CREATE TABLE IF NOT EXISTS message_admissions (
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
turn_id TEXT NOT NULL,
run_id TEXT NOT NULL,
message_id TEXT NOT NULL,
content_json TEXT NOT NULL,
submitted_content_digest TEXT NOT NULL,
submitted_placement TEXT NOT NULL
CHECK (submitted_placement IN ('current_turn', 'next_turn')),
placement TEXT NOT NULL CHECK (placement IN ('current_turn', 'next_turn')),
disposition TEXT NOT NULL CHECK (disposition IN ('steering', 'followup')),
queue_order INTEGER NOT NULL CHECK (queue_order >= 0),
admitted_at INTEGER NOT NULL CHECK (admitted_at >= 0),
UNIQUE (session_id, message_id),
FOREIGN KEY(session_id) REFERENCES session_metadata(session_id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS message_admissions_by_session_order
ON message_admissions(session_id, queue_order, sequence);

CREATE TABLE IF NOT EXISTS cancelled_message_admissions (
session_id TEXT NOT NULL,
message_id TEXT NOT NULL,
submitted_content_digest TEXT NOT NULL,
submitted_placement TEXT NOT NULL
CHECK (submitted_placement IN ('current_turn', 'next_turn')),
PRIMARY KEY (session_id, message_id),
FOREIGN KEY(session_id) REFERENCES session_metadata(session_id) ON DELETE CASCADE
);

CREATE UNIQUE INDEX IF NOT EXISTS session_metadata_one_workhub_coordination_session
ON session_metadata(json_extract(payload_json, '$.role'))
WHERE json_extract(payload_json, '$.role') = 'workhub_coordination';
`,
Expand Down