[GH-ISSUE #3170] [Bug] Boundary-field seeds cannot select analyzer-produced JavaScript boundaries #1110

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

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

The supported trace-javascript-semantics CLI accepts the documented boundary-field seed but cannot use it to select a boundary recovered by analyze-javascript-application. An inert application containing const port = Number(process.env.PORT); produces one boundary node with properties { "boundary_kind": "coerce", "method": "Number" }.

With the analyzer's unchanged application Evidence, queries for Number, coerce, PORT, method, boundary_kind, and missing-field each exit 0 and return status: "partial", seed_node_ids: [], and total_seed_matches: 0. An exact semantic-node seed for that same recovered boundary exits 0 and returns status: "found" with one seed match. The partial query status reflects incomplete static coverage and is not the defect reported here.

Reproduction

  1. From a clean checkout of the stated baseline, install the locked dependencies and build the CLI. The verifier reproduced the commands with already-installed dependencies and a prepared build; the clean-checkout install and build commands were not independently rerun.
npm ci
npm run build:cached
mkdir -p repro-boundary-field/home/config repro-boundary-field/home/cache repro-boundary-field/home/data
repro_home="$(pwd)/repro-boundary-field/home"
  1. Create a local fixture and analyze it.
mkdir -p repro-boundary-field/sample-app
cat > repro-boundary-field/sample-app/package.json <<'JSON'
{"name":"sample-app","version":"1.0.0","main":"main.js"}
JSON
cat > repro-boundary-field/sample-app/main.js <<'JS'
const port = Number(process.env.PORT);
JS
env HOME="$repro_home" XDG_CONFIG_HOME="$repro_home/config" XDG_CACHE_HOME="$repro_home/cache" XDG_DATA_HOME="$repro_home/data" \
  node scripts/rea.mjs analyze-javascript-application ./repro-boundary-field/sample-app --format json > repro-boundary-field/application.json
  1. Save and run this comparison script. It reads the analyzer's unchanged Evidence, prints the recovered boundary properties, writes complete trace requests, invokes the supported CLI, and prints the matching result for each seed.
cat > repro-boundary-field/compare.mjs <<'JS'
import { readFileSync, writeFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';

const root = 'repro-boundary-field';
const application = JSON.parse(readFileSync(`${root}/application.json`, 'utf8'));
const boundaries = application.normalized_result.semantic_graph.nodes.filter(
  node => node.kind === 'boundary'
);
if (boundaries.length !== 1) throw new Error('Expected one recovered boundary');
const boundary = boundaries[0];
console.log(JSON.stringify({ boundary_properties: boundary.properties }));
const seeds = ['Number', 'coerce', 'PORT', 'method', 'boundary_kind', 'missing-field']
  .map(field => ({ kind: 'boundary-field', field }));
seeds.push({ kind: 'semantic-node', node_id: boundary.node_id });
for (const [index, seed] of seeds.entries()) {
  const inputPath = `${root}/trace-${index}.json`;
  writeFileSync(inputPath, JSON.stringify({
    application,
    query: { seed, direction: 'forward-influence' }
  }));
  const run = spawnSync(process.execPath, [
    'scripts/rea.mjs', 'trace-javascript-semantics', inputPath, '--format', 'json'
  ], { encoding: 'utf8' });
  if (run.status !== 0) throw new Error(run.stderr || run.stdout);
  const result = JSON.parse(run.stdout).normalized_result;
  console.log(JSON.stringify({
    seed,
    exit_code: run.status,
    status: result.status,
    seed_node_ids: result.seed_node_ids,
    total_seed_matches: result.summary.total_seed_matches
  }));
}
JS
env HOME="$repro_home" XDG_CONFIG_HOME="$repro_home/config" XDG_CACHE_HOME="$repro_home/cache" XDG_DATA_HOME="$repro_home/data" \
  node repro-boundary-field/compare.mjs

Expected behavior

docs/javascript-application-workflows.md:60-66 documents boundary fields as supported semantic trace seeds over authenticated application Evidence and promises every matching seed and its reachable subgraph. Analyzer-produced boundaries must expose an applicable field identity so this seed variant can select a recovered boundary.

The contract does not define whether that identity is a method name, a coercion kind, or another value. This report leaves that mapping open. The requirement is that the documented variant be usable for a supported recovered boundary rather than fail for every accepted string.

Impact and scope

Callers cannot start traces of analyzer-produced boundaries through the advertised boundary-field seed. They must inspect the retained semantic graph and supply exact node IDs. The exact-node workaround selected the same recovered boundary from the same unchanged Evidence with one match.

The observed CLI failure concerns seed lookup. Source inspection establishes the broader scope for analyzer-produced boundary nodes because their constructor never supplies the field property required by the resolver. This does not claim that a separately constructed graph carrying that property could never match. The retained graph remains available; this reproduction does not establish a security-boundary violation.

REA version

6.4.0 (main at 5830088520)

Runtime and platform

Node.js 26.10.0; Darwin 27.0.0 arm64. A repeat with Node.js 24.21.0 reproduced the Number and missing-field results and the successful exact-node control. The repository's exact .nvmrc runtime, 24.18.0, was not used.

Target and artifact context

An inert extracted JavaScript application directory containing the inline package.json and main.js inputs above. Analysis returned direct authenticated application Evidence containing a semantic graph with one boundary node. No application code or external analysis engine was executed.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The excerpt shows the boundary properties, one failed boundary-field seed, and the exact-node control from the same application Evidence. The other five tested boundary-field strings also returned zero matches.

{"boundary_properties":{"boundary_kind":"coerce","method":"Number"}}
{"seed":{"kind":"boundary-field","field":"Number"},"exit_code":0,"status":"partial","seed_node_ids":[],"total_seed_matches":0}
{"seed":{"kind":"semantic-node","node_id":"jsrg_node_3be4222d83d56910dd7ea61e913c13451b8428a740125dc0a1b739564223e77e"},"exit_code":0,"status":"found","seed_node_ids":["jsrg_node_3be4222d83d56910dd7ea61e913c13451b8428a740125dc0a1b739564223e77e"],"total_seed_matches":1}

Typed outcome or recovery expected

A trace using the supported boundary-field identity for this recovered boundary should include that boundary in seed_node_ids and report one seed match. An absent field should still return zero matches. The exact-node seed should continue to select the same boundary from unchanged Evidence. Preserve graph authentication, partial coverage, and static-analysis uncertainty.

Analysis or suspected cause

Source-derived reasoning at the reported baseline:

  • src/domain/javascript/javascriptSemanticQueryIdentity.ts:94 requires node.kind === "boundary" and node.properties.field === seed.field.
  • src/application/javascript/JavaScriptSemanticGraphDataProjection.ts:250-268 constructs boundary nodes with only boundary_kind and method in their properties.
  • src/application/javascript/JavaScriptSemanticGraphConstruction.ts:104-127 preserves the supplied properties unchanged.
  • src/domain/javascript/javascriptSemanticQuerySchemas.ts:54-57 accepts a nonempty string for the boundary-field seed. src/domain/javascript/javascriptSemanticTraceSchemas.ts:13-16 and src/cli/applicationCommands.ts:42-52 connect that schema to the reproduced CLI workflow.

An absent field property cannot equal any accepted nonempty string. This general conclusion comes from the producer and resolver, not an exhaustive runtime enumeration. Request-field relations can carry a field property, but those relations are not boundary nodes. Dropping the seed from the schema and documentation would remove the advertised capability rather than restore it.

Additional context

P2 impact is supported because a documented lookup variant is unusable for analyzer-produced boundaries, with a demonstrated safe workaround through exact semantic-node IDs. The defect is bounded lookup behavior and does not corrupt the retained graph.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3170 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior The supported `trace-javascript-semantics` CLI accepts the documented `boundary-field` seed but cannot use it to select a boundary recovered by `analyze-javascript-application`. An inert application containing `const port = Number(process.env.PORT);` produces one boundary node with properties `{ "boundary_kind": "coerce", "method": "Number" }`. With the analyzer's unchanged application Evidence, queries for `Number`, `coerce`, `PORT`, `method`, `boundary_kind`, and `missing-field` each exit 0 and return `status: "partial"`, `seed_node_ids: []`, and `total_seed_matches: 0`. An exact `semantic-node` seed for that same recovered boundary exits 0 and returns `status: "found"` with one seed match. The partial query status reflects incomplete static coverage and is not the defect reported here. ### Reproduction 1. From a clean checkout of the stated baseline, install the locked dependencies and build the CLI. The verifier reproduced the commands with already-installed dependencies and a prepared build; the clean-checkout install and build commands were not independently rerun. ```sh npm ci npm run build:cached mkdir -p repro-boundary-field/home/config repro-boundary-field/home/cache repro-boundary-field/home/data repro_home="$(pwd)/repro-boundary-field/home" ``` 2. Create a local fixture and analyze it. ```sh mkdir -p repro-boundary-field/sample-app cat > repro-boundary-field/sample-app/package.json <<'JSON' {"name":"sample-app","version":"1.0.0","main":"main.js"} JSON cat > repro-boundary-field/sample-app/main.js <<'JS' const port = Number(process.env.PORT); JS env HOME="$repro_home" XDG_CONFIG_HOME="$repro_home/config" XDG_CACHE_HOME="$repro_home/cache" XDG_DATA_HOME="$repro_home/data" \ node scripts/rea.mjs analyze-javascript-application ./repro-boundary-field/sample-app --format json > repro-boundary-field/application.json ``` 3. Save and run this comparison script. It reads the analyzer's unchanged Evidence, prints the recovered boundary properties, writes complete trace requests, invokes the supported CLI, and prints the matching result for each seed. ```sh cat > repro-boundary-field/compare.mjs <<'JS' import { readFileSync, writeFileSync } from 'node:fs'; import { spawnSync } from 'node:child_process'; const root = 'repro-boundary-field'; const application = JSON.parse(readFileSync(`${root}/application.json`, 'utf8')); const boundaries = application.normalized_result.semantic_graph.nodes.filter( node => node.kind === 'boundary' ); if (boundaries.length !== 1) throw new Error('Expected one recovered boundary'); const boundary = boundaries[0]; console.log(JSON.stringify({ boundary_properties: boundary.properties })); const seeds = ['Number', 'coerce', 'PORT', 'method', 'boundary_kind', 'missing-field'] .map(field => ({ kind: 'boundary-field', field })); seeds.push({ kind: 'semantic-node', node_id: boundary.node_id }); for (const [index, seed] of seeds.entries()) { const inputPath = `${root}/trace-${index}.json`; writeFileSync(inputPath, JSON.stringify({ application, query: { seed, direction: 'forward-influence' } })); const run = spawnSync(process.execPath, [ 'scripts/rea.mjs', 'trace-javascript-semantics', inputPath, '--format', 'json' ], { encoding: 'utf8' }); if (run.status !== 0) throw new Error(run.stderr || run.stdout); const result = JSON.parse(run.stdout).normalized_result; console.log(JSON.stringify({ seed, exit_code: run.status, status: result.status, seed_node_ids: result.seed_node_ids, total_seed_matches: result.summary.total_seed_matches })); } JS env HOME="$repro_home" XDG_CONFIG_HOME="$repro_home/config" XDG_CACHE_HOME="$repro_home/cache" XDG_DATA_HOME="$repro_home/data" \ node repro-boundary-field/compare.mjs ``` ### Expected behavior `docs/javascript-application-workflows.md:60-66` documents boundary fields as supported semantic trace seeds over authenticated application Evidence and promises every matching seed and its reachable subgraph. Analyzer-produced boundaries must expose an applicable field identity so this seed variant can select a recovered boundary. The contract does not define whether that identity is a method name, a coercion kind, or another value. This report leaves that mapping open. The requirement is that the documented variant be usable for a supported recovered boundary rather than fail for every accepted string. ### Impact and scope Callers cannot start traces of analyzer-produced boundaries through the advertised boundary-field seed. They must inspect the retained semantic graph and supply exact node IDs. The exact-node workaround selected the same recovered boundary from the same unchanged Evidence with one match. The observed CLI failure concerns seed lookup. Source inspection establishes the broader scope for analyzer-produced boundary nodes because their constructor never supplies the field property required by the resolver. This does not claim that a separately constructed graph carrying that property could never match. The retained graph remains available; this reproduction does not establish a security-boundary violation. ### REA version 6.4.0 (main at 58300885207133422af235e0f2b10658cf958b03) ### Runtime and platform Node.js 26.10.0; Darwin 27.0.0 arm64. A repeat with Node.js 24.21.0 reproduced the Number and missing-field results and the successful exact-node control. The repository's exact .nvmrc runtime, 24.18.0, was not used. ### Target and artifact context An inert extracted JavaScript application directory containing the inline package.json and main.js inputs above. Analysis returned direct authenticated application Evidence containing a semantic graph with one boundary node. No application code or external analysis engine was executed. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The excerpt shows the boundary properties, one failed boundary-field seed, and the exact-node control from the same application Evidence. The other five tested boundary-field strings also returned zero matches. ```text {"boundary_properties":{"boundary_kind":"coerce","method":"Number"}} {"seed":{"kind":"boundary-field","field":"Number"},"exit_code":0,"status":"partial","seed_node_ids":[],"total_seed_matches":0} {"seed":{"kind":"semantic-node","node_id":"jsrg_node_3be4222d83d56910dd7ea61e913c13451b8428a740125dc0a1b739564223e77e"},"exit_code":0,"status":"found","seed_node_ids":["jsrg_node_3be4222d83d56910dd7ea61e913c13451b8428a740125dc0a1b739564223e77e"],"total_seed_matches":1} ``` ### Typed outcome or recovery expected A trace using the supported boundary-field identity for this recovered boundary should include that boundary in `seed_node_ids` and report one seed match. An absent field should still return zero matches. The exact-node seed should continue to select the same boundary from unchanged Evidence. Preserve graph authentication, partial coverage, and static-analysis uncertainty. ### Analysis or suspected cause Source-derived reasoning at the reported baseline: - `src/domain/javascript/javascriptSemanticQueryIdentity.ts:94` requires `node.kind === "boundary"` and `node.properties.field === seed.field`. - `src/application/javascript/JavaScriptSemanticGraphDataProjection.ts:250-268` constructs boundary nodes with only `boundary_kind` and `method` in their properties. - `src/application/javascript/JavaScriptSemanticGraphConstruction.ts:104-127` preserves the supplied properties unchanged. - `src/domain/javascript/javascriptSemanticQuerySchemas.ts:54-57` accepts a nonempty string for the boundary-field seed. `src/domain/javascript/javascriptSemanticTraceSchemas.ts:13-16` and `src/cli/applicationCommands.ts:42-52` connect that schema to the reproduced CLI workflow. An absent field property cannot equal any accepted nonempty string. This general conclusion comes from the producer and resolver, not an exhaustive runtime enumeration. Request-field relations can carry a field property, but those relations are not boundary nodes. Dropping the seed from the schema and documentation would remove the advertised capability rather than restore it. ### Additional context P2 impact is supported because a documented lookup variant is unusable for analyzer-produced boundaries, with a demonstrated safe workaround through exact semantic-node IDs. The defect is bounded lookup behavior and does not corrupt the retained graph.
bsakaguchi 2026-10-15 18:31:08 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Delivered on main in fffb07419.

The semantic graph producer stored a boundary method in a field different from the one its query consumer reads. The producer now emits the existing canonical boundary field.

Validation: Graph builder selection regression, including the missing-field negative control. Full exact-revision qualification passed.

<!-- gh-comment-id:6177600775 --> @morluto commented on GitHub (Oct 14, 2026): Delivered on main in [fffb07419](https://github.com/morluto/rea/commit/fffb0741936067530d1ce9777461cd53e87398c2). The semantic graph producer stored a boundary method in a field different from the one its query consumer reads. The producer now emits the existing canonical boundary field. Validation: Graph builder selection regression, including the missing-field negative control. Full exact-revision [qualification](https://github.com/morluto/rea/actions/runs/38629313022) passed.
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#1110
No description provided.