[PR #4446] [MERGED] fix(managed): retain descriptor ownership through hash cancellation #6246

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4446
Author: @N0zoM1z0
Created: 10/16/2026
Status: ✅ Merged
Merged: 10/16/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/managed-hash-cancellation-4381


📝 Commits (2)

  • 320e319 fix(managed): preserve owned handles during hash cancellation
  • d6fa191 fix(managed): preserve opaque hash cancellation reasons

📊 Changes

2 files changed (+212 additions, -23 deletions)

View changed files

📝 src/dotnet/ManagedSnapshot.ts (+33 -23)
➕ tests/boundary/providers/managed/managedHashCancellation.test.ts (+179 -0)

📄 Description

Summary

Fixes #4381; lifecycle audit follow-up for #4227.

Cancelling a cached managed-source hash let Node's ReadStream invalidate a borrowed FileHandle before its owner confirmed close. The provider then retained unconfirmable cleanup and could not recover. Hashing now uses bounded reads through the existing owner; cancellation closes normally, and genuine close failure retains that exact owner for retry.

This adopts @xu91102's published patch, preserving original commit authorship. Independent Linux verification also exposed cancellation reasons with filesystem codes or cleanup-record shapes being reinterpreted. Exact caller reasons now remain opaque; independent read errors retain their primary meaning.

Change and boundary impact

  • Owner/earliest stage: managed static provider source hashing and managed read-error normalization. Fixed 64 KiB buffer; existing 128 MiB snapshot budget and one-byte growth probe remain. Each cached use still verifies the current source digest.
  • Scope decision: not applicable; ordinary fix to existing read-only static analysis. No target execution, new provider, permissions or recovery authority.
  • CLI/MCP, schemas, package/dependencies/generated metadata: unchanged. Both adapters retain their shared workflow. No additional response data or cache.
  • Evidence: same source identity, digest, coverage and full retained Evidence. Cancellation is typed; denied close remains cleanup_incomplete with the primary cancellation, blocks admission, and retries the same descriptor owner.

Expected effects:

  • Read existing files or captured data.

Evidence and regression coverage

Executed on Linux with pinned Node 24.18.0/npm 11.16.0:

  • Original issue probe on latest main c8848648: exact SHA-256/pre-abort controls passed; 3/3 real stream cancellations reproduced failed cleanup and rejected retry/close. This does not establish a physical descriptor leak.
  • Original contributor's two cancellation/denied-close cases passed independently. Additional filesystem-shaped reasons failed 2/4 cases before normalization; an opaque cleanup-record reason failed 1/7 before moving identity recognition before cleanup interpretation.
  • npm run test:focused -- <28 managed/owner/CLI/MCP files>: 484 passed on the final head, including all seven new hash cases, independent read failure, blocked admission and same-client recovery. The final 15-case owner subset also passed independently.
  • Final compiled real provider: seven cancellation/read-close/final-close recovery scenarios passed against unchanged Microsoft.Extensions.Primitives 8.0.0, SHA-256 446ff16e903e7479558816e213a3adee9a1c1adad65a56d853801b10933e29d7, downloaded from official NuGet as data, without executing it.
  • Actual CLI/stdio MCP: two paired runs per revision passed. Each completed task used 2 CLI and 9 MCP requests, selected-type summaries, two method pages, a failed-path recovery control and complete Evidence export. Summary links, exact rows, coverage and source bytes were verified.
  • npm run check:fast: passed on final source. npm run docs:check: passed (5 tests).

Public managed requests create one-shot providers. Their repetition proves normal public behavior, not cached-hash cancellation; the latter was verified on the retained real provider/file boundary. Public SDK cancellation, other OSes, external disassemblers and physical devices were not exercised for this fix.

Performance

Two runs per revision, same Linux host/two-core affinity, completed equivalent tasks. OS cache uncontrolled; no speedup claim. Public-task medians, base → fix: 7.22 → 7.21 s wall, 9.07 → 9.05 s CPU, 0.673 → 0.669 GiB sampled process-family RSS. Forty warm retained-provider queries: 602 → 604 ms; first snapshot 25.8 → 26.0 ms.

o200k_base estimates for each public task: 9 MCP arguments plus full SDK replies 26,780 → 26,784 tokens; 2 CLI argument/full-report replies 87,351 on both. Complete CLI reports are validation artifacts, not extra agent context. Estimates exclude tool schemas, initialization/control/framing, prompts and model billing; SDK text/structured duplicates are included. Complete Evidence stays local and pageable. A separate synthetic 32 MiB hashing-only control passed exact digests on both revisions; it does not establish managed parsing performance. RSS was sampled every 200 ms and CPU includes reaped descendants.

Compatibility, safety, and release

No breaking changes, migrations or installation changes. Ownership checks remain intact, failed cleanup stays retained, and ambient environment values were not persisted. Local files/packages served as static data only.

Author readiness

Human owner: @N0zoM1z0

Entered under the human owner's explicit working-session instruction to complete the declarations and request review. The assistant performed implementation and validation review; this does not claim a separate manual human review.

  • 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.

🔄 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/4446 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/16/2026 **Status:** ✅ Merged **Merged:** 10/16/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/managed-hash-cancellation-4381` --- ### 📝 Commits (2) - [`320e319`](https://github.com/morluto/rea/commit/320e31900d51285a2f8f4078ae69f48459c4a0ae) fix(managed): preserve owned handles during hash cancellation - [`d6fa191`](https://github.com/morluto/rea/commit/d6fa191e89a3ecd63fc381927e064fcf4e62ba07) fix(managed): preserve opaque hash cancellation reasons ### 📊 Changes **2 files changed** (+212 additions, -23 deletions) <details> <summary>View changed files</summary> 📝 `src/dotnet/ManagedSnapshot.ts` (+33 -23) ➕ `tests/boundary/providers/managed/managedHashCancellation.test.ts` (+179 -0) </details> ### 📄 Description ## Summary Fixes #4381; lifecycle audit follow-up for #4227. Cancelling a cached managed-source hash let Node's ReadStream invalidate a borrowed FileHandle before its owner confirmed close. The provider then retained unconfirmable cleanup and could not recover. Hashing now uses bounded reads through the existing owner; cancellation closes normally, and genuine close failure retains that exact owner for retry. This adopts @xu91102's published [patch](https://github.com/xu91102/rea/commit/ebeec580c839f2f72144282a44f4e11ea5759843), preserving original commit authorship. Independent Linux verification also exposed cancellation reasons with filesystem codes or cleanup-record shapes being reinterpreted. Exact caller reasons now remain opaque; independent read errors retain their primary meaning. ## Change and boundary impact - Owner/earliest stage: managed static provider source hashing and managed read-error normalization. Fixed 64 KiB buffer; existing 128 MiB snapshot budget and one-byte growth probe remain. Each cached use still verifies the current source digest. - Scope decision: not applicable; ordinary fix to existing read-only static analysis. No target execution, new provider, permissions or recovery authority. - CLI/MCP, schemas, package/dependencies/generated metadata: unchanged. Both adapters retain their shared workflow. No additional response data or cache. - Evidence: same source identity, digest, coverage and full retained Evidence. Cancellation is typed; denied close remains `cleanup_incomplete` with the primary cancellation, blocks admission, and retries the same descriptor owner. Expected effects: - [x] Read existing files or captured data. ## Evidence and regression coverage Executed on Linux with pinned Node 24.18.0/npm 11.16.0: - Original issue probe on latest main `c8848648`: exact SHA-256/pre-abort controls passed; 3/3 real stream cancellations reproduced failed cleanup and rejected retry/close. This does not establish a physical descriptor leak. - Original contributor's two cancellation/denied-close cases passed independently. Additional filesystem-shaped reasons failed 2/4 cases before normalization; an opaque cleanup-record reason failed 1/7 before moving identity recognition before cleanup interpretation. - `npm run test:focused -- <28 managed/owner/CLI/MCP files>`: **484 passed on the final head**, including all seven new hash cases, independent read failure, blocked admission and same-client recovery. The final 15-case owner subset also passed independently. - Final compiled real provider: seven cancellation/read-close/final-close recovery scenarios passed against unchanged **Microsoft.Extensions.Primitives 8.0.0**, SHA-256 `446ff16e903e7479558816e213a3adee9a1c1adad65a56d853801b10933e29d7`, downloaded from official NuGet as data, without executing it. - Actual CLI/stdio MCP: two paired runs per revision passed. Each completed task used 2 CLI and 9 MCP requests, selected-type summaries, two method pages, a failed-path recovery control and complete Evidence export. Summary links, exact rows, coverage and source bytes were verified. - `npm run check:fast`: passed on final source. `npm run docs:check`: passed (5 tests). Public managed requests create one-shot providers. Their repetition proves normal public behavior, **not** cached-hash cancellation; the latter was verified on the retained real provider/file boundary. Public SDK cancellation, other OSes, external disassemblers and physical devices were not exercised for this fix. ## Performance Two runs per revision, same Linux host/two-core affinity, completed equivalent tasks. OS cache uncontrolled; no speedup claim. Public-task medians, base → fix: **7.22 → 7.21 s wall**, **9.07 → 9.05 s CPU**, **0.673 → 0.669 GiB sampled process-family RSS**. Forty warm retained-provider queries: **602 → 604 ms**; first snapshot **25.8 → 26.0 ms**. `o200k_base` estimates for each public task: 9 MCP arguments plus full SDK replies **26,780 → 26,784 tokens**; 2 CLI argument/full-report replies **87,351 on both**. Complete CLI reports are validation artifacts, not extra agent context. Estimates exclude tool schemas, initialization/control/framing, prompts and model billing; SDK text/structured duplicates are included. Complete Evidence stays local and pageable. A separate synthetic 32 MiB hashing-only control passed exact digests on both revisions; it does not establish managed parsing performance. RSS was sampled every 200 ms and CPU includes reaped descendants. ## Compatibility, safety, and release No breaking changes, migrations or installation changes. Ownership checks remain intact, failed cleanup stays retained, and ambient environment values were not persisted. Local files/packages served as static data only. ## Author readiness Human owner: @N0zoM1z0 Entered under the human owner's explicit working-session instruction to complete the declarations and request review. The assistant performed implementation and validation review; this does not claim a separate manual human review. - [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. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:13:00 +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#6246
No description provided.