[GH-ISSUE #4619] [Bug] Firmware input growth past the snapshot limit is reported as a provider execution failure #2400

Closed
opened 2026-10-17 21:04:10 +00:00 by bsakaguchi · 2 comments
Owner

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

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

If a firmware input grows from 134217728 to 134217729 bytes after size admission but during snapshot copying, REA reports the primary failure as execution_failure / execution_failure, retryable: false, with generic advice to run rea doctor. An input already at 134217729 bytes instead returns invalid_request / invalid_input, retryable: true, with a path issue explaining the 134217728-byte allowance. No producer command has run at the point of the snapshot failure.

Both public commands, inspect-firmware-regions and extract-firmware, reproduced this in 3/3 growth attempts per command on each tested build. The release reports execution_failure directly. The main build reports top-level cleanup_incomplete, with the same execution_failure preserved as its nested primary error. This report concerns the primary input-limit classification; it does not request hiding a real cleanup failure.

Reproduction

This deterministic reproduction appends a real byte to an ordinary sparse input when its source read stream emits its first data chunk. It changes neither REA's error objects nor the 128 MiB allowance. It uses a preloader to set the platform value to Linux and existing placeholder executables to pass prerequisite admission on the tested macOS host. No real Binwalk, Unblob, or Linux resource limiter is exercised, and this does not establish real Linux provider behavior.

  1. Obtain either tested build. For the release, install rea-agents at the version below into a disposable directory. For source, install locked dependencies and run npm run build:cached. Set entry to the absolute path of that build's scripts/rea.mjs.
  2. Save the following as preload.mjs in a fresh disposable directory. The hook acts only on the selected input handle and only when APPEND_DURING_COPY=1.
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import { syncBuiltinESMExports } from 'node:module';
Object.defineProperty(process, 'platform', { value: 'linux' });
const originalOpen = fsp.open;
fsp.open = async (...args) => {
  const handle = await originalOpen(...args);
  if (String(args[0]) === fs.realpathSync(process.env.FIRMWARE_FIXTURE) && process.env.APPEND_DURING_COPY === '1') {
    const createStream = handle.createReadStream.bind(handle);
    handle.createReadStream = (...options) => {
      const stream = createStream(...options);
      stream.prependOnceListener('data', () => {
        fs.appendFileSync(process.env.FIRMWARE_FIXTURE, Buffer.from([1]));
        console.error('Appended one byte after source streaming started');
      });
      return stream;
    };
  }
  return handle;
};
syncBuiltinESMExports();
  1. In that directory, with entry set, run this shell block. Each invocation has its own empty HOME and TMPDIR. The first case grows during copying; the second starts oversized and is the control. Repeat the block against the other build. All four growth command/build combinations were run three times; each static control ran once.
probe="$(pwd -P)"
node_bin="$(dirname "$(node -p process.execPath)")"
for command in inspect-firmware-regions extract-firmware; do
  for mode in growth oversized; do
    case_dir="$(mktemp -d "$probe/case.XXXXXX")"
    mkdir "$case_dir/home"
    fixture="$case_dir/firmware.bin"
    node -e 'const fs=require("node:fs");fs.writeFileSync(process.argv[1],"");fs.truncateSync(process.argv[1],Number(process.argv[2]))' "$fixture" "$([ "$mode" = growth ] && echo 134217728 || echo 134217729)"
    set -- "$command" "$fixture"
    if [ "$command" = extract-firmware ]; then set -- "$@" "$case_dir/output"; fi
    append=0
    if [ "$mode" = growth ]; then append=1; fi
    env -i PATH="$node_bin:/usr/bin:/bin" HOME="$case_dir/home" TMPDIR="$case_dir" LANG=C       REA_BINWALK_COMMAND=/usr/bin/true REA_UNBLOB_COMMAND=/usr/bin/true REA_FIRMWARE_PRLIMIT_COMMAND=/usr/bin/true       FIRMWARE_FIXTURE="$fixture" APPEND_DURING_COPY="$append"       node --import "$probe/preload.mjs" "$entry" "$@" --json > "$case_dir/result.json" 2> "$case_dir/stderr.txt"
    case_exit=$?
    echo "$command $mode exit=$case_exit"
    cat "$case_dir/result.json"
    node -e 'console.log("input bytes:",require("node:fs").statSync(process.argv[1]).size)' "$fixture"
    rm "$fixture"
  done
 done

Both cases exit 1 and finish with a 134217729-byte input. Growth stderr confirms the append. The growth result contains Firmware grew beyond the input byte budget; the static result contains the typed path issue. Use a shell without errexit, since failures are the expected output.

Expected behavior

Report exceeding the firmware input-size allowance during copying as a typed input/admission failure with the size allowance and stable-input correction guidance, consistently with rejecting an already oversized file. The existing firmware admission branch supplies invalid_request / invalid_input for this same allowance. The firmware guide documents the 128 MiB limit and copying before analysis, but does not explicitly specify a category for growth during copying. This expectation is grounded in that existing admission behavior, rather than a claim that every changing-artifact workflow must use invalid_input.

Impact and scope

The refusal remains enforced. The observed defect is machine-readable attribution, retryability, and recovery guidance for a selected file that grows past the input limit. No successful oversized snapshot, source corruption, limit bypass, or downstream incident was observed. Natural race frequency, real Linux engines, and MCP transport were not measured.

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded input-limit refusal is attributed to provider execution and provider recovery, although the same static allowance yields a caller-correctable input outcome.
  • Workaround status: available
  • Workaround basis: Supply a stable regular copy within the allowance. Native snapshot controls at 32 bytes and exactly 128 MiB both completed successfully. This establishes snapshot acquisition, not subsequent producer analysis.

REA version

Published npm rea-agents 6.5.0, confirmed by scripts/rea.mjs --version; current main source commit 0c7b6d834af2d044b23196e0e522cc2468327a1e, built locally. Both declare package version 6.5.0.

Runtime and platform

Node.js v26.12.0; Darwin arm64. The CLI reproduction uses the controlled Linux platform value described above. A separate native production snapshot-boundary check retained Darwin and the unchanged byte allowance. The source build used this supported runtime rather than the repository's preferred development Node version.

Target and artifact context

Self-generated ordinary sparse firmware files, initially 128 MiB or 128 MiB plus one byte. The growth hook appends one real byte after streaming starts. No selected input is executed.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

  • Expected source: docs/firmware-analysis.md:153-157 and src/firmware/FirmwareFiles.ts:102-103,282-289, with src/domain/analysisErrorProjection.ts:200 and src/domain/analysisErrorPresentation.ts:220 defining the existing input classification.
  • Failure source: The public command results below; source breadcrumbs are src/firmware/FirmwareFiles.ts:107-111,255-262, src/firmware/FirmwareFailures.ts:101-106, and src/domain/analysisErrorProjection.ts:215 in the tested main tree.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Meaningful CLI output, omitting input paths and repeated cleanup wrappers:

Both builds, both commands, stable oversized control:
  exit 1; code invalid_request; category invalid_input; retryable true
  issue: path=["path"], reason=out_of_range
  message: Firmware must be a nonempty regular file no larger than 134217728 bytes

Release, both commands, growth 3/3 each:
  exit 1; code execution_failure; category execution_failure; retryable false
  details.diagnostics.reason: Firmware grew beyond the input byte budget
  remediation: Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.

Main build, both commands, growth 3/3 each:
  exit 1; top-level code cleanup_incomplete; category execution_failure
  nested primary: code execution_failure; category execution_failure; retryable false
  primary details.diagnostics.reason: Firmware grew beyond the input byte budget
  cleanup reason: File handle was invalidated before this owner confirmed its close

A separate compiled production-boundary check on native Darwin, without the platform override, exercised FirmwareFileAccess.snapshot and the normal firmware error projection. Stable 32-byte and exactly-at-limit inputs copied and closed successfully; the stable oversized file returned invalid_request / invalid_input; a real append past the allowance returned the same primary execution_failure inside cleanup_incomplete. Each native firmware case ran once. The same native check observed Android's snapshot reader reject a 32-to-33-byte input change as invalid_request / invalid_input, while its stable control succeeded. This is comparison evidence, not a universal artifact-category contract.

Typed outcome or recovery expected

Keep refusing an input that crosses the limit during copying. Preserve a typed input/admission primary error with the byte allowance and stable-file recovery, matching the static oversized control. Keep successful snapshots at or below the allowance. If descriptor cleanup remains independently incomplete, retain that truthful cleanup wrapper and ownership diagnostics around the corrected primary outcome.

Analysis or suspected cause

Source-derived reasoning: the copy meter creates an ordinary Error for the known input-budget condition. The admission translator only converts nonregular-file errors, so the growth error reaches the generic ProviderAdapterError fallback and its provider-oriented projection. Snapshotting occurs in FirmwareProvider.ts:328 before the first producer version command at line 355. No existing firmware test was found that pins this growth classification. REA also has an artifact_changed / integrity_mismatch outcome for other changing artifacts; maintainers may prefer that explicit mutation outcome, but generic provider recovery does not explain this detected input condition.

Additional context

Related #4475 concerns firmware read-handle cleanup ownership and primary-outcome preservation; the cleanup wrapper above is separate from this report's primary classification. #4192 concerns PE resource-kind attribution, and #1855 concerns retry guidance after a missing firmware producer report. Open and closed issues and PRs were searched for firmware snapshot growth, the size allowance, and error-category terms. No matching report or last-known-good revision was found.

Originally created by @coygeek on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4619 ### 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 If a firmware input grows from 134217728 to 134217729 bytes after size admission but during snapshot copying, REA reports the primary failure as `execution_failure` / `execution_failure`, `retryable: false`, with generic advice to run `rea doctor`. An input already at 134217729 bytes instead returns `invalid_request` / `invalid_input`, `retryable: true`, with a `path` issue explaining the 134217728-byte allowance. No producer command has run at the point of the snapshot failure. Both public commands, `inspect-firmware-regions` and `extract-firmware`, reproduced this in 3/3 growth attempts per command on each tested build. The release reports `execution_failure` directly. The `main` build reports top-level `cleanup_incomplete`, with the same `execution_failure` preserved as its nested primary error. This report concerns the primary input-limit classification; it does not request hiding a real cleanup failure. ### Reproduction This deterministic reproduction appends a real byte to an ordinary sparse input when its source read stream emits its first data chunk. It changes neither REA's error objects nor the 128 MiB allowance. It uses a preloader to set the platform value to Linux and existing placeholder executables to pass prerequisite admission on the tested macOS host. No real Binwalk, Unblob, or Linux resource limiter is exercised, and this does not establish real Linux provider behavior. 1. Obtain either tested build. For the release, install `rea-agents` at the version below into a disposable directory. For source, install locked dependencies and run `npm run build:cached`. Set `entry` to the absolute path of that build's `scripts/rea.mjs`. 2. Save the following as `preload.mjs` in a fresh disposable directory. The hook acts only on the selected input handle and only when `APPEND_DURING_COPY=1`. ```js import fs from 'node:fs'; import fsp from 'node:fs/promises'; import { syncBuiltinESMExports } from 'node:module'; Object.defineProperty(process, 'platform', { value: 'linux' }); const originalOpen = fsp.open; fsp.open = async (...args) => { const handle = await originalOpen(...args); if (String(args[0]) === fs.realpathSync(process.env.FIRMWARE_FIXTURE) && process.env.APPEND_DURING_COPY === '1') { const createStream = handle.createReadStream.bind(handle); handle.createReadStream = (...options) => { const stream = createStream(...options); stream.prependOnceListener('data', () => { fs.appendFileSync(process.env.FIRMWARE_FIXTURE, Buffer.from([1])); console.error('Appended one byte after source streaming started'); }); return stream; }; } return handle; }; syncBuiltinESMExports(); ``` 3. In that directory, with `entry` set, run this shell block. Each invocation has its own empty HOME and TMPDIR. The first case grows during copying; the second starts oversized and is the control. Repeat the block against the other build. All four growth command/build combinations were run three times; each static control ran once. ```sh probe="$(pwd -P)" node_bin="$(dirname "$(node -p process.execPath)")" for command in inspect-firmware-regions extract-firmware; do for mode in growth oversized; do case_dir="$(mktemp -d "$probe/case.XXXXXX")" mkdir "$case_dir/home" fixture="$case_dir/firmware.bin" node -e 'const fs=require("node:fs");fs.writeFileSync(process.argv[1],"");fs.truncateSync(process.argv[1],Number(process.argv[2]))' "$fixture" "$([ "$mode" = growth ] && echo 134217728 || echo 134217729)" set -- "$command" "$fixture" if [ "$command" = extract-firmware ]; then set -- "$@" "$case_dir/output"; fi append=0 if [ "$mode" = growth ]; then append=1; fi env -i PATH="$node_bin:/usr/bin:/bin" HOME="$case_dir/home" TMPDIR="$case_dir" LANG=C REA_BINWALK_COMMAND=/usr/bin/true REA_UNBLOB_COMMAND=/usr/bin/true REA_FIRMWARE_PRLIMIT_COMMAND=/usr/bin/true FIRMWARE_FIXTURE="$fixture" APPEND_DURING_COPY="$append" node --import "$probe/preload.mjs" "$entry" "$@" --json > "$case_dir/result.json" 2> "$case_dir/stderr.txt" case_exit=$? echo "$command $mode exit=$case_exit" cat "$case_dir/result.json" node -e 'console.log("input bytes:",require("node:fs").statSync(process.argv[1]).size)' "$fixture" rm "$fixture" done done ``` Both cases exit 1 and finish with a 134217729-byte input. Growth stderr confirms the append. The growth result contains `Firmware grew beyond the input byte budget`; the static result contains the typed `path` issue. Use a shell without `errexit`, since failures are the expected output. ### Expected behavior Report exceeding the firmware input-size allowance during copying as a typed input/admission failure with the size allowance and stable-input correction guidance, consistently with rejecting an already oversized file. The existing firmware admission branch supplies `invalid_request` / `invalid_input` for this same allowance. The firmware guide documents the 128 MiB limit and copying before analysis, but does not explicitly specify a category for growth during copying. This expectation is grounded in that existing admission behavior, rather than a claim that every changing-artifact workflow must use `invalid_input`. ### Impact and scope The refusal remains enforced. The observed defect is machine-readable attribution, retryability, and recovery guidance for a selected file that grows past the input limit. No successful oversized snapshot, source corruption, limit bypass, or downstream incident was observed. Natural race frequency, real Linux engines, and MCP transport were not measured. - Impact level: P2 - Assessment status: supported - Impact basis: A bounded input-limit refusal is attributed to provider execution and provider recovery, although the same static allowance yields a caller-correctable input outcome. - Workaround status: available - Workaround basis: Supply a stable regular copy within the allowance. Native snapshot controls at 32 bytes and exactly 128 MiB both completed successfully. This establishes snapshot acquisition, not subsequent producer analysis. ### REA version Published npm `rea-agents` 6.5.0, confirmed by `scripts/rea.mjs --version`; current `main` source commit `0c7b6d834af2d044b23196e0e522cc2468327a1e`, built locally. Both declare package version 6.5.0. ### Runtime and platform Node.js v26.12.0; Darwin arm64. The CLI reproduction uses the controlled Linux platform value described above. A separate native production snapshot-boundary check retained Darwin and the unchanged byte allowance. The source build used this supported runtime rather than the repository's preferred development Node version. ### Target and artifact context Self-generated ordinary sparse firmware files, initially 128 MiB or 128 MiB plus one byte. The growth hook appends one real byte after streaming starts. No selected input is executed. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence - Expected source: `docs/firmware-analysis.md:153-157` and `src/firmware/FirmwareFiles.ts:102-103,282-289`, with `src/domain/analysisErrorProjection.ts:200` and `src/domain/analysisErrorPresentation.ts:220` defining the existing input classification. - Failure source: The public command results below; source breadcrumbs are `src/firmware/FirmwareFiles.ts:107-111,255-262`, `src/firmware/FirmwareFailures.ts:101-106`, and `src/domain/analysisErrorProjection.ts:215` in the tested main tree. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Meaningful CLI output, omitting input paths and repeated cleanup wrappers: ```text Both builds, both commands, stable oversized control: exit 1; code invalid_request; category invalid_input; retryable true issue: path=["path"], reason=out_of_range message: Firmware must be a nonempty regular file no larger than 134217728 bytes Release, both commands, growth 3/3 each: exit 1; code execution_failure; category execution_failure; retryable false details.diagnostics.reason: Firmware grew beyond the input byte budget remediation: Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. Main build, both commands, growth 3/3 each: exit 1; top-level code cleanup_incomplete; category execution_failure nested primary: code execution_failure; category execution_failure; retryable false primary details.diagnostics.reason: Firmware grew beyond the input byte budget cleanup reason: File handle was invalidated before this owner confirmed its close ``` A separate compiled production-boundary check on native Darwin, without the platform override, exercised `FirmwareFileAccess.snapshot` and the normal firmware error projection. Stable 32-byte and exactly-at-limit inputs copied and closed successfully; the stable oversized file returned `invalid_request` / `invalid_input`; a real append past the allowance returned the same primary `execution_failure` inside `cleanup_incomplete`. Each native firmware case ran once. The same native check observed Android's snapshot reader reject a 32-to-33-byte input change as `invalid_request` / `invalid_input`, while its stable control succeeded. This is comparison evidence, not a universal artifact-category contract. ### Typed outcome or recovery expected Keep refusing an input that crosses the limit during copying. Preserve a typed input/admission primary error with the byte allowance and stable-file recovery, matching the static oversized control. Keep successful snapshots at or below the allowance. If descriptor cleanup remains independently incomplete, retain that truthful cleanup wrapper and ownership diagnostics around the corrected primary outcome. ### Analysis or suspected cause Source-derived reasoning: the copy meter creates an ordinary Error for the known input-budget condition. The admission translator only converts nonregular-file errors, so the growth error reaches the generic `ProviderAdapterError` fallback and its provider-oriented projection. Snapshotting occurs in `FirmwareProvider.ts:328` before the first producer version command at line 355. No existing firmware test was found that pins this growth classification. REA also has an `artifact_changed` / `integrity_mismatch` outcome for other changing artifacts; maintainers may prefer that explicit mutation outcome, but generic provider recovery does not explain this detected input condition. ### Additional context Related [#4475](https://github.com/morluto/rea/issues/4475) concerns firmware read-handle cleanup ownership and primary-outcome preservation; the cleanup wrapper above is separate from this report's primary classification. [#4192](https://github.com/morluto/rea/issues/4192) concerns PE resource-kind attribution, and [#1855](https://github.com/morluto/rea/issues/1855) concerns retry guidance after a missing firmware producer report. Open and closed issues and PRs were searched for firmware snapshot growth, the size allowance, and error-category terms. No matching report or last-known-good revision was found.
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Addressed the input-growth primary failure and related stream ownership in 0a51b246c. The meter now emits the same typed input/admission failure as static oversize rejection, with the byte allowance and stable-copy guidance. Independent cleanup failure remains truthful.

Firmware now uses the existing owner-preserving readArtifactFileChunks for hashing, snapshot/range copying and publication. Destroying a pipeline no longer closes the source descriptor outside its owner. The canonical source also owns cancellation: competing pipeline signals and obsolete stream-error reinterpretation were removed after snapshot/range controls reproduced EIO being replaced by cancellation (2 failed, 29 passed in that intermediate candidate).

Final validation on Node 24.18.0: 46 focused tests across four files passed, including actual native file growth from 128 MiB to one byte above the unchanged allowance, successful and denied close for both operations, exact-owner retry, a stable file exactly at the allowance, same-read EIO/cancellation, and existing finalization/mixed-owner/publication controls. Docs checks and five conformance tests passed. Native file IO and controlled faults on Darwin; no Linux firmware engines or public CLI growth reproduction claimed. Two separately selected Linux workspace checks were skipped on this host.

Bounded completed snapshot comparison against immediate parent 8451d2839: 32 MiB sparse source, identical size/digest, two alternating warm repeats/build plus separate first processes. Warm medians baseline/candidate: elapsed 0.07248/0.06984 s, CPU 0.06910/0.06844 s, sampled process-family RSS 64790528/57565184 bytes, result JSON tokens 51/51 (cl100k_base). No speed/memory improvement is established by these repeats; true cold, CLI/MCP/whole-agent/schema/request/retry and native-engine costs are unmeasured. Heavy Qodo tests remained stopped.

Related remaining shared error-model defect: #4628. After a composite cleanup dependency resolves, its old wrapper still projects execution_failure while the typed primary survives in diagnostics. The firmware patch preserves the corrected primary and exact cleanup ownership; it does not claim to repair that shared post-recovery projection.

<!-- gh-comment-id:6227631252 --> @morluto commented on GitHub (Oct 17, 2026): Addressed the input-growth primary failure and related stream ownership in `0a51b246c`. The meter now emits the same typed input/admission failure as static oversize rejection, with the byte allowance and stable-copy guidance. Independent cleanup failure remains truthful. Firmware now uses the existing owner-preserving `readArtifactFileChunks` for hashing, snapshot/range copying and publication. Destroying a pipeline no longer closes the source descriptor outside its owner. The canonical source also owns cancellation: competing pipeline signals and obsolete stream-error reinterpretation were removed after snapshot/range controls reproduced EIO being replaced by cancellation (2 failed, 29 passed in that intermediate candidate). Final validation on Node 24.18.0: 46 focused tests across four files passed, including actual native file growth from 128 MiB to one byte above the unchanged allowance, successful and denied close for both operations, exact-owner retry, a stable file exactly at the allowance, same-read EIO/cancellation, and existing finalization/mixed-owner/publication controls. Docs checks and five conformance tests passed. Native file IO and controlled faults on Darwin; no Linux firmware engines or public CLI growth reproduction claimed. Two separately selected Linux workspace checks were skipped on this host. Bounded completed snapshot comparison against immediate parent 8451d2839: 32 MiB sparse source, identical size/digest, two alternating warm repeats/build plus separate first processes. Warm medians baseline/candidate: elapsed 0.07248/0.06984 s, CPU 0.06910/0.06844 s, sampled process-family RSS 64790528/57565184 bytes, result JSON tokens 51/51 (cl100k_base). No speed/memory improvement is established by these repeats; true cold, CLI/MCP/whole-agent/schema/request/retry and native-engine costs are unmeasured. Heavy Qodo tests remained stopped. Related remaining shared error-model defect: #4628. After a composite cleanup dependency resolves, its old wrapper still projects execution_failure while the typed primary survives in diagnostics. The firmware patch preserves the corrected primary and exact cleanup ownership; it does not claim to repair that shared post-recovery projection.
Author
Owner

@coygeek commented on GitHub (Oct 18, 2026):

Closing as addressed on main by 0a51b246c. Firmware snapshot growth past the input allowance now produces the same typed input/admission failure as initial oversize rejection, with stable-copy guidance, while retaining independent cleanup failures. I verified the committed source and regression coverage; I have not rerun the runtime reproduction.

<!-- gh-comment-id:6244116242 --> @coygeek commented on GitHub (Oct 18, 2026): Closing as addressed on `main` by [0a51b246c](https://github.com/morluto/rea/commit/0a51b246c632a36b24c121282aeb51fda1ddb461). Firmware snapshot growth past the input allowance now produces the same typed input/admission failure as initial oversize rejection, with stable-copy guidance, while retaining independent cleanup failures. I verified the committed source and regression coverage; I have not rerun the runtime reproduction.
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#2400
No description provided.