[GH-ISSUE #4226] [Bug] Hopper pre-handshake startup failure causes repeated cleanup errors while session reports idle #1657

Open
opened 2026-10-16 21:08:34 +00:00 by bsakaguchi · 1 comment
Owner

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

Observed behavior

In a real REA 6.5.0 stdio MCP session on macOS arm64, opening a universal Mach-O with Hopper returned target metadata successfully, but the first provider queries never reached bridge readiness. The startup timeout was followed by repeated cleanup_incomplete failures from queries, close_binary, and an explicit open_binary retry.

During the outstanding search, binary_session reported the target open, the Hopper provider selected, analysis activity idle with no queued requests, and provider operation health idle. This did not distinguish a validated target from a provider whose bridge had not become ready.

This is a focused follow-up to #1808 and #2975, with additional context in #3268 and #3269. The failure here occurred before a successful bridge handshake, rather than after a working authenticated bridge exited.

Environment

  • rea-agents 6.5.0, installed npm package; MCP server reports version 6.5.0.
  • macOS, Apple Silicon arm64; exact OS and Node versions were not collected.
  • Hopper selected through REA. Exact Hopper version/license mode was not collected.
  • Target: xpression camera 3.6.6, a universal x86_64/arm64 Mach-O. REA selected and prepared the arm64 slice.
  • Target SHA-256: 8e7d59aee76b98efa42ed88cbfa63f88eb5173f23380bc8f33f8a078202ead20.
  • ARM64 slice length reported by REA: 17,278,880 bytes.
  • No source-level cause or independent minimal reproduction has been established.

Observed sequence

  1. open_binary({"path":"/Applications/xpression camera.app"}) returned successful executable identity metadata.
  2. Procedure/string searches were started. Some early calls were interrupted by the MCP client, so cancellation may be relevant; this was not isolated.
  3. A subsequent non-interrupted search_procedures({"pattern":"subscription","case_sensitive":false}) waited for provider readiness.
  4. While it was outstanding, binary_session reported open:true, Hopper selected, analysis_activity.status:"idle", no active/queued provider requests, and provider_operation_health.state:"idle".
  5. The search and subsequent current_document / list_documents queries returned a startup failure wrapped in cleanup_incomplete.
  6. Explicit close_binary({}) and open_binary({"path":"/Applications/xpression camera.app","provider_id":"hopper"}) retries each took approximately 30 seconds and returned the retained cleanup failure.
  7. A later accessibility inspection found Hopper running with an Untitled standard window. That limited inspection did not establish why the bridge failed or exclude a dialog at the time of startup.
  8. A normal AppleScript quit of the installed Hopper app returned successfully. The next close_binary still returned cleanup_incomplete after approximately 30 seconds.
  9. A subsequent process sample showed that sampled app PID had exited, and a later binary_session reported open:false. Another process named Hopper remained; its role/ownership was not established. A successful reopen was not tested. Permanent deadlock is not claimed.

Relevant error fields

Private runtime paths are replaced with a placeholder.

{
  "code": "cleanup_incomplete",
  "details": {
    "provider_id": "hopper",
    "operation": "open_binary",
    "resources": ["hopper-document", "/tmp/rea-REDACTED"],
    "diagnostics": {
      "primary_error": {
        "code": "provider_timeout",
        "details": {
          "stage": "startup",
          "timeout_ms": 120000,
          "provider_state": "not_started",
          "retry_action": "retry",
          "launcher": {
            "exit_code": 0,
            "signal": null,
            "stdout": {"text": "", "bytes": 0, "retained_bytes": 0},
            "stderr": {"text": "", "bytes": 0, "retained_bytes": 0},
            "output_closed": true,
            "diagnostic_truncated": false
          }
        }
      }
    }
  }
}

Primary message:

REA timed out waiting for Hopper bridge readiness. Hopper may be waiting for a loader or license dialog; inspect its window and the captured launcher outcome before retrying.

Repeated cleanup diagnostics:

hopper-document: authenticated shutdown acknowledgement was not observed
/tmp/rea-REDACTED: Private runtime retained because process or native document closure was not confirmed

Expected behavior / design boundary

  • Preserve lazy target validation if intentional, but expose provider lifecycle separately: not started, starting, ready, failed, and cleanup pending. An outstanding readiness wait should be visible rather than appearing idle with no work.
  • Retain the primary startup diagnostic alongside cleanup status, with actionable recovery guidance for the case where the bridge never authenticated.
  • Define recovery for pre-handshake failure: an acknowledgement from a bridge that never became ready cannot be the only recoverable path. Keep unknown ownership explicit, and release resources only with positive closure/ownership proof. Launcher exit 0 or generic process-name absence is insufficient.
  • Where closure cannot be verified in-band, state the exact manual steps and connection-restart implications.
  • Keep lifecycle recovery in the Hopper adapter and session state in the existing session tools; no new generic reset tool is necessarily required.

Verification requested

Add controlled coverage and a real macOS Hopper check for:

  1. Launcher exits 0, but bridge never registers.
  2. Client cancellation while the bridge is starting.
  3. Native application exits before the first authenticated handshake.
  4. Application remains alive with unknown document ownership (resources must remain retained).
  5. Session telemetry while readiness/cleanup is pending.
  6. Successful close/reopen in the same MCP connection after positive closure proof.

The initial startup cause remains unresolved. This report records the real failure sequence and lifecycle/diagnostic gaps, not a confirmed source-level regression of the #2975 fix.

Originally created by @morluto on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4226 ## Observed behavior In a real REA 6.5.0 stdio MCP session on macOS arm64, opening a universal Mach-O with Hopper returned target metadata successfully, but the first provider queries never reached bridge readiness. The startup timeout was followed by repeated `cleanup_incomplete` failures from queries, `close_binary`, and an explicit `open_binary` retry. During the outstanding search, `binary_session` reported the target open, the Hopper provider selected, analysis activity idle with no queued requests, and provider operation health idle. This did not distinguish a validated target from a provider whose bridge had not become ready. This is a focused follow-up to #1808 and #2975, with additional context in #3268 and #3269. The failure here occurred before a successful bridge handshake, rather than after a working authenticated bridge exited. ## Environment - rea-agents 6.5.0, installed npm package; MCP server reports version 6.5.0. - macOS, Apple Silicon arm64; exact OS and Node versions were not collected. - Hopper selected through REA. Exact Hopper version/license mode was not collected. - Target: xpression camera 3.6.6, a universal x86_64/arm64 Mach-O. REA selected and prepared the arm64 slice. - Target SHA-256: `8e7d59aee76b98efa42ed88cbfa63f88eb5173f23380bc8f33f8a078202ead20`. - ARM64 slice length reported by REA: 17,278,880 bytes. - No source-level cause or independent minimal reproduction has been established. ## Observed sequence 1. `open_binary({"path":"/Applications/xpression camera.app"})` returned successful executable identity metadata. 2. Procedure/string searches were started. Some early calls were interrupted by the MCP client, so cancellation may be relevant; this was not isolated. 3. A subsequent non-interrupted `search_procedures({"pattern":"subscription","case_sensitive":false})` waited for provider readiness. 4. While it was outstanding, `binary_session` reported `open:true`, Hopper selected, `analysis_activity.status:"idle"`, no active/queued provider requests, and `provider_operation_health.state:"idle"`. 5. The search and subsequent `current_document` / `list_documents` queries returned a startup failure wrapped in `cleanup_incomplete`. 6. Explicit `close_binary({})` and `open_binary({"path":"/Applications/xpression camera.app","provider_id":"hopper"})` retries each took approximately 30 seconds and returned the retained cleanup failure. 7. A later accessibility inspection found Hopper running with an `Untitled` standard window. That limited inspection did not establish why the bridge failed or exclude a dialog at the time of startup. 8. A normal AppleScript quit of the installed Hopper app returned successfully. The next `close_binary` still returned `cleanup_incomplete` after approximately 30 seconds. 9. A subsequent process sample showed that sampled app PID had exited, and a later `binary_session` reported `open:false`. Another process named `Hopper` remained; its role/ownership was not established. **A successful reopen was not tested. Permanent deadlock is not claimed.** ## Relevant error fields Private runtime paths are replaced with a placeholder. ```json { "code": "cleanup_incomplete", "details": { "provider_id": "hopper", "operation": "open_binary", "resources": ["hopper-document", "/tmp/rea-REDACTED"], "diagnostics": { "primary_error": { "code": "provider_timeout", "details": { "stage": "startup", "timeout_ms": 120000, "provider_state": "not_started", "retry_action": "retry", "launcher": { "exit_code": 0, "signal": null, "stdout": {"text": "", "bytes": 0, "retained_bytes": 0}, "stderr": {"text": "", "bytes": 0, "retained_bytes": 0}, "output_closed": true, "diagnostic_truncated": false } } } } } } ``` Primary message: > REA timed out waiting for Hopper bridge readiness. Hopper may be waiting for a loader or license dialog; inspect its window and the captured launcher outcome before retrying. Repeated cleanup diagnostics: ```text hopper-document: authenticated shutdown acknowledgement was not observed /tmp/rea-REDACTED: Private runtime retained because process or native document closure was not confirmed ``` ## Expected behavior / design boundary - Preserve lazy target validation if intentional, but expose provider lifecycle separately: not started, starting, ready, failed, and cleanup pending. An outstanding readiness wait should be visible rather than appearing idle with no work. - Retain the primary startup diagnostic alongside cleanup status, with actionable recovery guidance for the case where the bridge never authenticated. - Define recovery for pre-handshake failure: an acknowledgement from a bridge that never became ready cannot be the only recoverable path. Keep unknown ownership explicit, and release resources only with positive closure/ownership proof. Launcher exit 0 or generic process-name absence is insufficient. - Where closure cannot be verified in-band, state the exact manual steps and connection-restart implications. - Keep lifecycle recovery in the Hopper adapter and session state in the existing session tools; no new generic reset tool is necessarily required. ## Verification requested Add controlled coverage and a real macOS Hopper check for: 1. Launcher exits 0, but bridge never registers. 2. Client cancellation while the bridge is starting. 3. Native application exits before the first authenticated handshake. 4. Application remains alive with unknown document ownership (resources must remain retained). 5. Session telemetry while readiness/cleanup is pending. 6. Successful close/reopen in the same MCP connection after positive closure proof. The initial startup cause remains unresolved. This report records the real failure sequence and lifecycle/diagnostic gaps, not a confirmed source-level regression of the #2975 fix.
Author
Owner

@kaoru0822-kitauji commented on GitHub (Oct 17, 2026):

The reported symptoms appear addressed on main by #4238 (0e1f0bf2d, fix(lifecycle): preserve ownership, cancellation, and cleanup outcomes), merged shortly after this report.

Executed on main 3fc007534 (macOS arm64; simulated launcher, not real Hopper): a scratch npm run test:focused control with a HopperClient whose launcher returns external-application with a helper that exits 0, and no bridge ever registering.

  • While waiting: health reports {state: "busy", stage: "launch", retryAction: "wait"} instead of idle, and session status carries cleanup_pending.
  • On startup failure: cleanup_incomplete. The original provider_timeout is preserved (launcher exit_code: 0, output_closed: true) together with a cleanup error marked authenticated_application: "not_observed".
  • Recovery guidance: the remediation tells the user to let Hopper finish and retry close_binary. If no matching bridge appears, it says to manually close the reported document and restart the MCP connection, and notes that a helper exit or open:false does not establish completed cleanup.
  • Later queries: they return the retained failure without relaunching. close() waits the 30 s reconnect window and keeps holding hopper-document and the private runtime root, as required while the application's identity is unknown.

What remains is a scope question, so I am not opening a PR. Without an authenticated bridge REA never observes the Hopper app's identity, so no in-band signal can prove the document closed. Options would be:

  • (a) keep the current behaviour;
  • (b) a new positive-proof mechanism, such as a token-bound bridge "started" marker or withdrawing bootstrap.py before Hopper consumes it;
  • (c) an explicit caller attestation input that releases the hold without restarting the connection.

Separately, health still says retryAction: "retry" while cleanup is blocked; changing that would be a contract decision. Leaving this to a maintainer.

<!-- gh-comment-id:6233223795 --> @kaoru0822-kitauji commented on GitHub (Oct 17, 2026): The reported symptoms appear addressed on main by #4238 (0e1f0bf2d, `fix(lifecycle): preserve ownership, cancellation, and cleanup outcomes`), merged shortly after this report. Executed on main 3fc007534 (macOS arm64; simulated launcher, not real Hopper): a scratch `npm run test:focused` control with a `HopperClient` whose launcher returns `external-application` with a helper that exits 0, and no bridge ever registering. - **While waiting:** health reports `{state: "busy", stage: "launch", retryAction: "wait"}` instead of idle, and session status carries `cleanup_pending`. - **On startup failure:** `cleanup_incomplete`. The original `provider_timeout` is preserved (launcher `exit_code: 0`, `output_closed: true`) together with a cleanup error marked `authenticated_application: "not_observed"`. - **Recovery guidance:** the remediation tells the user to let Hopper finish and retry `close_binary`. If no matching bridge appears, it says to manually close the reported document and restart the MCP connection, and notes that a helper exit or `open:false` does not establish completed cleanup. - **Later queries:** they return the retained failure without relaunching. `close()` waits the 30 s reconnect window and keeps holding `hopper-document` and the private runtime root, as required while the application's identity is unknown. What remains is a scope question, so I am not opening a PR. Without an authenticated bridge REA never observes the Hopper app's identity, so no in-band signal can prove the document closed. Options would be: - **(a)** keep the current behaviour; - **(b)** a new positive-proof mechanism, such as a token-bound bridge "started" marker or withdrawing `bootstrap.py` before Hopper consumes it; - **(c)** an explicit caller attestation input that releases the hold without restarting the connection. Separately, health still says `retryAction: "retry"` while cleanup is blocked; changing that would be a contract decision. Leaving this to a maintainer.
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#1657
No description provided.