[PR #2117] [MERGED] fix(wasm): report WABT output past its budget as a resource constraint #5041

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2117
Author: @JayOfTheKeyboard
Created: 10/12/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/wasm-output-limit


📝 Commits (10+)

  • c1e7292 fix(wasm): report WABT output past its budget as a resource constraint
  • e8fba3a fix(wasm): keep observed sizes and whole code points in output-limit excerpts
  • adcb053 fix(wasm): match sibling captured-output fields for WABT output limits
  • 463a917 docs(wasm): scope the output-budget error to inspection commands
  • 913cd9c chore: merge upstream CI baseline fixes
  • b266431 docs(wasm): distinguish reported warm costs from unmeasured gaps
  • c5beb60 docs(wasm): clarify the scope of reported warm measurements
  • 5eeccab chore: merge captured monotonic deadline fixes
  • ab9214a Merge commit '8fef2aa64e' into HEAD
  • 15a783f Merge branch 'main' into fix/wasm-output-limit

📊 Changes

3 files changed (+219 additions, -9 deletions)

View changed files

📝 docs/wasm-artifacts.md (+18 -3)
📝 src/wasm/WabtArtifactProvider.test.ts (+156 -0)
📝 src/wasm/WabtFailures.ts (+45 -6)

📄 Description

Summary

inspect-wasm-artifact reports the wrong kind of failure when a module's WABT output is larger than the 32 MiB output budget. It returns unreadable_output, tells the caller to run rea doctor, and puts the first 33,554,432 bytes of WAT into details.captured_output.stdout, so the error is 33.6 MB of JSON. No issue is linked. I found this by running the tool over the real .wasm files on one machine, and the fix is small enough to explain here.

Problem and expected behavior

runOwnedCommand stops a WABT command when its output passes WABT_LIMITS.outputBytes (32 MiB) and throws OwnedCommandFailure with reason output-limit. wabtFailure in src/wasm/WabtFailures.ts has branches for cancelled, timeout and process, and none for output-limit. The failure falls through to AnalysisOutputError, which the CLI shows as an unreadable result, with all of the retained stdout attached.

The budget works as documented. The caller is told the result was unreadable when that documented limit was hit, and gets back the partial WAT that the limit exists to refuse.

3 of the 28 valid modules I ran hit this. All three are tree-sitter grammars. Sizes from WABT 1.0.42 run directly:

Module Input bytes wasm2wat --enable-all bytes wasm-objdump -h -x bytes
tree-sitter-cpp.wasm (VS Code Copilot) 3,434,931 43,505,653 14,665,080
tree-sitter-bash.wasm (@vscode/tree-sitter-wasm) 1,380,769 65,803,935 5,322,102
tree-sitter-powershell.wasm (@vscode/tree-sitter-wasm) 989,619 285,398,328 2,706,929
$ REA_WABT_BIN_DIRECTORY=.../wabt-1.0.42/bin rea inspect-wasm-artifact tree-sitter-cpp.wasm --format json
{"code":"unreadable_output","message":"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.", ...
 "details":{"operation":"inspect_wasm_artifact","reason":"Command diagnostic output exceeded its complete-output budget.","captured_output":{"stdout":"(module\n  (type ...   <- 33,554,432 bytes

Expected: an error that says which limit was hit and does not carry 32 MiB of partial output. The apktool provider (src/apktool/ApktoolProvider.ts) and the native macOS provider (src/native/NativeMacOSProvider.ts) already map output-limit to AnalysisResourceConstraintError with resource memory and max_output_bytes.

Change and scope

  • During inspection, wabtFailure maps output-limit to AnalysisResourceConstraintError, as apktool and native macOS do. The message gives the budget in bytes, and reported_limits carries max_output_bytes.
  • The remediation says the budget is fixed, so retrying with the same input fails the same way. The default text for a memory constraint says to retry with more memory, and no memory setting changes this budget. The text does not say the module is too large, because any of the three tools can fill the budget, including wasm-validate printing diagnostics for a malformed module.
  • For an output-limit failure, captured_output keeps up to the first 4,096 bytes that stdout and stderr each retained. The two streams share one budget, so either can be the one that filled it, and a stream that starts after the other has filled it retains nothing. The cut uses the existing boundedUtf8Text helper, so it never splits a character. truncated is always true here, because the command raises output-limit only after it truncated what it retained. It also records stdout_bytes, stderr_bytes, exit_code and signal, as apktool does. The byte counts are retained bytes, the meaning apktool and the firmware command give them.
  • If cleanup also fails, the error is still cleanup_incomplete. Its diagnostics now record the output limit and the budget as previous_error, and carry the same bounded excerpt.
  • capturedEvmOutput and capturedPwntoolsOutput already build captured output from a snapshot. They copy the full text and have no excerpt step, and importing them would make WABT depend on EVM or pwntools code, so I did not reuse them.
  • An oversized --version probe in the configuration phase keeps its current mapping. A misconfigured tool should not be reported as an oversized module.
  • wasm-validate, wasm-objdump and wasm2wat all run through the same execute helper, so all three reach this mapping. REA does not run wasm-decompile or any other WABT tool.
  • docs/wasm-artifacts.md said "truncation fails". It now gives the error code and the excerpt size.

Not changed, and yours to decide:

  • The resource is memory, as in apktool and native macOS for the same output budget. No sibling uses a closer value, so I kept it for consistency.
  • Timeout, process failures and the provider's fallback in WabtArtifactProvider.ts (around line 385) still attach full captured output. Only the output-limit path is bounded here.
  • The error's cause still holds the full snapshot in memory. It is not serialized.
  • EVMole, pwntools and browser capture still map output-limit to AnalysisOutputError, so they show the same rea doctor advice for a size limit. Apktool keeps its capture unbounded. One excerpt step at the owning boundary in src/process/ could cover all of them. That touches more providers, so I left it out of this PR.
  • stdout_bytes and stderr_bytes keep their shared meaning of retained bytes. The snapshot also knows how many bytes each stream produced before it stopped. That could go into the message or a new field if you want it.
  • When output passes the budget, execute() throws before it re-checks the executable digest and the module snapshot. So a swapped binary that floods output is reported as over budget, and its changed digest goes unnoticed. That control flow predates this change.
  • An oversized --version probe still maps to unreadable_output. capability_unavailable may fit a wrong tool better, as it does for a wrong banner.
  • A module this large still gets no result. Returning sections, imports and exports without inline WAT would be a separate feature.
  • PR #2084 also edits src/wasm/WabtFailures.ts and its test file. The two branches merge without conflicts.

Contract and boundary impact

  • Semantic owner and earliest changed stage: WABT failure mapping in wabtFailure (src/wasm/WabtFailures.ts).
  • CLI and MCP/tool-catalog contract: when WABT output passes the budget during inspection, inspect_wasm_artifact returns the existing resource_constraint code instead of unreadable_output. No schemas change.
  • Provider, bridge, target-format, or platform compatibility: none. Modules under the budget are unchanged.
  • Evidence, artifact, provenance, or reconstruction contract: for an output-limit failure, captured_output keeps up to 4,096 bytes of what each stream retained, the retained byte counts, exit_code, signal and truncated.
  • Process execution, authorization, cleanup, or containment impact: none. The budget and the process handling are unchanged.
  • Generated metadata, package, or installation impact: none.

Evidence and regression coverage

  • Tests added in src/wasm/WabtArtifactProvider.test.ts:
    • Through inspect, the real child processes run for the version probes and wasm-objdump, and the launcher raises an output-limit failure for wasm2wat. The test checks the error tag, resource, max_output_bytes, the projected resource_constraint code, that the message names the budget, the remediation, and the full captured_output with the excerpt, byte counts, exit code and signal. No test writes 32 MiB.
    • An oversized stderr is cut to the same excerpt and marks the output truncated.
    • An emoji that straddles the 4,096-byte cut is left out whole.
    • With a cleanup failure on top of the output limit, the diagnostics carry the excerpt and record the output limit as previous_error.
    • An output limit during the --version probe stays AnalysisOutputError.
  • Base reproduction: on main the first four tests fail. The fifth passes there, since it guards the configuration-phase behaviour this change keeps. Each part of the fix is needed. Keeping the full text fails the four excerpt tests. Cutting by UTF-16 units fails the emoji test. Setting truncated to false, reporting observed instead of retained byte counts, or dropping exit_code and signal each fails the inspect and stderr tests. Recording the generic command message as previous_error fails the cleanup test. Dropping the phase condition fails the --version test. Changing the resource to cpu, dropping max_output_bytes, dropping the byte count from the message, or using the old module-size remediation each fails the inspect test.
  • User-visible CLI output, with the fix, on tree-sitter-cpp.wasm (stdout excerpt shortened here):
{"code":"resource_constraint","category":"resource_constraint","message":"WABT output exceeded the 33554432-byte output budget","retryable":false,"remediation":{"action":"The WABT output budget is fixed, so retrying with the same input will fail the same way."},"details":{"operation":"inspect_wasm_artifact","resource":"memory","reason":"WABT output exceeded the 33554432-byte output budget","reported_limits":{"max_output_bytes":33554432},"captured_output":{"stdout":"(module\n  (type (;0;) (func (param i32))...","stderr":"","truncated":true,"stdout_bytes":33554432,"stderr_bytes":0,"exit_code":0,"signal":null}}}

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • vitest over src/wasm, tests/boundary/mcp/wasmArtifactMcp.test.ts, tests/acceptance/tools/localToolContracts.test.ts, src/contracts/toolEffects.test.ts and tests/boundary/filesystem/targetDiagnostics.test.ts: 6 files, 56 tests passed.
  • npm run check:fast: passed.
  • npm run docs:check: passed.
  • npm run verify:test-discovery: "Discovered all 915 test files exactly once."
  • Real modules, built CLI, WABT 1.0.42, before and after. After the fix each oversized module reports stdout_bytes 33,554,432. exit_code and signal depend on whether WABT finished before it was stopped: the same module gave exit 0 on one run and SIGKILL on another.
Module Before After
tree-sitter-cpp.wasm unreadable_output, 33,606,368-byte error resource_constraint, 4,932-byte error
tree-sitter-bash.wasm unreadable_output, 33,584,062-byte error resource_constraint, 4,931-byte error
tree-sitter-powershell.wasm unreadable_output, 33,568,405-byte error resource_constraint, 4,926-byte error
tree-sitter-c-sharp.wasm, onig.wasm, crc32.wasm ok ok, same output size
vsda_bg.wasm (not WebAssembly) invalid_request invalid_request

Costs, measured 2026-10-13 with the built CLI on this branch and on main at 4276aaf1, WABT 1.0.42, Linux x64, 12 cores. Each run had its own cgroup, so CPU and peak memory cover the whole process family, WABT children included. Per module and tree: one first run and three warm runs, with main and the branch alternating. The machine was shared, with a load average of 8 to 14 during the runs, so differences of a few hundred milliseconds are noise. "First" is not truly cold: the page cache was already warm from the build, and I could not drop it.

Module Tree First run: elapsed / CPU / peak Warm median: elapsed / CPU / peak Output
tree-sitter-cpp.wasm main 4.2 s / 5.5 s / 535 MiB 3.2 s / 5.5 s / 500 MiB 33,606,368 B
branch 3.2 s / 5.4 s / 485 MiB 3.1 s / 5.1 s / 513 MiB 4,924 B
tree-sitter-bash.wasm main 3.0 s / 4.9 s / 470 MiB 3.4 s / 5.1 s / 508 MiB 33,584,062 B
branch 2.8 s / 4.5 s / 517 MiB 3.6 s / 5.0 s / 502 MiB 4,931 B
tree-sitter-powershell.wasm main 3.4 s / 5.1 s / 572 MiB 3.2 s / 4.9 s / 598 MiB 33,568,405 B
branch 3.3 s / 4.9 s / 522 MiB 3.0 s / 4.7 s / 535 MiB 4,926 B
tree-sitter-c-sharp.wasm (control, succeeds) main 4.8 s / 7.5 s / 631 MiB 5.4 s / 7.7 s / 588 MiB 64,132,114 B
branch 4.8 s / 7.5 s / 588 MiB 5.2 s / 7.8 s / 587 MiB 64,132,114 B

Elapsed time, CPU time and peak memory show no change outside that noise. The process still reads the full 32 MiB before stopping, and cause still holds the snapshot, so I did not expect one. The change is in what the caller receives: about 4.9 KB instead of about 33.6 MB per failure. Token usage was not measured. I had no tokenizer for the agent's model on this machine, and fewer bytes alone do not prove fewer tokens.

Compatibility, safety, and release

  • Breaking changes or migration steps: a caller that matched unreadable_output for oversized modules now gets resource_constraint. Neither code is retryable.
  • Real Hopper/Ghidra, browser, or OS coverage: Linux x64 (Fedora 44) only, with the WABT 1.0.42 release binaries. No other provider runs.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: the output budget and process handling are unchanged. The error carries at most 8,192 bytes of producer output, down from up to 32 MiB.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 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/2117 **Author:** [@JayOfTheKeyboard](https://github.com/JayOfTheKeyboard) **Created:** 10/12/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/wasm-output-limit` --- ### 📝 Commits (10+) - [`c1e7292`](https://github.com/morluto/rea/commit/c1e729283a15addc307d170af69b7b6fab89274d) fix(wasm): report WABT output past its budget as a resource constraint - [`e8fba3a`](https://github.com/morluto/rea/commit/e8fba3afdd248fcba2bccc7744d16d5212d6cee4) fix(wasm): keep observed sizes and whole code points in output-limit excerpts - [`adcb053`](https://github.com/morluto/rea/commit/adcb053872603be2457366a3b505b1fa843bc2ac) fix(wasm): match sibling captured-output fields for WABT output limits - [`463a917`](https://github.com/morluto/rea/commit/463a9176deeb410e918b81b3a72ead15116bfdce) docs(wasm): scope the output-budget error to inspection commands - [`913cd9c`](https://github.com/morluto/rea/commit/913cd9c7a13cc08aef6267db14b317e6c0ef5bd3) chore: merge upstream CI baseline fixes - [`b266431`](https://github.com/morluto/rea/commit/b2664313998ac806275c9ad82bf650e6f65a15c8) docs(wasm): distinguish reported warm costs from unmeasured gaps - [`c5beb60`](https://github.com/morluto/rea/commit/c5beb6047fb669fc8b76f40f2ac1a15cbaca27fc) docs(wasm): clarify the scope of reported warm measurements - [`5eeccab`](https://github.com/morluto/rea/commit/5eeccab368df3444c81f9113821c6fa3be91efa3) chore: merge captured monotonic deadline fixes - [`ab9214a`](https://github.com/morluto/rea/commit/ab9214aa4385868bb4219e429b147bb5bb08e10b) Merge commit '8fef2aa64ec1ee742e8b70b825938d30a0ea7319' into HEAD - [`15a783f`](https://github.com/morluto/rea/commit/15a783f399c4b4ff8fbbbdde9206090bdaf10618) Merge branch 'main' into fix/wasm-output-limit ### 📊 Changes **3 files changed** (+219 additions, -9 deletions) <details> <summary>View changed files</summary> 📝 `docs/wasm-artifacts.md` (+18 -3) 📝 `src/wasm/WabtArtifactProvider.test.ts` (+156 -0) 📝 `src/wasm/WabtFailures.ts` (+45 -6) </details> ### 📄 Description ## Summary `inspect-wasm-artifact` reports the wrong kind of failure when a module's WABT output is larger than the 32 MiB output budget. It returns `unreadable_output`, tells the caller to run `rea doctor`, and puts the first 33,554,432 bytes of WAT into `details.captured_output.stdout`, so the error is 33.6 MB of JSON. No issue is linked. I found this by running the tool over the real `.wasm` files on one machine, and the fix is small enough to explain here. ## Problem and expected behavior `runOwnedCommand` stops a WABT command when its output passes `WABT_LIMITS.outputBytes` (32 MiB) and throws `OwnedCommandFailure` with reason `output-limit`. `wabtFailure` in `src/wasm/WabtFailures.ts` has branches for `cancelled`, `timeout` and `process`, and none for `output-limit`. The failure falls through to `AnalysisOutputError`, which the CLI shows as an unreadable result, with all of the retained stdout attached. The budget works as documented. The caller is told the result was unreadable when that documented limit was hit, and gets back the partial WAT that the limit exists to refuse. 3 of the 28 valid modules I ran hit this. All three are tree-sitter grammars. Sizes from WABT 1.0.42 run directly: | Module | Input bytes | `wasm2wat --enable-all` bytes | `wasm-objdump -h -x` bytes | | --- | --- | --- | --- | | `tree-sitter-cpp.wasm` (VS Code Copilot) | 3,434,931 | 43,505,653 | 14,665,080 | | `tree-sitter-bash.wasm` (`@vscode/tree-sitter-wasm`) | 1,380,769 | 65,803,935 | 5,322,102 | | `tree-sitter-powershell.wasm` (`@vscode/tree-sitter-wasm`) | 989,619 | 285,398,328 | 2,706,929 | ```text $ REA_WABT_BIN_DIRECTORY=.../wabt-1.0.42/bin rea inspect-wasm-artifact tree-sitter-cpp.wasm --format json {"code":"unreadable_output","message":"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.", ... "details":{"operation":"inspect_wasm_artifact","reason":"Command diagnostic output exceeded its complete-output budget.","captured_output":{"stdout":"(module\n (type ... <- 33,554,432 bytes ``` Expected: an error that says which limit was hit and does not carry 32 MiB of partial output. The apktool provider (`src/apktool/ApktoolProvider.ts`) and the native macOS provider (`src/native/NativeMacOSProvider.ts`) already map `output-limit` to `AnalysisResourceConstraintError` with resource `memory` and `max_output_bytes`. ## Change and scope - During inspection, `wabtFailure` maps `output-limit` to `AnalysisResourceConstraintError`, as apktool and native macOS do. The message gives the budget in bytes, and `reported_limits` carries `max_output_bytes`. - The remediation says the budget is fixed, so retrying with the same input fails the same way. The default text for a `memory` constraint says to retry with more memory, and no memory setting changes this budget. The text does not say the module is too large, because any of the three tools can fill the budget, including `wasm-validate` printing diagnostics for a malformed module. - For an `output-limit` failure, `captured_output` keeps up to the first 4,096 bytes that stdout and stderr each retained. The two streams share one budget, so either can be the one that filled it, and a stream that starts after the other has filled it retains nothing. The cut uses the existing `boundedUtf8Text` helper, so it never splits a character. `truncated` is always true here, because the command raises `output-limit` only after it truncated what it retained. It also records `stdout_bytes`, `stderr_bytes`, `exit_code` and `signal`, as apktool does. The byte counts are retained bytes, the meaning apktool and the firmware command give them. - If cleanup also fails, the error is still `cleanup_incomplete`. Its diagnostics now record the output limit and the budget as `previous_error`, and carry the same bounded excerpt. - `capturedEvmOutput` and `capturedPwntoolsOutput` already build captured output from a snapshot. They copy the full text and have no excerpt step, and importing them would make WABT depend on EVM or pwntools code, so I did not reuse them. - An oversized `--version` probe in the configuration phase keeps its current mapping. A misconfigured tool should not be reported as an oversized module. - `wasm-validate`, `wasm-objdump` and `wasm2wat` all run through the same `execute` helper, so all three reach this mapping. REA does not run `wasm-decompile` or any other WABT tool. - `docs/wasm-artifacts.md` said "truncation fails". It now gives the error code and the excerpt size. Not changed, and yours to decide: - The resource is `memory`, as in apktool and native macOS for the same output budget. No sibling uses a closer value, so I kept it for consistency. - Timeout, process failures and the provider's fallback in `WabtArtifactProvider.ts` (around line 385) still attach full captured output. Only the output-limit path is bounded here. - The error's `cause` still holds the full snapshot in memory. It is not serialized. - EVMole, pwntools and browser capture still map `output-limit` to `AnalysisOutputError`, so they show the same `rea doctor` advice for a size limit. Apktool keeps its capture unbounded. One excerpt step at the owning boundary in `src/process/` could cover all of them. That touches more providers, so I left it out of this PR. - `stdout_bytes` and `stderr_bytes` keep their shared meaning of retained bytes. The snapshot also knows how many bytes each stream produced before it stopped. That could go into the message or a new field if you want it. - When output passes the budget, `execute()` throws before it re-checks the executable digest and the module snapshot. So a swapped binary that floods output is reported as over budget, and its changed digest goes unnoticed. That control flow predates this change. - An oversized `--version` probe still maps to `unreadable_output`. `capability_unavailable` may fit a wrong tool better, as it does for a wrong banner. - A module this large still gets no result. Returning sections, imports and exports without inline WAT would be a separate feature. - PR #2084 also edits `src/wasm/WabtFailures.ts` and its test file. The two branches merge without conflicts. ## Contract and boundary impact - Semantic owner and earliest changed stage: WABT failure mapping in `wabtFailure` (`src/wasm/WabtFailures.ts`). - CLI and MCP/tool-catalog contract: when WABT output passes the budget during inspection, `inspect_wasm_artifact` returns the existing `resource_constraint` code instead of `unreadable_output`. No schemas change. - Provider, bridge, target-format, or platform compatibility: none. Modules under the budget are unchanged. - Evidence, artifact, provenance, or reconstruction contract: for an output-limit failure, `captured_output` keeps up to 4,096 bytes of what each stream retained, the retained byte counts, `exit_code`, `signal` and `truncated`. - Process execution, authorization, cleanup, or containment impact: none. The budget and the process handling are unchanged. - Generated metadata, package, or installation impact: none. ## Evidence and regression coverage - Tests added in `src/wasm/WabtArtifactProvider.test.ts`: - Through `inspect`, the real child processes run for the version probes and `wasm-objdump`, and the launcher raises an output-limit failure for `wasm2wat`. The test checks the error tag, resource, `max_output_bytes`, the projected `resource_constraint` code, that the message names the budget, the remediation, and the full `captured_output` with the excerpt, byte counts, exit code and signal. No test writes 32 MiB. - An oversized stderr is cut to the same excerpt and marks the output truncated. - An emoji that straddles the 4,096-byte cut is left out whole. - With a cleanup failure on top of the output limit, the diagnostics carry the excerpt and record the output limit as `previous_error`. - An output limit during the `--version` probe stays `AnalysisOutputError`. - Base reproduction: on `main` the first four tests fail. The fifth passes there, since it guards the configuration-phase behaviour this change keeps. Each part of the fix is needed. Keeping the full text fails the four excerpt tests. Cutting by UTF-16 units fails the emoji test. Setting `truncated` to false, reporting observed instead of retained byte counts, or dropping `exit_code` and `signal` each fails the `inspect` and stderr tests. Recording the generic command message as `previous_error` fails the cleanup test. Dropping the phase condition fails the `--version` test. Changing the resource to `cpu`, dropping `max_output_bytes`, dropping the byte count from the message, or using the old module-size remediation each fails the `inspect` test. - User-visible CLI output, with the fix, on `tree-sitter-cpp.wasm` (stdout excerpt shortened here): ```json {"code":"resource_constraint","category":"resource_constraint","message":"WABT output exceeded the 33554432-byte output budget","retryable":false,"remediation":{"action":"The WABT output budget is fixed, so retrying with the same input will fail the same way."},"details":{"operation":"inspect_wasm_artifact","resource":"memory","reason":"WABT output exceeded the 33554432-byte output budget","reported_limits":{"max_output_bytes":33554432},"captured_output":{"stdout":"(module\n (type (;0;) (func (param i32))...","stderr":"","truncated":true,"stdout_bytes":33554432,"stderr_bytes":0,"exit_code":0,"signal":null}}} ``` For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `vitest` over `src/wasm`, `tests/boundary/mcp/wasmArtifactMcp.test.ts`, `tests/acceptance/tools/localToolContracts.test.ts`, `src/contracts/toolEffects.test.ts` and `tests/boundary/filesystem/targetDiagnostics.test.ts`: 6 files, 56 tests passed. - `npm run check:fast`: passed. - `npm run docs:check`: passed. - `npm run verify:test-discovery`: "Discovered all 915 test files exactly once." - Real modules, built CLI, WABT 1.0.42, before and after. After the fix each oversized module reports `stdout_bytes` 33,554,432. `exit_code` and `signal` depend on whether WABT finished before it was stopped: the same module gave exit 0 on one run and `SIGKILL` on another. | Module | Before | After | | --- | --- | --- | | `tree-sitter-cpp.wasm` | `unreadable_output`, 33,606,368-byte error | `resource_constraint`, 4,932-byte error | | `tree-sitter-bash.wasm` | `unreadable_output`, 33,584,062-byte error | `resource_constraint`, 4,931-byte error | | `tree-sitter-powershell.wasm` | `unreadable_output`, 33,568,405-byte error | `resource_constraint`, 4,926-byte error | | `tree-sitter-c-sharp.wasm`, `onig.wasm`, `crc32.wasm` | ok | ok, same output size | | `vsda_bg.wasm` (not WebAssembly) | `invalid_request` | `invalid_request` | Costs, measured 2026-10-13 with the built CLI on this branch and on `main` at 4276aaf1, WABT 1.0.42, Linux x64, 12 cores. Each run had its own cgroup, so CPU and peak memory cover the whole process family, WABT children included. Per module and tree: one first run and three warm runs, with `main` and the branch alternating. The machine was shared, with a load average of 8 to 14 during the runs, so differences of a few hundred milliseconds are noise. "First" is not truly cold: the page cache was already warm from the build, and I could not drop it. | Module | Tree | First run: elapsed / CPU / peak | Warm median: elapsed / CPU / peak | Output | | --- | --- | --- | --- | --- | | `tree-sitter-cpp.wasm` | `main` | 4.2 s / 5.5 s / 535 MiB | 3.2 s / 5.5 s / 500 MiB | 33,606,368 B | | | branch | 3.2 s / 5.4 s / 485 MiB | 3.1 s / 5.1 s / 513 MiB | 4,924 B | | `tree-sitter-bash.wasm` | `main` | 3.0 s / 4.9 s / 470 MiB | 3.4 s / 5.1 s / 508 MiB | 33,584,062 B | | | branch | 2.8 s / 4.5 s / 517 MiB | 3.6 s / 5.0 s / 502 MiB | 4,931 B | | `tree-sitter-powershell.wasm` | `main` | 3.4 s / 5.1 s / 572 MiB | 3.2 s / 4.9 s / 598 MiB | 33,568,405 B | | | branch | 3.3 s / 4.9 s / 522 MiB | 3.0 s / 4.7 s / 535 MiB | 4,926 B | | `tree-sitter-c-sharp.wasm` (control, succeeds) | `main` | 4.8 s / 7.5 s / 631 MiB | 5.4 s / 7.7 s / 588 MiB | 64,132,114 B | | | branch | 4.8 s / 7.5 s / 588 MiB | 5.2 s / 7.8 s / 587 MiB | 64,132,114 B | Elapsed time, CPU time and peak memory show no change outside that noise. The process still reads the full 32 MiB before stopping, and `cause` still holds the snapshot, so I did not expect one. The change is in what the caller receives: about 4.9 KB instead of about 33.6 MB per failure. Token usage was not measured. I had no tokenizer for the agent's model on this machine, and fewer bytes alone do not prove fewer tokens. ## Compatibility, safety, and release - Breaking changes or migration steps: a caller that matched `unreadable_output` for oversized modules now gets `resource_constraint`. Neither code is retryable. - Real Hopper/Ghidra, browser, or OS coverage: Linux x64 (Fedora 44) only, with the WABT 1.0.42 release binaries. No other provider runs. - Package or release metadata impact: none. - Security, privacy, process, or containment review: the output budget and process handling are unchanged. The error carries at most 8,192 bytes of producer output, down from up to 32 MiB. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:00:15 +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#5041
No description provided.