[GH-ISSUE #7643] [Bug] CLI route-page budget refusal gives MCP discovery advice instead of the supported field selection #4567

Closed
opened 2026-10-31 00:50:51 +00:00 by bsakaguchi · 0 comments
Owner

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

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

After successfully analyzing a generated JavaScript application and saving its complete Evidence, this CLI call refuses a route page containing one oversized path:

node scripts/rea.mjs inspect-analysis-view REQUEST.json --format json

The request uses a local evidence-file source and a javascript-routes / routes view. The error correctly reports the 1,048,576-byte page limit and retryable: false. Its message says to select fewer fields, but remediation.action instead tells the caller to discover records with get_evidence_bundle, inspect them through inspect_analysis_view, and export them with export_evidence_bundle, or use complete CLI JSON. The command already reads a saved parent and uses JSON. Those discovery/export instructions concern an MCP session rather than changing this selected page.

Reducing the page to one row still fails. Selecting only classification and confidence succeeds for the same parent and row. Complete CLI readback of the saved parent also succeeds and preserves the oversized path; it does not raise the view's fixed allowance.

Reproduction

  1. Use the baseline below with its locked dependencies and built runtime prepared, and select Node 24.22.1 on PATH. The verifier used the prepared build without modifying it.
  2. From the checkout root, run this complete inline reproduction. It isolates HOME/XDG/temp state, puts inert package-manager fixtures first on PATH, creates the application, invokes the supported CLI, checks the refusal and both recovery controls, and removes its generated files.
python3 - <<'PYTHON'
import json, os, pathlib, shutil, subprocess, tempfile
root = pathlib.Path.cwd()
node = shutil.which('node')
assert node, 'Select Node 24.22.1 on PATH first'
with tempfile.TemporaryDirectory(prefix='rea-route-check-') as temporary:
    work = pathlib.Path(temporary)
    for name in ['bin', 'app', 'home', 'config', 'cache', 'data', 'state', 'tmp']:
        (work / name).mkdir()
    # Prevent package-manager/provider discovery from invoking real installers.
    for name, version in [('npx', '11.11.0'), ('npm', '11.11.0'), ('bun', '1.3.1')]:
        fixture = work / 'bin' / name
        fixture.write_text('#!/bin/sh\ncase "$1" in --version|-v) echo ' + version + '; exit 0;; esac\nexit 127\n')
        fixture.chmod(0o755)
    env = {'PATH': str(work / 'bin') + os.pathsep + str(pathlib.Path(node).parent) + os.pathsep + os.defpath,
           '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 / 'tmp'),
           'NO_COLOR': '1', 'REA_LOG_LEVEL': 'silent'}
    def call(*args):
        result = subprocess.run([node, 'scripts/rea.mjs', *args], cwd=root, env=env,
                                capture_output=True, text=True, timeout=180)
        return result, json.loads(result.stdout)
    route = '/api/huge/' + 'a' * 1200000
    (work / 'app' / 'package.json').write_text('{"name":"oversized-route","main":"app.js"}\n')
    (work / 'app' / 'app.js').write_text('router.push(' + json.dumps(route) + ');\n')
    bundle = work / 'bundle.json'
    analyzed, _ = call('analyze-javascript-application', str(work / 'app'),
                       '--format', 'json', '--evidence_output', str(bundle))
    assert analyzed.returncode == 0, analyzed.stderr
    parent = json.loads(bundle.read_text())['records'][0]
    assert parent['normalized_result']['route_inventory']['routes'][0]['path'] == route
    print('analysis:', analyzed.returncode, 'route_length:', len(route))
    errors = []
    for label, options in [('wide-1', {}), ('wide-2', {}), ('one-row', {'limit': 1}),
                           ('narrow', {'fields': ['classification', 'confidence']})]:
        request = {'source': {'kind': 'evidence-file', 'path': str(bundle)},
                   'view': {'kind': 'javascript-routes', 'collection': 'routes',
                            'offset': 0, 'limit': 10, **options}}
        request_file = work / (label + '.json')
        request_file.write_text(json.dumps(request))
        result, value = call('inspect-analysis-view', str(request_file), '--format', 'json')
        assert result.stderr == ''
        if label == 'narrow':
            assert result.returncode == 0
            view = value['normalized_result']
            assert view['parent_evidence_id'] == parent['evidence_id']
            assert len(view['items']) == 1 and 'path' not in view['items'][0]
            print(label + ':', result.returncode, json.dumps(view['coverage']))
        else:
            assert result.returncode == 1 and value['code'] == 'resource_constraint'
            assert value['retryable'] is False
            assert value['details']['reported_limits']['limit_bytes'] == 1048576
            errors.append(value)
            print(label + ':', result.returncode, value['code'])
    assert errors[0] == errors[1] == errors[2]
    print('message:', errors[0]['message'])
    print('action:', errors[0]['remediation']['action'])
    complete, output = call('inspect-evidence-bundle', json.dumps({'path': str(bundle)}), '--format', 'json')
    assert complete.returncode == 0
    assert output['records'][0]['normalized_result']['route_inventory']['routes'][0]['path'] == route
    print('complete saved parent:', complete.returncode, 'exact route retained')
PYTHON

The complete inline procedure above ran once successfully. An earlier independent probe also completed analysis, reproduced the default-page and one-row refusals, and passed the narrowed-field control. The complete procedure performs two identical default-page calls and confirms their error documents also match the one-row refusal.

Expected behavior

Keep the intentional refusal, retained parent identity, numeric allowance, and non-retryable classification. The designated recovery action should identify the fixed page-projection budget and give an applicable selection change. For this indivisible path, omitting the path field is a demonstrated way to obtain a smaller view; merely reducing row count cannot help. Clearly distinguish consuming the complete saved parent from making the oversized view fit.

The documented contract distinguishes the shared 1 MiB projection allowance from MCP wire admission and supports fewer fields or complete-parent retrieval. The limits/recovery guide says fixed ceilings must identify their effective value and lack of a runtime override, and directs agents to follow remediation.action for fixed controls. Exact sources are in Evidence below. This report does not assert a general ban on mentioning both CLI and MCP alternatives in shared text.

Impact and scope

P2: the prescribed recovery step for an oversized local route page directs a caller to session-specific discovery/export tools and omits the supported field-selection step from the action agents are told to follow. The failure is bounded to an oversized selected row; no downstream automatic loop or wasted export was measured.

Practical workarounds were observed: follow the error message's field-selection advice, or read the complete saved parent with inspect-evidence-bundle --format json. The latter preserved the exact 1,200,010-character path; the narrow view intentionally omits it. No data loss or source reanalysis was needed for either read. Live MCP behavior, other view kinds and other platforms were not exercised.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0.
Source baseline: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; arm64. Built CLI with the checkout's locked dependencies. The generated JavaScript was parsed as inert source; no external analysis provider or GUI was used. Fixture npx/npm/bun commands answered version probes and refused execution.

Target and artifact context

One application directory with a small package manifest and one router.push(...) call. Its route is /api/huge/ followed by 1,200,000 ASCII characters. The analyzer retained one route row in the saved Evidence bundle.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

Selected output from the exact inline procedure:

analysis: 0 route_length: 1200010
wide-1: 1 resource_constraint
wide-2: 1 resource_constraint
one-row: 1 resource_constraint
narrow: 0 {"status": "page", "examined": 1, "total": 1, "next_offset": null, "exhausted": true}
message: The requested route page cannot fit the analysis-view byte budget; select fewer fields or a smaller selection. The complete parent is retained.
action: Discover retained records with get_evidence_bundle and detail: summary, then inspect compatible records through inspect_analysis_view using an exact Evidence reference. Export complete retained session evidence through export_evidence_bundle to a caller-selected path, or use complete CLI JSON output. The connection remains usable.
complete saved parent: 0 exact route retained

All view calls had empty stderr. The three failed calls returned code and category equal to resource_constraint, retryable: false, details.operation: "inspect_analysis_view", details.resource: "transport", and details.reported_limits.limit_bytes: 1048576. The repeated refusals retained the same parent ID.

Expected-contract sources at the baseline:

  • docs/javascript-route-inventory.md:24-38,65-87 documents CLI saved Evidence, independent page/wire allowances, oversized indivisible rows, field selection, and complete-parent access.
  • docs/design/limits-and-recovery.md:250-280,286-292 requires fixed-limit naming and applicable recovery and tells agents to follow remediation.action for fixed controls.
  • docs/cli.md:572-578 distinguishes connection-local retained references from the complete saved records a separate CLI invocation can consume.

Failure-source locators:

  • src/domain/analysisView/javascriptRoutesView.ts:304-307,396-408,477-503,529-561 defines the fixed page allowance, constructs a transport error without refusal-specific recovery, refuses the first oversized projected row, and supports the demonstrated field selection.
  • src/domain/analysisErrorPresentation.ts:43-48,88-104 supplies the MCP retained-frame fallback when this producer supplies no recovery override.
  • src/cli/analysisViewCommands.ts:77-133 exposes the supported CLI workflow and projects the resulting diagnostic.

Typed outcome or recovery expected

Preserve resource_constraint, retryable: false, the 1 MiB bound and retained parent ID. Put the supported selection remedy in remediation.action, identify this as the fixed projection allowance with no runtime override, and explain full-parent access as an alternative that does not enlarge that allowance. No new error code or structured recovery field is required.

Analysis or suspected cause

Source-derived explanation: the page producer uses resource transport without a producer-owned remediation or fixed-allowance descriptor. Shared presentation therefore interprets the failure as an oversized retained MCP result and supplies that recovery family. The actual admission occurred while forming a local page before output formatting; the complete parent already exists.

Additional context

Duplicate searches covered open/closed issues, their comments, and open/closed/merged PRs. Open #7553 concerns an MCP committed-unknown receipt recommending paging an indivisible head. Correcting that instruction to use same-session export leaves this route-page producer unchanged. Open #7552 concerns oversized MCP unknown listings. #7290 concerns DOL bundle-format admission; #7603 concerns divergent-history imports.

Closed #5459 and merged #5633 fixed a different 96 MiB HAR/network projection accumulator. That producer has fixed-allowance recovery at this baseline. This report concerns the separate 1 MiB route-page producer, so it is not evidence that the closed HAR fix regressed. Closed #6109 concerns a worker checkpoint rejected before retained facts exist. The broader #5910 naming work and merged #6005 concern other response/startup limits; that PR explicitly left analysis-view caps unchanged.

No prior-good route-page revision or first-bad release was established. Both independent analyses exited successfully; the reproduction does not depend on a cleanup failure.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The local CLI page refusal gives same-session MCP discovery/export as its designated recovery action and omits the demonstrated selection change, despite the documented agent recovery contract. The refusal is bounded to oversized selected rows and preserves data.
  • Workaround status: available
  • Workaround basis: The complete inline replay retrieved one field-selected row from the same parent, and complete CLI inspection of the saved bundle recovered the exact oversized path.
Originally created by @coygeek on GitHub (Oct 28, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7643 ### 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 After successfully analyzing a generated JavaScript application and saving its complete Evidence, this CLI call refuses a route page containing one oversized path: ```sh node scripts/rea.mjs inspect-analysis-view REQUEST.json --format json ``` The request uses a local `evidence-file` source and a `javascript-routes` / `routes` view. The error correctly reports the 1,048,576-byte page limit and `retryable: false`. Its message says to select fewer fields, but `remediation.action` instead tells the caller to discover records with `get_evidence_bundle`, inspect them through `inspect_analysis_view`, and export them with `export_evidence_bundle`, or use complete CLI JSON. The command already reads a saved parent and uses JSON. Those discovery/export instructions concern an MCP session rather than changing this selected page. Reducing the page to one row still fails. Selecting only `classification` and `confidence` succeeds for the same parent and row. Complete CLI readback of the saved parent also succeeds and preserves the oversized path; it does not raise the view's fixed allowance. ### Reproduction 1. Use the baseline below with its locked dependencies and built runtime prepared, and select Node 24.22.1 on PATH. The verifier used the prepared build without modifying it. 2. From the checkout root, run this complete inline reproduction. It isolates HOME/XDG/temp state, puts inert package-manager fixtures first on PATH, creates the application, invokes the supported CLI, checks the refusal and both recovery controls, and removes its generated files. ```sh python3 - <<'PYTHON' import json, os, pathlib, shutil, subprocess, tempfile root = pathlib.Path.cwd() node = shutil.which('node') assert node, 'Select Node 24.22.1 on PATH first' with tempfile.TemporaryDirectory(prefix='rea-route-check-') as temporary: work = pathlib.Path(temporary) for name in ['bin', 'app', 'home', 'config', 'cache', 'data', 'state', 'tmp']: (work / name).mkdir() # Prevent package-manager/provider discovery from invoking real installers. for name, version in [('npx', '11.11.0'), ('npm', '11.11.0'), ('bun', '1.3.1')]: fixture = work / 'bin' / name fixture.write_text('#!/bin/sh\ncase "$1" in --version|-v) echo ' + version + '; exit 0;; esac\nexit 127\n') fixture.chmod(0o755) env = {'PATH': str(work / 'bin') + os.pathsep + str(pathlib.Path(node).parent) + os.pathsep + os.defpath, '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 / 'tmp'), 'NO_COLOR': '1', 'REA_LOG_LEVEL': 'silent'} def call(*args): result = subprocess.run([node, 'scripts/rea.mjs', *args], cwd=root, env=env, capture_output=True, text=True, timeout=180) return result, json.loads(result.stdout) route = '/api/huge/' + 'a' * 1200000 (work / 'app' / 'package.json').write_text('{"name":"oversized-route","main":"app.js"}\n') (work / 'app' / 'app.js').write_text('router.push(' + json.dumps(route) + ');\n') bundle = work / 'bundle.json' analyzed, _ = call('analyze-javascript-application', str(work / 'app'), '--format', 'json', '--evidence_output', str(bundle)) assert analyzed.returncode == 0, analyzed.stderr parent = json.loads(bundle.read_text())['records'][0] assert parent['normalized_result']['route_inventory']['routes'][0]['path'] == route print('analysis:', analyzed.returncode, 'route_length:', len(route)) errors = [] for label, options in [('wide-1', {}), ('wide-2', {}), ('one-row', {'limit': 1}), ('narrow', {'fields': ['classification', 'confidence']})]: request = {'source': {'kind': 'evidence-file', 'path': str(bundle)}, 'view': {'kind': 'javascript-routes', 'collection': 'routes', 'offset': 0, 'limit': 10, **options}} request_file = work / (label + '.json') request_file.write_text(json.dumps(request)) result, value = call('inspect-analysis-view', str(request_file), '--format', 'json') assert result.stderr == '' if label == 'narrow': assert result.returncode == 0 view = value['normalized_result'] assert view['parent_evidence_id'] == parent['evidence_id'] assert len(view['items']) == 1 and 'path' not in view['items'][0] print(label + ':', result.returncode, json.dumps(view['coverage'])) else: assert result.returncode == 1 and value['code'] == 'resource_constraint' assert value['retryable'] is False assert value['details']['reported_limits']['limit_bytes'] == 1048576 errors.append(value) print(label + ':', result.returncode, value['code']) assert errors[0] == errors[1] == errors[2] print('message:', errors[0]['message']) print('action:', errors[0]['remediation']['action']) complete, output = call('inspect-evidence-bundle', json.dumps({'path': str(bundle)}), '--format', 'json') assert complete.returncode == 0 assert output['records'][0]['normalized_result']['route_inventory']['routes'][0]['path'] == route print('complete saved parent:', complete.returncode, 'exact route retained') PYTHON ``` The complete inline procedure above ran once successfully. An earlier independent probe also completed analysis, reproduced the default-page and one-row refusals, and passed the narrowed-field control. The complete procedure performs two identical default-page calls and confirms their error documents also match the one-row refusal. ### Expected behavior Keep the intentional refusal, retained parent identity, numeric allowance, and non-retryable classification. The designated recovery action should identify the fixed page-projection budget and give an applicable selection change. For this indivisible path, omitting the path field is a demonstrated way to obtain a smaller view; merely reducing row count cannot help. Clearly distinguish consuming the complete saved parent from making the oversized view fit. The documented contract distinguishes the shared 1 MiB projection allowance from MCP wire admission and supports fewer fields or complete-parent retrieval. The limits/recovery guide says fixed ceilings must identify their effective value and lack of a runtime override, and directs agents to follow `remediation.action` for fixed controls. Exact sources are in Evidence below. This report does not assert a general ban on mentioning both CLI and MCP alternatives in shared text. ### Impact and scope P2: the prescribed recovery step for an oversized local route page directs a caller to session-specific discovery/export tools and omits the supported field-selection step from the action agents are told to follow. The failure is bounded to an oversized selected row; no downstream automatic loop or wasted export was measured. Practical workarounds were observed: follow the error message's field-selection advice, or read the complete saved parent with `inspect-evidence-bundle --format json`. The latter preserved the exact 1,200,010-character path; the narrow view intentionally omits it. No data loss or source reanalysis was needed for either read. Live MCP behavior, other view kinds and other platforms were not exercised. ### REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Source baseline: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node.js v24.22.1; macOS 27.0.1; arm64. Built CLI with the checkout's locked dependencies. The generated JavaScript was parsed as inert source; no external analysis provider or GUI was used. Fixture npx/npm/bun commands answered version probes and refused execution. ### Target and artifact context One application directory with a small package manifest and one `router.push(...)` call. Its route is `/api/huge/` followed by 1,200,000 ASCII characters. The analyzer retained one route row in the saved Evidence bundle. ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence Selected output from the exact inline procedure: ```text analysis: 0 route_length: 1200010 wide-1: 1 resource_constraint wide-2: 1 resource_constraint one-row: 1 resource_constraint narrow: 0 {"status": "page", "examined": 1, "total": 1, "next_offset": null, "exhausted": true} message: The requested route page cannot fit the analysis-view byte budget; select fewer fields or a smaller selection. The complete parent is retained. action: Discover retained records with get_evidence_bundle and detail: summary, then inspect compatible records through inspect_analysis_view using an exact Evidence reference. Export complete retained session evidence through export_evidence_bundle to a caller-selected path, or use complete CLI JSON output. The connection remains usable. complete saved parent: 0 exact route retained ``` All view calls had empty stderr. The three failed calls returned `code` and `category` equal to `resource_constraint`, `retryable: false`, `details.operation: "inspect_analysis_view"`, `details.resource: "transport"`, and `details.reported_limits.limit_bytes: 1048576`. The repeated refusals retained the same parent ID. Expected-contract sources at the baseline: - `docs/javascript-route-inventory.md:24-38,65-87` documents CLI saved Evidence, independent page/wire allowances, oversized indivisible rows, field selection, and complete-parent access. - `docs/design/limits-and-recovery.md:250-280,286-292` requires fixed-limit naming and applicable recovery and tells agents to follow `remediation.action` for fixed controls. - `docs/cli.md:572-578` distinguishes connection-local retained references from the complete saved records a separate CLI invocation can consume. Failure-source locators: - `src/domain/analysisView/javascriptRoutesView.ts:304-307,396-408,477-503,529-561` defines the fixed page allowance, constructs a transport error without refusal-specific recovery, refuses the first oversized projected row, and supports the demonstrated field selection. - `src/domain/analysisErrorPresentation.ts:43-48,88-104` supplies the MCP retained-frame fallback when this producer supplies no recovery override. - `src/cli/analysisViewCommands.ts:77-133` exposes the supported CLI workflow and projects the resulting diagnostic. ### Typed outcome or recovery expected Preserve `resource_constraint`, `retryable: false`, the 1 MiB bound and retained parent ID. Put the supported selection remedy in `remediation.action`, identify this as the fixed projection allowance with no runtime override, and explain full-parent access as an alternative that does not enlarge that allowance. No new error code or structured recovery field is required. ### Analysis or suspected cause Source-derived explanation: the page producer uses resource `transport` without a producer-owned remediation or fixed-allowance descriptor. Shared presentation therefore interprets the failure as an oversized retained MCP result and supplies that recovery family. The actual admission occurred while forming a local page before output formatting; the complete parent already exists. ### Additional context Duplicate searches covered open/closed issues, their comments, and open/closed/merged PRs. Open [#7553](https://github.com/morluto/rea/issues/7553) concerns an MCP committed-unknown receipt recommending paging an indivisible head. Correcting that instruction to use same-session export leaves this route-page producer unchanged. Open [#7552](https://github.com/morluto/rea/issues/7552) concerns oversized MCP unknown listings. [#7290](https://github.com/morluto/rea/issues/7290) concerns DOL bundle-format admission; [#7603](https://github.com/morluto/rea/issues/7603) concerns divergent-history imports. Closed [#5459](https://github.com/morluto/rea/issues/5459) and merged [#5633](https://github.com/morluto/rea/pull/5633) fixed a different 96 MiB HAR/network projection accumulator. That producer has fixed-allowance recovery at this baseline. This report concerns the separate 1 MiB route-page producer, so it is not evidence that the closed HAR fix regressed. Closed [#6109](https://github.com/morluto/rea/issues/6109) concerns a worker checkpoint rejected before retained facts exist. The broader [#5910](https://github.com/morluto/rea/issues/5910) naming work and merged [#6005](https://github.com/morluto/rea/pull/6005) concern other response/startup limits; that PR explicitly left analysis-view caps unchanged. No prior-good route-page revision or first-bad release was established. Both independent analyses exited successfully; the reproduction does not depend on a cleanup failure. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The local CLI page refusal gives same-session MCP discovery/export as its designated recovery action and omits the demonstrated selection change, despite the documented agent recovery contract. The refusal is bounded to oversized selected rows and preserves data. - Workaround status: available - Workaround basis: The complete inline replay retrieved one field-selected row from the same parent, and complete CLI inspection of the saved bundle recovered the exact oversized path.
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#4567
No description provided.