[GH-ISSUE #7388] [Bug] prefix-variance input guidance omits its 32-segment comparison limit #4395

Open
opened 2026-10-31 00:49:28 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7388

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Documentation

Observed behavior

The input JSON Schema prepared for the MCP inspect_analysis_view registration describes the environment-manifest prefix-variance rule as applying "at any method or length", without qualifying the route-length limit. In a focused source test of the shared application handler, an accepted manifest request with two GET donor routes and one PATCH route templated the PATCH identifier at 32 path segments. With the same prefix and identifier shape at 33 segments, it retained the literal identifier and returned a limitation explaining the 32-segment cap. That runtime behavior matches the feature specification; the defect is the incomplete scope description presented before the caller selects the rule. The public guide's rule-table entry uses similarly unqualified language, although a later paragraph correctly states the cap.

Reproduction

Use a fresh clone at f8f7ac96de8a66a4ab9a23d87e04779bfcd11045, Node.js v24.22.1, and locked dependencies installed with npm ci. From the repository root, create and run this single temporary source test. It constructs all request fixtures locally, projects the registration's input schema, and submits inline capture Evidence through the same application function used by the MCP handler. No capture server or optional analysis provider is required. This probe passed once during independent verification; it asserts the mismatch rather than treating the intentional cap as an implementation failure.

cat > src/application/analysisView/verify-probe.test.ts <<'EOF'
import { expect, it } from "vitest";
import { analysisViewCaptureEvidence, environmentManifestCaptureFixture } from "../../../tests/fixtures/analysisView.js";
import { inspectAnalysisView } from "./AnalysisViewService.js";
import { ANALYSIS_VIEW_TOOL_CONTRACTS } from "../../contracts/analysisViewToolContracts.js";
import { applicationToolRegistrationOptions } from "../../server/toolRegistrationOptions.js";

it("compares the advertised rule scope with accepted 32 and 33 segment requests", async () => {
  const registration = applicationToolRegistrationOptions(ANALYSIS_VIEW_TOOL_CONTRACTS[0]);
  const schema = registration.inputSchema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
  const serialized = JSON.stringify(schema);
  expect(serialized).toContain("at any method or length");
  console.log("Advertised schema contains: at any method or length");

  for (const segments of [32, 33]) {
    const suffix = Array.from({length: segments - 4}, (_, i) => `s${i}`).join("/");
    const requests = [
      ["GET", "https://example.test/api/v1/collections/0RZ576QZQA5KG"],
      ["GET", "https://example.test/api/v1/collections/0RZ576QZQA5KH"],
      ["PATCH", `https://example.test/api/v1/collections/0RZ576QZQA5KJ/${suffix}`],
    ];
    const entries = requests.map(([method, url]) => ({request: {method, url}, response: {status: 200, content: {mimeType: "application/json"}}}));
    const evidence = analysisViewCaptureEvidence(environmentManifestCaptureFixture(entries));
    const result = await inspectAnalysisView({
      source: {kind: "inline", evidence},
      view: {kind: "environment-manifest", template_rules: ["sibling-variance", "prefix-variance"]},
    });
    if (!result.ok) throw result.error;
    const manifest = result.value.normalized_result as {
      tools: { method: string; path_template: string }[];
      limitations: string[];
    };
    const patch = manifest.tools.find((tool) => tool.method === "PATCH")!;
    expect(patch.path_template.split("/").filter(Boolean)).toHaveLength(segments);
    expect(patch.path_template).toContain(segments === 32 ? "{collection_id}" : "0RZ576QZQA5KJ");
    const limit = "Routes with more than 32 segments are not compared by prefix-variance; they keep their grouped templates.";
    expect(manifest.limitations.includes(limit)).toBe(segments === 33);
    console.log(JSON.stringify({segments, path_template: patch.path_template, limitations: manifest.limitations}));
  }
});
EOF
npm run test:local -- src/application/analysisView/verify-probe.test.ts
rm src/application/analysisView/verify-probe.test.ts

Expected behavior

The MCP field description should explicitly state that prefix-variance compares routes of at most 32 segments, including when it explains that methods and route lengths need not match. Expected source: the feature specification requires that cap and a limitation for longer routes at docs/specs/agent-environments/prefix-variance/spec.md:49; the guide states the same qualification at docs/web-network-captures.md:555. Failure source: the standalone input description at src/domain/analysisView/environmentManifestView.ts:37 and rule-table entry at docs/web-network-captures.md:528 omit that qualification. This report does not request removing or changing the cap.

Impact and scope

P3: the verified defect is misleading scope wording. An MCP caller relying on the input description can expect prefix sharing for a route that is deliberately outside the comparison scope. The result itself accurately discloses the omission, and the complete guide documents it. Reading that limitation or the cap paragraph gives the caller the actual scope; neither changes the long route's intended literal result. No incorrect manifest under the complete specification, data loss, failure to execute a write, or blocked core workflow was demonstrated. The observed case uses one synthetic origin and compares only the 32/33-segment boundary.

REA version

6.8.0; source baseline f8f7ac96de8a66a4ab9a23d87e04779bfcd11045.

Runtime and platform

Node.js v24.22.1; macOS/Darwin 27.0.0; arm64.

Target and artifact context

Synthetic HAR-shaped capture Evidence containing two GET donor requests and one PATCH request, all answered with JSON content type. No executable, live application, or external service was used.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

The focused service test passed with these observed results; the path tails are abbreviated here only for readability:

Advertised schema contains: at any method or length
32 segments: PATCH /api/v1/collections/{collection_id}/s0/.../s27
33 segments: PATCH /api/v1/collections/0RZ576QZQA5KJ/s0/.../s28
33-segment limitation: Routes with more than 32 segments are not compared by prefix-variance; they keep their grouped templates.
Test Files  1 passed (1)
Tests       1 passed (1)

The MCP contract binds the input schema at src/contracts/analysisViewToolContracts.ts:21; registration uses it and dispatches to the tested application function at src/server/registerAnalysisViewTool.ts:23. The cap is defined at src/domain/analysisView/environmentManifestRules.ts:85, applied to the prefix pass at src/domain/analysisView/environmentManifestRules.ts:562, and disclosed in result limitations at src/domain/analysisView/EnvironmentManifestAccumulator.ts:473. An existing test explicitly requires the long-route behavior at src/domain/analysisView/environmentManifestView.test.ts:1383. Schema projection and application admission were executed; a compiled MCP transport was not launched.

Additional context

Verified at the commit above with the temporary test shown; no source change is proposed beyond the wording. The 32-segment cap itself is intentional and is not reported as a defect.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7388 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Documentation ### Observed behavior The input JSON Schema prepared for the MCP `inspect_analysis_view` registration describes the environment-manifest `prefix-variance` rule as applying "at any method or length", without qualifying the route-length limit. In a focused source test of the shared application handler, an accepted manifest request with two GET donor routes and one PATCH route templated the PATCH identifier at 32 path segments. With the same prefix and identifier shape at 33 segments, it retained the literal identifier and returned a limitation explaining the 32-segment cap. That runtime behavior matches the feature specification; the defect is the incomplete scope description presented before the caller selects the rule. The public guide's rule-table entry uses similarly unqualified language, although a later paragraph correctly states the cap. ### Reproduction Use a fresh clone at `f8f7ac96de8a66a4ab9a23d87e04779bfcd11045`, Node.js v24.22.1, and locked dependencies installed with `npm ci`. From the repository root, create and run this single temporary source test. It constructs all request fixtures locally, projects the registration's input schema, and submits inline capture Evidence through the same application function used by the MCP handler. No capture server or optional analysis provider is required. This probe passed once during independent verification; it asserts the mismatch rather than treating the intentional cap as an implementation failure. ```sh cat > src/application/analysisView/verify-probe.test.ts <<'EOF' import { expect, it } from "vitest"; import { analysisViewCaptureEvidence, environmentManifestCaptureFixture } from "../../../tests/fixtures/analysisView.js"; import { inspectAnalysisView } from "./AnalysisViewService.js"; import { ANALYSIS_VIEW_TOOL_CONTRACTS } from "../../contracts/analysisViewToolContracts.js"; import { applicationToolRegistrationOptions } from "../../server/toolRegistrationOptions.js"; it("compares the advertised rule scope with accepted 32 and 33 segment requests", async () => { const registration = applicationToolRegistrationOptions(ANALYSIS_VIEW_TOOL_CONTRACTS[0]); const schema = registration.inputSchema["~standard"].jsonSchema.input({ target: "draft-2020-12" }); const serialized = JSON.stringify(schema); expect(serialized).toContain("at any method or length"); console.log("Advertised schema contains: at any method or length"); for (const segments of [32, 33]) { const suffix = Array.from({length: segments - 4}, (_, i) => `s${i}`).join("/"); const requests = [ ["GET", "https://example.test/api/v1/collections/0RZ576QZQA5KG"], ["GET", "https://example.test/api/v1/collections/0RZ576QZQA5KH"], ["PATCH", `https://example.test/api/v1/collections/0RZ576QZQA5KJ/${suffix}`], ]; const entries = requests.map(([method, url]) => ({request: {method, url}, response: {status: 200, content: {mimeType: "application/json"}}})); const evidence = analysisViewCaptureEvidence(environmentManifestCaptureFixture(entries)); const result = await inspectAnalysisView({ source: {kind: "inline", evidence}, view: {kind: "environment-manifest", template_rules: ["sibling-variance", "prefix-variance"]}, }); if (!result.ok) throw result.error; const manifest = result.value.normalized_result as { tools: { method: string; path_template: string }[]; limitations: string[]; }; const patch = manifest.tools.find((tool) => tool.method === "PATCH")!; expect(patch.path_template.split("/").filter(Boolean)).toHaveLength(segments); expect(patch.path_template).toContain(segments === 32 ? "{collection_id}" : "0RZ576QZQA5KJ"); const limit = "Routes with more than 32 segments are not compared by prefix-variance; they keep their grouped templates."; expect(manifest.limitations.includes(limit)).toBe(segments === 33); console.log(JSON.stringify({segments, path_template: patch.path_template, limitations: manifest.limitations})); } }); EOF npm run test:local -- src/application/analysisView/verify-probe.test.ts rm src/application/analysisView/verify-probe.test.ts ``` ### Expected behavior The MCP field description should explicitly state that `prefix-variance` compares routes of at most 32 segments, including when it explains that methods and route lengths need not match. Expected source: the feature specification requires that cap and a limitation for longer routes at `docs/specs/agent-environments/prefix-variance/spec.md:49`; the guide states the same qualification at `docs/web-network-captures.md:555`. Failure source: the standalone input description at `src/domain/analysisView/environmentManifestView.ts:37` and rule-table entry at `docs/web-network-captures.md:528` omit that qualification. This report does not request removing or changing the cap. ### Impact and scope P3: the verified defect is misleading scope wording. An MCP caller relying on the input description can expect prefix sharing for a route that is deliberately outside the comparison scope. The result itself accurately discloses the omission, and the complete guide documents it. Reading that limitation or the cap paragraph gives the caller the actual scope; neither changes the long route's intended literal result. No incorrect manifest under the complete specification, data loss, failure to execute a write, or blocked core workflow was demonstrated. The observed case uses one synthetic origin and compares only the 32/33-segment boundary. ### REA version 6.8.0; source baseline `f8f7ac96de8a66a4ab9a23d87e04779bfcd11045`. ### Runtime and platform Node.js v24.22.1; macOS/Darwin 27.0.0; arm64. ### Target and artifact context Synthetic HAR-shaped capture Evidence containing two GET donor requests and one PATCH request, all answered with JSON content type. No executable, live application, or external service was used. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence The focused service test passed with these observed results; the path tails are abbreviated here only for readability: ```text Advertised schema contains: at any method or length 32 segments: PATCH /api/v1/collections/{collection_id}/s0/.../s27 33 segments: PATCH /api/v1/collections/0RZ576QZQA5KJ/s0/.../s28 33-segment limitation: Routes with more than 32 segments are not compared by prefix-variance; they keep their grouped templates. Test Files 1 passed (1) Tests 1 passed (1) ``` The MCP contract binds the input schema at `src/contracts/analysisViewToolContracts.ts:21`; registration uses it and dispatches to the tested application function at `src/server/registerAnalysisViewTool.ts:23`. The cap is defined at `src/domain/analysisView/environmentManifestRules.ts:85`, applied to the prefix pass at `src/domain/analysisView/environmentManifestRules.ts:562`, and disclosed in result limitations at `src/domain/analysisView/EnvironmentManifestAccumulator.ts:473`. An existing test explicitly requires the long-route behavior at `src/domain/analysisView/environmentManifestView.test.ts:1383`. Schema projection and application admission were executed; a compiled MCP transport was not launched. ### Additional context Verified at the commit above with the temporary test shown; no source change is proposed beyond the wording. The 32-segment cap itself is intentional and is not reported as a defect.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4395
No description provided.