[GH-ISSUE #3311] [Bug] GraphQL operation literals disappear from body objects with locationOffset #1184

Closed
opened 2026-10-15 18:31:49 +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/3311

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

analyze-javascript-application drops a named GraphQL operation literal when the literal is an object's body property and the same object has a locationOffset property. The input contains no precompiled document or second operation observation to deduplicate. The endpoint inventory becomes empty with complete graph coverage and no parse failure. Removing only locationOffset restores the expected operation candidate.

Both analysis commands in the reproduction exited successfully. The results came from compiled CLI analysis of the inline local files. Local verification reproduced the omission with a complete reproduction.

Reproduction

  1. Start from a clean checkout of https://github.com/morluto/rea and select the source baseline. Run the commands below from the repository root.
git checkout --detach 8dde6370d0809ad04cda3342d4e6f290f48aa063
npm ci
npm run build:cached
  1. Create the affected source and a control that removes only locationOffset.
mkdir -p graphql-case/app graphql-case/control
cat > graphql-case/app/app.js <<'EOF'
const source = {
  body: 'query GetUser { user { id } }',
  locationOffset: { line: 1, column: 1 }
};
EOF
cat > graphql-case/control/app.js <<'EOF'
const source = {
  body: 'query GetUser { user { id } }'
};
EOF
  1. Analyze both directories and select their endpoint properties, graph coverage, and parse-failure counts.
node scripts/rea.mjs analyze-javascript-application "$PWD/graphql-case/app" --json > graphql-case/actual.json
node scripts/rea.mjs analyze-javascript-application "$PWD/graphql-case/control" --json > graphql-case/control.json
node --input-type=module <<'EOF'
import { readFileSync } from 'node:fs';
for (const file of ['actual', 'control']) {
  const result = JSON.parse(readFileSync(`graphql-case/${file}.json`, 'utf8')).normalized_result;
  console.log(JSON.stringify({
    file,
    endpoints: result.graph.nodes.filter(node => node.kind === 'endpoint').flatMap(node => node.observations.map(item => item.properties)),
    coverage: result.graph.coverage.status,
    parse_failures: result.statistics.parse_failures
  }));
}
EOF
  1. Observe that the affected source has no endpoint while the control contains GetUser with mechanism graphql:query. Both report complete graph coverage and zero parse failures. The input is valid JavaScript with one literal named GraphQL operation at the start of body; it contains no OperationDefinition object, document wrapper, or repeated operation literal.

Expected behavior

The application graph should contain one network endpoint candidate with value: "GetUser" and mechanism: "graphql:query" in both cases. docs/javascript-artifact-reconstruction.md:269 documents named GraphQL operations at the start of string or cooked-template literals and duplicate suppression for a precompiled graphql-tag loc.source.body copy. That duplicate suppression should not remove the only operation occurrence in a standalone source object.

Impact and scope

Impact level: P2. The assessment is supported by the reproduced omission. A supported literal operation disappears from the endpoint inventory when ordinary source-location metadata is present. The complete-coverage result provides no endpoint candidate for that operation, which makes the RPC inventory incomplete for affected inputs. The operation remains in the source string, and the analysis reports no parse failure or incomplete graph coverage for its omission.

Workaround status: available. The original source and its literal remain available. Callers can inspect the retained semantic string literal or the original source to recover the operation name manually. Removing metadata from a copied input reproduces the endpoint, but that control changes the analyzed artifact identity and should not replace Evidence for the original bytes.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js v26.10.0; macOS 27.0.1 arm64.

Target and artifact context

Two local JavaScript source directories containing the inline files above. The source files were analyzed as inert local text; their JavaScript was never executed. The affected file contains one standalone source object with a GraphQL operation string and source-location metadata. The control removes only the metadata property.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The observed selected output was:

{"file":"actual","endpoints":[],"coverage":"complete","parse_failures":0}
{"file":"control","endpoints":[{"endpoint_kind":"network","value":"GetUser","mechanism":"graphql:query"}],"coverage":"complete","parse_failures":0}

Local verification also recorded all 52 tests passing in the focused source test file. src/domain/javascript/javascriptRpcEndpoints.test.ts:425 pins one observation for a precompiled graphql-tag document with a repeated source body; that duplicate fixture includes an OperationDefinition, unlike the affected input.

Typed outcome or recovery expected

Analyze both directories unchanged. Each must return one GetUser network endpoint candidate with graphql:query. Also preserve the existing behavior that a precompiled graphql-tag document and its repeated loc.source.body produce one operation observation rather than two. The existing control in src/domain/javascript/javascriptRpcEndpoints.test.ts:425 distinguishes valid duplicate suppression from removal of the only operation occurrence.

Analysis or suspected cause

Source-derived reasoning: src/domain/javascript/javascriptRpcEndpoints.ts:320 suppresses a string body whenever its containing object has locationOffset, without requiring a precompiled document or another recovered operation. This condition treats the standalone source object as a duplicate source body even though the input has no other operation observation to retain.

Additional context

Related: #2523, closed as completed, concerns GraphQL comments between the operation keyword and name; this reproduction has a comment-free header and instead loses the literal because its containing object has locationOffset.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3311 ### 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 `analyze-javascript-application` drops a named GraphQL operation literal when the literal is an object's `body` property and the same object has a `locationOffset` property. The input contains no precompiled document or second operation observation to deduplicate. The endpoint inventory becomes empty with complete graph coverage and no parse failure. Removing only `locationOffset` restores the expected operation candidate. Both analysis commands in the reproduction exited successfully. The results came from compiled CLI analysis of the inline local files. Local verification reproduced the omission with a complete reproduction. ### Reproduction 1. Start from a clean checkout of `https://github.com/morluto/rea` and select the source baseline. Run the commands below from the repository root. ```sh git checkout --detach 8dde6370d0809ad04cda3342d4e6f290f48aa063 npm ci npm run build:cached ``` 2. Create the affected source and a control that removes only `locationOffset`. ```sh mkdir -p graphql-case/app graphql-case/control cat > graphql-case/app/app.js <<'EOF' const source = { body: 'query GetUser { user { id } }', locationOffset: { line: 1, column: 1 } }; EOF cat > graphql-case/control/app.js <<'EOF' const source = { body: 'query GetUser { user { id } }' }; EOF ``` 3. Analyze both directories and select their endpoint properties, graph coverage, and parse-failure counts. ```sh node scripts/rea.mjs analyze-javascript-application "$PWD/graphql-case/app" --json > graphql-case/actual.json node scripts/rea.mjs analyze-javascript-application "$PWD/graphql-case/control" --json > graphql-case/control.json node --input-type=module <<'EOF' import { readFileSync } from 'node:fs'; for (const file of ['actual', 'control']) { const result = JSON.parse(readFileSync(`graphql-case/${file}.json`, 'utf8')).normalized_result; console.log(JSON.stringify({ file, endpoints: result.graph.nodes.filter(node => node.kind === 'endpoint').flatMap(node => node.observations.map(item => item.properties)), coverage: result.graph.coverage.status, parse_failures: result.statistics.parse_failures })); } EOF ``` 4. Observe that the affected source has no endpoint while the control contains `GetUser` with mechanism `graphql:query`. Both report complete graph coverage and zero parse failures. The input is valid JavaScript with one literal named GraphQL operation at the start of `body`; it contains no `OperationDefinition` object, document wrapper, or repeated operation literal. ### Expected behavior The application graph should contain one network endpoint candidate with `value: "GetUser"` and `mechanism: "graphql:query"` in both cases. `docs/javascript-artifact-reconstruction.md:269` documents named GraphQL operations at the start of string or cooked-template literals and duplicate suppression for a precompiled graphql-tag `loc.source.body` copy. That duplicate suppression should not remove the only operation occurrence in a standalone source object. ### Impact and scope Impact level: P2. The assessment is supported by the reproduced omission. A supported literal operation disappears from the endpoint inventory when ordinary source-location metadata is present. The complete-coverage result provides no endpoint candidate for that operation, which makes the RPC inventory incomplete for affected inputs. The operation remains in the source string, and the analysis reports no parse failure or incomplete graph coverage for its omission. Workaround status: available. The original source and its literal remain available. Callers can inspect the retained semantic string literal or the original source to recover the operation name manually. Removing metadata from a copied input reproduces the endpoint, but that control changes the analyzed artifact identity and should not replace Evidence for the original bytes. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js v26.10.0; macOS 27.0.1 arm64. ### Target and artifact context Two local JavaScript source directories containing the inline files above. The source files were analyzed as inert local text; their JavaScript was never executed. The affected file contains one standalone source object with a GraphQL operation string and source-location metadata. The control removes only the metadata property. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The observed selected output was: ```text {"file":"actual","endpoints":[],"coverage":"complete","parse_failures":0} {"file":"control","endpoints":[{"endpoint_kind":"network","value":"GetUser","mechanism":"graphql:query"}],"coverage":"complete","parse_failures":0} ``` Local verification also recorded all 52 tests passing in the focused source test file. `src/domain/javascript/javascriptRpcEndpoints.test.ts:425` pins one observation for a precompiled graphql-tag document with a repeated source body; that duplicate fixture includes an `OperationDefinition`, unlike the affected input. ### Typed outcome or recovery expected Analyze both directories unchanged. Each must return one `GetUser` network endpoint candidate with `graphql:query`. Also preserve the existing behavior that a precompiled graphql-tag document and its repeated `loc.source.body` produce one operation observation rather than two. The existing control in `src/domain/javascript/javascriptRpcEndpoints.test.ts:425` distinguishes valid duplicate suppression from removal of the only operation occurrence. ### Analysis or suspected cause Source-derived reasoning: `src/domain/javascript/javascriptRpcEndpoints.ts:320` suppresses a string `body` whenever its containing object has `locationOffset`, without requiring a precompiled document or another recovered operation. This condition treats the standalone source object as a duplicate source body even though the input has no other operation observation to retain. ### Additional context Related: [#2523](https://github.com/morluto/rea/issues/2523), closed as completed, concerns GraphQL comments between the operation keyword and name; this reproduction has a comment-free header and instead loses the literal because its containing object has `locationOffset`.
Author
Owner

@CassieFox23 commented on GitHub (Oct 15, 2026):

TL;DR: Confirmed on Linux. Main still has this bug. Adding locationOffset to an object makes REA drop its body GraphQL query; without that property, REA finds the query.

Results

I ran your recipe on main 7d1e4d0e2 (#3778), package version 6.5.0. It is 164 commits after your base 8dde6370d. One commit touched src/domain/javascript/javascriptRpcEndpoints.ts since then: 12b3cdb80. It made the rule cover more body strings, so the omission remains.

I ran both cases on Node 24.18.0 and on Node 26.11.1. Every run exited 0. I printed the same three fields your script prints.

Case Found Coverage Failures Match
body plus locationOffset none complete 0 yes
body only (control) GetUser, graphql:query complete 0 yes

The output matched your report on both Node versions. I found no open pull request that claims to fix this issue.

Not run

  • Your base 8dde6370d (main already reproduces it).
  • The repo test with a precompiled document.
  • macOS and Windows.

Thanks, coygeek, for the exact recipe and the control.

Commands
npm ci
npm run build:cached
# once per case and Node version, fresh HOME each time
env -C /tmp/i3311/main HOME=/tmp/i3311/home/app-n24 \
  XDG_CONFIG_HOME=/tmp/i3311/home/app-n24/config \
  XDG_CACHE_HOME=/tmp/i3311/home/app-n24/cache \
  XDG_DATA_HOME=/tmp/i3311/home/app-n24/data \
  node scripts/rea.mjs analyze-javascript-application \
  /tmp/i3311/work/graphql-case/app --json > actual.json

I wrote the two input files and the selection script as in your steps, with absolute paths.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 24.18.0 (build and runs), 26.11.1 (runs); npm 11.16.0
  • Main / your base: 7d1e4d0e2 / 8dde6370d
  • Other: the box was shared with a benchmark; runs used low priority and a 6 GB memory cap

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6182455934 --> @CassieFox23 commented on GitHub (Oct 15, 2026): **TL;DR:** Confirmed on Linux. Main still has this bug. Adding `locationOffset` to an object makes REA drop its `body` GraphQL query; without that property, REA finds the query. ### Results I ran your recipe on main 7d1e4d0e2 (#3778), package version 6.5.0. It is 164 commits after your base 8dde6370d. One commit touched `src/domain/javascript/javascriptRpcEndpoints.ts` since then: 12b3cdb80. It made the rule cover more `body` strings, so the omission remains. I ran both cases on Node 24.18.0 and on Node 26.11.1. Every run exited 0. I printed the same three fields your script prints. | Case | Found | Coverage | Failures | Match | |---|---|---|---|---| | `body` plus `locationOffset` | none | complete | 0 | yes | | `body` only (control) | `GetUser`, `graphql:query` | complete | 0 | yes | The output matched your report on both Node versions. I found no open pull request that claims to fix this issue. ### Not run - Your base 8dde6370d (main already reproduces it). - The repo test with a precompiled document. - macOS and Windows. Thanks, coygeek, for the exact recipe and the control. <details> <summary>Commands</summary> ```sh npm ci npm run build:cached # once per case and Node version, fresh HOME each time env -C /tmp/i3311/main HOME=/tmp/i3311/home/app-n24 \ XDG_CONFIG_HOME=/tmp/i3311/home/app-n24/config \ XDG_CACHE_HOME=/tmp/i3311/home/app-n24/cache \ XDG_DATA_HOME=/tmp/i3311/home/app-n24/data \ node scripts/rea.mjs analyze-javascript-application \ /tmp/i3311/work/graphql-case/app --json > actual.json ``` I wrote the two input files and the selection script as in your steps, with absolute paths. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 24.18.0 (build and runs), 26.11.1 (runs); npm 11.16.0 - Main / your base: 7d1e4d0e2 / 8dde6370d - Other: the box was shared with a benchmark; runs used low priority and a 6 GB memory cap </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
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#1184
No description provided.