[GH-ISSUE #262] Doctor should detect broken and ambiguous Node runtime installations #151

Closed
opened 2026-10-15 18:21:42 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Jul 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/262

Problem

rea doctor can report the active Node runtime as healthy while another
installed Node/npm toolchain that an agent or REA-adjacent workflow can resolve
is dynamically broken. The resulting failure looks like an analysis/build
failure even though it is host-runtime drift.

Observed while running a local reconstruction verifier:

dyld: Library not loaded: /opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib
  Referenced from: /opt/homebrew/Cellar/node/25.2.1/bin/node
  Reason: tried ... libsimdjson.29.dylib (no such file)

The machine has two Node/npm installations:

$ which -a node npm
/Users/will/.nvm/versions/node/v25.1.0/bin/node
/opt/homebrew/bin/node
/Users/will/.nvm/versions/node/v25.1.0/bin/npm
/opt/homebrew/bin/npm

The active interactive runtime is healthy:

$ node --version
v25.1.0

The Homebrew runtime is not executable:

$ /opt/homebrew/bin/node --version
dyld: Library not loaded: /opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib

Its linkage expects ABI 29:

$ otool -L /opt/homebrew/Cellar/node/25.2.1/bin/node | grep simdjson
/opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib

The linked Homebrew simdjson keg provides ABI 33 instead:

libsimdjson.33.0.0.dylib
libsimdjson.33.dylib -> libsimdjson.33.0.0.dylib
libsimdjson.dylib -> libsimdjson.33.dylib

Homebrew metadata reports bottled Node 25.2.1 and linked simdjson 4.6.4. This
issue does not claim REA caused that package mismatch. It asks REA to make
the host-runtime ambiguity and unusable candidate actionable before a long
analysis or verifier run.

Why REA should surface this

  • REA and its agent workflows launch Node CLIs, npm/npx commands, fixture
    processes, and generated verification scripts.
  • #!/usr/bin/env node resolves according to the environment at the actual
    spawn site, which may differ from the shell used to run rea doctor.
  • Package-manager scripts can alter PATH, so checking only the first node
    does not prove every resolved runtime is usable.
  • A dynamic-loader failure is deterministic and cheap to detect.
  • Agents need to know which exact runtime REA will use and which duplicate
    candidates are broken; otherwise they may attempt unrelated source repairs.

Requested behavior

1. Report exact runtime identity

Extend rea doctor identity output with at least:

Active Node: /Users/.../.nvm/.../bin/node (v25.1.0) healthy
REA launcher Node: /path/resolved/by/rea healthy
Active npm: /Users/.../.nvm/.../bin/npm (11.6.2) healthy

Do not report only a version. Preserve canonical executable paths and explain
whether REA is a native binary, shell wrapper, or Node shebang launch.

2. Detect ambiguous duplicate toolchains

When multiple node, npm, or npx candidates are visible, report them as a
diagnostic inventory. Probe each bounded candidate with --version and retain:

  • lexical and canonical path;
  • version when runnable;
  • exit/signal/loader-failure classification;
  • whether it can be selected by REA, subprocesses, or package scripts;
  • remediation scoped to the failing installation.

Duplicates should be informational when all candidates are healthy and their
selection is unambiguous. A broken selectable candidate should make the host
runtime check degraded or unhealthy.

3. Classify macOS loader failures

Recognize dyld: Library not loaded as a host dependency/linkage failure, not a
REA analysis-provider or target failure. Return safe structured details such as:

{
  "code": "runtime_dynamic_library_missing",
  "category": "host_runtime",
  "executable": "/opt/homebrew/bin/node",
  "dependency": "/opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib",
  "retryable": false,
  "remediation": {
    "action": "Use the healthy Node runtime or repair/reinstall the broken Homebrew Node linkage, then rerun rea doctor."
  }
}

Do not suggest fabricating a compatibility symlink between incompatible ABI
versions.

4. Add a preflight mode for spawned workflows

Provide a bounded diagnostic or reusable library check that verifies the exact
node, npm, npx, and other configured executables a workflow will spawn
under its effective environment. The report should distinguish:

  • current shell resolution;
  • REA server resolution;
  • explicit absolute paths;
  • shebang resolution under the effective PATH;
  • package-script resolution when applicable.

This could be part of a broader rea doctor --workflow <name> or a structured
runtime-preflight operation rather than making the default doctor execute every
package manager.

5. Preserve a safe fallback without hiding drift

When a healthy explicit runtime exists, REA may recommend or accept it for the
current workflow. It must still report the broken candidate and must not mutate
shell profiles, Homebrew packages, NVM selection, or symlinks automatically.

Acceptance criteria

  • Doctor reports canonical path and version for the active and REA-launcher
    Node runtimes.
  • Multiple Node/npm/npx candidates are inventoried with bounded probes.
  • A selectable candidate that fails before main execution is classified as
    a host-runtime failure with captured exit/signal and safe stderr summary.
  • macOS dyld: Library not loaded gets a stable typed diagnostic and names
    the missing dependency.
  • The report distinguishes a broken alternate installation from the healthy
    active runtime; it does not falsely claim all Node support is unavailable.
  • Remediation recommends selecting a verified healthy runtime or repairing
    the package installation and rerunning doctor.
  • REA never creates ABI compatibility symlinks or mutates package managers
    as an automatic repair.
  • Tests cover one healthy runtime, two healthy runtimes, first healthy plus
    second broken, first broken plus second healthy, shebang resolution, and
    a synthetic macOS loader failure.
  • Structured output is stable enough for an agent to select the verified
    runtime without parsing prose.

Environment

  • macOS arm64
  • REA 1.7.0
  • Active Node: NVM 25.1.0
  • Alternate Node: Homebrew 25.2.1
  • Homebrew simdjson linked keg: 4.6.4 / dylib ABI 33
  • Missing ABI requested by Node: 29
Originally created by @morluto on GitHub (Jul 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/262 ## Problem `rea doctor` can report the active Node runtime as healthy while another installed Node/npm toolchain that an agent or REA-adjacent workflow can resolve is dynamically broken. The resulting failure looks like an analysis/build failure even though it is host-runtime drift. Observed while running a local reconstruction verifier: ```text dyld: Library not loaded: /opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib Referenced from: /opt/homebrew/Cellar/node/25.2.1/bin/node Reason: tried ... libsimdjson.29.dylib (no such file) ``` The machine has two Node/npm installations: ```text $ which -a node npm /Users/will/.nvm/versions/node/v25.1.0/bin/node /opt/homebrew/bin/node /Users/will/.nvm/versions/node/v25.1.0/bin/npm /opt/homebrew/bin/npm ``` The active interactive runtime is healthy: ```text $ node --version v25.1.0 ``` The Homebrew runtime is not executable: ```text $ /opt/homebrew/bin/node --version dyld: Library not loaded: /opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib ``` Its linkage expects ABI 29: ```text $ otool -L /opt/homebrew/Cellar/node/25.2.1/bin/node | grep simdjson /opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib ``` The linked Homebrew `simdjson` keg provides ABI 33 instead: ```text libsimdjson.33.0.0.dylib libsimdjson.33.dylib -> libsimdjson.33.0.0.dylib libsimdjson.dylib -> libsimdjson.33.dylib ``` Homebrew metadata reports bottled Node 25.2.1 and linked simdjson 4.6.4. This issue does **not** claim REA caused that package mismatch. It asks REA to make the host-runtime ambiguity and unusable candidate actionable before a long analysis or verifier run. ## Why REA should surface this - REA and its agent workflows launch Node CLIs, npm/npx commands, fixture processes, and generated verification scripts. - `#!/usr/bin/env node` resolves according to the environment at the actual spawn site, which may differ from the shell used to run `rea doctor`. - Package-manager scripts can alter `PATH`, so checking only the first `node` does not prove every resolved runtime is usable. - A dynamic-loader failure is deterministic and cheap to detect. - Agents need to know which exact runtime REA will use and which duplicate candidates are broken; otherwise they may attempt unrelated source repairs. ## Requested behavior ### 1. Report exact runtime identity Extend `rea doctor` identity output with at least: ```text Active Node: /Users/.../.nvm/.../bin/node (v25.1.0) healthy REA launcher Node: /path/resolved/by/rea healthy Active npm: /Users/.../.nvm/.../bin/npm (11.6.2) healthy ``` Do not report only a version. Preserve canonical executable paths and explain whether REA is a native binary, shell wrapper, or Node shebang launch. ### 2. Detect ambiguous duplicate toolchains When multiple `node`, `npm`, or `npx` candidates are visible, report them as a diagnostic inventory. Probe each bounded candidate with `--version` and retain: - lexical and canonical path; - version when runnable; - exit/signal/loader-failure classification; - whether it can be selected by REA, subprocesses, or package scripts; - remediation scoped to the failing installation. Duplicates should be informational when all candidates are healthy and their selection is unambiguous. A broken selectable candidate should make the host runtime check degraded or unhealthy. ### 3. Classify macOS loader failures Recognize `dyld: Library not loaded` as a host dependency/linkage failure, not a REA analysis-provider or target failure. Return safe structured details such as: ```json { "code": "runtime_dynamic_library_missing", "category": "host_runtime", "executable": "/opt/homebrew/bin/node", "dependency": "/opt/homebrew/opt/simdjson/lib/libsimdjson.29.dylib", "retryable": false, "remediation": { "action": "Use the healthy Node runtime or repair/reinstall the broken Homebrew Node linkage, then rerun rea doctor." } } ``` Do not suggest fabricating a compatibility symlink between incompatible ABI versions. ### 4. Add a preflight mode for spawned workflows Provide a bounded diagnostic or reusable library check that verifies the exact `node`, `npm`, `npx`, and other configured executables a workflow will spawn under its effective environment. The report should distinguish: - current shell resolution; - REA server resolution; - explicit absolute paths; - shebang resolution under the effective `PATH`; - package-script resolution when applicable. This could be part of a broader `rea doctor --workflow <name>` or a structured runtime-preflight operation rather than making the default doctor execute every package manager. ### 5. Preserve a safe fallback without hiding drift When a healthy explicit runtime exists, REA may recommend or accept it for the current workflow. It must still report the broken candidate and must not mutate shell profiles, Homebrew packages, NVM selection, or symlinks automatically. ## Acceptance criteria - [ ] Doctor reports canonical path and version for the active and REA-launcher Node runtimes. - [ ] Multiple Node/npm/npx candidates are inventoried with bounded probes. - [ ] A selectable candidate that fails before main execution is classified as a host-runtime failure with captured exit/signal and safe stderr summary. - [ ] macOS `dyld: Library not loaded` gets a stable typed diagnostic and names the missing dependency. - [ ] The report distinguishes a broken alternate installation from the healthy active runtime; it does not falsely claim all Node support is unavailable. - [ ] Remediation recommends selecting a verified healthy runtime or repairing the package installation and rerunning doctor. - [ ] REA never creates ABI compatibility symlinks or mutates package managers as an automatic repair. - [ ] Tests cover one healthy runtime, two healthy runtimes, first healthy plus second broken, first broken plus second healthy, shebang resolution, and a synthetic macOS loader failure. - [ ] Structured output is stable enough for an agent to select the verified runtime without parsing prose. ## Environment - macOS arm64 - REA 1.7.0 - Active Node: NVM 25.1.0 - Alternate Node: Homebrew 25.2.1 - Homebrew simdjson linked keg: 4.6.4 / dylib ABI 33 - Missing ABI requested by Node: 29
bsakaguchi 2026-10-15 18:21:42 +00:00
Author
Owner

@morluto commented on GitHub (Jul 16, 2026):

Closing this host-specific incident report; no REA source defect is established by the package-manager linkage drift alone.

<!-- gh-comment-id:4990030758 --> @morluto commented on GitHub (Jul 16, 2026): Closing this host-specific incident report; no REA source defect is established by the package-manager linkage drift alone.
Author
Owner

@morluto commented on GitHub (Jul 16, 2026):

Reopening now that the report is generalized; ambiguous and broken selectable runtime detection remains a useful diagnostics improvement.

<!-- gh-comment-id:4990044184 --> @morluto commented on GitHub (Jul 16, 2026): Reopening now that the report is generalized; ambiguous and broken selectable runtime detection remains a useful diagnostics improvement.
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#151
No description provided.