import assert from "node:assert/strict"; import { randomUUID } from "node:crypto"; import { probeAuthorityCapabilities } from "../../runtime/authority-capabilities.js"; import { AuthorityGraphStore } from "../../sync/authority-graph-store.js"; import { deleteAuthorityTriviumNodes, filterAuthorityTriviumNodes, normalizeAuthorityVectorConfig, purgeAuthorityTriviumNamespace, queryAuthorityTriviumNeighbors, searchAuthorityTriviumNodes, syncAuthorityTriviumLinks, upsertAuthorityTriviumEntries, } from "../../vector/authority-vector-primary-adapter.js"; import { buildAuthorityJobIdempotencyKey, createAuthorityJobAdapter, } from "../../maintenance/authority-job-adapter.js"; import { createAuthorityBlobAdapter } from "../../maintenance/authority-blob-adapter.js"; const env = process.env; const baseUrl = String(env.AUTHORITY_E2E_BASE_URL || "").trim(); if (!baseUrl) { console.log("authority-server-primary E2E skipped: set AUTHORITY_E2E_BASE_URL to run against a real Authority server"); process.exit(0); } function parsePositiveInteger(value, fallback, min = 1, max = Number.MAX_SAFE_INTEGER) { const parsed = Number(value); if (!Number.isFinite(parsed)) return fallback; return Math.min(max, Math.max(min, Math.trunc(parsed))); } function parseJsonObject(value, fallback = {}) { if (!value) return fallback; try { const parsed = JSON.parse(String(value)); return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : fallback; } catch { return fallback; } } function resolveBaseUrl(value) { const normalized = String(value || "").replace(/\/+$/g, ""); if (/^https?:\/\//i.test(normalized)) return normalized; const origin = String(env.AUTHORITY_E2E_ORIGIN || "").replace(/\/+$/g, ""); if (origin && normalized.startsWith("/")) return `${origin}${normalized}`; throw new Error("AUTHORITY_E2E_BASE_URL must be absolute, or set AUTHORITY_E2E_ORIGIN for relative plugin paths"); } function createHeaderProvider() { const staticHeaders = parseJsonObject(env.AUTHORITY_E2E_HEADER_JSON, {}); const token = String(env.AUTHORITY_E2E_TOKEN || "").trim(); const cookie = String(env.AUTHORITY_E2E_COOKIE || "").trim(); return () => ({ ...staticHeaders, ...(token ? { Authorization: /^Bearer\s+/i.test(token) ? token : `Bearer ${token}` } : {}), ...(cookie ? { Cookie: cookie } : {}), }); } function createFetchWithTimeout(timeoutMs) { return async (url, options = {}) => { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(new Error(`Authority E2E request timeout after ${timeoutMs}ms`)), timeoutMs); try { return await fetch(url, { ...options, signal: controller.signal, }); } finally { clearTimeout(timer); } }; } function createContractNode(id, title, nowMs) { return { id, type: "fact", fields: { title, summary: `${title} generated by Authority server-primary E2E contract smoke`, }, seqRange: [1, 1], scope: { layer: "global", ownerType: "system", ownerId: "authority-e2e", bucket: "contract", regionKey: "authority-e2e-region", }, storySegmentId: "authority-e2e-segment", importance: 0.8, archived: false, updatedAt: nowMs, }; } function createContractGraph(chatId, runId) { const nowMs = Date.now(); const nodeA = createContractNode(`${runId}-node-a`, "Authority E2E Alpha", nowMs); const nodeB = createContractNode(`${runId}-node-b`, "Authority E2E Beta", nowMs); return { meta: { schemaVersion: 1, chatId, deviceId: "authority-e2e", revision: 1, lastModified: nowMs, nodeCount: 2, edgeCount: 1, tombstoneCount: 0, }, nodes: [nodeA, nodeB], edges: [ { id: `${runId}-edge-a-b`, fromId: nodeA.id, toId: nodeB.id, relation: "related", type: "semantic", strength: 0.7, updatedAt: nowMs, }, ], tombstones: [], state: { lastProcessedFloor: 1, extractionCount: 1, }, }; } function buildVectorEntries(graph) { return graph.nodes.map((node, index) => ({ nodeId: node.id, index, hash: `${node.id}:hash`, text: `${node.fields.title}. ${node.fields.summary}`, })); } async function runStep(name, fn) { const startedAt = Date.now(); try { const result = await fn(); const durationMs = Date.now() - startedAt; console.log(`authority E2E ${name}: ok (${durationMs}ms)`); return { name, ok: true, durationMs, result }; } catch (error) { const durationMs = Date.now() - startedAt; console.error(`authority E2E ${name}: failed (${durationMs}ms)`); console.error(error?.stack || error?.message || String(error)); throw error; } } const resolvedBaseUrl = resolveBaseUrl(baseUrl); const timeoutMs = parsePositiveInteger(env.AUTHORITY_E2E_TIMEOUT_MS, 15000, 1000, 300000); const jobWaitTimeoutMs = parsePositiveInteger(env.AUTHORITY_E2E_JOB_WAIT_TIMEOUT_MS, 15000, 1000, 300000); const headerProvider = createHeaderProvider(); const fetchImpl = createFetchWithTimeout(timeoutMs); const runId = String(env.AUTHORITY_E2E_RUN_ID || `authority-e2e-${Date.now()}-${randomUUID().slice(0, 8)}`) .replace(/[^A-Za-z0-9._:-]+/g, "-"); const chatId = String(env.AUTHORITY_E2E_CHAT_ID || `st-bme-${runId}`); const namespace = String(env.AUTHORITY_E2E_NAMESPACE || `st-bme-e2e-${runId}`); const collectionId = String(env.AUTHORITY_E2E_COLLECTION_ID || `${namespace}::${chatId}`); const blobPath = String(env.AUTHORITY_E2E_BLOB_PATH || `st-bme/e2e/${runId}/contract.json`); const graph = createContractGraph(chatId, runId); const context = { baseUrl: resolvedBaseUrl, chatId, namespace, collectionId, blobPath, }; console.log(`authority-server-primary E2E started: ${JSON.stringify(context)}`); await runStep("probe", async () => { const state = await probeAuthorityCapabilities({ settings: { authorityBaseUrl: resolvedBaseUrl }, fetchImpl, headerProvider, allowRelativeUrl: false, }); assert.equal(state.installed, true); assert.equal(state.healthy, true); return { endpoint: state.endpoint, features: state.features, missingFeatures: state.missingFeatures, }; }); await runStep("sql", async () => { const store = new AuthorityGraphStore(chatId, { baseUrl: resolvedBaseUrl, fetchImpl, headerProvider, }); try { await store.open(); const importResult = await store.importSnapshot(graph, { mode: "replace", preserveRevision: true, markSyncDirty: false, }); assert.equal(importResult.imported.nodes, graph.nodes.length); assert.equal(importResult.imported.edges, graph.edges.length); const commitResult = await store.commitDelta( { upsertNodes: [createContractNode(`${runId}-node-c`, "Authority E2E Gamma", Date.now())], runtimeMetaPatch: { authorityE2eRunId: runId }, }, { reason: "authority-e2e-contract", markSyncDirty: false }, ); assert.ok(commitResult.revision >= importResult.revision); const snapshot = await store.exportSnapshot({ includeTombstones: false }); assert.equal(snapshot.meta.chatId, chatId); assert.ok(snapshot.nodes.some((node) => node.id === graph.nodes[0].id)); assert.ok(snapshot.nodes.some((node) => node.id === `${runId}-node-c`)); return { revision: snapshot.meta.revision, nodes: snapshot.nodes.length, edges: snapshot.edges.length, }; } finally { await store.clearAll().catch(() => null); await store.close().catch(() => null); } }); await runStep("trivium", async () => { const config = normalizeAuthorityVectorConfig({ authorityBaseUrl: resolvedBaseUrl }); const entries = buildVectorEntries(graph); await purgeAuthorityTriviumNamespace(config, { namespace, collectionId, chatId, fetchImpl, headerProvider, }).catch(() => null); try { const upsertResult = await upsertAuthorityTriviumEntries(graph, config, entries, { namespace, collectionId, chatId, modelScope: "authority-e2e", revision: 1, fetchImpl, headerProvider, }); assert.equal(upsertResult.upserted, entries.length); const linkResult = await syncAuthorityTriviumLinks(graph, config, { namespace, collectionId, chatId, revision: 1, fetchImpl, headerProvider, }); assert.equal(linkResult.linked, graph.edges.length); const searchResults = await searchAuthorityTriviumNodes(graph, "Authority E2E Alpha", config, { namespace, collectionId, chatId, topK: 5, fetchImpl, headerProvider, }); assert.ok(Array.isArray(searchResults)); const filteredIds = await filterAuthorityTriviumNodes(config, { namespace, collectionId, chatId, topK: 10, where: { chatId, archived: false }, searchText: "Authority E2E", fetchImpl, headerProvider, }); assert.ok(Array.isArray(filteredIds)); const neighborIds = await queryAuthorityTriviumNeighbors(config, [graph.nodes[0].id], { namespace, collectionId, chatId, topK: 5, fetchImpl, headerProvider, }); assert.ok(Array.isArray(neighborIds)); return { upserted: upsertResult.upserted, linked: linkResult.linked, searchResults: searchResults.length, filteredIds: filteredIds.length, neighborIds: neighborIds.length, }; } finally { await deleteAuthorityTriviumNodes(config, graph.nodes.map((node) => node.id), { namespace, collectionId, chatId, fetchImpl, headerProvider, }).catch(() => null); await purgeAuthorityTriviumNamespace(config, { namespace, collectionId, chatId, fetchImpl, headerProvider, }).catch(() => null); } }); await runStep("jobs", async () => { const adapter = createAuthorityJobAdapter( { authorityBaseUrl: resolvedBaseUrl, pollIntervalMs: 500, waitTimeoutMs: jobWaitTimeoutMs, }, { fetchImpl, headerProvider, }, ); const listBefore = await adapter.listPage({ limit: 5 }); assert.ok(Array.isArray(listBefore.jobs)); const kind = String(env.AUTHORITY_E2E_JOB_KIND || "authority.vector.rebuild"); const idempotencyKey = buildAuthorityJobIdempotencyKey({ kind, chatId, collectionId, revision: 1, }); const submitted = await adapter.submit( kind, { chatId, collectionId, namespace, modelScope: "authority-e2e", source: "authority-e2e-contract", purge: false, dryRun: true, contractSmoke: true, idempotencyKey, }, { idempotencyKey }, ); assert.ok(submitted.id); const waited = await adapter.waitForCompletion(submitted.id, { timeoutMs: jobWaitTimeoutMs, pollIntervalMs: 500, }); assert.ok(waited.id || waited.status); const requeued = await adapter.requeue(submitted.id, { safe: true }); assert.ok(requeued.id || requeued.status); const listAfter = await adapter.listPage({ limit: 5 }); assert.ok(Array.isArray(listAfter.jobs)); return { listBefore: listBefore.jobs.length, submitted: submitted.id, waitedStatus: waited.status, requeuedStatus: requeued.status, listAfter: listAfter.jobs.length, }; }); await runStep("blob", async () => { const adapter = createAuthorityBlobAdapter( { authorityBaseUrl: resolvedBaseUrl, authorityBlobNamespace: namespace }, { fetchImpl, headerProvider }, ); const payload = { runId, chatId, collectionId, createdAt: new Date().toISOString(), graph: { nodes: graph.nodes.length, edges: graph.edges.length, }, }; try { const writeResult = await adapter.writeJson(blobPath, payload, { metadata: { chatId, runId, purpose: "authority-e2e-contract" }, }); assert.equal(writeResult.ok, true); const statResult = await adapter.stat(blobPath); assert.equal(statResult.exists, true); const readResult = await adapter.readJson(blobPath); assert.equal(readResult.exists, true); assert.equal(readResult.payload.runId, runId); return { path: writeResult.path, size: writeResult.size, etag: writeResult.etag, }; } finally { const deleteResult = await adapter.delete(blobPath).catch(() => null); if (deleteResult) assert.equal(deleteResult.ok, true); } }); console.log("authority-server-primary E2E passed");