[GH-ISSUE #7398] [Bug] Prefixed XHTML link elements omit declared agent hints #4403

Closed
opened 2026-10-31 00:49:32 +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/7398

Before submitting

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

The issue search used the supplied offline cache of 300 issue records; a current exhaustive live search remains for the parent reviewer.

Area

Process capture or runtime observation

Observed behavior

A passive page inspection through REA's shared inspection service returned different agent-hint metadata for two DOMSnapshot replies that differ only in XHTML namespace spelling. The default-namespace document returned four dom_link_rel hints for a link declaring rel="mcp model-context ai-plugin service-desc". The equivalent prefixed document returned none. Both retained the same approved href destination at node index 3.

The application call succeeded for both inputs. Neither result contained a metadata exclusion for the lost declarations. Both captures already reported policy_filtered and attach_limited conditions, including attach-limited metadata; this reproduction does not establish that the whole capture was reported complete.

Reproduction

Use a fresh clone at commit f8f7ac96de with Node 24.22.1. Install the locked dependencies with npm ci if needed. Dependencies were already installed in the verifier checkout; installation was not rerun. No compiled build is needed for this source-level production-service reproduction.

Create src/browser/verify-probe.test.ts with the following complete test. It supplies two loopback CDP snapshots, calls the same production composition factory and shared inspection operation used by the CLI, validates the returned Evidence, and asserts the incorrect baseline behavior so the diagnostic test passes when the omission occurs.

import { expect, it } from "vitest";
import { startFakeCdpBrowser } from "../../tests/fixtures/fakeCdpBrowser.js";
import { createBrowserObservationProvider } from "../composition/browserObservation.js";
import { inspectWebPage } from "../application/BrowserObservationService.js";
import { inspectWebPageInputSchema } from "../domain/browserObservation.js";
import { webPageInspectionSchema } from "../domain/browserObservationSchemas.js";

const rel = "mcp model-context ai-plugin service-desc";
const snapshot = (prefix: string, origin: string) => ({
  strings: ["#document", `${prefix}html`, `${prefix}head`, `${prefix}link`, "",
    prefix ? "xmlns:h" : "xmlns", "http://www.w3.org/1999/xhtml",
    "rel", rel, "href", "/agent", `${origin}/root/page.xhtml`],
  documents: [{ documentURL: 11, nodes: {
    nodeType: [9, 1, 1, 1], nodeName: [0, 1, 2, 3],
    nodeValue: [4, 4, 4, 4], parentIndex: [-1, 0, 1, 2],
    attributes: [[], [5, 6], [], [7, 8, 9, 10]],
  }}],
});

it("compares equivalent XHTML link declarations through the shared inspection service", async () => {
  for (const prefix of ["", "h:"]) {
    const browser = await startFakeCdpBrowser({ commandResult: (command, origin) =>
      command.method === "DOMSnapshot.captureSnapshot" ? snapshot(prefix, origin) : undefined,
    });
    const provider = createBrowserObservationProvider();
    try {
      const result = await inspectWebPage(provider, inspectWebPageInputSchema.parse({
        cdp_endpoint: browser.endpoint, target_id: "allowed-page", observation_ms: 1,
      }));
      if (!result.ok) throw result.error;
      const value = webPageInspectionSchema.parse(result.value.normalized_result);
      const hints = value.metadata.agent_hints.filter(hint => hint.mechanism === "dom_link_rel");
      const summary = { prefix, dom_urls: value.metadata.dom_urls, hints, completeness: value.completeness };
      console.log(JSON.stringify(summary));
      expect(browser.commands.some(command => command.method === "DOMSnapshot.captureSnapshot")).toBe(true);
      expect(value.metadata.dom_urls).toEqual([{ node_index: 3, attribute: "href", url: `${browser.allowedOrigin}/agent`, destination_scope: "approved" }]);
      expect(hints.map(hint => hint.declaration)).toEqual(prefix ? [] : rel.split(" "));
      expect(value.completeness.unavailable_sections).toEqual([]);
      expect(value.completeness.excluded.filter(exclusion => exclusion.section === "metadata")).toEqual([]);
    } finally {
      await provider.close?.();
      await browser.close();
    }
  }
}, 30_000);

Run it with the pinned Node active and an isolated application home, then delete the temporary test:

probe_home=$(mktemp -d)
HOME="$probe_home" npm_config_update_notifier=false npm run test:local -- src/browser/verify-probe.test.ts
rm src/browser/verify-probe.test.ts
rm -rf "$probe_home"

The corrected probe passed once, completing one inspection for each namespace form. An earlier attempt stopped on a verifier-side typo in the completeness field name before running the prefixed case; the test above uses the actual excluded field.

Expected behavior

Both XHTML representations should retain the same declared agent hints because their link elements have the same namespace and local name. Expected source: the page-inspection surface promises DOM metadata in docs/browser-observation.md:25, and src/domain/browserObservationSchemas.ts:212 defines the dom_link_rel mechanism and untrusted declaration fields. src/browser/CdpCaptureDomNamespaces.ts:61 explicitly supports prefixed XML names; src/browser/CdpCaptureDocuments.ts:356 passes resolved namespace facts to metadata capture, and src/browser/CdpCaptureDocuments.ts:724 already recognizes XHTML element names through those facts. The boundary ownership rule in docs/tool-design.md:86 requires consumers to use the parsed interpretation. The successful unprefixed control demonstrates that all four rel values already belong to the existing hint projection.

Impact and scope

P2: this is a bounded consequential omission from advisory discovery metadata. A caller relying on agent_hints misses declarations on admitted prefixed XHTML link elements, although the page inspection succeeds and preserves their approved href destinations. The two-input test reproduced the difference for all four recognized declaration tokens. It did not establish severe harm, failure of the whole inspection workflow, or prevalence on real websites. Reading dom_urls can recover the destination but does not by itself recover the omitted rel declarations; a complete caller workaround was not verified. No security boundary is crossed.

REA version

6.8.0 from package.json; baseline f8f7ac96de.

Runtime and platform

Node v24.22.1; macOS 27.0.1; darwin arm64.

Target and artifact context

Repository fake CDP browser bound to loopback HTTP/WebSocket, target allowed-page. The two inline snapshots describe a document, XHTML root, head, and link; one binds the default namespace and the other binds prefix h to the same XHTML namespace. Both declare the same relative href and rel tokens. No live browser, external website, or binary artifact was involved.

Interface

CLI

Earliest failure stage

Capture or observation

Relevant output or evidence

The focused source test passed with two successful production inspection-service calls. The relevant logged results, with the ephemeral loopback ports normalized to PORT, were:

Default namespace:
  dom_urls = [{node_index: 3, attribute: "href", url: "http://127.0.0.1:PORT/agent", destination_scope: "approved"}]
  dom_link_rel declarations = ["mcp", "model-context", "ai-plugin", "service-desc"]
Prefixed namespace:
  dom_urls = [{node_index: 3, attribute: "href", url: "http://127.0.0.1:PORT/agent", destination_scope: "approved"}]
  dom_link_rel declarations = []
Both:
  completeness.status = "policy_filtered"
  completeness.conditions = ["attach_limited", "policy_filtered"]
  completeness.attach_limited_sections includes "metadata"
  completeness.unavailable_sections = []
  completeness.excluded has no entry with section "metadata"

Failure source: src/browser/CdpCaptureDocuments.ts:758 requires the raw lowercased node name to equal link, so h:link fails the hint condition. The resolved href survives independently. Supported-entry reachability is source-confirmed: src/cli/browserCommands.ts:114 constructs the same provider, src/cli/browserCommands.ts:129 validates the request, and src/cli/browserCommands.ts:139 invokes the tested shared service. src/browser/CdpPageCapture.ts:315 requests DOMSnapshot.captureSnapshot and src/browser/CdpPageCapture.ts:325 feeds the reply into the affected capture function. The probe also asserted that the real loopback session sent that CDP command.

Typed outcome or recovery expected

Successful inspection should include the same dom_link_rel entries for equivalent XHTML expanded names, preserving declaration, resolved URL, and page-declared-untrusted trust classification.

Additional context

This verifies REA's handling of the supplied admitted CDP snapshots through its production service and provider. A compiled CLI invocation and a real Chrome-family browser serving application/xhtml+xml were not exercised. No introducing commit or unrelated XML false-positive behavior is claimed.

References

  • #6561 (closed) fixed prefixed XHTML form actions resolving against the wrong base. This report concerns link rel agent hints on prefixed XHTML elements; a shared cause is not established.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7398 ### 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. The issue search used the supplied offline cache of 300 issue records; a current exhaustive live search remains for the parent reviewer. ### Area Process capture or runtime observation ### Observed behavior A passive page inspection through REA's shared inspection service returned different agent-hint metadata for two DOMSnapshot replies that differ only in XHTML namespace spelling. The default-namespace document returned four dom_link_rel hints for a link declaring `rel="mcp model-context ai-plugin service-desc"`. The equivalent prefixed document returned none. Both retained the same approved href destination at node index 3. The application call succeeded for both inputs. Neither result contained a metadata exclusion for the lost declarations. Both captures already reported policy_filtered and attach_limited conditions, including attach-limited metadata; this reproduction does not establish that the whole capture was reported complete. ### Reproduction Use a fresh clone at commit f8f7ac96de8a66a4ab9a23d87e04779bfcd11045 with Node 24.22.1. Install the locked dependencies with `npm ci` if needed. Dependencies were already installed in the verifier checkout; installation was not rerun. No compiled build is needed for this source-level production-service reproduction. Create `src/browser/verify-probe.test.ts` with the following complete test. It supplies two loopback CDP snapshots, calls the same production composition factory and shared inspection operation used by the CLI, validates the returned Evidence, and asserts the incorrect baseline behavior so the diagnostic test passes when the omission occurs. ```ts import { expect, it } from "vitest"; import { startFakeCdpBrowser } from "../../tests/fixtures/fakeCdpBrowser.js"; import { createBrowserObservationProvider } from "../composition/browserObservation.js"; import { inspectWebPage } from "../application/BrowserObservationService.js"; import { inspectWebPageInputSchema } from "../domain/browserObservation.js"; import { webPageInspectionSchema } from "../domain/browserObservationSchemas.js"; const rel = "mcp model-context ai-plugin service-desc"; const snapshot = (prefix: string, origin: string) => ({ strings: ["#document", `${prefix}html`, `${prefix}head`, `${prefix}link`, "", prefix ? "xmlns:h" : "xmlns", "http://www.w3.org/1999/xhtml", "rel", rel, "href", "/agent", `${origin}/root/page.xhtml`], documents: [{ documentURL: 11, nodes: { nodeType: [9, 1, 1, 1], nodeName: [0, 1, 2, 3], nodeValue: [4, 4, 4, 4], parentIndex: [-1, 0, 1, 2], attributes: [[], [5, 6], [], [7, 8, 9, 10]], }}], }); it("compares equivalent XHTML link declarations through the shared inspection service", async () => { for (const prefix of ["", "h:"]) { const browser = await startFakeCdpBrowser({ commandResult: (command, origin) => command.method === "DOMSnapshot.captureSnapshot" ? snapshot(prefix, origin) : undefined, }); const provider = createBrowserObservationProvider(); try { const result = await inspectWebPage(provider, inspectWebPageInputSchema.parse({ cdp_endpoint: browser.endpoint, target_id: "allowed-page", observation_ms: 1, })); if (!result.ok) throw result.error; const value = webPageInspectionSchema.parse(result.value.normalized_result); const hints = value.metadata.agent_hints.filter(hint => hint.mechanism === "dom_link_rel"); const summary = { prefix, dom_urls: value.metadata.dom_urls, hints, completeness: value.completeness }; console.log(JSON.stringify(summary)); expect(browser.commands.some(command => command.method === "DOMSnapshot.captureSnapshot")).toBe(true); expect(value.metadata.dom_urls).toEqual([{ node_index: 3, attribute: "href", url: `${browser.allowedOrigin}/agent`, destination_scope: "approved" }]); expect(hints.map(hint => hint.declaration)).toEqual(prefix ? [] : rel.split(" ")); expect(value.completeness.unavailable_sections).toEqual([]); expect(value.completeness.excluded.filter(exclusion => exclusion.section === "metadata")).toEqual([]); } finally { await provider.close?.(); await browser.close(); } } }, 30_000); ``` Run it with the pinned Node active and an isolated application home, then delete the temporary test: ```bash probe_home=$(mktemp -d) HOME="$probe_home" npm_config_update_notifier=false npm run test:local -- src/browser/verify-probe.test.ts rm src/browser/verify-probe.test.ts rm -rf "$probe_home" ``` The corrected probe passed once, completing one inspection for each namespace form. An earlier attempt stopped on a verifier-side typo in the completeness field name before running the prefixed case; the test above uses the actual `excluded` field. ### Expected behavior Both XHTML representations should retain the same declared agent hints because their link elements have the same namespace and local name. Expected source: the page-inspection surface promises DOM metadata in docs/browser-observation.md:25, and src/domain/browserObservationSchemas.ts:212 defines the dom_link_rel mechanism and untrusted declaration fields. src/browser/CdpCaptureDomNamespaces.ts:61 explicitly supports prefixed XML names; src/browser/CdpCaptureDocuments.ts:356 passes resolved namespace facts to metadata capture, and src/browser/CdpCaptureDocuments.ts:724 already recognizes XHTML element names through those facts. The boundary ownership rule in docs/tool-design.md:86 requires consumers to use the parsed interpretation. The successful unprefixed control demonstrates that all four rel values already belong to the existing hint projection. ### Impact and scope P2: this is a bounded consequential omission from advisory discovery metadata. A caller relying on agent_hints misses declarations on admitted prefixed XHTML link elements, although the page inspection succeeds and preserves their approved href destinations. The two-input test reproduced the difference for all four recognized declaration tokens. It did not establish severe harm, failure of the whole inspection workflow, or prevalence on real websites. Reading dom_urls can recover the destination but does not by itself recover the omitted rel declarations; a complete caller workaround was not verified. No security boundary is crossed. ### REA version 6.8.0 from package.json; baseline f8f7ac96de8a66a4ab9a23d87e04779bfcd11045. ### Runtime and platform Node v24.22.1; macOS 27.0.1; darwin arm64. ### Target and artifact context Repository fake CDP browser bound to loopback HTTP/WebSocket, target allowed-page. The two inline snapshots describe a document, XHTML root, head, and link; one binds the default namespace and the other binds prefix h to the same XHTML namespace. Both declare the same relative href and rel tokens. No live browser, external website, or binary artifact was involved. ### Interface CLI ### Earliest failure stage Capture or observation ### Relevant output or evidence The focused source test passed with two successful production inspection-service calls. The relevant logged results, with the ephemeral loopback ports normalized to PORT, were: ```text Default namespace: dom_urls = [{node_index: 3, attribute: "href", url: "http://127.0.0.1:PORT/agent", destination_scope: "approved"}] dom_link_rel declarations = ["mcp", "model-context", "ai-plugin", "service-desc"] Prefixed namespace: dom_urls = [{node_index: 3, attribute: "href", url: "http://127.0.0.1:PORT/agent", destination_scope: "approved"}] dom_link_rel declarations = [] Both: completeness.status = "policy_filtered" completeness.conditions = ["attach_limited", "policy_filtered"] completeness.attach_limited_sections includes "metadata" completeness.unavailable_sections = [] completeness.excluded has no entry with section "metadata" ``` Failure source: src/browser/CdpCaptureDocuments.ts:758 requires the raw lowercased node name to equal link, so h:link fails the hint condition. The resolved href survives independently. Supported-entry reachability is source-confirmed: src/cli/browserCommands.ts:114 constructs the same provider, src/cli/browserCommands.ts:129 validates the request, and src/cli/browserCommands.ts:139 invokes the tested shared service. src/browser/CdpPageCapture.ts:315 requests DOMSnapshot.captureSnapshot and src/browser/CdpPageCapture.ts:325 feeds the reply into the affected capture function. The probe also asserted that the real loopback session sent that CDP command. ### Typed outcome or recovery expected Successful inspection should include the same dom_link_rel entries for equivalent XHTML expanded names, preserving declaration, resolved URL, and page-declared-untrusted trust classification. ### Additional context This verifies REA's handling of the supplied admitted CDP snapshots through its production service and provider. A compiled CLI invocation and a real Chrome-family browser serving `application/xhtml+xml` were not exercised. No introducing commit or unrelated XML false-positive behavior is claimed. ## References - #6561 (closed) fixed prefixed XHTML form actions resolving against the wrong base. This report concerns link `rel` agent hints on prefixed XHTML elements; a shared cause is not established.
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#4403
No description provided.