From 3ffe26aa3fbd5ede44e1223d5577a0cb862728ed Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 9 Oct 2026 22:46:48 -0700 Subject: [PATCH 1/4] perf(search): fetch Lucid page regions concurrently on a live read A Lucid read made about 11 MCP calls in sequence: metadata, a metadata-only manifest, one fetch per page region (up to 8), then metadata again. At 1-2 s per call that ran past the 15 s live read deadline. The first metadata and manifest now run together, and region fetches run four at a time. Their validation still walks them in page and region order, and the before/after change checks are unchanged. --- .../sim/lib/sim-search/live/lucid-mcp.test.ts | 83 +++++++++++++++++++ apps/sim/lib/sim-search/live/lucid-mcp.ts | 40 +++++---- 2 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 apps/sim/lib/sim-search/live/lucid-mcp.test.ts diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.test.ts b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts new file mode 100644 index 00000000000..2c54bed8e9f --- /dev/null +++ b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from 'vitest' +import { readLucidMcp } from '@/lib/sim-search/live/lucid-mcp' +import type { ManagedSearchMcpClient } from '@/lib/sim-search/live/managed-mcp' + +const ID = '0b6a3f0e-5a52-4c55-9d8c-6d2f2a1b9c11' +const COUNTS = [2, 1] +const metadataRow = { + documentId: ID, + viewUrl: `https://lucid.app/lucidchart/${ID}/view`, + product: 'lucidchart', + title: 'Fixture diagram', + version: 7, + pageCount: COUNTS.length, + lastModified: '2026-10-01T12:00:00Z', +} + +function manifest(extra: Record = {}) { + return { + document_id: ID, + edit_url: `https://lucid.app/lucidchart/${ID}/edit`, + title: 'Fixture diagram', + metadata: { page_count: COUNTS.length, page_region_counts: COUNTS, ...extra }, + } +} + +function regionResponse(pageIndex: number, region: number) { + const pageId = `page-${pageIndex}` + return { + ...manifest({ page_index: pageIndex + 1 }), + page_index: pageIndex + 1, + page_id: pageId, + text: JSON.stringify({ + pages: [ + { + pageIndex, + pageId, + pageTitle: `Page ${pageIndex + 1}`, + totalChunks: COUNTS[pageIndex], + requestedChunks: [{ chunkIndex: region, data: { label: `p${pageIndex}r${region}` } }], + }, + ], + }), + } +} + +/** Region fetches settle in reverse request order, after a number of ticks, to expose ordering. */ +function lucidClient() { + let inFlight = 0 + let maxInFlight = 0 + let regionCalls = 0 + const client: ManagedSearchMcpClient = { + async call(name, args) { + if (name === 'lucid_get_document_metadata') return metadataRow + if (args.metadata_only) return manifest() + const pageIndex = Number(args.page_index) - 1 + const region = Array.isArray(args.region_index) ? Number(args.region_index[0]) - 1 : 0 + const delay = 10 - regionCalls++ + inFlight++ + maxInFlight = Math.max(maxInFlight, inFlight) + for (let tick = 0; tick < delay; tick++) await Promise.resolve() + inFlight-- + return regionResponse(pageIndex, region) + }, + } + return { client, maxInFlight: () => maxInFlight } +} + +describe('readLucidMcp', () => { + it('fetches page regions concurrently and assembles them in page and region order', async () => { + const { client, maxInFlight } = lucidClient() + const document = await readLucidMcp(client, { id: ID, kind: 'lucidchart', revision: '7' }) + expect(maxInFlight()).toBeGreaterThan(1) + const pages = JSON.parse(document.content ?? '').pages as { + pageId: string + requestedChunks: { data: { label: string } }[] + }[] + expect(pages.map((page) => page.pageId)).toEqual(['page-0', 'page-1']) + expect(pages.map((page) => page.requestedChunks.map((chunk) => chunk.data.label))).toEqual([ + ['p0r0', 'p0r1'], + ['p1r0'], + ]) + }) +}) diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.ts b/apps/sim/lib/sim-search/live/lucid-mcp.ts index 34ed17a7324..ba1bf680b3f 100644 --- a/apps/sim/lib/sim-search/live/lucid-mcp.ts +++ b/apps/sim/lib/sim-search/live/lucid-mcp.ts @@ -322,23 +322,28 @@ function manifest(value: unknown, id: string, kind: string | undefined) { return { row, counts: counts as number[] } } +/** + * Region fetches are independent provider reads; running them together keeps a full read inside + * the live read deadline. Validation still walks them in page and region order. + */ +const REGION_FETCH_CONCURRENCY = 4 + /** Complete, bounded provider pages preserve graph data; no returned URL is fetched. */ export async function readLucidMcp( client: ManagedSearchMcpClient, reference: Pick ): Promise { - const before = await metadata(client, reference.id) + const [before, initialRaw] = await Promise.all([ + metadata(client, reference.id), + client.call('fetch', { id: reference.id, metadata_only: true }), + ]) if (!before) invalid('Lucid document metadata is incomplete or no longer readable.') if ( (reference.kind && reference.kind !== before.kind) || (reference.revision && reference.revision !== before.revision) ) invalid('Lucid document changed since this result was issued. Search again before reading.') - const initial = manifest( - await client.call('fetch', { id: before.id, metadata_only: true }), - before.id, - before.kind - ) + const initial = manifest(initialRaw, before.id, before.kind) if ( initial.counts.length !== before.accessMetadata?.pageCount || initial.row.title !== before.title @@ -346,20 +351,23 @@ export async function readLucidMcp( invalid('Lucid document coverage changed before reading. Search again.') const pages: Record[] = [] const output = () => JSON.stringify({ document_id: before.id, title: before.title, pages }) + const requests = initial.counts.flatMap((count, pageIndex) => + Array.from({ length: Math.max(1, count) }, (_, region) => ({ pageIndex, region, count })) + ) + const responses = await mapWithConcurrency(requests, REGION_FETCH_CONCURRENCY, (request) => + client.call('fetch', { + id: before.id, + page_index: request.pageIndex + 1, + ...(request.count ? { region_index: [request.region + 1] } : {}), + }) + ) + let next = 0 for (let pageIndex = 0; pageIndex < initial.counts.length; pageIndex++) { - const count = initial.counts[pageIndex]! + const count = initial.counts[pageIndex] ?? 0 let assembled: Record | undefined const chunks: Record[] = [] for (let region = 0; region < Math.max(1, count); region++) { - const fetched = manifest( - await client.call('fetch', { - id: before.id, - page_index: pageIndex + 1, - ...(count ? { region_index: [region + 1] } : {}), - }), - before.id, - before.kind - ) + const fetched = manifest(responses[next++], before.id, before.kind) if ( fetched.counts.some((value, index) => value !== initial.counts[index]) || fetched.counts.length !== initial.counts.length || From b5122ab409d00f4420fd234536874d580c589865 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sat, 10 Oct 2026 00:10:44 -0700 Subject: [PATCH 2/4] chore(audits): shrink the non-null baseline for lucid-mcp --- scripts/check-explicit-any.baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check-explicit-any.baseline.json b/scripts/check-explicit-any.baseline.json index 75c4908b83e..fc91cce8dc6 100644 --- a/scripts/check-explicit-any.baseline.json +++ b/scripts/check-explicit-any.baseline.json @@ -1652,7 +1652,7 @@ "apps/sim/lib/sim-search/live/google-meet.ts": 1, "apps/sim/lib/sim-search/live/granola-mcp.ts": 2, "apps/sim/lib/sim-search/live/hubspot-mcp.test.ts": 1, - "apps/sim/lib/sim-search/live/lucid-mcp.ts": 2, + "apps/sim/lib/sim-search/live/lucid-mcp.ts": 1, "apps/sim/lib/sim-search/live/pages.ts": 1, "apps/sim/lib/sim-search/live/policy-schema.ts": 1, "apps/sim/lib/sim-search/live/policy.ts": 2, From 43e8ec90390b58e54fa93b0054d1d0408265b273 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sat, 10 Oct 2026 13:44:19 -0700 Subject: [PATCH 3/4] refactor(search): build Lucid region fetch args in place --- apps/sim/lib/sim-search/live/lucid-mcp.test.ts | 5 +++-- apps/sim/lib/sim-search/live/lucid-mcp.ts | 17 ++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.test.ts b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts index 2c54bed8e9f..d5d0581054b 100644 --- a/apps/sim/lib/sim-search/live/lucid-mcp.test.ts +++ b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts @@ -4,11 +4,12 @@ import type { ManagedSearchMcpClient } from '@/lib/sim-search/live/managed-mcp' const ID = '0b6a3f0e-5a52-4c55-9d8c-6d2f2a1b9c11' const COUNTS = [2, 1] +const TITLE = 'Fixture diagram' const metadataRow = { documentId: ID, viewUrl: `https://lucid.app/lucidchart/${ID}/view`, product: 'lucidchart', - title: 'Fixture diagram', + title: TITLE, version: 7, pageCount: COUNTS.length, lastModified: '2026-10-01T12:00:00Z', @@ -18,7 +19,7 @@ function manifest(extra: Record = {}) { return { document_id: ID, edit_url: `https://lucid.app/lucidchart/${ID}/edit`, - title: 'Fixture diagram', + title: TITLE, metadata: { page_count: COUNTS.length, page_region_counts: COUNTS, ...extra }, } } diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.ts b/apps/sim/lib/sim-search/live/lucid-mcp.ts index ba1bf680b3f..ac61f068a72 100644 --- a/apps/sim/lib/sim-search/live/lucid-mcp.ts +++ b/apps/sim/lib/sim-search/live/lucid-mcp.ts @@ -352,18 +352,17 @@ export async function readLucidMcp( const pages: Record[] = [] const output = () => JSON.stringify({ document_id: before.id, title: before.title, pages }) const requests = initial.counts.flatMap((count, pageIndex) => - Array.from({ length: Math.max(1, count) }, (_, region) => ({ pageIndex, region, count })) - ) - const responses = await mapWithConcurrency(requests, REGION_FETCH_CONCURRENCY, (request) => - client.call('fetch', { + Array.from({ length: Math.max(1, count) }, (_, region) => ({ id: before.id, - page_index: request.pageIndex + 1, - ...(request.count ? { region_index: [request.region + 1] } : {}), - }) + page_index: pageIndex + 1, + ...(count ? { region_index: [region + 1] } : {}), + })) + ) + const responses = await mapWithConcurrency(requests, REGION_FETCH_CONCURRENCY, (args) => + client.call('fetch', args) ) let next = 0 - for (let pageIndex = 0; pageIndex < initial.counts.length; pageIndex++) { - const count = initial.counts[pageIndex] ?? 0 + for (const [pageIndex, count] of initial.counts.entries()) { let assembled: Record | undefined const chunks: Record[] = [] for (let region = 0; region < Math.max(1, count); region++) { From 131b4213cbeaaaaf055d3046b438e8a7723ea2f8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sat, 10 Oct 2026 13:45:46 -0700 Subject: [PATCH 4/4] fix(search): stop scheduling Lucid region fetches once a region fails validation --- .../sim/lib/sim-search/live/lucid-mcp.test.ts | 42 ++++++++++++------- apps/sim/lib/sim-search/live/lucid-mcp.ts | 20 ++++++--- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.test.ts b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts index d5d0581054b..7b71a627677 100644 --- a/apps/sim/lib/sim-search/live/lucid-mcp.test.ts +++ b/apps/sim/lib/sim-search/live/lucid-mcp.test.ts @@ -3,7 +3,7 @@ import { readLucidMcp } from '@/lib/sim-search/live/lucid-mcp' import type { ManagedSearchMcpClient } from '@/lib/sim-search/live/managed-mcp' const ID = '0b6a3f0e-5a52-4c55-9d8c-6d2f2a1b9c11' -const COUNTS = [2, 1] +const COUNTS = [3, 0, 2, 1] const TITLE = 'Fixture diagram' const metadataRow = { documentId: ID, @@ -37,7 +37,9 @@ function regionResponse(pageIndex: number, region: number) { pageId, pageTitle: `Page ${pageIndex + 1}`, totalChunks: COUNTS[pageIndex], - requestedChunks: [{ chunkIndex: region, data: { label: `p${pageIndex}r${region}` } }], + requestedChunks: COUNTS[pageIndex] + ? [{ chunkIndex: region, data: { label: `p${pageIndex}r${region}` } }] + : [], }, ], }), @@ -45,7 +47,7 @@ function regionResponse(pageIndex: number, region: number) { } /** Region fetches settle in reverse request order, after a number of ticks, to expose ordering. */ -function lucidClient() { +function lucidClient(options: { corruptFirstRegion?: boolean } = {}) { let inFlight = 0 let maxInFlight = 0 let regionCalls = 0 @@ -55,30 +57,42 @@ function lucidClient() { if (args.metadata_only) return manifest() const pageIndex = Number(args.page_index) - 1 const region = Array.isArray(args.region_index) ? Number(args.region_index[0]) - 1 : 0 - const delay = 10 - regionCalls++ + const call = regionCalls++ inFlight++ maxInFlight = Math.max(maxInFlight, inFlight) - for (let tick = 0; tick < delay; tick++) await Promise.resolve() + for (let tick = 0; tick < 10 - call; tick++) await Promise.resolve() inFlight-- - return regionResponse(pageIndex, region) + const response = regionResponse(pageIndex, region) + return options.corruptFirstRegion && call === 0 ? { ...response, page_id: 'other' } : response }, } - return { client, maxInFlight: () => maxInFlight } + return { client, maxInFlight: () => maxInFlight, regionCalls: () => regionCalls } } +const REFERENCE = { id: ID, kind: 'lucidchart', revision: '7' } + describe('readLucidMcp', () => { - it('fetches page regions concurrently and assembles them in page and region order', async () => { - const { client, maxInFlight } = lucidClient() - const document = await readLucidMcp(client, { id: ID, kind: 'lucidchart', revision: '7' }) - expect(maxInFlight()).toBeGreaterThan(1) + it('fetches at most four regions at once and assembles them in page and region order', async () => { + const { client, maxInFlight, regionCalls } = lucidClient() + const document = await readLucidMcp(client, REFERENCE) + expect(regionCalls()).toBe(7) + expect(maxInFlight()).toBe(4) const pages = JSON.parse(document.content ?? '').pages as { pageId: string requestedChunks: { data: { label: string } }[] }[] - expect(pages.map((page) => page.pageId)).toEqual(['page-0', 'page-1']) + expect(pages.map((page) => page.pageId)).toEqual(['page-0', 'page-1', 'page-2', 'page-3']) expect(pages.map((page) => page.requestedChunks.map((chunk) => chunk.data.label))).toEqual([ - ['p0r0', 'p0r1'], - ['p1r0'], + ['p0r0', 'p0r1', 'p0r2'], + [], + ['p2r0', 'p2r1'], + ['p3r0'], ]) }) + + it('stops scheduling region fetches once a region fails validation', async () => { + const { client, regionCalls } = lucidClient({ corruptFirstRegion: true }) + await expect(readLucidMcp(client, REFERENCE)).rejects.toThrow(/mismatched page regions/) + expect(regionCalls()).toBe(4) + }) }) diff --git a/apps/sim/lib/sim-search/live/lucid-mcp.ts b/apps/sim/lib/sim-search/live/lucid-mcp.ts index ac61f068a72..89dfaff71cb 100644 --- a/apps/sim/lib/sim-search/live/lucid-mcp.ts +++ b/apps/sim/lib/sim-search/live/lucid-mcp.ts @@ -324,7 +324,9 @@ function manifest(value: unknown, id: string, kind: string | undefined) { /** * Region fetches are independent provider reads; running them together keeps a full read inside - * the live read deadline. Validation still walks them in page and region order. + * the live read deadline. Validation walks them in page and region order, and a fetch is only + * scheduled once the region this many places before it has been validated, so a rejected or + * oversized document stops further reads and holds at most this many responses. */ const REGION_FETCH_CONCURRENCY = 4 @@ -358,15 +360,21 @@ export async function readLucidMcp( ...(count ? { region_index: [region + 1] } : {}), })) ) - const responses = await mapWithConcurrency(requests, REGION_FETCH_CONCURRENCY, (args) => - client.call('fetch', args) - ) + const responses: Promise[] = [] + const schedule = (index: number) => { + if (index >= requests.length) return + const response = client.call('fetch', requests[index]) + // An invalid earlier region abandons in-flight fetches; their rejections must not go unhandled. + response.catch(() => {}) + responses[index] = response + } + for (let index = 0; index < REGION_FETCH_CONCURRENCY; index++) schedule(index) let next = 0 for (const [pageIndex, count] of initial.counts.entries()) { let assembled: Record | undefined const chunks: Record[] = [] for (let region = 0; region < Math.max(1, count); region++) { - const fetched = manifest(responses[next++], before.id, before.kind) + const fetched = manifest(await responses[next], before.id, before.kind) if ( fetched.counts.some((value, index) => value !== initial.counts[index]) || fetched.counts.length !== initial.counts.length || @@ -411,6 +419,8 @@ export async function readLucidMcp( chunks.push(...returnedChunks) if (Buffer.byteLength(output(), 'utf8') > MAX_CONTENT_BYTES) invalid('Lucid document exceeds the 512 KiB complete-read limit. Open the source document.') + schedule(next + REGION_FETCH_CONCURRENCY) + next++ } } const after = await metadata(client, before.id)