test(ci): trim duplicate SQLite lifecycle tours (#122308)

* test(ci): accelerate SQLite flip proof

* test(sessions): replace duplicate archive stress tour

* test(sessions): preserve SQLite lifecycle contracts

* test(sessions): drop duplicate archive assertions

---------

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Peter Steinberger
2026-08-11 16:51:28 -07:00
committed by GitHub
parent 087fb56f77
commit 76c7cd7308
4 changed files with 169 additions and 839 deletions
@@ -67,36 +67,6 @@ export function assertSqliteFlipProofCore(report: SqliteFlipProofReport): void {
),
),
).toBe(true);
expect(report.pluginSdkConsumer).toMatchObject({
activeJsonlForSessionExists: false,
latestAssistantTextBeforeAppend: report.fullTurnAssistantText,
latestAssistantTextAfterAppend: "sqlite sdk consumer appended by identity",
sessionKey: report.pluginSdkSessionKey,
});
expect(report.pluginSdkConsumer?.sessionIdentity).toBe(report.pluginSdkSessionKey);
expect(report.pluginSdkConsumer?.listedSessionKeys).toContain(report.pluginSdkSessionKey);
expect(
report.checkpoints.some(
(checkpoint) =>
checkpoint.label === "after-plugin-sdk-consumer" &&
checkpoint.sqlite.trackedEntries.some(
(entry) => entry.sessionKey === report.pluginSdkSessionKey && entry.transcriptEvents >= 3,
),
),
).toBe(true);
const cleanupCheckpoint = report.checkpoints.find(
(checkpoint) => checkpoint.label === "after-cleanup-pruning",
);
expect(
cleanupCheckpoint?.sqlite.trackedEntries.some(
(entry) => entry.sessionKey === report.cleanupPruneSessionKey,
),
).toBe(false);
const cleanupArchive = cleanupCheckpoint?.archiveArtifacts.find(
(artifact) =>
artifact.archiveReason === "deleted" && artifact.archiveSessionId === "sqlite-cleanup-prune",
);
expect(cleanupArchive?.messageTexts).toContain("sqlite cleanup prune me");
const idempotenceCheckpoint = report.checkpoints.find(
(checkpoint) => checkpoint.label === "after-doctor-import-idempotence",
);
@@ -145,4 +115,164 @@ export function assertSqliteFlipProofCore(report: SqliteFlipProofReport): void {
(entry) => entry.sessionKey === report.concurrentDeleteSessionKey,
),
).toBe(false);
expect(report.checkpoints.map((checkpoint) => checkpoint.label)).toEqual([
"seeded-legacy-store",
"after-startup-import",
"after-doctor-inspect",
"after-doctor-validate",
"after-rollback-restore",
"after-gateway-restart",
"after-chat-send",
"after-full-agent-turn",
"after-doctor-import-idempotence",
"after-downgrade-reupgrade-import",
"after-sqlite-busy-contention",
"after-concurrent-multi-client",
"after-sessions-reset",
"after-second-startup-after-reset",
"after-transcript-append",
"after-sessions-delete",
"after-shared-first-delete",
"after-shared-final-delete",
"after-final-doctor-inspect",
]);
expect(
startupImportCheckpoint?.archiveArtifacts.some(
(artifact) =>
artifact.path.includes("old-orphan.deleted.jsonl") &&
artifact.textTail?.includes("old-orphan") === true,
),
).toBe(true);
expect(report.rollbackRestore).toMatchObject({
archivedBeforeRestore: true,
failedManifestIssueCode: "e2e_forced_post_archive_failure",
sourceRestored: true,
sqliteStillExists: true,
});
expect(report.rollbackRestore?.manifestPath).toContain("session-sqlite-migration-runs");
expect(
report.rollbackRestore?.restoredFiles.some((filePath) =>
filePath.replaceAll("\\", "/").endsWith("/sqlite-rollback-restore.jsonl"),
),
).toBe(true);
expect(
report.rollbackRestore?.idempotentRestoreSkippedFiles.some((filePath) =>
filePath.replaceAll("\\", "/").endsWith("/sqlite-rollback-restore.jsonl"),
),
).toBe(true);
expect(report.scaleMigration).toMatchObject({
minTranscriptEventsPerSession: 4,
seededEvents: 96,
seededSessions: 24,
});
expect(report.scaleMigration?.importedSessionKeys).toHaveLength(24);
expect(report.scaleMigration?.startupImportElapsedMs).toBeGreaterThanOrEqual(0);
expect(
report.checkpoints.some(
(checkpoint) =>
checkpoint.label === "after-full-agent-turn" &&
checkpoint.sqlite.trackedEntries.some(
(entry) =>
entry.sessionKey === report.fullTurnSessionKey &&
entry.transcriptEvents >= 2 &&
entry.trajectoryEvents >= 1,
),
),
).toBe(true);
expect(report.downgradeReupgrade).toMatchObject({
activeJsonlArchived: true,
doctorImportedEntries: 1,
doctorImportedTranscriptEvents: 2,
sessionId: "sqlite-downgrade-reupgrade",
sessionKey: "agent:main:dashboard:sqlite-downgrade-reupgrade",
trajectoryPointerArchived: true,
trajectoryPointerSourceRemoved: true,
trajectorySidecarArchived: true,
trajectorySidecarSourceRemoved: true,
transcriptEvents: 2,
});
const downgradeCheckpoint = report.checkpoints.find(
(checkpoint) => checkpoint.label === "after-downgrade-reupgrade-import",
);
expect(
downgradeCheckpoint?.archiveArtifacts.some(
(artifact) =>
artifact.path.includes("sqlite-downgrade-reupgrade.trajectory.jsonl") &&
artifact.textTail?.includes("trajectory") === true,
),
).toBe(true);
expect(
downgradeCheckpoint?.archiveArtifacts.some((artifact) =>
artifact.path.includes("sqlite-downgrade-reupgrade.trajectory-path.json"),
),
).toBe(true);
expect(
report.checkpoints.some(
(checkpoint) =>
checkpoint.label === "after-downgrade-reupgrade-import" &&
checkpoint.sqlite.trackedEntries.some(
(entry) =>
entry.sessionKey === "agent:main:dashboard:sqlite-downgrade-reupgrade" &&
entry.transcriptEvents === 2,
),
),
).toBe(true);
expect(report.busyContention).toMatchObject({
childExitCode: 0,
childSignal: null,
holdMs: 500,
sessionId: "sqlite-busy-contention",
sessionKey: "agent:main:dashboard:sqlite-busy-contention",
transcriptEvents: 2,
});
expect(report.busyContention?.elapsedMs).toBeGreaterThanOrEqual(250);
expect(report.secondStartupAfterReset).toMatchObject({
activeJsonlForSessionExists: false,
historyContainsPostResetAppend: true,
sessionKey: report.resetSessionKey,
});
expect(report.secondStartupAfterReset?.transcriptEvents).toBeGreaterThanOrEqual(1);
expect(
report.checkpoints.some(
(checkpoint) =>
checkpoint.label === "after-transcript-append" &&
checkpoint.sqlite.trackedEntries.some(
(entry) => entry.sessionKey === report.resetSessionKey && entry.transcriptEvents >= 1,
),
),
).toBe(true);
const deleteCheckpoint = report.checkpoints.find(
(checkpoint) => checkpoint.label === "after-sessions-delete",
);
const deleteArchive = deleteCheckpoint?.archiveArtifacts.find(
(artifact) =>
artifact.archiveReason === "deleted" && artifact.archiveSessionId === "sqlite-delete-session",
);
expect(deleteArchive?.messageTexts).toContain("delete me");
const sharedFinalCheckpoint = report.checkpoints.find(
(checkpoint) => checkpoint.label === "after-shared-final-delete",
);
const sharedFinalArchive = sharedFinalCheckpoint?.archiveArtifacts.find(
(artifact) =>
artifact.archiveReason === "deleted" && artifact.archiveSessionId === "sqlite-shared-session",
);
const retainedSharedImportSources = sharedFinalCheckpoint?.archiveArtifacts.filter(
(artifact) =>
artifact.path.includes("session-sqlite-import-archive") &&
(artifact.path.includes("sqlite-shared-a.jsonl") ||
artifact.path.includes("sqlite-shared-b.jsonl")),
);
expect(
sharedFinalArchive?.messageTexts?.includes("shared") ||
(retainedSharedImportSources?.length === 2 &&
retainedSharedImportSources.every((artifact) =>
artifact.messageTexts?.some((text) => text.includes("shared")),
)),
).toBe(true);
expect(
report.checkpoints.some(
(checkpoint) =>
checkpoint.label === "after-shared-final-delete" && checkpoint.archiveArtifacts.length > 0,
),
).toBe(true);
}
@@ -25,21 +25,9 @@ import {
connectGatewayClient,
disconnectGatewayClient,
} from "../../src/gateway/test-helpers.e2e.js";
import {
getSessionEntry as getSdkSessionEntry,
listSessionEntries as listSdkSessionEntries,
loadTranscriptEventsSync as loadSdkTranscriptEventsSync,
} from "../../src/plugin-sdk/session-store-runtime.js";
import {
appendSessionTranscriptMessageByIdentity,
readLatestAssistantTextByIdentity,
readSessionTranscriptEvents,
resolveSessionTranscriptIdentity,
} from "../../src/plugin-sdk/session-transcript-runtime.js";
import { closeOpenClawAgentDatabasesForTest } from "../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../src/state/openclaw-state-db.js";
import { sleep } from "../../src/utils.js";
import { normalizeSessionDeliveryState } from "../../src/utils/delivery-context.shared.js";
import { createOpenClawTestInstance } from "./openclaw-test-instance.js";
type DoctorMode = "import" | "inspect" | "validate" | "restore";
@@ -52,8 +40,6 @@ type DoctorCommandEvidence = Awaited<ReturnType<typeof runDoctor>>;
type FileInventoryEntry = Awaited<ReturnType<typeof inventoryFile>>;
type ProofCheckpoint = Awaited<ReturnType<typeof captureCheckpoint>>;
type PluginSdkConsumerEvidence = Awaited<ReturnType<typeof runPluginSdkConsumerProbe>>;
type ManualCompactionEvidence = Awaited<ReturnType<typeof runManualCompactionProof>>;
type ScaleMigrationEvidence = ReturnType<typeof requireScaleMigrationProof>;
type DowngradeReupgradeEvidence = Awaited<ReturnType<typeof runDowngradeReupgradeProof>>;
type BusyContentionEvidence = Awaited<ReturnType<typeof runSqliteBusyContentionProof>>;
@@ -77,14 +63,8 @@ const CONCURRENT_RESET_SESSION_KEY = "agent:main:dashboard:sqlite-concurrent-res
const CONCURRENT_DELETE_SESSION_KEY = "agent:main:dashboard:sqlite-concurrent-delete";
const CONCURRENT_SEND_TEXT = "sqlite concurrent send history reset";
const CONCURRENT_DELETE_TEXT = "sqlite concurrent delete while send is active";
const CLEANUP_PRUNE_SESSION_ID = "sqlite-cleanup-prune";
const CLEANUP_PRUNE_SESSION_KEY = "agent:main:dashboard:sqlite-cleanup-prune";
const CLEANUP_PRUNE_TEXT = "sqlite cleanup prune me";
const FULL_TURN_ASSISTANT_TEXT = "OPENCLAW_E2E_OK_12";
const FULL_TURN_SESSION_KEY = "agent:main:sqlite-full-turn";
const MANUAL_COMPACTION_SESSION_KEY = "agent:main:dashboard:sqlite-manual-compact";
const PLUGIN_SDK_APPEND_TEXT = "sqlite sdk consumer appended by identity";
const PLUGIN_SDK_SESSION_KEY = "agent:main:dashboard:sqlite-sdk-consumer";
const DOWNGRADE_REUPGRADE_SESSION_ID = "sqlite-downgrade-reupgrade";
const DOWNGRADE_REUPGRADE_SESSION_KEY = "agent:main:dashboard:sqlite-downgrade-reupgrade";
const DOWNGRADE_REUPGRADE_TEXT = "sqlite downgrade wrote file-backed state";
@@ -120,6 +100,13 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
HTTP_PROXY: undefined,
HTTPS_PROXY: undefined,
NO_PROXY: "127.0.0.1,localhost",
...(options.requireBuiltCli !== true
? {
OPENCODE_API_KEY: undefined,
OPENCODE_ZEN_API_KEY: undefined,
OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1",
}
: {}),
OPENAI_API_KEY: "sk-openclaw-e2e-mock",
OPENCLAW_TEST_MINIMAL_GATEWAY: undefined,
OPENCLAW_SKIP_PROVIDERS: undefined,
@@ -128,8 +115,7 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
startTimeoutMs: 90_000,
stopTimeoutMs: 3_000,
});
// The proof mixes child-process CLI calls with in-process SDK accessors.
// Apply the fixture environment so both paths resolve the same isolated DB.
// Doctor commands and the gateway must resolve the same isolated database.
inst.state.applyEnv();
const context = buildProofContext(inst.stateDir);
const checkpoints: ProofCheckpoint[] = [];
@@ -137,9 +123,7 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
let gatewayEntrypoint: string[] = [];
let busyContention: BusyContentionEvidence | undefined;
let downgradeReupgrade: DowngradeReupgradeEvidence | undefined;
let manualCompaction: ManualCompactionEvidence | undefined;
let mockOpenAi: ProofChildProcess | undefined;
let pluginSdkConsumer: PluginSdkConsumerEvidence | undefined;
let rollbackRestore: RollbackRestoreEvidence | undefined;
let scaleMigration: ScaleMigrationEvidence | undefined;
let secondStartupAfterReset: SecondStartupAfterResetEvidence | undefined;
@@ -249,37 +233,6 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
await requireMockOpenAiRequest(context.mockOpenAiRequestLog);
await record("after-full-agent-turn");
manualCompaction = await runManualCompactionProof(restartedClient, context);
await record("after-manual-compaction");
const pluginSdkRunId = await sendGatewayUserMessage(
restartedClient,
context.pluginSdkSessionKey,
`Reply with exactly ${context.fullTurnAssistantText}. SDK consumer proof.`,
);
await waitForAgentRunOk(restartedClient, pluginSdkRunId);
const pluginSdkSessionId = await waitForSqliteSessionId(
context.agentDbPath,
context.pluginSdkSessionKey,
);
await waitForSqliteMessageContains(
context.agentDbPath,
pluginSdkSessionId,
"assistant",
context.fullTurnAssistantText,
);
pluginSdkConsumer = await runPluginSdkConsumerProbe(context, pluginSdkSessionId);
await waitForSqliteMessageContains(
context.agentDbPath,
pluginSdkSessionId,
"assistant",
context.pluginSdkAppendText,
);
await record("after-plugin-sdk-consumer");
await runGatewayCleanupPruningProof(restartedClient, context);
await record("after-cleanup-pruning");
const idempotentImportDoctor = await runDoctorIdempotenceProof(inst, context);
await record("after-doctor-import-idempotence", idempotentImportDoctor);
@@ -357,7 +310,6 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
ok: failures.length === 0,
agentId: context.agentId,
checkpoints,
cleanupPruneSessionKey: context.cleanupPruneSessionKey,
concurrentDeleteSessionKey: context.concurrentDeleteSessionKey,
concurrentResetSessionKey: context.concurrentResetSessionKey,
concurrentSendSessionKey: context.concurrentSendSessionKey,
@@ -367,12 +319,8 @@ export async function runSqliteSessionsTranscriptsFlipProof(options: RunOptions
fullTurnSessionKey: context.fullTurnSessionKey,
gatewayEntrypoint,
legacySessionId: context.legacySessionId,
...(manualCompaction ? { manualCompaction } : {}),
manualCompactionSessionKey: context.manualCompactionSessionKey,
mockOpenAiRequestLog: context.mockOpenAiRequestLog,
oldStateSessionKeys: [...context.oldStateSessionKeys],
...(pluginSdkConsumer ? { pluginSdkConsumer } : {}),
pluginSdkSessionKey: context.pluginSdkSessionKey,
resetSessionKey: context.resetSessionKey,
...(rollbackRestore ? { rollbackRestore } : {}),
...(busyContention ? { busyContention } : {}),
@@ -402,7 +350,6 @@ function buildProofContext(stateDir: string) {
agentDbPath: path.join(agentDir, "agent", "openclaw-agent.sqlite"),
agentId: AGENT_ID,
archiveRoots: [path.join(agentDir, "session-sqlite-import-archive"), activeSessionsDir],
cleanupPruneSessionKey: CLEANUP_PRUNE_SESSION_KEY,
concurrentDeleteSessionKey: CONCURRENT_DELETE_SESSION_KEY,
concurrentResetSessionKey: CONCURRENT_RESET_SESSION_KEY,
concurrentSendSessionKey: CONCURRENT_SEND_SESSION_KEY,
@@ -411,11 +358,8 @@ function buildProofContext(stateDir: string) {
fullTurnSessionKey: FULL_TURN_SESSION_KEY,
legacySessionsDir,
legacySessionId: "sqlite-legacy-main",
manualCompactionSessionKey: MANUAL_COMPACTION_SESSION_KEY,
mockOpenAiRequestLog: path.join(stateDir, "mock-openai-requests.ndjson"),
oldStateSessionKeys: [...OLD_STATE_SESSION_KEYS],
pluginSdkAppendText: PLUGIN_SDK_APPEND_TEXT,
pluginSdkSessionKey: PLUGIN_SDK_SESSION_KEY,
resetSessionKey: RESET_SESSION_KEY,
sharedSessionKeys: [...SHARED_SESSION_KEYS],
stateDir,
@@ -423,13 +367,10 @@ function buildProofContext(stateDir: string) {
trackedSessionKeys: [
RESET_SESSION_KEY,
DELETE_SESSION_KEY,
CLEANUP_PRUNE_SESSION_KEY,
CONCURRENT_SEND_SESSION_KEY,
CONCURRENT_RESET_SESSION_KEY,
CONCURRENT_DELETE_SESSION_KEY,
FULL_TURN_SESSION_KEY,
MANUAL_COMPACTION_SESSION_KEY,
PLUGIN_SDK_SESSION_KEY,
DOWNGRADE_REUPGRADE_SESSION_KEY,
SQLITE_BUSY_SESSION_KEY,
...SHARED_SESSION_KEYS,
@@ -991,192 +932,6 @@ async function appendProofMessage(
}
}
async function runManualCompactionProof(client: GatewayClient, context: ProofContext) {
const runId = await sendGatewayUserMessage(
client,
context.manualCompactionSessionKey,
`Reply with exactly ${context.fullTurnAssistantText}. Manual compaction proof.`,
);
await waitForAgentRunOk(client, runId);
const sessionId = await waitForSqliteSessionId(
context.agentDbPath,
context.manualCompactionSessionKey,
);
await waitForSqliteMessageContains(
context.agentDbPath,
sessionId,
"assistant",
context.fullTurnAssistantText,
);
const rowCountBefore = countSqliteTranscriptEvents(context.agentDbPath, sessionId);
if (rowCountBefore < 2) {
throw new Error(
`manual compaction source transcript had too few rows: ${rowCountBefore} for ${sessionId}`,
);
}
const listed: { sessions?: Array<{ key?: string; sessionId?: string }> } = await client.request(
"sessions.list",
{},
);
const listedSession = (listed.sessions ?? []).find(
(session) =>
session.sessionId === sessionId || session.key === context.manualCompactionSessionKey,
);
if (!listedSession?.key) {
throw new Error(
`manual compaction session was not listed before compact: ${JSON.stringify(listed)}`,
);
}
const compacted: {
compacted?: boolean;
key?: string;
ok?: boolean;
} = await client.request("sessions.compact", {
key: listedSession.key,
});
if (compacted.ok !== true || compacted.compacted !== true) {
throw new Error(
`manual compaction did not compact using ${listedSession.key}: ${JSON.stringify(
compacted,
)}; listed=${JSON.stringify(listed)}`,
);
}
const evidence = readSqliteEvidence(context.agentDbPath, [context.manualCompactionSessionKey]);
const row = evidence.trackedEntries.find(
(entry) => entry.sessionKey === context.manualCompactionSessionKey,
);
if (!row?.entry) {
throw new Error(`manual compaction entry missing for ${context.manualCompactionSessionKey}`);
}
const checkpointCount = Array.isArray(row.entry.compactionCheckpoints)
? row.entry.compactionCheckpoints.length
: 0;
if (checkpointCount < 1) {
throw new Error(`manual compaction did not write checkpoint metadata: ${JSON.stringify(row)}`);
}
if (Object.hasOwn(row.entry, "sessionFile")) {
throw new Error(`manual compaction entry retained file-era identity: ${JSON.stringify(row)}`);
}
return {
checkpointCount,
compacted: compacted.compacted,
rowCountAfter: countSqliteTranscriptEvents(context.agentDbPath, row.sessionId),
rowCountBefore,
transcriptIdentity: context.manualCompactionSessionKey,
sessionId: row.sessionId,
sessionKey: context.manualCompactionSessionKey,
};
}
async function runPluginSdkConsumerProbe(context: ProofContext, sessionId: string) {
const scope = {
agentId: context.agentId,
sessionId,
sessionKey: context.pluginSdkSessionKey,
storePath: context.storePath,
};
const sessionEntry = getSdkSessionEntry({
agentId: context.agentId,
readConsistency: "latest",
sessionKey: context.pluginSdkSessionKey,
storePath: context.storePath,
});
if (sessionEntry?.sessionId !== sessionId) {
throw new Error(
`SDK session store read returned ${JSON.stringify(sessionEntry)} for ${context.pluginSdkSessionKey}`,
);
}
if (Object.hasOwn(sessionEntry, "sessionFile")) {
throw new Error(`SDK session store exposed retired transcript locator`);
}
const listedSessionKeys = listSdkSessionEntries({
agentId: context.agentId,
storePath: context.storePath,
}).map((entry) => entry.sessionKey);
if (!listedSessionKeys.includes(context.pluginSdkSessionKey)) {
throw new Error(`SDK session list omitted ${context.pluginSdkSessionKey}`);
}
const identity = await resolveSessionTranscriptIdentity(scope);
const latestBefore = await readLatestAssistantTextByIdentity(scope);
if (latestBefore?.text !== context.fullTurnAssistantText) {
throw new Error(
`SDK latest assistant read returned ${JSON.stringify(latestBefore)} for ${context.pluginSdkSessionKey}`,
);
}
const transcriptEventsBeforeAppend = (await readSessionTranscriptEvents(scope)).length;
const storeTranscriptEvents = loadSdkTranscriptEventsSync(scope).length;
const artifacts = sessionArtifactPaths(context.activeSessionsDir, sessionId);
const activeJsonlForSessionExists = fsSync.existsSync(artifacts.jsonl);
if (activeJsonlForSessionExists) {
throw new Error(`SDK probe found active JSONL for SQLite session at ${artifacts.jsonl}`);
}
const activeTrajectorySessionSidecarForSessionExists = fsSync.existsSync(artifacts.trajectory);
const activeTrajectoryPointerForSessionExists = fsSync.existsSync(artifacts.pointer);
const activeTrajectoryRuntimeSidecarForSessionExists = fsSync.existsSync(artifacts.runtime);
if (
activeTrajectorySessionSidecarForSessionExists ||
activeTrajectoryPointerForSessionExists ||
activeTrajectoryRuntimeSidecarForSessionExists
) {
throw new Error(
`SDK trajectory probe found active sidecar paths: ${JSON.stringify({
pointer: artifacts.pointer,
runtime: artifacts.runtime,
session: artifacts.trajectory,
})}`,
);
}
const appended = await appendSessionTranscriptMessageByIdentity({
...scope,
message: {
role: "assistant",
content: [{ type: "text", text: context.pluginSdkAppendText }],
timestamp: Date.now(),
},
});
if (!appended?.appended || !appended.messageId) {
throw new Error(`SDK transcript append failed for ${context.pluginSdkSessionKey}`);
}
const latestAfter = await readLatestAssistantTextByIdentity(scope);
if (latestAfter?.text !== context.pluginSdkAppendText) {
throw new Error(
`SDK latest assistant after append returned ${JSON.stringify(latestAfter)} for ${
context.pluginSdkSessionKey
}`,
);
}
const transcriptEventsAfterAppend = (await readSessionTranscriptEvents(scope)).length;
if (transcriptEventsAfterAppend <= transcriptEventsBeforeAppend) {
throw new Error(
`SDK transcript append did not increase event count for ${context.pluginSdkSessionKey}`,
);
}
return {
activeJsonlForSessionExists,
activeTrajectoryPointerForSessionExists,
activeTrajectoryRuntimeSidecarForSessionExists,
activeTrajectorySessionSidecarForSessionExists,
appendedMessageId: appended.messageId,
identityMemoryKey: identity.memoryKey,
latestAssistantTextBeforeAppend: latestBefore.text,
latestAssistantTextAfterAppend: latestAfter.text,
listedSessionKeys,
sessionIdentity: context.pluginSdkSessionKey,
sessionId,
sessionKey: context.pluginSdkSessionKey,
storeTranscriptEvents,
transcriptEventsAfterAppend,
transcriptEventsBeforeAppend,
};
}
function sessionArtifactPaths(sessionsDir: string, sessionId: string) {
return {
jsonl: path.join(sessionsDir, `${sessionId}.jsonl`),
@@ -1186,48 +941,6 @@ function sessionArtifactPaths(sessionsDir: string, sessionId: string) {
};
}
async function runGatewayCleanupPruningProof(
client: GatewayClient,
context: ProofContext,
): Promise<void> {
const updatedAt = Date.now() - 31 * 24 * 60 * 60 * 1000;
await importProofSession(
context,
context.cleanupPruneSessionKey,
CLEANUP_PRUNE_SESSION_ID,
{
delivery: normalizeSessionDeliveryState({ context: { channel: "cli" } }),
chatType: "direct",
sessionFile: formatSqliteSessionFileMarker({
agentId: context.agentId,
sessionId: CLEANUP_PRUNE_SESSION_ID,
storePath: context.storePath,
}),
sessionId: CLEANUP_PRUNE_SESSION_ID,
sessionStartedAt: updatedAt - 500,
updatedAt,
},
[messageEvent("sqlite-cleanup-prune-1", "user", CLEANUP_PRUNE_TEXT)],
);
await waitForSqliteMessageContains(
context.agentDbPath,
CLEANUP_PRUNE_SESSION_ID,
"user",
CLEANUP_PRUNE_TEXT,
);
const result: { afterCount?: number; applied?: boolean; pruned?: number } = await client.request(
"sessions.cleanup",
{ enforce: true },
{ timeoutMs: SQLITE_FLIP_PROOF_OPERATION_TIMEOUT_MS },
);
if (result?.applied !== true || (result.pruned ?? 0) < 1) {
throw new Error(`sessions.cleanup did not prune stale SQLite rows: ${JSON.stringify(result)}`);
}
await waitForSessionEntryAbsent(context.agentDbPath, context.cleanupPruneSessionKey);
await waitForSqliteEventsAbsent(context.agentDbPath, CLEANUP_PRUNE_SESSION_ID);
}
async function runDoctorIdempotenceProof(
inst: OpenClawTestInstance,
context: ProofContext,
@@ -1792,15 +1505,6 @@ async function waitForSessionEntryAbsent(dbPath: string, sessionKey: string): Pr
);
}
async function waitForSqliteEventsAbsent(dbPath: string, sessionId: string): Promise<void> {
await pollUntil(
() => countSqliteTranscriptEvents(dbPath, sessionId),
(eventCount) => eventCount === 0,
() => new Error(`timed out waiting for SQLite transcript row deletion for ${sessionId}`),
{ stableMs: 1_500 },
);
}
async function waitForSqliteMessageContains(
dbPath: string,
sessionId: string,
@@ -2229,21 +1933,6 @@ function validateCheckpointInvariants(
sessionId: "sqlite-delete-session",
});
}
if (checkpoint.label === "after-cleanup-pruning") {
requireArchiveText(checkpoint, failures, {
description: "cleanup-pruned transcript archive",
includes: [CLEANUP_PRUNE_TEXT],
reason: "deleted",
sessionId: CLEANUP_PRUNE_SESSION_ID,
});
if (
checkpoint.sqlite.trackedEntries.some(
(entry) => entry.sessionKey === context.cleanupPruneSessionKey,
)
) {
failures.push(`${checkpoint.label}: cleanup-pruned entry still exists in SQLite`);
}
}
if (checkpoint.label === "after-doctor-import-idempotence") {
const totals = checkpoint.doctor?.totals ?? {};
if (totals.importedEntries !== 0 || totals.importedTranscriptEvents !== 0) {