[GH-ISSUE #7325] [Bug] capabilities Markdown loses provider identities when rendered with the repository's VitePress renderer #4353

Closed
opened 2026-10-31 00:49:08 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

CLI

Observed behavior

The built capabilities --format md command succeeds and writes ordinary provider metadata as JSON in the provider column. Rendering that table with the repository's locked VitePress renderer leaves all four provider cells empty in the tested environment. The raw Markdown still contains the IDs, names and versions. This is a rendered literal-display failure; JSON and TOON retain the provider metadata.

Reproduction

Use the built source checkout with its locked dependencies and pinned Node available as node. From its root, run this target-free comparison. The provider count depends on the environment; the tested isolated environment returned four rows. The commands and renderer comparison below were executed locally.

export VERIFY_ROOT="$(mktemp -d)"
mkdir -p "$VERIFY_ROOT/home" "$VERIFY_ROOT/tmp"
HOME="$VERIFY_ROOT/home" TMPDIR="$VERIFY_ROOT/tmp" node --input-type=module <<'NODE'
import { spawnSync } from 'node:child_process';
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { createMarkdownRenderer, disposeMdItInstance } from 'vitepress';
import { parseFragment } from 'parse5';
const root = process.env.VERIFY_ROOT;
const env = {
  HOME: join(root, 'home'), TMPDIR: join(root, 'tmp'),
  XDG_CONFIG_HOME: join(root, 'home/config'),
  XDG_CACHE_HOME: join(root, 'home/cache'),
  XDG_DATA_HOME: join(root, 'home/data'),
  XDG_STATE_HOME: join(root, 'home/state'),
  PATH: process.env.PATH, REA_LOG_LEVEL: 'silent'
};
const outputs = {};
for (const format of ['md', 'json', 'toon']) {
  const result = spawnSync(process.execPath,
    ['scripts/rea.mjs', 'capabilities', '--format', format],
    { env, encoding: 'utf8', timeout: 30000, maxBuffer: 4194304 });
  console.log(format, 'exit', result.status, 'stderr bytes',
    Buffer.byteLength(result.stderr ?? ''));
  if (result.status !== 0) throw new Error(result.stderr || String(result.error));
  outputs[format] = result.stdout;
  writeFileSync(join(root, `capabilities.${format}`), result.stdout);
}
const source = outputs.md.split('## capabilities\n')[1].split('\n## ')[0].trim();
const text = node => node.nodeName === '#text' ? node.value :
  (node.childNodes ?? []).map(text).join('');
function providerCells(html) {
  const rows = [];
  function visit(node) {
    if (node.tagName === 'tr') rows.push(node);
    else (node.childNodes ?? []).forEach(visit);
  }
  visit(parseFragment(html));
  return rows.slice(1).map(row =>
    text(row.childNodes.find(node => node.tagName === 'td')));
}
const expected = JSON.parse(outputs.json).capabilities.map(row =>
  JSON.stringify(row.provider));
const renderer = await createMarkdownRenderer(root, { linkify: false });
const actual = providerCells(renderer.render(source));
const escaped = source.replaceAll('{', '\\{').replaceAll('}', '\\}');
const control = providerCells(renderer.render(escaped));
console.log('expected provider cells:', JSON.stringify(expected));
console.log('actual provider cells:', JSON.stringify(actual));
console.log('escaped control matches JSON:',
  JSON.stringify(control) === JSON.stringify(expected));
console.log('TOON retains all provider IDs:', expected.every(value =>
  outputs.toon.includes(JSON.parse(value).id)));
disposeMdItInstance();
NODE

Expected behavior

Each rendered provider cell should display its JSON text, including the ID, name and version, rather than appear empty. The CLI documentation promises literal source text in Markdown cells and preservation of nested field names and values. The repository already uses this VitePress renderer to verify visible text from public CLI Markdown tables, so this check follows its existing consumer oracle.

Impact and scope

All four provider identity cells were empty in the executed comparison, making the capability groups harder to associate with their providers. Raw Markdown, JSON and TOON preserve the metadata, providing practical alternatives. The observed scope is this command's ordinary built-in provider objects rendered with locked VitePress and its default attributes extension. Disabling that extension also restored all four cells. GFM and other renderers were not tested; this report makes no claim that their output is affected. No target analysis or stored Evidence loss was observed.

REA version

6.8.0, source commit ace4dbf36e.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, arm64; locked VitePress 1.6.4 and parse5. No external analysis engine was used.

Target and artifact context

Target-free built-in provider capability metadata. The affected objects contain only ordinary id, name and version fields; no user target or crafted attribute input is required.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

All three CLI invocations exited 0 with zero stderr bytes. The comparison printed:

actual provider cells: ["","","",""]
escaped control matches JSON: true
TOON retains all provider IDs: true

The first expected cell was {"id":"native-macos","name":"macOS native inspection utilities","version":null}. The others identified the artifact-graph, managed-static-analysis and SQLite providers. A separate executed control using the same renderer with attrs: { disable: true } retained every provider cell exactly.

  • Expected source: docs/cli.md:960 promises literal table-cell display and nested JSON facts; tests/boundary/cli/markdownLiteralCells.test.ts:80 renders public CLI output with VitePress and compares cell text with original values.
  • Failure source: the executed built CLI and VitePress comparison above. Source trace: src/cli/utilityCommands.ts:182 dispatches target-free status; src/application/DirectAnalysisStatus.ts:20 returns capability records; src/cli/cliResultOutput.ts:321 retains Markdown formatting ownership; src/cli/cliOutputFormatter.ts:99 serializes nested cells as JSON, while its cell escaping at line 61 leaves braces unchanged. The rendered provider cells have empty text; the two controls preserve the same text.
  • Evidence provenance: observed; source tracing separately explains the result path.
  • Local verification: reproduced through the built public executable and locked renderer.
  • Reproduction completeness: complete for the tested renderer and built-in metadata.

Additional context

Restoration check: the same public command and default renderer should produce provider cell text exactly equal to each provider object's JSON representation. Keep the JSON, TOON and escaped-brace comparisons as controls; merely hiding the column would not restore the missing identities.

Related merged PR #7073 establishes literal table-cell handling for emphasis, links and similar syntax, but the ordinary brace-delimited provider case still fails after that change. PR #7062 concerns headings and explicitly excludes table cells. Issue #7271 and PR #7278 concern TOON/YAML envelope token counts, which have a separate failure signal. Closed issue #5525 concerns source cells becoming [object Object]; here the source JSON is intact and its rendered text disappears.

NOT_ENOUGH_INFO: the first affected release and last known good release were not established. Ordinary GFM comparison was not run because no suitable renderer was installed; no dependency was installed for this verification.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The supported Markdown display path hides all four provider identities in this bounded run despite successful command completion, reducing the information available in the rendered capability report. This does not establish loss of stored data or impact on other renderers.
  • Workaround status: available
  • Workaround basis: The executed JSON and TOON commands preserve provider metadata, and the raw Markdown retains the JSON. The escaped-brace and attributes-disabled controls also restore the rendered text in the tested renderer.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7325 ## 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 CLI ## Observed behavior The built `capabilities --format md` command succeeds and writes ordinary provider metadata as JSON in the provider column. Rendering that table with the repository's locked VitePress renderer leaves all four provider cells empty in the tested environment. The raw Markdown still contains the IDs, names and versions. This is a rendered literal-display failure; JSON and TOON retain the provider metadata. ## Reproduction Use the built source checkout with its locked dependencies and pinned Node available as `node`. From its root, run this target-free comparison. The provider count depends on the environment; the tested isolated environment returned four rows. The commands and renderer comparison below were executed locally. ```sh export VERIFY_ROOT="$(mktemp -d)" mkdir -p "$VERIFY_ROOT/home" "$VERIFY_ROOT/tmp" HOME="$VERIFY_ROOT/home" TMPDIR="$VERIFY_ROOT/tmp" node --input-type=module <<'NODE' import { spawnSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { createMarkdownRenderer, disposeMdItInstance } from 'vitepress'; import { parseFragment } from 'parse5'; const root = process.env.VERIFY_ROOT; const env = { HOME: join(root, 'home'), TMPDIR: join(root, 'tmp'), XDG_CONFIG_HOME: join(root, 'home/config'), XDG_CACHE_HOME: join(root, 'home/cache'), XDG_DATA_HOME: join(root, 'home/data'), XDG_STATE_HOME: join(root, 'home/state'), PATH: process.env.PATH, REA_LOG_LEVEL: 'silent' }; const outputs = {}; for (const format of ['md', 'json', 'toon']) { const result = spawnSync(process.execPath, ['scripts/rea.mjs', 'capabilities', '--format', format], { env, encoding: 'utf8', timeout: 30000, maxBuffer: 4194304 }); console.log(format, 'exit', result.status, 'stderr bytes', Buffer.byteLength(result.stderr ?? '')); if (result.status !== 0) throw new Error(result.stderr || String(result.error)); outputs[format] = result.stdout; writeFileSync(join(root, `capabilities.${format}`), result.stdout); } const source = outputs.md.split('## capabilities\n')[1].split('\n## ')[0].trim(); const text = node => node.nodeName === '#text' ? node.value : (node.childNodes ?? []).map(text).join(''); function providerCells(html) { const rows = []; function visit(node) { if (node.tagName === 'tr') rows.push(node); else (node.childNodes ?? []).forEach(visit); } visit(parseFragment(html)); return rows.slice(1).map(row => text(row.childNodes.find(node => node.tagName === 'td'))); } const expected = JSON.parse(outputs.json).capabilities.map(row => JSON.stringify(row.provider)); const renderer = await createMarkdownRenderer(root, { linkify: false }); const actual = providerCells(renderer.render(source)); const escaped = source.replaceAll('{', '\\{').replaceAll('}', '\\}'); const control = providerCells(renderer.render(escaped)); console.log('expected provider cells:', JSON.stringify(expected)); console.log('actual provider cells:', JSON.stringify(actual)); console.log('escaped control matches JSON:', JSON.stringify(control) === JSON.stringify(expected)); console.log('TOON retains all provider IDs:', expected.every(value => outputs.toon.includes(JSON.parse(value).id))); disposeMdItInstance(); NODE ``` ## Expected behavior Each rendered provider cell should display its JSON text, including the ID, name and version, rather than appear empty. The CLI documentation promises literal source text in Markdown cells and preservation of nested field names and values. The repository already uses this VitePress renderer to verify visible text from public CLI Markdown tables, so this check follows its existing consumer oracle. ## Impact and scope All four provider identity cells were empty in the executed comparison, making the capability groups harder to associate with their providers. Raw Markdown, JSON and TOON preserve the metadata, providing practical alternatives. The observed scope is this command's ordinary built-in provider objects rendered with locked VitePress and its default attributes extension. Disabling that extension also restored all four cells. GFM and other renderers were not tested; this report makes no claim that their output is affected. No target analysis or stored Evidence loss was observed. ## REA version 6.8.0, source commit ace4dbf36e8c8f36a0e192aff9a11484ed428358. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1, arm64; locked VitePress 1.6.4 and parse5. No external analysis engine was used. ## Target and artifact context Target-free built-in provider capability metadata. The affected objects contain only ordinary `id`, `name` and `version` fields; no user target or crafted attribute input is required. ## Interface CLI ## Earliest failure stage Transport or result projection ## Relevant output or evidence All three CLI invocations exited 0 with zero stderr bytes. The comparison printed: ```text actual provider cells: ["","","",""] escaped control matches JSON: true TOON retains all provider IDs: true ``` The first expected cell was `{"id":"native-macos","name":"macOS native inspection utilities","version":null}`. The others identified the artifact-graph, managed-static-analysis and SQLite providers. A separate executed control using the same renderer with `attrs: { disable: true }` retained every provider cell exactly. - Expected source: `docs/cli.md:960` promises literal table-cell display and nested JSON facts; `tests/boundary/cli/markdownLiteralCells.test.ts:80` renders public CLI output with VitePress and compares cell text with original values. - Failure source: the executed built CLI and VitePress comparison above. Source trace: `src/cli/utilityCommands.ts:182` dispatches target-free status; `src/application/DirectAnalysisStatus.ts:20` returns capability records; `src/cli/cliResultOutput.ts:321` retains Markdown formatting ownership; `src/cli/cliOutputFormatter.ts:99` serializes nested cells as JSON, while its cell escaping at line 61 leaves braces unchanged. The rendered provider cells have empty text; the two controls preserve the same text. - Evidence provenance: observed; source tracing separately explains the result path. - Local verification: reproduced through the built public executable and locked renderer. - Reproduction completeness: complete for the tested renderer and built-in metadata. ## Additional context Restoration check: the same public command and default renderer should produce provider cell text exactly equal to each provider object's JSON representation. Keep the JSON, TOON and escaped-brace comparisons as controls; merely hiding the column would not restore the missing identities. Related merged [PR #7073](https://github.com/morluto/rea/pull/7073) establishes literal table-cell handling for emphasis, links and similar syntax, but the ordinary brace-delimited provider case still fails after that change. [PR #7062](https://github.com/morluto/rea/pull/7062) concerns headings and explicitly excludes table cells. [Issue #7271](https://github.com/morluto/rea/issues/7271) and [PR #7278](https://github.com/morluto/rea/pull/7278) concern TOON/YAML envelope token counts, which have a separate failure signal. Closed [issue #5525](https://github.com/morluto/rea/issues/5525) concerns source cells becoming `[object Object]`; here the source JSON is intact and its rendered text disappears. NOT_ENOUGH_INFO: the first affected release and last known good release were not established. Ordinary GFM comparison was not run because no suitable renderer was installed; no dependency was installed for this verification. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The supported Markdown display path hides all four provider identities in this bounded run despite successful command completion, reducing the information available in the rendered capability report. This does not establish loss of stored data or impact on other renderers. - Workaround status: available - Workaround basis: The executed JSON and TOON commands preserve provider metadata, and the raw Markdown retains the JSON. The escaped-brace and attributes-disabled controls also restore the rendered text in the tested renderer.
Author
Owner

@coygeek commented on GitHub (Oct 31, 2026):

I checked this against latest main, and the issue appears resolved. The capabilities --format md provider cells were rendering empty in the repository's VitePress renderer because the brace-delimited provider JSON, such as {"id":"native-macos","name":"macOS native inspection utilities","version":null}, was being interpreted as renderer attributes instead of literal text, while the raw Markdown, JSON, and TOON output all retained the metadata. PR #7938 (merge commit e124bdfc5, merged into main on 2026-10-29) fixes this in the exact area the issue traced: src/cli/cliOutputFormatter.ts, where escapeTableCell now escapes { and } (along with other renderer-extension introducers) so the provider JSON is emitted as literal text in Markdown table cells rather than being swallowed during rendering. The PR also adds a regression test, "preserves capability provider identities in rendered Markdown," that runs the public capabilities command, renders the Markdown output with the VitePress renderer, and checks the rendered provider column against each provider object's JSON representation — the same restoration check described in this issue. I verified the merge commit is an ancestor of current main, so this fix is present on the default branch. Closing as resolved.

<!-- gh-comment-id:6537222290 --> @coygeek commented on GitHub (Oct 31, 2026): I checked this against latest main, and the issue appears resolved. The `capabilities --format md` provider cells were rendering empty in the repository's VitePress renderer because the brace-delimited provider JSON, such as `{"id":"native-macos","name":"macOS native inspection utilities","version":null}`, was being interpreted as renderer attributes instead of literal text, while the raw Markdown, JSON, and TOON output all retained the metadata. [PR #7938](https://github.com/morluto/rea/pull/7938) (merge commit [`e124bdfc5`](https://github.com/morluto/rea/commit/e124bdfc54707da138a58ae61b901f0bf93a9bac), merged into main on 2026-10-29) fixes this in the exact area the issue traced: `src/cli/cliOutputFormatter.ts`, where `escapeTableCell` now escapes `{` and `}` (along with other renderer-extension introducers) so the provider JSON is emitted as literal text in Markdown table cells rather than being swallowed during rendering. The PR also adds a regression test, "preserves capability provider identities in rendered Markdown," that runs the public `capabilities` command, renders the Markdown output with the VitePress renderer, and checks the rendered provider column against each provider object's JSON representation — the same restoration check described in this issue. I verified the merge commit is an ancestor of current main, so this fix is present on the default branch. Closing as resolved.
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#4353
No description provided.