[PR #2632] [CLOSED] fix(setup): report the failing package-manager command and its output #5291

Closed
opened 2026-10-31 01:05:30 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2632
Author: @LaT-SKY
Created: 10/13/2026
Status: ❌ Closed

Base: main ← Head: fix/linux-hopper-package-manager-diagnostic


📝 Commits (5)

  • 3986a68 fix(setup): report the failing package-manager command and its output
  • 1a0f50a fix(setup): keep package installation alive while bounding diagnostics
  • d3fbd5a Merge origin/main into fix/linux-hopper-package-manager-diagnostic
  • 7e5a390 fix(setup): preserve final package errors and command arguments
  • b451f61 Merge branch 'main' into fix/linux-hopper-package-manager-diagnostic

📊 Changes

8 files changed (+454 additions, -26 deletions)

View changed files

📝 docs/installation.md (+10 -0)
📝 src/application/LinuxHopper.test.ts (+50 -2)
📝 src/application/LinuxHopper.ts (+82 -21)
📝 src/application/SetupHost.ts (+1 -1)
📝 src/application/SetupInstallFailure.test.ts (+114 -0)
📝 src/application/SetupInstallFailure.ts (+74 -2)
➕ src/process/ExecFileBoundedOutput.test.ts (+50 -0)
➕ src/process/ExecFileBoundedOutput.ts (+73 -0)

📄 Description

Summary

Setup reports one remediation for every failure of the Linux package-manager step: "Allow the system package-manager operation or install the planned Hopper package and Linux runtime dependencies, then rerun rea setup." That advice is wrong whenever the authorization layer succeeded and the package manager itself rejected the package, and the package manager's own output — which says exactly what happened — was discarded.

This PR preserves the failing command and its output and quotes it in the remediation. Failure codes and the reason vocabulary are unchanged. No upstream issue tracks this failure; the reproduction is under "Evidence and regression coverage".

Problem and expected behavior

Smallest trigger: install the official Hopper Arch package on a host whose zlib is provided only through an unversioned compatibility package.

On CachyOS, zlib-ng-compat declares Provides: zlib with no version, so the package's depend = zlib>=1.3 cannot be satisfied by the installed provider (pacman -T 'zlib>=1.3' fails while pacman -T zlib resolves). pacman then resolves the versioned dependency to the conflicting zlib package and asks whether to remove zlib-ng-compat; --noconfirm answers "no", ending the transaction:

:: zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in conflict
error: unresolvable package conflicts detected
error: failed to prepare transaction (conflicting dependencies)

Violated invariant: a setup remediation must describe the failure that occurred, and boundary evidence REA already captured must not be dropped. installSystemPackage caught the execFile rejection and returned a bare false, discarding stdout and stderr; setupInstallFailure then mapped it to authorization advice. In the reported run pkexec had authorized and the same pacman -S step had already installed xorg-xauth and xorg-server-xvfb, so the message named the one thing that had not failed. setupInstallFailure is the only mapping for that reason, so a caller cannot recover the cause elsewhere.

Expected behaviour: setup names the failing command, its exit status, and what it printed, so a rejected package is distinguishable from a refused authorization.

Change and scope

  • installSystemPackage runs each command through the existing execFileOutput helper and, on failure, returns a tagged LinuxPackageInstallOutcome carrying the command, exit status, both streams, and whether output was truncated (bounded at 64 KiB). The previous boolean return discarded all of it.
  • LinuxHopperInstallHost.installPackage and LinuxHopperInstallResult carry that outcome; SetupHost forwards it to setupInstallFailure.
  • setupInstallFailure takes an optional LinuxPackageInstallFailure and, for authorization_or_package_manager, quotes a bounded (400 character), single-line, escape-free excerpt trimmed to a word boundary. The previous wording is kept verbatim when no command output was recorded, so every other reason is untouched.
  • docs/installation.md records the failure mode and what setup now reports.

Intentionally not included: resolving the conflict or bypassing the dependency check (for example pacman --assume-installed). That would give the installer new authority over an unrelated system package and needs its own decision. This change only reports what already happened.

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/application/LinuxHopper.ts owns the package-manager step and now owns its failure detail; src/application/SetupInstallFailure.ts owns remediation wording.
  • Contribution scope fit and linked maintainer decision: ordinary fix within existing boundaries; not applicable. It adds no capability, target execution, injection, or mutation.
  • CLI and MCP/tool-catalog contract: SetupFailureCode and HopperInstallFailureReason are unchanged, so the generated error schema and tool catalog are unaffected. The user-visible remediation text for authorization_or_package_manager_failed changes.
  • Provider, bridge, target-format, or platform compatibility: Linux only. LinuxHopperInstallHost is an internal seam implemented by systemLinuxHopperInstallHost and one test fixture. macOS reasons and result.reason for every other failure are unchanged.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Target selection, authority, upstream behavior, and cleanup details: the package-manager invocation, arguments, and effects are unchanged; no new process or network access is added, and the temporary archive lifecycle is untouched.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible.

  • Documentation or usability only; no target interaction.

The package-manager side effects that setup already performs are unchanged; this diff changes only what REA reports about an already-failing command.

Evidence and regression coverage

  • Tests added or updated: new src/application/SetupInstallFailure.test.ts covers quoting the command, exit status, and output; stripping terminal escapes and newlines; both truncation shapes (word boundary and none); an unavailable exit status with empty output; and the previous wording when no output was recorded. src/application/LinuxHopper.test.ts moves the fixture to the tagged outcome, keeps the reason-classification table exact, and adds a case asserting the failing command and output survive.

  • Base reproduction: on CachyOS x86_64 the verified Arch package (Hopper-6.4.2-Linux-demo.pkg.tar.xz, SHA-1 92d780b61cab38eda95dc4112dee4fbeb0920f46) fails through pkexec pacman -U --noconfirm with the conflict above, while pkexec itself authorizes and the dependency command succeeds.

  • How the regression fails on the base revision: installSystemPackage returns false, so LinuxHopperInstallResult carries no packageFailure and the remediation is the fixed authorization sentence; every new assertion about the command, exit status, and output fails.

  • User-visible CLI/MCP output (real host, modified runtime):
    status: needs_human, code: authorization_or_package_manager_failed, and this
    remediation (the archive path is REA's temporary copy, later removed):

    The system package-manager command failed (pkexec pacman -U --noconfirm
    /tmp/rea-hopper-Djh5Sx/hopper.arch; exit 1); its output: loading packages...
    resolving dependencies... looking for conflicting packages... ::
    zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in conflict. Remove
    zlib-ng-compat? [y/N] :: zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in
    conflict warning: hopper-6.4.2-1 is up to date -- reinstalling error:
    unresolvable package conflicts detected error: failed to prepare transaction
    (conflicting… Resolve the reported problem, grant the authorization the
    command needs, or install the planned Hopper package and Linux runtime
    dependencies manually, then rerun rea setup.
    
  • Remaining proof gaps: the reason vocabulary still does not distinguish authorization from package-manager failure. That separation needs a new reason and SetupFailureCode member; it is deliberately left out of this diagnostics-only change.

Validation performed

  • npx vitest run src/application — 65 files, 799 tests pass, including the new coverage.
  • npm run check:fast — typecheck and lint pass.
  • npx tsc --noEmit -p tsconfig.json — clean.
  • npm run knip — pass.
  • npm run verify:test-discovery — 1023 test files discovered exactly once.
  • npm run verify:architecture-guards — pass across 1287 source files.
  • npm run docs:check — pass, including doc facts, error schema, and licenses.
  • npx oxfmt --check on the changed files — clean.
  • Real host (CachyOS, Arch family): node scripts/rea.mjs setup --yes --client codex --install-hopper — reports the failing command and pacman's conflict output; exit 1, status: needs_human, code: authorization_or_package_manager_failed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. No exported type is removed; the only signature changes are LinuxHopperInstallHost.installPackage's return type and the optional second parameter of setupInstallFailure, both internal to src/application. One failure code's remediation wording changes.
  • Real Hopper/Ghidra, browser, or OS coverage: CachyOS x86_64 only. macOS Hopper setup and a successful Linux package-manager install were not exercised by this change.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: the quoted excerpt is bounded and strips terminal escapes and control characters, and stdout/stderr stay separate rather than asserting an interleaved order that execFile cannot recover. No credentials are involved; package-manager output is not otherwise redacted, matching existing rea doctor reporting.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

Summary by CodeRabbit

  • Bug Fixes

    • Linux setup now reports the failed package-manager command, exit status, and a concise output excerpt when installation fails.
    • CachyOS setup guidance explains how to resolve the zlib package conflict and retry installation.
  • Documentation

    • Updated Linux installation troubleshooting steps, including options for resolving package conflicts or installing Hopper’s official package manually.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2632 **Author:** [@LaT-SKY](https://github.com/LaT-SKY) **Created:** 10/13/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/linux-hopper-package-manager-diagnostic` --- ### 📝 Commits (5) - [`3986a68`](https://github.com/morluto/rea/commit/3986a682f06c27ee2c9a0010c125430e419c311e) fix(setup): report the failing package-manager command and its output - [`1a0f50a`](https://github.com/morluto/rea/commit/1a0f50ac9f2b952ef8a51f7324822f890860da5e) fix(setup): keep package installation alive while bounding diagnostics - [`d3fbd5a`](https://github.com/morluto/rea/commit/d3fbd5ab20240427f9a8ac99708ba89ee42ffc78) Merge origin/main into fix/linux-hopper-package-manager-diagnostic - [`7e5a390`](https://github.com/morluto/rea/commit/7e5a39030a0e332dea6ade6192e416494a6cf5e3) fix(setup): preserve final package errors and command arguments - [`b451f61`](https://github.com/morluto/rea/commit/b451f618763ed2a38441c7a59728aeddb0ca1564) Merge branch 'main' into fix/linux-hopper-package-manager-diagnostic ### 📊 Changes **8 files changed** (+454 additions, -26 deletions) <details> <summary>View changed files</summary> 📝 `docs/installation.md` (+10 -0) 📝 `src/application/LinuxHopper.test.ts` (+50 -2) 📝 `src/application/LinuxHopper.ts` (+82 -21) 📝 `src/application/SetupHost.ts` (+1 -1) 📝 `src/application/SetupInstallFailure.test.ts` (+114 -0) 📝 `src/application/SetupInstallFailure.ts` (+74 -2) ➕ `src/process/ExecFileBoundedOutput.test.ts` (+50 -0) ➕ `src/process/ExecFileBoundedOutput.ts` (+73 -0) </details> ### 📄 Description ## Summary Setup reports one remediation for every failure of the Linux package-manager step: "Allow the system package-manager operation or install the planned Hopper package and Linux runtime dependencies, then rerun rea setup." That advice is wrong whenever the authorization layer succeeded and the package manager itself rejected the package, and the package manager's own output — which says exactly what happened — was discarded. This PR preserves the failing command and its output and quotes it in the remediation. Failure codes and the reason vocabulary are unchanged. No upstream issue tracks this failure; the reproduction is under "Evidence and regression coverage". ## Problem and expected behavior Smallest trigger: install the official Hopper Arch package on a host whose `zlib` is provided only through an unversioned compatibility package. On CachyOS, `zlib-ng-compat` declares `Provides: zlib` with no version, so the package's `depend = zlib>=1.3` cannot be satisfied by the installed provider (`pacman -T 'zlib>=1.3'` fails while `pacman -T zlib` resolves). pacman then resolves the versioned dependency to the conflicting `zlib` package and asks whether to remove `zlib-ng-compat`; `--noconfirm` answers "no", ending the transaction: ``` :: zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in conflict error: unresolvable package conflicts detected error: failed to prepare transaction (conflicting dependencies) ``` Violated invariant: a setup remediation must describe the failure that occurred, and boundary evidence REA already captured must not be dropped. `installSystemPackage` caught the `execFile` rejection and returned a bare `false`, discarding `stdout` and `stderr`; `setupInstallFailure` then mapped it to authorization advice. In the reported run `pkexec` had authorized and the same `pacman -S` step had already installed `xorg-xauth` and `xorg-server-xvfb`, so the message named the one thing that had not failed. `setupInstallFailure` is the only mapping for that reason, so a caller cannot recover the cause elsewhere. Expected behaviour: setup names the failing command, its exit status, and what it printed, so a rejected package is distinguishable from a refused authorization. ## Change and scope - `installSystemPackage` runs each command through the existing `execFileOutput` helper and, on failure, returns a tagged `LinuxPackageInstallOutcome` carrying the command, exit status, both streams, and whether output was truncated (bounded at 64 KiB). The previous boolean return discarded all of it. - `LinuxHopperInstallHost.installPackage` and `LinuxHopperInstallResult` carry that outcome; `SetupHost` forwards it to `setupInstallFailure`. - `setupInstallFailure` takes an optional `LinuxPackageInstallFailure` and, for `authorization_or_package_manager`, quotes a bounded (400 character), single-line, escape-free excerpt trimmed to a word boundary. The previous wording is kept verbatim when no command output was recorded, so every other reason is untouched. - `docs/installation.md` records the failure mode and what setup now reports. Intentionally not included: resolving the conflict or bypassing the dependency check (for example `pacman --assume-installed`). That would give the installer new authority over an unrelated system package and needs its own decision. This change only reports what already happened. ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/application/LinuxHopper.ts` owns the package-manager step and now owns its failure detail; `src/application/SetupInstallFailure.ts` owns remediation wording. - Contribution scope fit and linked maintainer decision: ordinary fix within existing boundaries; not applicable. It adds no capability, target execution, injection, or mutation. - CLI and MCP/tool-catalog contract: `SetupFailureCode` and `HopperInstallFailureReason` are unchanged, so the generated error schema and tool catalog are unaffected. The user-visible remediation text for `authorization_or_package_manager_failed` changes. - Provider, bridge, target-format, or platform compatibility: Linux only. `LinuxHopperInstallHost` is an internal seam implemented by `systemLinuxHopperInstallHost` and one test fixture. macOS reasons and `result.reason` for every other failure are unchanged. - Evidence, artifact, provenance, or reconstruction contract: none. - Target selection, authority, upstream behavior, and cleanup details: the package-manager invocation, arguments, and effects are unchanged; no new process or network access is added, and the temporary archive lifecycle is untouched. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Documentation or usability only; no target interaction. The package-manager side effects that setup already performs are unchanged; this diff changes only what REA reports about an already-failing command. ## Evidence and regression coverage - Tests added or updated: new `src/application/SetupInstallFailure.test.ts` covers quoting the command, exit status, and output; stripping terminal escapes and newlines; both truncation shapes (word boundary and none); an unavailable exit status with empty output; and the previous wording when no output was recorded. `src/application/LinuxHopper.test.ts` moves the fixture to the tagged outcome, keeps the reason-classification table exact, and adds a case asserting the failing command and output survive. - Base reproduction: on CachyOS x86_64 the verified Arch package (`Hopper-6.4.2-Linux-demo.pkg.tar.xz`, `SHA-1 92d780b61cab38eda95dc4112dee4fbeb0920f46`) fails through `pkexec pacman -U --noconfirm` with the conflict above, while `pkexec` itself authorizes and the dependency command succeeds. - How the regression fails on the base revision: `installSystemPackage` returns `false`, so `LinuxHopperInstallResult` carries no `packageFailure` and the remediation is the fixed authorization sentence; every new assertion about the command, exit status, and output fails. - User-visible CLI/MCP output (real host, modified runtime): `status: needs_human`, `code: authorization_or_package_manager_failed`, and this remediation (the archive path is REA's temporary copy, later removed): ``` The system package-manager command failed (pkexec pacman -U --noconfirm /tmp/rea-hopper-Djh5Sx/hopper.arch; exit 1); its output: loading packages... resolving dependencies... looking for conflicting packages... :: zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in conflict. Remove zlib-ng-compat? [y/N] :: zlib-1:1.3.2-3.1 and zlib-ng-compat-2.3.3-2 are in conflict warning: hopper-6.4.2-1 is up to date -- reinstalling error: unresolvable package conflicts detected error: failed to prepare transaction (conflicting… Resolve the reported problem, grant the authorization the command needs, or install the planned Hopper package and Linux runtime dependencies manually, then rerun rea setup. ``` - Remaining proof gaps: the reason vocabulary still does not distinguish authorization from package-manager failure. That separation needs a new reason and `SetupFailureCode` member; it is deliberately left out of this diagnostics-only change. ## Validation performed - `npx vitest run src/application` — 65 files, 799 tests pass, including the new coverage. - `npm run check:fast` — typecheck and lint pass. - `npx tsc --noEmit -p tsconfig.json` — clean. - `npm run knip` — pass. - `npm run verify:test-discovery` — 1023 test files discovered exactly once. - `npm run verify:architecture-guards` — pass across 1287 source files. - `npm run docs:check` — pass, including doc facts, error schema, and licenses. - `npx oxfmt --check` on the changed files — clean. - Real host (CachyOS, Arch family): `node scripts/rea.mjs setup --yes --client codex --install-hopper` — reports the failing command and pacman's conflict output; exit 1, `status: needs_human`, `code: authorization_or_package_manager_failed`. ## Compatibility, safety, and release - Breaking changes or migration steps: none. No exported type is removed; the only signature changes are `LinuxHopperInstallHost.installPackage`'s return type and the optional second parameter of `setupInstallFailure`, both internal to `src/application`. One failure code's remediation wording changes. - Real Hopper/Ghidra, browser, or OS coverage: CachyOS x86_64 only. macOS Hopper setup and a successful Linux package-manager install were not exercised by this change. - Package or release metadata impact: none. - Security, privacy, process, or containment review: the quoted excerpt is bounded and strips terminal escapes and control characters, and stdout/stderr stay separate rather than asserting an interleaved order that `execFile` cannot recover. No credentials are involved; package-manager output is not otherwise redacted, matching existing `rea doctor` reporting. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Linux setup now reports the failed package-manager command, exit status, and a concise output excerpt when installation fails. * CachyOS setup guidance explains how to resolve the `zlib` package conflict and retry installation. * **Documentation** * Updated Linux installation troubleshooting steps, including options for resolving package conflicts or installing Hopper’s official package manually. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:30 +00:00
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#5291
No description provided.