[PR #6229] [MERGED] fix(pcap): report workspace allocation failures by their system cause #7212

Closed
opened 2026-11-01 21:46:11 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

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

Base: main ← Head: fix/6123-pcap-workspace-allocation-errors


📝 Commits (2)

  • eb23efc fix(pcap): report workspace allocation failures by their system cause
  • f43b377 fix(flutter): locate owned storage failures by their workspace

📊 Changes

8 files changed (+430 additions, -79 deletions)

View changed files

📝 src/captures/TsharkCaptureProvider.ts (+7 -25)
📝 src/flutter/FlutterBuildProvider.ts (+24 -12)
📝 src/pcap/PcapSnapshot.ts (+3 -14)
➕ src/process/privateWorkspaceFailure.test.ts (+56 -0)
➕ src/process/privateWorkspaceFailure.ts (+77 -0)
📝 src/signals/SigrokRecordingProvider.ts (+7 -25)
📝 tests/boundary/filesystem/flutterBuildProvider.test.ts (+26 -3)
➕ tests/boundary/mcp/pcapWorkspaceAllocation.test.ts (+230 -0)

📄 Description

What broke: inspect_pcap_capture reported any failure to allocate or write its private workspace, including real ENOTDIR/EACCES from mkdtemp, as resource_constraint / resource: "file-size" with reported_limits: null and worker file-size advice. The errno and failing path were lost. Flutter's owned snapshot storage had the same errno-blind mapping.
Fix: One shared owner, src/process/privateWorkspaceFailure.ts, classifies private-workspace filesystem failures. ENOSPC/EDQUOT/EFBIG stay file-size resource constraints, now with their system code and path. All other failures become a provider workspace failure (execution_failure) with stage, workspace path, failing path, system code and recovery that fits the cause. Pcap, Flutter, TShark and sigrok all use it, and the duplicate TShark/sigrok copies are removed.
Risk: Low. No schema change. Pcap and Flutter workspace failures that are not about storage move from resource_constraint to execution_failure with diagnostics. TShark/sigrok keep their classification and gain path plus cause-specific remediation.

Summary

Fixes #6123.

Before this change, PcapSnapshot.create turned every allocation failure except the privacy-capability one into a file-size resource constraint. PcapSnapshot.capture did the same for writes inside the workspace (Owned capture snapshot I/O failed). A denied or non-directory temporary parent was therefore reported as an exceeded size allowance, with no errno and no path. Now a workspace failure keeps its system cause, its failing path and cause-specific recovery. Real size refusals are still reported as size limits.

Problem and expected behavior

Smallest trigger: run inspect_pcap_capture with the pcap workspace parent set to a regular file (ENOTDIR) or to a mode-0500 directory (EACCES). This violates the AnalysisResourceConstraintError contract, which means a measured resource limit or a bounded admission refusal. A permission denial or a bad path does not establish either. Expected: a workspace-preparation failure that preserves system_code and the path and points recovery at the temporary parent. Genuine storage exhaustion keeps its cause and gets storage-specific recovery.

Change and scope

  • src/process/privateWorkspaceFailure.ts (new) is the single owner of private-workspace filesystem failure projection:
    • ENOSPC/EDQUOT produce AnalysisResourceConstraintError("file-size"). reported_limits carries {workspace_path, path, system_code} and the remediation says to free disk space or quota.
    • EFBIG produces the same constraint and keeps the default worker file-size recovery.
    • EMFILE/ENFILE produce ProviderAdapterError whose remediation says to close files or raise the open-file limit.
    • Any other errno, or a cause with no errno, produces ProviderAdapterError. Its diagnostics hold {stage: "workspace", workspace_path, path, system_code, reason} and its remediation covers TMPDIR existence, permission and writability.
    • path is the errno's own coordinate when one exists (for example the mkdtemp template) and otherwise the workspace path.
  • src/pcap/PcapSnapshot.ts: allocation failures and snapshot workspace writes (mkdir of the configuration directory, the wx open, write, chmod) use the shared owner. The privacy-capability path (PrivateRuntimeRootUnavailableError) and source-read handling are unchanged.
  • src/flutter/FlutterBuildProvider.ts: the errno branch of mapOwnedIoFailure uses the shared owner. It previously mapped every errno, EACCES included, to file-size. mapOwnedIoFailure now receives the owned root (null only before mkdtemp succeeds). Package-reader system errors propagate to the request owner, which maps them against snapshot.root, so failures with no errno path still name their workspace.
  • src/captures/TsharkCaptureProvider.ts and src/signals/SigrokRecordingProvider.ts: their identical inline workspace classification is replaced by the shared owner.
  • Sweep: I checked every other "file-size" producer. They are real size guards or SIGXFSZ projections. Other PrivateRuntimeRoot.create callers (firmware, apktool, lldb, kuna, ida, and others) do not project allocation errors as size limits.
  • Not included: no new public error type or resource kind, and no change to how PrivateRuntimeRoot allocates.

Contribution scope: not applicable. This is an ordinary fix within existing boundaries.

Contract and boundary impact

  • Semantic owner and earliest changed stage: privateWorkspaceFailure (src/process), at workspace allocation and owned-snapshot writes.

  • Contribution scope fit and linked maintainer decision: not applicable (ordinary fix).

  • CLI and MCP/tool-catalog contract: no schema change. Error projections for non-storage workspace failures change from resource_constraint to execution_failure and now include details.diagnostics.

  • Provider, bridge, target-format, or platform compatibility: pcap, Flutter, TShark and sigrok. No platform behavior change.

  • Evidence, artifact, provenance, or reconstruction contract: none. The failure happens before any capture bytes are read.

  • Target selection, authority, upstream behavior, and cleanup details: unchanged. A partially prepared pcap workspace is still removed; the new test covers this.

  • Generated metadata, package, or installation impact: none.

  • Read existing files or captured data.

(This is what the existing tools already do. This PR adds no new effects.)

Evidence and regression coverage

  • Tests added or updated:

    • tests/boundary/mcp/pcapWorkspaceAllocation.test.ts (new) runs through the production MCP server, PcapProvider and the POSIX tool stubs. Native admission is simulated so macOS reaches allocation, as in the issue. It covers:
      • real ENOTDIR and real EACCES from mkdtemp;
      • a writable-parent control, which reaches invalid_request;
      • simulated ENOSPC/EDQUOT (resource constraint plus storage recovery);
      • simulated EMFILE/ENFILE (descriptor recovery);
      • simulated EROFS;
      • a real EACCES on the configuration directory inside an allocated workspace, checking workspace_path, the failing path and that the partial workspace is removed;
      • a counterexample: a sparse capture one byte over the 2 GiB snapshot allowance is still resource_constraint / file-size with max_capture_bytes.
    • src/process/privateWorkspaceFailure.test.ts (new): EFBIG keeps the file-size recovery, and errno without a path, an error without errno, and a non-Error value all fall back to the workspace coordinate.
    • tests/boundary/filesystem/flutterBuildProvider.test.ts: owned-storage ENOSPC stays resource_constraint, and EACCES/EPERM/EIO become workspace execution_failure with system_code. Each case also asserts workspace_path and path: null for the root stage and the rea-flutter-* root otherwise. 7 of the 8 cases fail without the root threading.
  • Base reproduction: on base 34fd7bdf7, the issue's focused test reproduced the bug verbatim. ENOTDIR and EACCES both projected as resource_constraint / file-size / reported_limits: null with no errno, and the normal-parent control returned invalid_request. With only src/pcap/PcapSnapshot.ts reverted, 8 of the 10 new MCP tests fail. The 2 that still pass are the control and the size-limit counterexample.

  • User-visible MCP output (fixed, real EACCES from mkdtemp):

    {"code":"execution_failure","category":"execution_failure","message":"Cannot prepare the private analysis workspace (EACCES): EACCES: permission denied, mkdtemp '<fixture-root>/parent/rea-pcap-Gq5FCR'","retryable":false,"remediation":{"action":"Review details.diagnostics.system_code and details.diagnostics.path. Make the host temporary directory (TMPDIR) an existing directory this user can create files in on a writable filesystem, then retry."},"details":{"provider_id":"pcap","operation":"inspect_pcap_capture","diagnostics":{"stage":"workspace","workspace_path":null,"path":"<fixture-root>/parent/rea-pcap-Gq5FCR","system_code":"EACCES","reason":"EACCES: permission denied, mkdtemp '<fixture-root>/parent/rea-pcap-Gq5FCR'"}}}
    
  • Remaining proof gaps:

    • ENOSPC, EDQUOT, EMFILE, ENFILE and EROFS were simulated as thrown errno errors, not produced by a full disk or exhausted descriptors.
    • No real Wireshark, and no native Linux/Windows run; native admission was simulated on macOS.
    • The Linux-only pcap, TShark and sigrok suites were skipped locally on macOS and rely on CI.
  • 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

All runs were on macOS arm64 as a non-root user.

  • Issue repro test (temporary file, base code): reproduced, with both cases projected as file-size.
  • vitest run tests/boundary/mcp/pcapWorkspaceAllocation.test.ts: 10 passed. With the pcap fix reverted: 8 failed, 2 passed.
  • vitest run across the Flutter provider, tests/boundary/{captures,signals,pcap}, the pcap and packet-capture MCP tests, the artifact process boundary tests and the new unit test: 262 passed and 44 skipped, the skips being Linux-only suites.
  • npm run check:fast: passed.
  • npm run format:check: passed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. A caller that keyed on resource_constraint for a non-storage pcap or Flutter workspace failure now gets execution_failure with details.diagnostics.system_code.
  • Real Hopper/Ghidra, browser, or OS coverage: real macOS filesystem ENOTDIR/EACCES only. No real Wireshark.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: diagnostics expose only the local temporary path and errno text that the provider itself chose. No caller input bytes are included.

Author readiness

Human owner: @kaoru0822-kitauji

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • 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.

🤖 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/6229 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/22/2026 **Status:** ✅ Merged **Merged:** 10/22/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/6123-pcap-workspace-allocation-errors` --- ### 📝 Commits (2) - [`eb23efc`](https://github.com/morluto/rea/commit/eb23efc1bf33712132cb648f487155bfd3dc72b9) fix(pcap): report workspace allocation failures by their system cause - [`f43b377`](https://github.com/morluto/rea/commit/f43b37719ce8b4d41c15044c05b815e06b206f54) fix(flutter): locate owned storage failures by their workspace ### 📊 Changes **8 files changed** (+430 additions, -79 deletions) <details> <summary>View changed files</summary> 📝 `src/captures/TsharkCaptureProvider.ts` (+7 -25) 📝 `src/flutter/FlutterBuildProvider.ts` (+24 -12) 📝 `src/pcap/PcapSnapshot.ts` (+3 -14) ➕ `src/process/privateWorkspaceFailure.test.ts` (+56 -0) ➕ `src/process/privateWorkspaceFailure.ts` (+77 -0) 📝 `src/signals/SigrokRecordingProvider.ts` (+7 -25) 📝 `tests/boundary/filesystem/flutterBuildProvider.test.ts` (+26 -3) ➕ `tests/boundary/mcp/pcapWorkspaceAllocation.test.ts` (+230 -0) </details> ### 📄 Description **What broke:** `inspect_pcap_capture` reported any failure to allocate or write its private workspace, including real `ENOTDIR`/`EACCES` from `mkdtemp`, as `resource_constraint` / `resource: "file-size"` with `reported_limits: null` and worker file-size advice. The errno and failing path were lost. Flutter's owned snapshot storage had the same errno-blind mapping. **Fix:** One shared owner, `src/process/privateWorkspaceFailure.ts`, classifies private-workspace filesystem failures. `ENOSPC`/`EDQUOT`/`EFBIG` stay file-size resource constraints, now with their system code and path. All other failures become a provider workspace failure (`execution_failure`) with stage, workspace path, failing path, system code and recovery that fits the cause. Pcap, Flutter, TShark and sigrok all use it, and the duplicate TShark/sigrok copies are removed. **Risk:** Low. No schema change. Pcap and Flutter workspace failures that are not about storage move from `resource_constraint` to `execution_failure` with diagnostics. TShark/sigrok keep their classification and gain `path` plus cause-specific remediation. ## Summary Fixes #6123. Before this change, `PcapSnapshot.create` turned every allocation failure except the privacy-capability one into a `file-size` resource constraint. `PcapSnapshot.capture` did the same for writes inside the workspace (`Owned capture snapshot I/O failed`). A denied or non-directory temporary parent was therefore reported as an exceeded size allowance, with no errno and no path. Now a workspace failure keeps its system cause, its failing path and cause-specific recovery. Real size refusals are still reported as size limits. ## Problem and expected behavior Smallest trigger: run `inspect_pcap_capture` with the pcap workspace parent set to a regular file (`ENOTDIR`) or to a mode-0500 directory (`EACCES`). This violates the `AnalysisResourceConstraintError` contract, which means a measured resource limit or a bounded admission refusal. A permission denial or a bad path does not establish either. Expected: a workspace-preparation failure that preserves `system_code` and the path and points recovery at the temporary parent. Genuine storage exhaustion keeps its cause and gets storage-specific recovery. ## Change and scope - `src/process/privateWorkspaceFailure.ts` (new) is the single owner of private-workspace filesystem failure projection: - `ENOSPC`/`EDQUOT` produce `AnalysisResourceConstraintError("file-size")`. `reported_limits` carries `{workspace_path, path, system_code}` and the remediation says to free disk space or quota. - `EFBIG` produces the same constraint and keeps the default worker file-size recovery. - `EMFILE`/`ENFILE` produce `ProviderAdapterError` whose remediation says to close files or raise the open-file limit. - Any other errno, or a cause with no errno, produces `ProviderAdapterError`. Its `diagnostics` hold `{stage: "workspace", workspace_path, path, system_code, reason}` and its remediation covers TMPDIR existence, permission and writability. - `path` is the errno's own coordinate when one exists (for example the `mkdtemp` template) and otherwise the workspace path. - `src/pcap/PcapSnapshot.ts`: allocation failures and snapshot workspace writes (`mkdir` of the configuration directory, the `wx` open, write, `chmod`) use the shared owner. The privacy-capability path (`PrivateRuntimeRootUnavailableError`) and source-read handling are unchanged. - `src/flutter/FlutterBuildProvider.ts`: the errno branch of `mapOwnedIoFailure` uses the shared owner. It previously mapped every errno, `EACCES` included, to `file-size`. `mapOwnedIoFailure` now receives the owned root (`null` only before `mkdtemp` succeeds). Package-reader system errors propagate to the request owner, which maps them against `snapshot.root`, so failures with no errno path still name their workspace. - `src/captures/TsharkCaptureProvider.ts` and `src/signals/SigrokRecordingProvider.ts`: their identical inline workspace classification is replaced by the shared owner. - Sweep: I checked every other `"file-size"` producer. They are real size guards or SIGXFSZ projections. Other `PrivateRuntimeRoot.create` callers (firmware, apktool, lldb, kuna, ida, and others) do not project allocation errors as size limits. - Not included: no new public error type or resource kind, and no change to how `PrivateRuntimeRoot` allocates. Contribution scope: not applicable. This is an ordinary fix within existing boundaries. ## Contract and boundary impact - Semantic owner and earliest changed stage: `privateWorkspaceFailure` (src/process), at workspace allocation and owned-snapshot writes. - Contribution scope fit and linked maintainer decision: not applicable (ordinary fix). - CLI and MCP/tool-catalog contract: no schema change. Error projections for non-storage workspace failures change from `resource_constraint` to `execution_failure` and now include `details.diagnostics`. - Provider, bridge, target-format, or platform compatibility: pcap, Flutter, TShark and sigrok. No platform behavior change. - Evidence, artifact, provenance, or reconstruction contract: none. The failure happens before any capture bytes are read. - Target selection, authority, upstream behavior, and cleanup details: unchanged. A partially prepared pcap workspace is still removed; the new test covers this. - Generated metadata, package, or installation impact: none. - [x] Read existing files or captured data. (This is what the existing tools already do. This PR adds no new effects.) ## Evidence and regression coverage - Tests added or updated: - `tests/boundary/mcp/pcapWorkspaceAllocation.test.ts` (new) runs through the production MCP server, `PcapProvider` and the POSIX tool stubs. Native admission is simulated so macOS reaches allocation, as in the issue. It covers: - real `ENOTDIR` and real `EACCES` from `mkdtemp`; - a writable-parent control, which reaches `invalid_request`; - simulated `ENOSPC`/`EDQUOT` (resource constraint plus storage recovery); - simulated `EMFILE`/`ENFILE` (descriptor recovery); - simulated `EROFS`; - a real `EACCES` on the configuration directory inside an allocated workspace, checking `workspace_path`, the failing path and that the partial workspace is removed; - a counterexample: a sparse capture one byte over the 2 GiB snapshot allowance is still `resource_constraint` / `file-size` with `max_capture_bytes`. - `src/process/privateWorkspaceFailure.test.ts` (new): `EFBIG` keeps the file-size recovery, and errno without a path, an error without errno, and a non-Error value all fall back to the workspace coordinate. - `tests/boundary/filesystem/flutterBuildProvider.test.ts`: owned-storage `ENOSPC` stays `resource_constraint`, and `EACCES`/`EPERM`/`EIO` become workspace `execution_failure` with `system_code`. Each case also asserts `workspace_path` and `path`: `null` for the root stage and the `rea-flutter-*` root otherwise. 7 of the 8 cases fail without the root threading. - Base reproduction: on base `34fd7bdf7`, the issue's focused test reproduced the bug verbatim. `ENOTDIR` and `EACCES` both projected as `resource_constraint` / `file-size` / `reported_limits: null` with no errno, and the normal-parent control returned `invalid_request`. With only `src/pcap/PcapSnapshot.ts` reverted, 8 of the 10 new MCP tests fail. The 2 that still pass are the control and the size-limit counterexample. - User-visible MCP output (fixed, real `EACCES` from `mkdtemp`): ```json {"code":"execution_failure","category":"execution_failure","message":"Cannot prepare the private analysis workspace (EACCES): EACCES: permission denied, mkdtemp '<fixture-root>/parent/rea-pcap-Gq5FCR'","retryable":false,"remediation":{"action":"Review details.diagnostics.system_code and details.diagnostics.path. Make the host temporary directory (TMPDIR) an existing directory this user can create files in on a writable filesystem, then retry."},"details":{"provider_id":"pcap","operation":"inspect_pcap_capture","diagnostics":{"stage":"workspace","workspace_path":null,"path":"<fixture-root>/parent/rea-pcap-Gq5FCR","system_code":"EACCES","reason":"EACCES: permission denied, mkdtemp '<fixture-root>/parent/rea-pcap-Gq5FCR'"}}} ``` - Remaining proof gaps: - `ENOSPC`, `EDQUOT`, `EMFILE`, `ENFILE` and `EROFS` were simulated as thrown errno errors, not produced by a full disk or exhausted descriptors. - No real Wireshark, and no native Linux/Windows run; native admission was simulated on macOS. - The Linux-only pcap, TShark and sigrok suites were skipped locally on macOS and rely on CI. - [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 All runs were on macOS arm64 as a non-root user. - Issue repro test (temporary file, base code): reproduced, with both cases projected as `file-size`. - `vitest run tests/boundary/mcp/pcapWorkspaceAllocation.test.ts`: 10 passed. With the pcap fix reverted: 8 failed, 2 passed. - `vitest run` across the Flutter provider, `tests/boundary/{captures,signals,pcap}`, the pcap and packet-capture MCP tests, the artifact process boundary tests and the new unit test: 262 passed and 44 skipped, the skips being Linux-only suites. - `npm run check:fast`: passed. - `npm run format:check`: passed. ## Compatibility, safety, and release - Breaking changes or migration steps: none. A caller that keyed on `resource_constraint` for a non-storage pcap or Flutter workspace failure now gets `execution_failure` with `details.diagnostics.system_code`. - Real Hopper/Ghidra, browser, or OS coverage: real macOS filesystem `ENOTDIR`/`EACCES` only. No real Wireshark. - Package or release metadata impact: none. - Security, privacy, process, or containment review: diagnostics expose only the local temporary path and errno text that the provider itself chose. No caller input bytes are included. ## Author readiness Human owner: @kaoru0822-kitauji - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [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. 🤖 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-11-01 21:46:11 +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#7212
No description provided.