[GH-ISSUE #7570] [Bug] Native UI commands hide the reason both capture sources are refused #4508

Open
opened 2026-10-31 00:50:22 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

CLI

Observed behavior

Disabling both native UI capture sources returns a generic input error without saying that at least one source must remain enabled. With a copied Mach-O executable, I ran:

node scripts/rea.mjs observe-native-ui "$target" --pid 1 --window-id 1 \
  --screenshot=false --accessibility=false --format json
node scripts/rea.mjs capture-native-ui-scenario "$target" --pid 1 --window-id 1 \
  --screenshot=false --accessibility=false --format json \
  --steps '[{"kind":"wait","milliseconds":0}]'

Both exited 1 with invalid_request, category invalid_input, and the message Analysis input is invalid. Check the arguments and try again. Neither response contained details or any other explanation of the rejected capture mode. Both instructed the caller to correct “the listed fields,” but listed none.

The two command schemas, read through --schema --json, expose independent screenshot and accessibility booleans defaulting to true. They do not describe a requirement to enable at least one. Re-reading discovery as directed by recovery therefore does not supply the missing correction.

Reproduction

  1. From the built baseline checkout with locked dependencies and Node 24.22.1 on PATH, run the following block. It creates a byte copy of the local system Mach-O, isolates REA's HOME/XDG/runtime directories, runs both commands, and removes its fixtures. The positive PID/window numbers are parser inputs only; the mode refusal precedes native helper invocation.
python3 - <<'PYTHON'
import json, os, pathlib, shutil, subprocess, tempfile

with tempfile.TemporaryDirectory(prefix='native-ui-mode-') as directory:
    work = pathlib.Path(directory).resolve()
    shutil.copyfile('/usr/bin/true', work / 'target')
    for name in ['home', 'config', 'cache', 'data', 'state', 'runtime']:
        (work / name).mkdir()
    env = {'PATH': os.environ['PATH'], 'HOME': str(work / 'home'),
           'XDG_CONFIG_HOME': str(work / 'config'), 'XDG_CACHE_HOME': str(work / 'cache'),
           'XDG_DATA_HOME': str(work / 'data'), 'XDG_STATE_HOME': str(work / 'state'),
           'TMPDIR': str(work / 'runtime')}
    for command in ['observe-native-ui', 'capture-native-ui-scenario']:
        args = ['node', 'scripts/rea.mjs', command, str(work / 'target'),
                '--pid', '1', '--window-id', '1', '--screenshot=false',
                '--accessibility=false', '--format', 'json']
        if command == 'capture-native-ui-scenario':
            args += ['--steps', '[{"kind":"wait","milliseconds":0}]']
        result = subprocess.run(args, env=env, capture_output=True, text=True, timeout=30)
        error = json.loads(result.stdout)
        assert result.returncode == 1 and result.stderr == ''
        assert error['code'] == 'invalid_request' and 'details' not in error
        assert error['message'] == 'Analysis input is invalid. Check the arguments and try again.'
        assert 'Correct the listed fields' in error['remediation']['action']
        print(json.dumps({'command': command, 'exit': result.returncode, 'result': error}))
PYTHON
  1. Observe two exit-1 results with the generic input message and no details. Each command reproduced 2/2 times across an initial independent run and the reduced replay above; the exact block above ran once. No native application, GUI, or deep-analysis provider was launched.

Expected behavior

Continue refusing a request that selects no capture source, while telling the caller to enable screenshot or accessibility capture. Preserve that known refusal reason and make the recovery actionable. Field issues naming the capture options are one suitable representation; a specific user message and correction would also satisfy this expectation.

The repository requires meaningful failure reasons to survive boundaries. The recovery contract directs callers to inspect the input contract and correct listed fields, matching the remediation actually returned by these CLI calls. This report concerns lost correction information, not a requirement for every error to contain details or for every schema-valid request to succeed.

Impact and scope

P2: scripts and agents cannot identify this known mode error or its correction from the response, even after following its schema-inspection advice. The failure is bounded and safely rejects invalid work. Keeping at least one capture source enabled avoids this mode guard by source inspection; a successful capture also needs a valid running application/window and the necessary permissions. Successful capture was not tested.

Observed scope is both CLI commands on this baseline. MCP delivery, other platforms, session-availability effects, and occurrence frequency outside these invocations were not tested. No data loss, capture, scenario action, or target mutation was observed; source inspection places this refusal before the helper call.

REA version

Exact node scripts/rea.mjs --version stdout:

6.8.0

Source baseline: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, build 26A434; darwin arm64. No Hopper, Ghidra, IDA, Swift compiler, or native UI helper version is needed for this pre-helper refusal.

Target and artifact context

Byte copy of /usr/bin/true, identified locally as a universal Mach-O executable with x86_64, arm64e and arm64e.x1 slices. The fixture was never executed. PID 1 and window ID 1 were not asserted to identify a valid application window.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Complete stdout from the passive command, obtained with --format json (exit 1; stderr empty):

{"error":"Analysis failed","code":"invalid_request","category":"invalid_input","message":"Analysis input is invalid. Check the arguments and try again.","retryable":false,"remediation":{"action":"Read the declared input schema or CLI usage for observe_native_ui; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call."},"recovery":{"kind":"inspect_input_contract","operation":"observe_native_ui"}}

The active command returned the same fields, with capture_native_ui_scenario in the remediation and recovery operation. Both omit the known mode reason. Both schemas returned default-true boolean entries for the two sources without a cross-field condition or description of this restriction. The active schema correctly required steps and described one or more decoded steps.

Source evidence at the baseline:

  • AGENTS.md, Architecture and Cleanup: preserve meaningful failure reasons when modeling expected failures.
  • docs/mcp-contracts.md:140–147: input-contract recovery directs correction of listed fields. This paragraph documents MCP; the CLI output above independently demonstrates the same remediation language.
  • src/cli/utilityCommands.ts:100–156: supported public commands forward the selected sources, with decoded scenario-step validation before dispatch.
  • src/domain/native/nativeUiObservation.ts:13–31: the input schema accepts the individual boolean values without the mode constraint.
  • src/native/NativeUiObservation.ts:138–159: after parsing and Mach-O admission, the both-false check knows the correction but puts it only in an error cause. The helper invocation is below the guard.
  • src/native/NativeUiHelperRuntime.ts:26–113: helper compilation and launch are lazy, inside the invocation path.
  • src/domain/analysisErrorCore.ts:108–126, src/domain/analysisErrorProjection.ts:363–379, and src/domain/analysisErrorPresentation.ts:170–175,301–305: absent explicit issues/message/remediation, the cause-only input error becomes the generic diagnostic above.

Typed outcome or recovery expected

Retain the nonzero invalid_request refusal and inspect_input_contract recovery, with an explicit instruction to enable screenshot or accessibility. A consumer should not have to infer that relationship from a generic input failure.

Analysis or suspected cause

Source-derived: the capture-mode admission branch constructs AnalysisInputError with an internal cause but no field issues or user-facing overrides. The shared projector has no issue list to publish, and presentation chooses its generic input message and remediation. The specific correction is lost at the local admission boundary; this does not require treating the shared error projector as globally defective.

Additional context

Duplicate search covered open/closed issues, all PR states, and comments. Related reports have different triggers and closure conditions:

  • #7549 concerns ADB push/install losing the refused local path and missing/nonregular-file reason. Its filesystem admission fix does not cover native capture-source selection.
  • #6466 concerns scenario steps advertised as optional. The current schema requires them, and this reproduction supplies a valid nonempty list.
  • #5306 and PR #5307 concern helper PID/window selection errors and session availability. This request fails earlier and already has the input-error category.
  • PR #854 preserves helper/OS exception diagnostics. Its actual diff changes the later provider-error catch, not this pre-helper mode guard.

No last-known-good revision or regression of a claimed fix was established. The closure signal for this report is that both commands explain the both-disabled mode and its correction while continuing to refuse it before capture.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Both public CLI operations discard a known capture-mode correction and direct callers to nonexistent listed fields; following the advertised schema does not reveal the missing requirement. Invalid work remains safely refused.
  • Workaround status: available
  • Workaround basis: Keep at least one capture source enabled, which avoids the verified both-false guard by source inspection. Successful real capture was not exercised and additionally requires a valid process/window and host permissions.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7570 ### 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 CLI ### Observed behavior Disabling both native UI capture sources returns a generic input error without saying that at least one source must remain enabled. With a copied Mach-O executable, I ran: ```sh node scripts/rea.mjs observe-native-ui "$target" --pid 1 --window-id 1 \ --screenshot=false --accessibility=false --format json node scripts/rea.mjs capture-native-ui-scenario "$target" --pid 1 --window-id 1 \ --screenshot=false --accessibility=false --format json \ --steps '[{"kind":"wait","milliseconds":0}]' ``` Both exited 1 with `invalid_request`, category `invalid_input`, and the message `Analysis input is invalid. Check the arguments and try again.` Neither response contained `details` or any other explanation of the rejected capture mode. Both instructed the caller to correct “the listed fields,” but listed none. The two command schemas, read through `--schema --json`, expose independent `screenshot` and `accessibility` booleans defaulting to true. They do not describe a requirement to enable at least one. Re-reading discovery as directed by recovery therefore does not supply the missing correction. ### Reproduction 1. From the built baseline checkout with locked dependencies and Node 24.22.1 on PATH, run the following block. It creates a byte copy of the local system Mach-O, isolates REA's HOME/XDG/runtime directories, runs both commands, and removes its fixtures. The positive PID/window numbers are parser inputs only; the mode refusal precedes native helper invocation. ```sh python3 - <<'PYTHON' import json, os, pathlib, shutil, subprocess, tempfile with tempfile.TemporaryDirectory(prefix='native-ui-mode-') as directory: work = pathlib.Path(directory).resolve() shutil.copyfile('/usr/bin/true', work / 'target') for name in ['home', 'config', 'cache', 'data', 'state', 'runtime']: (work / name).mkdir() env = {'PATH': os.environ['PATH'], 'HOME': str(work / 'home'), 'XDG_CONFIG_HOME': str(work / 'config'), 'XDG_CACHE_HOME': str(work / 'cache'), 'XDG_DATA_HOME': str(work / 'data'), 'XDG_STATE_HOME': str(work / 'state'), 'TMPDIR': str(work / 'runtime')} for command in ['observe-native-ui', 'capture-native-ui-scenario']: args = ['node', 'scripts/rea.mjs', command, str(work / 'target'), '--pid', '1', '--window-id', '1', '--screenshot=false', '--accessibility=false', '--format', 'json'] if command == 'capture-native-ui-scenario': args += ['--steps', '[{"kind":"wait","milliseconds":0}]'] result = subprocess.run(args, env=env, capture_output=True, text=True, timeout=30) error = json.loads(result.stdout) assert result.returncode == 1 and result.stderr == '' assert error['code'] == 'invalid_request' and 'details' not in error assert error['message'] == 'Analysis input is invalid. Check the arguments and try again.' assert 'Correct the listed fields' in error['remediation']['action'] print(json.dumps({'command': command, 'exit': result.returncode, 'result': error})) PYTHON ``` 2. Observe two exit-1 results with the generic input message and no `details`. Each command reproduced 2/2 times across an initial independent run and the reduced replay above; the exact block above ran once. No native application, GUI, or deep-analysis provider was launched. ### Expected behavior Continue refusing a request that selects no capture source, while telling the caller to enable screenshot or accessibility capture. Preserve that known refusal reason and make the recovery actionable. Field issues naming the capture options are one suitable representation; a specific user message and correction would also satisfy this expectation. The repository requires meaningful failure reasons to survive boundaries. The recovery contract directs callers to inspect the input contract and correct listed fields, matching the remediation actually returned by these CLI calls. This report concerns lost correction information, not a requirement for every error to contain `details` or for every schema-valid request to succeed. ### Impact and scope P2: scripts and agents cannot identify this known mode error or its correction from the response, even after following its schema-inspection advice. The failure is bounded and safely rejects invalid work. Keeping at least one capture source enabled avoids this mode guard by source inspection; a successful capture also needs a valid running application/window and the necessary permissions. Successful capture was not tested. Observed scope is both CLI commands on this baseline. MCP delivery, other platforms, session-availability effects, and occurrence frequency outside these invocations were not tested. No data loss, capture, scenario action, or target mutation was observed; source inspection places this refusal before the helper call. ### REA version Exact `node scripts/rea.mjs --version` stdout: ```text 6.8.0 ``` Source baseline: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node.js v24.22.1; macOS 27.0.1, build 26A434; darwin arm64. No Hopper, Ghidra, IDA, Swift compiler, or native UI helper version is needed for this pre-helper refusal. ### Target and artifact context Byte copy of `/usr/bin/true`, identified locally as a universal Mach-O executable with x86_64, arm64e and arm64e.x1 slices. The fixture was never executed. PID 1 and window ID 1 were not asserted to identify a valid application window. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence Complete stdout from the passive command, obtained with `--format json` (exit 1; stderr empty): ```json {"error":"Analysis failed","code":"invalid_request","category":"invalid_input","message":"Analysis input is invalid. Check the arguments and try again.","retryable":false,"remediation":{"action":"Read the declared input schema or CLI usage for observe_native_ui; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call."},"recovery":{"kind":"inspect_input_contract","operation":"observe_native_ui"}} ``` The active command returned the same fields, with `capture_native_ui_scenario` in the remediation and recovery operation. Both omit the known mode reason. Both schemas returned default-true boolean entries for the two sources without a cross-field condition or description of this restriction. The active schema correctly required `steps` and described one or more decoded steps. Source evidence at the baseline: - `AGENTS.md`, Architecture and Cleanup: preserve meaningful failure reasons when modeling expected failures. - `docs/mcp-contracts.md:140–147`: input-contract recovery directs correction of listed fields. This paragraph documents MCP; the CLI output above independently demonstrates the same remediation language. - `src/cli/utilityCommands.ts:100–156`: supported public commands forward the selected sources, with decoded scenario-step validation before dispatch. - `src/domain/native/nativeUiObservation.ts:13–31`: the input schema accepts the individual boolean values without the mode constraint. - `src/native/NativeUiObservation.ts:138–159`: after parsing and Mach-O admission, the both-false check knows the correction but puts it only in an error cause. The helper invocation is below the guard. - `src/native/NativeUiHelperRuntime.ts:26–113`: helper compilation and launch are lazy, inside the invocation path. - `src/domain/analysisErrorCore.ts:108–126`, `src/domain/analysisErrorProjection.ts:363–379`, and `src/domain/analysisErrorPresentation.ts:170–175,301–305`: absent explicit issues/message/remediation, the cause-only input error becomes the generic diagnostic above. ### Typed outcome or recovery expected Retain the nonzero `invalid_request` refusal and `inspect_input_contract` recovery, with an explicit instruction to enable `screenshot` or `accessibility`. A consumer should not have to infer that relationship from a generic input failure. ### Analysis or suspected cause Source-derived: the capture-mode admission branch constructs `AnalysisInputError` with an internal cause but no field issues or user-facing overrides. The shared projector has no issue list to publish, and presentation chooses its generic input message and remediation. The specific correction is lost at the local admission boundary; this does not require treating the shared error projector as globally defective. ### Additional context Duplicate search covered open/closed issues, all PR states, and comments. Related reports have different triggers and closure conditions: - [#7549](https://github.com/morluto/rea/issues/7549) concerns ADB push/install losing the refused local path and missing/nonregular-file reason. Its filesystem admission fix does not cover native capture-source selection. - [#6466](https://github.com/morluto/rea/issues/6466) concerns scenario steps advertised as optional. The current schema requires them, and this reproduction supplies a valid nonempty list. - [#5306](https://github.com/morluto/rea/issues/5306) and [PR #5307](https://github.com/morluto/rea/pull/5307) concern helper PID/window selection errors and session availability. This request fails earlier and already has the input-error category. - [PR #854](https://github.com/morluto/rea/pull/854) preserves helper/OS exception diagnostics. Its actual diff changes the later provider-error catch, not this pre-helper mode guard. No last-known-good revision or regression of a claimed fix was established. The closure signal for this report is that both commands explain the both-disabled mode and its correction while continuing to refuse it before capture. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Both public CLI operations discard a known capture-mode correction and direct callers to nonexistent listed fields; following the advertised schema does not reveal the missing requirement. Invalid work remains safely refused. - Workaround status: available - Workaround basis: Keep at least one capture source enabled, which avoids the verified both-false guard by source inspection. Successful real capture was not exercised and additionally requires a valid process/window and host permissions.
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#4508
No description provided.