Observed behavior: Static review confirms consumerLockCallback cleanup closes the publication descriptor before the root descriptor without isolating close failures. A publication close failure overwrites any callback/admission error and prevents the root close from being attempted.
Expected behavior: Attempt cleanup of every acquired descriptor even when an earlier close fails, and preserve the original operation failure plus independent cleanup failures.
Root cause: The finally in src/storage/backend-publication.ts:1385-1388 sequentially calls publicationHandle?.close() then rootHandle?.close(). A throw skips the second statement. The analogous asynchronous path should be assessed when implementing this issue.
How to reproduce safely: Use a private publication fixture and the existing descriptor-lifetime fs seam. Invoke withBackendPublicationConsumerLock with an injected callback error. Have publication-descriptor close genuinely close the fixture fd then throw another error. Verify the root close is skipped and the cleanup error replaces the callback error. Ensure the fixture harness finally closes outstanding descriptors. This is a source-validated report; that dynamic fixture has not been run. Do not use live HOME or daemon locks.
Environment:
- Agent: Codex / GLM-5.3 candidate review and Astra owner
- Connector: local source review
- OS: Fedora Linux
Found during #994 candidate 192d480286ce2588c8523fafa7f2b223a25733c3. Distinct from closed #837, which covers publication-open failure before entering cleanup; this concerns failure during cleanup itself. Distinct from #994 shared opener authentication catch. Preexisting out-of-scope follow-up outside frozen S3; no campaign native parent. Originating PR: #1043. Source:
|
return withBackendPublicationLock(homeDir, run); |
|
} finally { |
|
publicationHandle?.close(); |
|
rootHandle?.close(); |
Observed behavior: Static review confirms
consumerLockCallbackcleanup closes the publication descriptor before the root descriptor without isolating close failures. A publication close failure overwrites any callback/admission error and prevents the root close from being attempted.Expected behavior: Attempt cleanup of every acquired descriptor even when an earlier close fails, and preserve the original operation failure plus independent cleanup failures.
Root cause: The
finallyinsrc/storage/backend-publication.ts:1385-1388sequentially callspublicationHandle?.close()thenrootHandle?.close(). A throw skips the second statement. The analogous asynchronous path should be assessed when implementing this issue.How to reproduce safely: Use a private publication fixture and the existing descriptor-lifetime fs seam. Invoke
withBackendPublicationConsumerLockwith an injected callback error. Have publication-descriptor close genuinely close the fixture fd then throw another error. Verify the root close is skipped and the cleanup error replaces the callback error. Ensure the fixture harness finally closes outstanding descriptors. This is a source-validated report; that dynamic fixture has not been run. Do not use live HOME or daemon locks.Environment:
Found during #994 candidate
192d480286ce2588c8523fafa7f2b223a25733c3. Distinct from closed #837, which covers publication-open failure before entering cleanup; this concerns failure during cleanup itself. Distinct from #994 shared opener authentication catch. Preexisting out-of-scope follow-up outside frozen S3; no campaign native parent. Originating PR: #1043. Source:lcm/src/storage/backend-publication.ts
Lines 1385 to 1388 in 192d480