fix: enforce data directory compatibility gate at runtime boundaries

MCP server checks the gate at startup and exits before opening stdio if
the data directory requires a newer runtime. Desktop HTTP API maps
DataDirCompatibilityError (including wrapped causes) to a 409 response
so the renderer can surface a clear upgrade prompt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
diguaandClaude Sonnet 4.6 committed 2026-06-08 10:14:42 +08:00
1 parent e7561e224e
commit c3a5d22a43
9 files changed
+155 -8

No files matched your search

+33 -2
View File
@@ -4,8 +4,13 @@ import os from 'node:os'
import path from 'node:path'
import test from 'node:test'
import type { PathProvider } from '@openchatlab/core'
import { DatabaseManager, readDataDirCompatibilityMeta } from '@openchatlab/node-runtime'
import { incrementalImport } from './stream-import'
import {
DatabaseManager,
DataDirCompatibilityError,
raiseDataDirMinRuntimeVersion,
readDataDirCompatibilityMeta,
} from '@openchatlab/node-runtime'
import { analyzeIncrementalImport, incrementalImport } from './stream-import'
const nativeBinding = path.resolve('apps/cli/native/better_sqlite3.node')
@@ -79,3 +84,29 @@ test('incrementalImport raises the data directory gate after successful writes',
assert.equal(meta?.dataCompatibilityVersion, 1)
assert.deepEqual(meta?.reasons, ['segment-schema'])
})
test('analyzeIncrementalImport propagates data directory compatibility errors', async () => {
const root = makeTempDir()
const pathProvider = createPathProvider(root)
fs.mkdirSync(pathProvider.getDatabaseDir(), { recursive: true })
fs.writeFileSync(path.join(pathProvider.getDatabaseDir(), 'existing.db'), 'not opened before compatibility check')
raiseDataDirMinRuntimeVersion(pathProvider, {
minRuntimeVersion: '0.26.0',
dataCompatibilityVersion: 2,
reason: 'future-schema',
runtime: { version: '0.26.0', kind: 'desktop' },
module: 'future-migration',
now: () => 1780830000,
})
const manager = new DatabaseManager(pathProvider, {
nativeBinding,
runtime: { version: '0.25.1', kind: 'cli' },
})
const filePath = path.join(root, 'incremental.jsonl')
writeIncrementalJsonl(filePath)
await assert.rejects(
() => analyzeIncrementalImport(manager, 'existing', filePath),
(error) => error instanceof DataDirCompatibilityError && error.code === 'DATA_DIR_REQUIRES_NEWER_RUNTIME'
)
})
+10 -1
View File
@@ -223,7 +223,16 @@ export async function analyzeIncrementalImport(
filePath: string,
onProgress?: ImportProgressCallback
): Promise<IncrementalAnalyzeResult> {
return sharedAnalyzeIncremental(sessionId, filePath, buildIncrementalDeps(dbManager, onProgress))
let compatibilityError: DataDirCompatibilityError | null = null
const result = await sharedAnalyzeIncremental(
sessionId,
filePath,
buildIncrementalDeps(dbManager, onProgress, (error) => {
compatibilityError = error
})
)
if (compatibilityError) throw compatibilityError
return result
}
export async function analyzeNewImport(