From 22d8e133901697d4bedc9364377dce2bb3a51790 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 5 Sep 2026 18:03:56 +0100 Subject: [PATCH] fix(smoke): match the _resultId format the pipeline actually emits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drill-down checks matched /_resultId:\s*(\S+)/ — the legacy paginator's JSON spelling. The content pipeline writes _resultId="pm-abc", so the regex found nothing: "Has _resultId for drill-down" reported a false failure on every run, and the drill-down tests that used the same regex to extract an id skipped themselves as "not large enough for section-split". Both were invisible in a green suite. One shared extractResultId() in the smoke harness now accepts either spelling and returns the bare id, so the ad-hoc character strip on the captured group goes away too. proxy-pipeline's check block reports 21/21 instead of 20 with a phantom failure. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01JQr5Z9gYrqBQXTGBBuemZ2 --- src/mcplocal/tests/smoke/mcp-client.ts | 15 ++++++++++++++ .../tests/smoke/prompt-drilldown.test.ts | 7 +++---- .../tests/smoke/proxy-pipeline.test.ts | 20 +++++++------------ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/mcplocal/tests/smoke/mcp-client.ts b/src/mcplocal/tests/smoke/mcp-client.ts index cb25e74..bbb1d46 100644 --- a/src/mcplocal/tests/smoke/mcp-client.ts +++ b/src/mcplocal/tests/smoke/mcp-client.ts @@ -261,6 +261,21 @@ export async function isMcplocalRunning(): Promise { } } +/** + * Pull the drill-down id out of a paginated result or TOC. + * + * The instruction is written `_resultId="pm-abc"`, while the legacy paginator + * emits it as JSON (`"_resultId": "pm-abc"`). A regex matching only the JSON + * form silently found nothing in the current format, so drill-down checks + * either reported a false failure or skipped themselves as "not large enough + * for section-split" — both invisible in a green run. Accept either spelling + * and return the bare id. + */ +export function extractResultId(text: string): string | null { + const match = /_resultId"?\s*[:=]\s*"?(pm-[a-zA-Z0-9]+)/.exec(text); + return match?.[1] ?? null; +} + /** * Run an mcpctl CLI command and return stdout. */ diff --git a/src/mcplocal/tests/smoke/prompt-drilldown.test.ts b/src/mcplocal/tests/smoke/prompt-drilldown.test.ts index 1925611..74cff82 100644 --- a/src/mcplocal/tests/smoke/prompt-drilldown.test.ts +++ b/src/mcplocal/tests/smoke/prompt-drilldown.test.ts @@ -7,7 +7,7 @@ * Requires: mcplocal running on localhost:3200, mcpd at https://mcpctl.ad.itaz.eu */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { SmokeMcpSession, isMcplocalRunning } from './mcp-client.js'; +import { SmokeMcpSession, isMcplocalRunning, extractResultId } from './mcp-client.js'; const PROJECT_NAME = 'smoke-data'; @@ -90,9 +90,8 @@ describe('Smoke: Prompt section drill-down', () => { console.log(` TOC preview: ${text.slice(0, 200)}...`); // Extract _resultId - const match = /_resultId:\s*(pm-[a-z0-9]+)/.exec(text); - if (match) { - const resultId = match[1]; + const resultId = extractResultId(text); + if (resultId !== null) { // Extract first section id from TOC const sectionMatch = /\[([^\]]+)\]/.exec(text); if (sectionMatch) { diff --git a/src/mcplocal/tests/smoke/proxy-pipeline.test.ts b/src/mcplocal/tests/smoke/proxy-pipeline.test.ts index cb53c0b..e339d17 100644 --- a/src/mcplocal/tests/smoke/proxy-pipeline.test.ts +++ b/src/mcplocal/tests/smoke/proxy-pipeline.test.ts @@ -17,7 +17,7 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { writeFile, mkdir, rm } from 'node:fs/promises'; import { join, resolve } from 'node:path'; -import { SmokeMcpSession, isMcplocalRunning, mcpctl } from './mcp-client.js'; +import { SmokeMcpSession, isMcplocalRunning, mcpctl, extractResultId } from './mcp-client.js'; import { ChatReporter } from './reporter.js'; const PROJECT_NAME = 'smoke-data'; @@ -286,8 +286,7 @@ describe('Smoke: ProxyModel pipeline', () => { chat.check('Response is manageable size', text.length, (v) => v < 20_000); if (text.includes('_resultId')) { - const match = text.match(/_resultId:\s*(\S+)/); - chat.check('_resultId is present', !!match, (v) => v === true); + chat.check('_resultId is present', extractResultId(text) !== null, (v) => v === true); } else { chat.info('Content small enough — no pagination needed'); } @@ -307,14 +306,12 @@ describe('Smoke: ProxyModel pipeline', () => { }); const text = result.content[0]?.text ?? ''; - const match = text.match(/_resultId:\s*(\S+)/); - if (!match) { + const resultId = extractResultId(text); + if (resultId === null) { chat.info('Content not large enough for pagination — skip drill-down'); return; } - const resultId = match[1]!.replace(/[^a-zA-Z0-9-]/g, ''); - const sectionResult = await chat.callTool('smoke-aws-docs_read_documentation', { url: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html', _resultId: resultId, @@ -401,8 +398,7 @@ describe('Smoke: ProxyModel pipeline', () => { chat.check('Response is manageable size', text.length, (v) => v < 20_000); if (text.includes('_resultId')) { - const match = text.match(/_resultId:\s*(\S+)/); - chat.check('Has _resultId for drill-down', !!match, (v) => v === true); + chat.check('Has _resultId for drill-down', extractResultId(text) !== null, (v) => v === true); } }, 60_000); @@ -420,14 +416,12 @@ describe('Smoke: ProxyModel pipeline', () => { }); const text = result.content[0]?.text ?? ''; - const match = text.match(/_resultId:\s*(\S+)/); - if (!match) { + const resultId = extractResultId(text); + if (resultId === null) { chat.info('Content not large enough for section-split'); return; } - const resultId = match[1]!.replace(/[^a-zA-Z0-9-]/g, ''); - const sectionResult = await chat.callTool('smoke-aws-docs_read_documentation', { url: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html', _resultId: resultId, -- 2.49.1