[GH-ISSUE #4483] [Bug] Artifact readback can replace IO failures and report success after cancellation #1775

Closed
opened 2026-10-16 21:10:08 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

  • Searched related open/closed readback and artifact cancellation reports; no matching primary defect found.
  • No credentials or sensitive target data included.

Area

Evidence, artifacts, or reconstruction

Observed behavior

A controlled real-file SafeOutputTree.write regression observes three readback defects: cancellation from a rejected read replaces the original EIO; cancellation at EOF retains a generated AbortError instead of the caller reason; cancellation during final pathname identity validation returns a successful write. All five cases fail before correction (three caller-reason controls).

Reproduction

Run npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts in the local audit checkout. The regression uses real private directories/files and production SafeOutputTree.write/readback, injecting read completion and lstat cancellation. No real archive/firmware producer failure or natural EIO occurrence is claimed.

Expected behavior

AGENTS.md requires preserving primary failures, explicit caller values and operation completion semantics. Normalize cancellation at its observed producing boundary; retain an existing I/O failure, exact caller reason and final identity-validation lifetime.

Impact and scope

Observed in controlled local production-boundary tests. Source-derived: DirectoryArtifactReader and MachOSliceArtifactReader have similar late-signal reclassification catches around the shared chunk reader. Natural failure frequency and full CLI/MCP impact are unverified.

REA version

6.5.0; main base fe2a398dd9 with ongoing audit changes.

Runtime and platform

Node24.18.0, macOS arm64. Native Windows not run.

Target and artifact context

Owned output file durable readback, streamed directory/archive members.

Interface

Shared artifact provider; executed production filesystem boundary, not public CLI/MCP.

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

Before-fix regression:5 failed/5. Source: src/artifacts/SafeOutputTreeReadback.ts catches all read errors and checks the later signal; src/filesystem/readFileHandleChunks.ts attaches stream cancellation while raw read is pending; readback lacks a signal check after final assertFilePathIdentity. The exact original EIO object is replaced; explicit null/string/typed-error caller reasons become AbortError; final identity case returns {relativePath,sha256,bytesWritten}.

Typed outcome or recovery expected

Original EIO remains primary. Actual interruption is a typed cancellation with the exact reason. Readback final identity validation belongs to the operation lifetime. Confirmed tree rollback removes only its owned files.

Analysis or suspected cause

Duplicated downstream interpretation of current signal state plus a producer stream that can settle cancellation before its pending descriptor read. Correct the shared read representation and consumers instead of guessing from a later signal.

Additional context

AI-assisted source audit plus controlled runtime regression. Complete real archive, firmware and CLI/MCP runs are not established by these tests.

Originally created by @morluto on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4483 ### Before submitting - [x] Searched related open/closed readback and artifact cancellation reports; no matching primary defect found. - [x] No credentials or sensitive target data included. ### Area Evidence, artifacts, or reconstruction ### Observed behavior A controlled real-file SafeOutputTree.write regression observes three readback defects: cancellation from a rejected read replaces the original EIO; cancellation at EOF retains a generated AbortError instead of the caller reason; cancellation during final pathname identity validation returns a successful write. All five cases fail before correction (three caller-reason controls). ### Reproduction Run `npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts` in the local audit checkout. The regression uses real private directories/files and production SafeOutputTree.write/readback, injecting read completion and lstat cancellation. No real archive/firmware producer failure or natural EIO occurrence is claimed. ### Expected behavior AGENTS.md requires preserving primary failures, explicit caller values and operation completion semantics. Normalize cancellation at its observed producing boundary; retain an existing I/O failure, exact caller reason and final identity-validation lifetime. ### Impact and scope Observed in controlled local production-boundary tests. Source-derived: DirectoryArtifactReader and MachOSliceArtifactReader have similar late-signal reclassification catches around the shared chunk reader. Natural failure frequency and full CLI/MCP impact are unverified. ### REA version 6.5.0; main base fe2a398dd9ab290ba6cb3411403d319cec8d07a2 with ongoing audit changes. ### Runtime and platform Node24.18.0, macOS arm64. Native Windows not run. ### Target and artifact context Owned output file durable readback, streamed directory/archive members. ### Interface Shared artifact provider; executed production filesystem boundary, not public CLI/MCP. ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence Before-fix regression:5 failed/5. Source: src/artifacts/SafeOutputTreeReadback.ts catches all read errors and checks the later signal; src/filesystem/readFileHandleChunks.ts attaches stream cancellation while raw read is pending; readback lacks a signal check after final assertFilePathIdentity. The exact original EIO object is replaced; explicit null/string/typed-error caller reasons become AbortError; final identity case returns `{relativePath,sha256,bytesWritten}`. ### Typed outcome or recovery expected Original EIO remains primary. Actual interruption is a typed cancellation with the exact reason. Readback final identity validation belongs to the operation lifetime. Confirmed tree rollback removes only its owned files. ### Analysis or suspected cause Duplicated downstream interpretation of current signal state plus a producer stream that can settle cancellation before its pending descriptor read. Correct the shared read representation and consumers instead of guessing from a later signal. ### Additional context AI-assisted source audit plus controlled runtime regression. Complete real archive, firmware and CLI/MCP runs are not established by these tests.
Author
Owner

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

TL;DR: This does not reproduce on main 8f7d12e30 (#4962) on Linux. The test the issue names passes 8 of 8 on Node 22, 24 and 26. On Node 24, the same test fails 8 of 8 on 9abdad335, the parent of 542fa8495, and passes 8 of 8 at 542fa8495.

The report came from Node 24.18.0 on macOS arm64. I ran the issue's command on Linux:
npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts

Commit 542fa8495 says "Refs #4458, #4483". It added this test file. It also changed both source files the issue names: SafeOutputTreeReadback.ts and readFileHandleChunks.ts. So the test on main is the fix's own regression test. This issue is still open. Open PR #4493 lists it under "Resolves"; I did not run that PR.

Results

Check Node 22.23.1 Node 24.18.0 Node 26.11.1
main 8f7d12e30, 8 tests 8 pass 8 pass 8 pass
542fa8495, same 8 tests (control) not run 8 pass not run
9abdad335, same 8 tests (control) not run 8 fail not run

The file has 8 cases. The issue's five look like the first five cases to me. One is a rejected read with cancellation. Three are end-of-file caller reasons. One is a final identity check. The other three are unpacked ASAR cases.

On 9abdad335 I saw the three defects the issue describes:

  • The rejected read gave Artifact extraction cancelled, not the original EIO error.
  • The end-of-file cases gave no cancellation reason, not the caller reason.
  • The final identity check returned a successful write result.

The three ASAR cases failed there too. I did not look into why.

Not run

  • macOS arm64 and native Windows.
  • The two controls on Node 22 and 26. I ran them on Node 24 only.
  • The late-signal catches in DirectoryArtifactReader and MachOSliceArtifactReader. The issue calls them source-derived. I wrote no separate test for them.
  • Real archive, firmware, CLI and MCP runs. The issue does not claim them either.
  • PR #4493, which I did not build or test.
  • Any other test file, and the full suite.

Thanks, morluto, for the detailed report and the ready-made test.

Commands

Run from a clone of morluto/rea. Node 24 is shown. For Node 22 I used the system node. For Node 26 I put its bin first on PATH.

git archive 8f7d12e30d63f3d3b4cfe2a90336362841438f56 | tar -x -C /tmp/i4483/src
env -C /tmp/i4483/src PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts
env -C /tmp/i4483/src PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts

Control on the parent of 542fa8495. The parent has no copy of the test, so I copied in the one from main:

git archive 9abdad335c22cf5af2a4518a0a3f8864ea7f983a | tar -x -C /tmp/i4483/prefix
cp /tmp/i4483/src/tests/process-global/artifactReadFailurePrecedence.test.ts /tmp/i4483/prefix/tests/process-global/
env -C /tmp/i4483/prefix PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts
env -C /tmp/i4483/prefix PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts

Control at 542fa8495. The test file is already in that commit:

git archive 542fa84957bbd8a21c1969d88b23a613fb437e36 | tar -x -C /tmp/i4483/fixcommit
env -C /tmp/i4483/fixcommit PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts
env -C /tmp/i4483/fixcommit PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts

Exit codes: 0 on main for Node 22, 24 and 26. 1 on 9abdad335. 0 on 542fa8495.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 22.23.1, 24.18.0, 26.11.1
  • Head / base: 8f7d12e30 (#4962) / none, since this is an issue check
  • Other: rea-agents 6.6.0 on main, 6.5.0 on the two control trees; vitest 5.0.3; each run wrapped in an 8 GB memory cap; other test agents may have shared the box, and I report no timings

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6247496894 --> @CassieFox23 commented on GitHub (Oct 18, 2026): **TL;DR:** This does not reproduce on main 8f7d12e30 (#4962) on Linux. The test the issue names passes 8 of 8 on Node 22, 24 and 26. On Node 24, the same test fails 8 of 8 on 9abdad335, the parent of 542fa8495, and passes 8 of 8 at 542fa8495. The report came from Node 24.18.0 on macOS arm64. I ran the issue's command on Linux: `npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts` Commit 542fa8495 says "Refs #4458, #4483". It added this test file. It also changed both source files the issue names: `SafeOutputTreeReadback.ts` and `readFileHandleChunks.ts`. So the test on main is the fix's own regression test. This issue is still open. Open PR #4493 lists it under "Resolves"; I did not run that PR. ### Results | Check | Node 22.23.1 | Node 24.18.0 | Node 26.11.1 | |---|---|---|---| | main 8f7d12e30, 8 tests | 8 pass | 8 pass | 8 pass | | 542fa8495, same 8 tests (control) | not run | 8 pass | not run | | 9abdad335, same 8 tests (control) | not run | 8 fail | not run | The file has 8 cases. The issue's five look like the first five cases to me. One is a rejected read with cancellation. Three are end-of-file caller reasons. One is a final identity check. The other three are unpacked ASAR cases. On 9abdad335 I saw the three defects the issue describes: - The rejected read gave `Artifact extraction cancelled`, not the original EIO error. - The end-of-file cases gave no cancellation reason, not the caller reason. - The final identity check returned a successful write result. The three ASAR cases failed there too. I did not look into why. ### Not run - macOS arm64 and native Windows. - The two controls on Node 22 and 26. I ran them on Node 24 only. - The late-signal catches in `DirectoryArtifactReader` and `MachOSliceArtifactReader`. The issue calls them source-derived. I wrote no separate test for them. - Real archive, firmware, CLI and MCP runs. The issue does not claim them either. - PR #4493, which I did not build or test. - Any other test file, and the full suite. Thanks, morluto, for the detailed report and the ready-made test. <details> <summary>Commands</summary> Run from a clone of morluto/rea. Node 24 is shown. For Node 22 I used the system node. For Node 26 I put its `bin` first on PATH. ```bash git archive 8f7d12e30d63f3d3b4cfe2a90336362841438f56 | tar -x -C /tmp/i4483/src env -C /tmp/i4483/src PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts env -C /tmp/i4483/src PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts ``` Control on the parent of 542fa8495. The parent has no copy of the test, so I copied in the one from main: ```bash git archive 9abdad335c22cf5af2a4518a0a3f8864ea7f983a | tar -x -C /tmp/i4483/prefix cp /tmp/i4483/src/tests/process-global/artifactReadFailurePrecedence.test.ts /tmp/i4483/prefix/tests/process-global/ env -C /tmp/i4483/prefix PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts env -C /tmp/i4483/prefix PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts ``` Control at 542fa8495. The test file is already in that commit: ```bash git archive 542fa84957bbd8a21c1969d88b23a613fb437e36 | tar -x -C /tmp/i4483/fixcommit env -C /tmp/i4483/fixcommit PATH=$HOME/.local/opt/node24/bin:$PATH npm ci --ignore-scripts env -C /tmp/i4483/fixcommit PATH=$HOME/.local/opt/node24/bin:$PATH npm run test:focused -- tests/process-global/artifactReadFailurePrecedence.test.ts ``` Exit codes: 0 on main for Node 22, 24 and 26. 1 on 9abdad335. 0 on 542fa8495. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 22.23.1, 24.18.0, 26.11.1 - Head / base: 8f7d12e30 (#4962) / none, since this is an issue check - Other: rea-agents 6.6.0 on main, 6.5.0 on the two control trees; vitest 5.0.3; each run wrapped in an 8 GB memory cap; other test agents may have shared the box, and I report no timings </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

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

Closing as fixed on main after reconciling this report with the landed owner/consumer changes.

  • 542fa8495: fix(artifacts): retain descriptor ownership and read completion facts. Own admitted descriptors through final close, retain exact failed owners, and preserve physical read failures and cancellation reasons. Track stream coverage independently from delivered bytes and share the boundary across archive, Mach-O, hashing, and output readback consumers.

Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.

<!-- gh-comment-id:6256014675 --> @morluto commented on GitHub (Oct 18, 2026): <!-- rea-backlog-reconciliation-2026-10-19-4483 --> Closing as fixed on `main` after reconciling this report with the landed owner/consumer changes. - [542fa8495](https://github.com/morluto/rea/commit/542fa84957bbd8a21c1969d88b23a613fb437e36): fix(artifacts): retain descriptor ownership and read completion facts. Own admitted descriptors through final close, retain exact failed owners, and preserve physical read failures and cancellation reasons. Track stream coverage independently from delivered bytes and share the boundary across archive, Mach-O, hashing, and output readback consumers. Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.
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#1775
No description provided.