[PR #2764] [MERGED] fix(native): bound captured output carried by native command failures #5371

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2764
Author: @kaoru0822-kitauji
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/native-failure-diagnostic-bound


📝 Commits (4)

  • 877232c fix(native): bound captured output carried by native command failures
  • 7878737 fix(native): bound codesign failures and cover excerpt cuts
  • dba1d57 test(native): build excerpt test output inside the child process
  • 460d7a6 Merge remote-tracking branch 'origin/main' into fix/native-failure-diagnostic-bound

📊 Changes

3 files changed (+107 additions, -19 deletions)

View changed files

📝 src/native/CommandRunner.ts (+29 -10)
📝 src/native/NativeMacOSProvider.ts (+3 -9)
📝 tests/boundary/providers/native/nativeProvider.test.ts (+75 -0)

📄 Description

Problem

A failing native command can return an error the size of its whole output budget. For example, rea inspect-plist on an app bundle whose Info.plist holds a 200 MB string:

$ rea inspect-plist Big.app --format json | wc -c
67109599

The error is the expected resource_constraint ("Native command output exceeded 67108864 bytes"), but details.captured_output.stdout repeats the entire 64 MiB of retained plutil output. An agent or MCP client receives that much text in an error, and nothing in it helps diagnose the failure.

Cause

XcrunCommandRunner keeps up to NATIVE_COMMAND_OUTPUT_BUDGET_BYTES (64 MiB) of output because successful analysis needs it complete. failureCapture copied that whole retained output into every NativeCommandFailure, and NativeMacOSProvider projects it as captured_output. Other providers bound failure diagnostics separately: maxDiagnosticBytes, 16 KiB in LldbCallTracer, 256 KiB in the JS worker.

Fix

failureCapture, the single owner of native failure captures, now keeps a UTF-8-safe excerpt of at most NATIVE_FAILURE_DIAGNOSTIC_BYTES (64 KiB) per stream, using the existing boundedUtf8Text helper. It sets truncated when either stream was cut, and keeps stdoutBytes/stderrBytes as the observed totals. Successful captures, used for analysis, are unchanged. Consumers use failure captures only for diagnostics, so no parsing behaviour changes.

Measurements

The same 200 MB-string Info.plist bundle, rea inspect-plist --format json:

main branch
error JSON bytes 67,109,599 66,271
captured_output full 64 MiB stdout 65,536-byte excerpt, truncated: true, stdout_bytes: 67108864
wall time 2.84 s 2.81 s

Peak RSS stays about 1 GB on both, because it is dominated by the command's own output. The saving is in what the caller receives: about 1000× fewer bytes in the error.

Validation

  • tests/boundary/providers/native/nativeProvider.test.ts: the real over-budget runner test now also asserts that the failure's stdout is exactly the 64 KiB excerpt while stdoutBytes reports more. 42 passed.
  • npm run test:focused on the native/command test files (18 files): 189 passed.
  • npm run check:fast passes; jscpd is at 2.99%.

🤖 Generated with Claude Code


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

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2764 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/native-failure-diagnostic-bound` --- ### 📝 Commits (4) - [`877232c`](https://github.com/morluto/rea/commit/877232c627aca5924471928247a04c6db4e06f28) fix(native): bound captured output carried by native command failures - [`7878737`](https://github.com/morluto/rea/commit/78787378cb432b037d3e89be3c5c5ee35012301c) fix(native): bound codesign failures and cover excerpt cuts - [`dba1d57`](https://github.com/morluto/rea/commit/dba1d5721748701abe7b5225613ef2ff932f9a68) test(native): build excerpt test output inside the child process - [`460d7a6`](https://github.com/morluto/rea/commit/460d7a6f25cc7ba666aac52b5a48b55de10a289c) Merge remote-tracking branch 'origin/main' into fix/native-failure-diagnostic-bound ### 📊 Changes **3 files changed** (+107 additions, -19 deletions) <details> <summary>View changed files</summary> 📝 `src/native/CommandRunner.ts` (+29 -10) 📝 `src/native/NativeMacOSProvider.ts` (+3 -9) 📝 `tests/boundary/providers/native/nativeProvider.test.ts` (+75 -0) </details> ### 📄 Description ## Problem A failing native command can return an error the size of its whole output budget. For example, `rea inspect-plist` on an app bundle whose `Info.plist` holds a 200 MB string: ``` $ rea inspect-plist Big.app --format json | wc -c 67109599 ``` The error is the expected `resource_constraint` ("Native command output exceeded 67108864 bytes"), but `details.captured_output.stdout` repeats the entire 64 MiB of retained `plutil` output. An agent or MCP client receives that much text in an error, and nothing in it helps diagnose the failure. ## Cause `XcrunCommandRunner` keeps up to `NATIVE_COMMAND_OUTPUT_BUDGET_BYTES` (64 MiB) of output because successful analysis needs it complete. `failureCapture` copied that whole retained output into every `NativeCommandFailure`, and `NativeMacOSProvider` projects it as `captured_output`. Other providers bound failure diagnostics separately: `maxDiagnosticBytes`, 16 KiB in `LldbCallTracer`, 256 KiB in the JS worker. ## Fix `failureCapture`, the single owner of native failure captures, now keeps a UTF-8-safe excerpt of at most `NATIVE_FAILURE_DIAGNOSTIC_BYTES` (64 KiB) per stream, using the existing `boundedUtf8Text` helper. It sets `truncated` when either stream was cut, and keeps `stdoutBytes`/`stderrBytes` as the observed totals. Successful captures, used for analysis, are unchanged. Consumers use failure captures only for diagnostics, so no parsing behaviour changes. ## Measurements The same 200 MB-string `Info.plist` bundle, `rea inspect-plist --format json`: | | main | branch | | --- | --- | --- | | error JSON bytes | 67,109,599 | 66,271 | | `captured_output` | full 64 MiB stdout | 65,536-byte excerpt, `truncated: true`, `stdout_bytes: 67108864` | | wall time | 2.84 s | 2.81 s | Peak RSS stays about 1 GB on both, because it is dominated by the command's own output. The saving is in what the caller receives: about 1000× fewer bytes in the error. ## Validation - `tests/boundary/providers/native/nativeProvider.test.ts`: the real over-budget runner test now also asserts that the failure's stdout is exactly the 64 KiB excerpt while `stdoutBytes` reports more. 42 passed. - `npm run test:focused` on the native/command test files (18 files): 189 passed. - `npm run check:fast` passes; `jscpd` is at 2.99%. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:06:08 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5371
No description provided.