Skip to content

fix: stop block reassembly on premature EOF - #151

Draft
robjarawan wants to merge 2 commits into
developmentfrom
fix/block-reassembly-short-read-refresh
Draft

fix: stop block reassembly on premature EOF#151
robjarawan wants to merge 2 commits into
developmentfrom
fix/block-reassembly-short-read-refresh

Conversation

@robjarawan

Copy link
Copy Markdown
Owner

Closes #65

What happened

Block_reassembly.after_work() kept reading until it reached the manifest byte count. If the part reached EOF first, read() returned b'', the byte counter stopped moving, and the loop held result.flufl_lock forever.

I reproduced it through a real local subscribe flow using the normal result§block_0000,4bytes_§ suffix. The source and announcement both had four bytes, then a proof callback truncated the downloaded part to two bytes immediately before reassembly.

Before this change:

{"hung": true, "lock_available": false, "part_exists": true,
 "retry_records": 0, "returncode": -9, "root_size": 0}

The complete four-byte control returned normally and produced the correct file.

What I changed

I changed the copy loop to detect EOF before the announced block size. It now closes both files, keeps the part, moves the message to worklist.failed, releases the reassembly lock and continues.

After the change, the same running-flow proof reports:

{"hung": false, "lock_available": true, "part_exists": true,
 "retry_records": 1, "returncode": 0, "root_size": 2}

The unit regression then repairs the retained part to four bytes and retries it. Reassembly produces the exact abcd result and releases the lock.

Validation

A naturally short source is caught by Flow.download() before this callback. The confirmed trigger is the part becoming short after download, including a filesystem race or an earlier callback.

The running proof also reaches the separate retry-path ordering problem in #66: the failed record is preserved, but its immediate retry uses an adjusted path. I left that out of this change so this PR only removes the infinite loop and preserves recovery state.

CI scope

This branch includes the existing local-fixture workflow repair from #140 so fork CI does not run public dynamic flows.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Test Results

376 tests   375 ✅  1m 44s ⏱️
  1 suites    1 💤
  1 files      0 ❌

Results for commit bee6465.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prevent short block reassembly from hanging under lock

1 participant