[GH-ISSUE #5623] [Bug] JavaScript application analysis drops the selected path and host resolution reason #3407

Closed
opened 2026-10-31 00:40:02 +00:00 by bsakaguchi · 1 comment
Owner

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

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

node scripts/rea.mjs analyze-javascript-application <selected-path> --format json rejects a 300-character filename component and a two-link symbolic-link cycle with identical complete JSON errors. Neither error identifies the selected path or distinguishes ENAMETOOLONG from ELOOP. Both inputs are correctly refused; the defect is the lost diagnostic context.

Reproduction

An independent verifier executed the following Python 3 recipe from the prepared, built source checkout with the repository-pinned Node.js on PATH. It uses isolated fixtures and configuration directories, requires no external analysis provider, and runs as a non-root user for the permission control. Both application failures reproduced when the verifier replayed this recipe.

import json, os, pathlib, shutil, subprocess, tempfile
root = pathlib.Path(tempfile.mkdtemp(prefix="rea-path-")).resolve()
node = shutil.which("node")
assert node is not None
assert subprocess.check_output([node, "--version"], text=True).strip() == "v24.18.0"
env = {"PATH": os.environ["PATH"], "REA_LOG_LEVEL": "silent",
       "NODE_DISABLE_COMPILE_CACHE": "1"}
for key in ("HOME", "XDG_CONFIG_HOME", "XDG_DATA_HOME",
            "XDG_CACHE_HOME", "XDG_STATE_HOME", "TMPDIR"):
    folder = root / key.lower()
    folder.mkdir()
    env[key] = str(folder)
long_path = root / ("x" * 300)
(root / "loop-a").symlink_to("loop-b")
(root / "loop-b").symlink_to("loop-a")
(root / "readable").mkdir()
(root / "denied").mkdir()
(root / "denied").chmod(0)
results = {}
try:
    cases = [
        ("long", "analyze-javascript-application", long_path),
        ("loop", "analyze-javascript-application", root / "loop-a"),
        ("missing", "analyze-javascript-application", root / "absent"),
        ("readable", "analyze-javascript-application", root / "readable"),
        ("denied", "analyze-javascript-application", root / "denied"),
        ("inspect-long", "inspect-artifact", long_path),
        ("inspect-loop", "inspect-artifact", root / "loop-a"),
    ]
    for label, command, selected in cases:
        args = [node, "scripts/rea.mjs", command, str(selected), "--format", "json"]
        if command == "inspect-artifact":
            args += ["--evidence_output", str(root / (label + ".evidence.json"))]
        result = subprocess.run(args, env=env, capture_output=True,
                                text=True, timeout=60)
        (root / (label + ".stdout")).write_text(result.stdout)
        (root / (label + ".stderr")).write_text(result.stderr)
        data = json.loads(result.stdout)
        results[label] = data
        print(label, "exit", result.returncode,
              "code", data.get("code", "success"), "details", data.get("details"))
finally:
    (root / "denied").chmod(0o700)
print("Identical application errors:", results["long"] == results["loop"])

Both application cases exit 1 and compare equal. The missing-path control returns invalid_request with the selected path and ENOENT; the denied-directory control returns access_denied with its path and EACCES; the readable empty directory succeeds. Both inspect-artifact controls retain the selected path and the respective host reason.

Expected behavior

Continue refusing both unresolvable inputs while preserving the selected path and a meaningful filename-length or symbolic-link-loop reason. AGENTS.md:13,31 requires preserving caller-selected paths and meaningful failure reasons. This does not require accepting either input or choosing a particular replacement code or field layout.

Impact and scope

P3 diagnostic defect on the two tested host-unresolvable selections. Successful analysis remains available for the readable control. No data loss, wrong successful result, or core workflow failure was observed. A verified diagnostic workaround is to retain the selected command input and run inspect-artifact on it, which preserves the host cause and path. MCP, the published package, and other platforms were not executed.

REA version

6.7.0; built source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node.js v24.18.0, matching the repository pin; macOS 27.0.1 build 26A434; arm64. No Hopper/Ghidra provider was involved.

Target and artifact context

Locally generated selections: a 300-character final filename component and loop-a -> loop-b -> loop-a. Controls use a missing selection, a mode-000 directory, and a readable empty directory.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

The independent verifier captured this identical complete stdout JSON for both failing application calls. Progress records go to stderr.

{
  "error": "JavaScript application analysis failed",
  "code": "artifact_operation_failed",
  "category": "execution_failure",
  "message": "Artifact could not be read or written. Check file access and try again.",
  "retryable": false,
  "remediation": {
    "action": "Artifact could not be read or written. Check file access and try again."
  },
  "details": {
    "operation": "analyze_javascript_application",
    "reason": "io"
  }
}

Direct Node.js realpath probes on the same original fixtures independently returned ENAMETOOLONG and ELOOP. The inspect-artifact controls also retained those reasons and their selected paths.

Upstream re-check at 5b676ba9f302228b44c28ab076525abed3e647c1: no post-baseline changes to AGENTS.md, src/cli/electronCommands.ts, src/application/javascript/JavaScriptArtifactReconstruction.ts, or src/application/javascript/JavaScriptApplicationService.ts. Current-main applicability is source-inspected; runtime reproduction was at the baseline above.

Typed outcome or recovery expected

Keep both inputs rejected and make their path and host reason available so callers can distinguish shortening the filename from correcting the looping link. Retain the informative missing/permission failures and successful readable-directory control.

Analysis or suspected cause

Source-derived: resolveSelectedInput in src/application/javascript/JavaScriptArtifactReconstruction.ts:346-372 handles missing and permission errors but rethrows the two tested host errors. src/application/javascript/JavaScriptApplicationService.ts:152-158 recognizes them through FILESYSTEM_ERROR_CODES at :210-223, then constructs an ArtifactOperationError with only reason io.

Additional context

Prepared with AI assistance and independently reproduced. Related #5521 and its open PR #5571 concern misleading target-change wording in artifact commands, which retain the path and ELOOP diagnostic. Merged #1239 handles missing, permission, unsupported-kind, and contradictory-format application selections; merged #847 preserves internal artifact validation details. Closed #623 concerns a large-graph RangeError. These have different triggers and restoration checks.

NOT_ENOUGH_INFO: no last-known-good version or regression range was established.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5623 ### 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 `node scripts/rea.mjs analyze-javascript-application <selected-path> --format json` rejects a 300-character filename component and a two-link symbolic-link cycle with identical complete JSON errors. Neither error identifies the selected path or distinguishes `ENAMETOOLONG` from `ELOOP`. Both inputs are correctly refused; the defect is the lost diagnostic context. ### Reproduction An independent verifier executed the following Python 3 recipe from the prepared, built source checkout with the repository-pinned Node.js on PATH. It uses isolated fixtures and configuration directories, requires no external analysis provider, and runs as a non-root user for the permission control. Both application failures reproduced when the verifier replayed this recipe. ```python import json, os, pathlib, shutil, subprocess, tempfile root = pathlib.Path(tempfile.mkdtemp(prefix="rea-path-")).resolve() node = shutil.which("node") assert node is not None assert subprocess.check_output([node, "--version"], text=True).strip() == "v24.18.0" env = {"PATH": os.environ["PATH"], "REA_LOG_LEVEL": "silent", "NODE_DISABLE_COMPILE_CACHE": "1"} for key in ("HOME", "XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_STATE_HOME", "TMPDIR"): folder = root / key.lower() folder.mkdir() env[key] = str(folder) long_path = root / ("x" * 300) (root / "loop-a").symlink_to("loop-b") (root / "loop-b").symlink_to("loop-a") (root / "readable").mkdir() (root / "denied").mkdir() (root / "denied").chmod(0) results = {} try: cases = [ ("long", "analyze-javascript-application", long_path), ("loop", "analyze-javascript-application", root / "loop-a"), ("missing", "analyze-javascript-application", root / "absent"), ("readable", "analyze-javascript-application", root / "readable"), ("denied", "analyze-javascript-application", root / "denied"), ("inspect-long", "inspect-artifact", long_path), ("inspect-loop", "inspect-artifact", root / "loop-a"), ] for label, command, selected in cases: args = [node, "scripts/rea.mjs", command, str(selected), "--format", "json"] if command == "inspect-artifact": args += ["--evidence_output", str(root / (label + ".evidence.json"))] result = subprocess.run(args, env=env, capture_output=True, text=True, timeout=60) (root / (label + ".stdout")).write_text(result.stdout) (root / (label + ".stderr")).write_text(result.stderr) data = json.loads(result.stdout) results[label] = data print(label, "exit", result.returncode, "code", data.get("code", "success"), "details", data.get("details")) finally: (root / "denied").chmod(0o700) print("Identical application errors:", results["long"] == results["loop"]) ``` Both application cases exit 1 and compare equal. The missing-path control returns `invalid_request` with the selected path and `ENOENT`; the denied-directory control returns `access_denied` with its path and `EACCES`; the readable empty directory succeeds. Both `inspect-artifact` controls retain the selected path and the respective host reason. ### Expected behavior Continue refusing both unresolvable inputs while preserving the selected path and a meaningful filename-length or symbolic-link-loop reason. `AGENTS.md:13,31` requires preserving caller-selected paths and meaningful failure reasons. This does not require accepting either input or choosing a particular replacement code or field layout. ### Impact and scope P3 diagnostic defect on the two tested host-unresolvable selections. Successful analysis remains available for the readable control. No data loss, wrong successful result, or core workflow failure was observed. A verified diagnostic workaround is to retain the selected command input and run `inspect-artifact` on it, which preserves the host cause and path. MCP, the published package, and other platforms were not executed. ### REA version 6.7.0; built source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node.js v24.18.0, matching the repository pin; macOS 27.0.1 build 26A434; arm64. No Hopper/Ghidra provider was involved. ### Target and artifact context Locally generated selections: a 300-character final filename component and `loop-a -> loop-b -> loop-a`. Controls use a missing selection, a mode-000 directory, and a readable empty directory. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence The independent verifier captured this identical complete stdout JSON for both failing application calls. Progress records go to stderr. ```json { "error": "JavaScript application analysis failed", "code": "artifact_operation_failed", "category": "execution_failure", "message": "Artifact could not be read or written. Check file access and try again.", "retryable": false, "remediation": { "action": "Artifact could not be read or written. Check file access and try again." }, "details": { "operation": "analyze_javascript_application", "reason": "io" } } ``` Direct Node.js `realpath` probes on the same original fixtures independently returned `ENAMETOOLONG` and `ELOOP`. The `inspect-artifact` controls also retained those reasons and their selected paths. Upstream re-check at `5b676ba9f302228b44c28ab076525abed3e647c1`: no post-baseline changes to `AGENTS.md`, `src/cli/electronCommands.ts`, `src/application/javascript/JavaScriptArtifactReconstruction.ts`, or `src/application/javascript/JavaScriptApplicationService.ts`. Current-main applicability is source-inspected; runtime reproduction was at the baseline above. ### Typed outcome or recovery expected Keep both inputs rejected and make their path and host reason available so callers can distinguish shortening the filename from correcting the looping link. Retain the informative missing/permission failures and successful readable-directory control. ### Analysis or suspected cause Source-derived: `resolveSelectedInput` in `src/application/javascript/JavaScriptArtifactReconstruction.ts:346-372` handles missing and permission errors but rethrows the two tested host errors. `src/application/javascript/JavaScriptApplicationService.ts:152-158` recognizes them through `FILESYSTEM_ERROR_CODES` at `:210-223`, then constructs an `ArtifactOperationError` with only reason `io`. ### Additional context Prepared with AI assistance and independently reproduced. Related #5521 and its open PR #5571 concern misleading target-change wording in artifact commands, which retain the path and ELOOP diagnostic. Merged #1239 handles missing, permission, unsupported-kind, and contradictory-format application selections; merged #847 preserves internal artifact validation details. Closed #623 concerns a large-graph RangeError. These have different triggers and restoration checks. NOT_ENOUGH_INFO: no last-known-good version or regression range was established.
Author
Owner

@matbrgz commented on GitHub (Oct 20, 2026):

Cross-referencing with canonical issue #5103 (Canonical path resolution strips caller-selected target symlink in evidence) and siblings #5258, #5479, #5492, #5521. Addresses selected path preservation and host resolution reason reporting across path lengths. Cataloged under Cluster X in consolidation tracker #4330.

<!-- gh-comment-id:6297501309 --> @matbrgz commented on GitHub (Oct 20, 2026): Cross-referencing with canonical issue #5103 (`Canonical path resolution strips caller-selected target symlink in evidence`) and siblings #5258, #5479, #5492, #5521. Addresses selected path preservation and host resolution reason reporting across path lengths. Cataloged under Cluster X in consolidation tracker #4330.
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#3407
No description provided.