[PR #6363] [MERGED] fix(lifecycle): retain Android and Kuna descriptors when close fails #7309

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

📋 Pull Request Information

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

Base: main ← Head: cursor/android-kuna-close-ownership-89de


📝 Commits (10+)

  • 94e7e6c fix(android): retain snapshot descriptors when close fails
  • ea333bd fix(kuna): retain span descriptors when close fails
  • c671f1c fix(android): attribute snapshot cleanup to the descriptor that failed
  • a561443 fix(kuna): gate span admission until a retained close releases
  • 298c7f3 fix(android): preserve nested snapshot facts when both closes fail
  • 0e1b079 fix(kuna): release recovered span leases before the next open
  • 832be4b fix(android): retain a source descriptor when admission close fails
  • 2b9f510 fix(kuna): keep cancellation when a completed span close fails
  • fb071c2 style: format Android and Kuna close-ownership changes
  • 7268380 fix(android): keep the snapshot hash inside a nested cancellation

📊 Changes

7 files changed (+1912 additions, -118 deletions)

View changed files

📝 src/android/AndroidTargetSnapshot.ts (+277 -80)
📝 src/android/JadxFailure.ts (+144 -12)
📝 src/android/JadxProvider.ts (+32 -3)
📝 src/kuna/KunaProjectReader.ts (+195 -7)
📝 src/kuna/KunaSessionClient.ts (+180 -16)
➕ tests/boundary/process/androidSnapshotClose.test.ts (+630 -0)
➕ tests/boundary/providers/kuna/kunaSpanCloseOwnership.test.ts (+454 -0)

📄 Description

Summary

Fixes #6047 and Fixes #6052.

Android APK snapshot finalization and Kuna span reads closed raw file handles in finally. A rejected close replaced the primary copy-change diagnosis, the completed copy, or the completed span text, and the descriptor never entered the owner that retries it. Provider or session close could then report success while that handle was still open.

Both paths now keep the primary diagnosis or the completed facts, retain the exact handle, and stay cleanupIncomplete until that owner closes. This follows the Hopper and LLDB ownership pattern from #6357. Hopper and LLDB are unchanged.

Problem and expected behavior

A destination-close EIO during copyAndroidSnapshot turned an AndroidSnapshotChangedError or a finished copy into generic execution_failure, with cleanupIncomplete: false, and left the destination descriptor open after provider.close(). A Kuna span-close refusal did the same to a warm procedure_assembly read: the text or short-read diagnostic was lost, and client.close() returned success while the handle was still readable.

Close failure now preserves the stable-file diagnosis or the completed snapshot hash, and the span text or short-read diagnostic. The exact handle is retried before the next admission and on close. Cleanup stays incomplete until that release. Workspace retirement still waits until child descriptors close. Session close does not succeed while the span handle is open.

Change and scope

Follow the contribution scope.
Unresolved scope, authority, side effects, or required verification block
integration. Link the required maintainer scope decision for new providers or
capabilities involving target execution, injection, mutation, or protection
recovery; ordinary fixes within existing boundaries may state "not applicable".
Draft PRs may leave the scope decision pending and the readiness and merge checklists
unchecked. Maintainers can help resolve open questions.

Not applicable: ordinary lifecycle fixes inside the existing Android/JADX snapshot boundary and the existing Kuna session boundary. No new provider, target execution, injection, mutation, or protection recovery.

copyAndroidSnapshot closes the source and destination through withOwnedFileHandle. Stream destroy closes through that same owner, so a successful stream close is confirmed instead of looking abandoned. Nested close failures are walked: a finished copy keeps its file-snapshot-hash observation, and a changed APK keeps its AnalysisInputError, when the other descriptor also rejects close. Cleanup resources name each descriptor that rejected close. A cancellation recorded on a nested close is classified as cancellation or timeout. A destination close that succeeds after abort carries the finished copy inside RegularFileCancelled; the hash stays on the observation whether the source close then rejects or the cancellation is returned directly. If source admission rejects after the descriptor opens and that close also fails, the owner is retained before adoption. Jadx retirement retries only the owners from that close failure and removes the workspace root after they release.

KunaProjectReader.readSpan uses the same owned close. Span admission and close share one queue; the byte read stays outside it, so concurrent dossier reads still overlap. The caller signal is checked again immediately before open, and it is passed into finalization. A completed read whose close fails after the caller aborts stays AnalysisCancelledError, with the span text and the descriptor retained. A completed read whose close succeeds after that abort is AnalysisCancelledError with the caller's abort reason. A failed close is retained on the existing resource scope. A later successful close releases that exact scope record, so both the span map and the scope pending set drop it. Installation cleanup on that scope is not re-adjudicated by the span retry.

Deliberately left alone: Hopper, LLDB, ADB, real JADX or Kuna launches, and unrelated Android or Kuna behavior. Regressions cover destination-only, source-only, and both-close failures, including a changed APK, a nested cancellation, a source admission close failure, a finished copy nested in RegularFileCancelled, and a direct successful-close cancellation.

Contract and boundary impact

  • Semantic owner and earliest changed stage: Android snapshot destination (and source) descriptor close during JADX admission, before the engine session exists; Kuna span-descriptor close after a project export read, before session retirement.
  • Contribution scope fit and linked maintainer decision: ordinary fix inside existing boundaries. Maintainer scope decision not applicable.
  • CLI and MCP/tool-catalog contract: no schema or catalog change. These failures project as cleanup_incomplete. The stable-file diagnosis remains cleanupPrimary / diagnostics.primary_error (invalid_request). Completed snapshot bytes and span text stay on the cleanup error.
  • Provider, bridge, target-format, or platform compatibility: JADX APK snapshot admission and Kuna procedure_assembly / pseudocode span reads. No bridge protocol change.
  • Evidence, artifact, provenance, or reconstruction contract: a completed copy records file-snapshot-hash (path, sha256, bytes). A completed span records span_text and its byte range as cleanup diagnostics, not a successful result, until close succeeds.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): no new target authority. Failed close retains the exact descriptor. Child descriptors are released before workspace retirement. Kuna session close retries the span lease and stays incomplete while it is open.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact (CI generates and validates ignored catalogs and skills/; edit authored instructions in .agents/skills/reverse-engineer-anything/ and never commit build outputs): none.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated:
    • tests/boundary/process/androidSnapshotClose.test.ts
    • tests/boundary/providers/kuna/kunaSpanCloseOwnership.test.ts
  • Base reproduction or other evidence: adapted from the issue repros. On this branch, a changed APK keeps invalid_request and AndroidSnapshotChangedError when destination close succeeds, and keeps that diagnosis as cleanupPrimary when one or both closes reject. A finished copy keeps snapshot_sha256 and file-snapshot-hash when the source, the destination, or both reject close. Cleanup resources name the descriptor that failed. A nested destination cancellation is AnalysisCancelledError with the hash retained. A destination close that succeeds after abort keeps that hash both when the source close then rejects and when the cancellation is returned directly, and the direct case is not cleanup_incomplete. A source admission stat failure whose close also rejects keeps that descriptor, reports cleanup_incomplete, and does not open the destination. The unresolved fd stays open, the next admission does not open another snapshot handle, provider.close() rejects while the fd is open, and the workspace directory remains until the same owner closes. Kuna keeps the assembly text or the short-read message, blocks the next open while a close is still retained, refuses a queued open after the caller aborts, and keeps cancellation plus the completed span text when close rejects after that abort. When that close succeeds, the result is AnalysisCancelledError whose cause is the caller's abort reason. Session close rejects while the handle is still readable, and releases the span from the resource scope once that close succeeds.
  • User-visible CLI/MCP output (if applicable): projectAnalysisError for these close failures returns code: "cleanup_incomplete". The changed-APK primary remains invalid_request. No separate CLI or MCP adapter change.
  • Remaining proof gaps: no real JADX, JVM, or Kuna process was launched. Natural OS close-failure frequency was not measured.

For evidence-bearing changes:

  • 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

  • PATH="/usr/local/bin:$PATH" npm run check:fast — typecheck and lint passed. That script does not run format:check.
  • PATH="/usr/local/bin:$PATH" npx oxfmt --check . — passed after formatting the four close-ownership files CI rejected.
  • PATH="/usr/local/bin:$PATH" node node_modules/vitest/vitest.mjs run tests/boundary/process/androidSnapshotClose.test.ts tests/boundary/android/androidTargetSnapshot.test.ts tests/boundary/process/jadxHashCleanup.test.ts tests/boundary/process/jadxIntegration.test.ts tests/boundary/providers/kuna --maxWorkers 4 — 36 files, 385 tests passed. This run was before the format-only commit; oxfmt changed whitespace only.
  • PATH="/usr/local/bin:$PATH" npm run check:fast and npx oxfmt --check on the two edited files, then vitest on androidSnapshotClose, androidTargetSnapshot, jadxHashCleanup, and jadxIntegration — 4 files, 60 tests passed after recovering a snapshot hash nested in RegularFileCancelled.
  • PATH="/usr/local/bin:$PATH" npm run check:fast, npx oxfmt --check on the four edited files, then vitest on androidSnapshotClose, jadxIntegration, kunaSpanCloseOwnership, kunaReaderCancellation, and kunaProjectReaderConcurrency — 5 files, 71 tests passed after attaching a direct close cancellation's snapshot hash and returning the caller's abort reason when a completed span close succeeds.
  • GitHub Actions run 39834210977 on head 7c8bd59a7 failed Static checks and Build package while compiling the pull-request merge with the then-current main. src/application/ReconstructionObligationCandidates.ts called uniqueBy, which was not defined (5d3762456, #3826). This branch did not modify that file. The same merge checkout also failed source and portable tests in IDA, browser scenario diff, pcap, and reconstruction fixtures.
  • Merged origin/main at 7091be291 (#6375) in 225d2d742. No conflicts. Android snapshot and Kuna span close-ownership commits are unchanged. After that merge: PATH="/usr/local/bin:$PATH" npm run check:fast passed; npx oxfmt --check . passed (5125 files); vitest on androidSnapshotClose, jadxIntegration, kunaSpanCloseOwnership, kunaReaderCancellation, and kunaProjectReaderConcurrency passed (5 files, 71 tests). GitHub CI on 225d2d742 had not finished when this was recorded.

npm run test:focused was not run as a separate script. The vitest command above is the boundary-project run those tests use; they import src/ directly. No real JADX or Kuna installation was used.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Callers that matched execution_failure for a snapshot or span close rejection now receive cleanup_incomplete, with the previous diagnosis or completed facts retained. Successful copies and span reads are unchanged when close succeeds.
  • Real Hopper/Ghidra, browser, or OS coverage: not exercised. Linux Node handles and the repository's JADX and Kuna fixtures only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new process authority. Retained descriptors stay owned until their own retry confirms release. Workspace removal still follows descriptor release.

Author readiness

Human owner: @morluto

  • 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.
Open in Web Open in Cursor 

🔄 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/6363 **Author:** [@morluto](https://github.com/morluto) **Created:** 10/22/2026 **Status:** ✅ Merged **Merged:** 10/22/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `cursor/android-kuna-close-ownership-89de` --- ### 📝 Commits (10+) - [`94e7e6c`](https://github.com/morluto/rea/commit/94e7e6cbbce2c10abe600943f0f800ed9bf67a7c) fix(android): retain snapshot descriptors when close fails - [`ea333bd`](https://github.com/morluto/rea/commit/ea333bda26363971ae1e94d8098588e073da2f38) fix(kuna): retain span descriptors when close fails - [`c671f1c`](https://github.com/morluto/rea/commit/c671f1c30c7ba8184946f1ccfe125948d2b8b8ec) fix(android): attribute snapshot cleanup to the descriptor that failed - [`a561443`](https://github.com/morluto/rea/commit/a5614439f460fbad61d85b20346869b3d16b52b6) fix(kuna): gate span admission until a retained close releases - [`298c7f3`](https://github.com/morluto/rea/commit/298c7f319a7d7beb57726bc7dc4f61921fada14d) fix(android): preserve nested snapshot facts when both closes fail - [`0e1b079`](https://github.com/morluto/rea/commit/0e1b07957a4abb27e242607daf4de45b2f536857) fix(kuna): release recovered span leases before the next open - [`832be4b`](https://github.com/morluto/rea/commit/832be4b82efebc35ae8a479309ca5873806af747) fix(android): retain a source descriptor when admission close fails - [`2b9f510`](https://github.com/morluto/rea/commit/2b9f510053036c888f57f37905856dbf45e8de02) fix(kuna): keep cancellation when a completed span close fails - [`fb071c2`](https://github.com/morluto/rea/commit/fb071c2f3d55d139739f60fca5d457b11663a477) style: format Android and Kuna close-ownership changes - [`7268380`](https://github.com/morluto/rea/commit/7268380315fc805e4ab953b3ebe4d046e1554ad7) fix(android): keep the snapshot hash inside a nested cancellation ### 📊 Changes **7 files changed** (+1912 additions, -118 deletions) <details> <summary>View changed files</summary> 📝 `src/android/AndroidTargetSnapshot.ts` (+277 -80) 📝 `src/android/JadxFailure.ts` (+144 -12) 📝 `src/android/JadxProvider.ts` (+32 -3) 📝 `src/kuna/KunaProjectReader.ts` (+195 -7) 📝 `src/kuna/KunaSessionClient.ts` (+180 -16) ➕ `tests/boundary/process/androidSnapshotClose.test.ts` (+630 -0) ➕ `tests/boundary/providers/kuna/kunaSpanCloseOwnership.test.ts` (+454 -0) </details> ### 📄 Description <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Fixes #6047 and Fixes #6052. Android APK snapshot finalization and Kuna span reads closed raw file handles in `finally`. A rejected close replaced the primary copy-change diagnosis, the completed copy, or the completed span text, and the descriptor never entered the owner that retries it. Provider or session close could then report success while that handle was still open. Both paths now keep the primary diagnosis or the completed facts, retain the exact handle, and stay `cleanupIncomplete` until that owner closes. This follows the Hopper and LLDB ownership pattern from #6357. Hopper and LLDB are unchanged. ## Problem and expected behavior A destination-close EIO during `copyAndroidSnapshot` turned an `AndroidSnapshotChangedError` or a finished copy into generic `execution_failure`, with `cleanupIncomplete: false`, and left the destination descriptor open after `provider.close()`. A Kuna span-close refusal did the same to a warm `procedure_assembly` read: the text or short-read diagnostic was lost, and `client.close()` returned success while the handle was still readable. Close failure now preserves the stable-file diagnosis or the completed snapshot hash, and the span text or short-read diagnostic. The exact handle is retried before the next admission and on close. Cleanup stays incomplete until that release. Workspace retirement still waits until child descriptors close. Session close does not succeed while the span handle is open. ## Change and scope Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Unresolved scope, authority, side effects, or required verification block integration. Link the required maintainer scope decision for new providers or capabilities involving target execution, injection, mutation, or protection recovery; ordinary fixes within existing boundaries may state "not applicable". Draft PRs may leave the scope decision pending and the readiness and merge checklists unchecked. Maintainers can help resolve open questions. Not applicable: ordinary lifecycle fixes inside the existing Android/JADX snapshot boundary and the existing Kuna session boundary. No new provider, target execution, injection, mutation, or protection recovery. `copyAndroidSnapshot` closes the source and destination through `withOwnedFileHandle`. Stream destroy closes through that same owner, so a successful stream close is confirmed instead of looking abandoned. Nested close failures are walked: a finished copy keeps its `file-snapshot-hash` observation, and a changed APK keeps its `AnalysisInputError`, when the other descriptor also rejects close. Cleanup resources name each descriptor that rejected close. A cancellation recorded on a nested close is classified as cancellation or timeout. A destination close that succeeds after abort carries the finished copy inside `RegularFileCancelled`; the hash stays on the observation whether the source close then rejects or the cancellation is returned directly. If source admission rejects after the descriptor opens and that close also fails, the owner is retained before adoption. Jadx retirement retries only the owners from that close failure and removes the workspace root after they release. `KunaProjectReader.readSpan` uses the same owned close. Span admission and close share one queue; the byte read stays outside it, so concurrent dossier reads still overlap. The caller signal is checked again immediately before open, and it is passed into finalization. A completed read whose close fails after the caller aborts stays `AnalysisCancelledError`, with the span text and the descriptor retained. A completed read whose close succeeds after that abort is `AnalysisCancelledError` with the caller's abort reason. A failed close is retained on the existing resource scope. A later successful close releases that exact scope record, so both the span map and the scope pending set drop it. Installation cleanup on that scope is not re-adjudicated by the span retry. Deliberately left alone: Hopper, LLDB, ADB, real JADX or Kuna launches, and unrelated Android or Kuna behavior. Regressions cover destination-only, source-only, and both-close failures, including a changed APK, a nested cancellation, a source admission close failure, a finished copy nested in `RegularFileCancelled`, and a direct successful-close cancellation. ## Contract and boundary impact - Semantic owner and earliest changed stage: Android snapshot destination (and source) descriptor close during JADX admission, before the engine session exists; Kuna span-descriptor close after a project export read, before session retirement. - Contribution scope fit and linked maintainer decision: ordinary fix inside existing boundaries. Maintainer scope decision not applicable. - CLI and MCP/tool-catalog contract: no schema or catalog change. These failures project as `cleanup_incomplete`. The stable-file diagnosis remains `cleanupPrimary` / `diagnostics.primary_error` (`invalid_request`). Completed snapshot bytes and span text stay on the cleanup error. - Provider, bridge, target-format, or platform compatibility: JADX APK snapshot admission and Kuna `procedure_assembly` / pseudocode span reads. No bridge protocol change. - Evidence, artifact, provenance, or reconstruction contract: a completed copy records `file-snapshot-hash` (path, sha256, bytes). A completed span records `span_text` and its byte range as cleanup diagnostics, not a successful result, until close succeeds. - Target selection, authority, upstream behavior, and cleanup details (if applicable): no new target authority. Failed close retains the exact descriptor. Child descriptors are released before workspace retirement. Kuna session close retries the span lease and stays incomplete while it is open. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `.agents/skills/reverse-engineer-anything/` and never commit build outputs): none. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: - `tests/boundary/process/androidSnapshotClose.test.ts` - `tests/boundary/providers/kuna/kunaSpanCloseOwnership.test.ts` - Base reproduction or other evidence: adapted from the issue repros. On this branch, a changed APK keeps `invalid_request` and `AndroidSnapshotChangedError` when destination close succeeds, and keeps that diagnosis as `cleanupPrimary` when one or both closes reject. A finished copy keeps `snapshot_sha256` and `file-snapshot-hash` when the source, the destination, or both reject close. Cleanup resources name the descriptor that failed. A nested destination cancellation is `AnalysisCancelledError` with the hash retained. A destination close that succeeds after abort keeps that hash both when the source close then rejects and when the cancellation is returned directly, and the direct case is not `cleanup_incomplete`. A source admission `stat` failure whose close also rejects keeps that descriptor, reports `cleanup_incomplete`, and does not open the destination. The unresolved fd stays open, the next admission does not open another snapshot handle, `provider.close()` rejects while the fd is open, and the workspace directory remains until the same owner closes. Kuna keeps the assembly text or the short-read message, blocks the next open while a close is still retained, refuses a queued open after the caller aborts, and keeps cancellation plus the completed span text when close rejects after that abort. When that close succeeds, the result is `AnalysisCancelledError` whose cause is the caller's abort reason. Session close rejects while the handle is still readable, and releases the span from the resource scope once that close succeeds. - User-visible CLI/MCP output (if applicable): `projectAnalysisError` for these close failures returns `code: "cleanup_incomplete"`. The changed-APK primary remains `invalid_request`. No separate CLI or MCP adapter change. - Remaining proof gaps: no real JADX, JVM, or Kuna process was launched. Natural OS close-failure frequency was not measured. For evidence-bearing changes: - [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 - `PATH="/usr/local/bin:$PATH" npm run check:fast` — typecheck and lint passed. That script does not run `format:check`. - `PATH="/usr/local/bin:$PATH" npx oxfmt --check .` — passed after formatting the four close-ownership files CI rejected. - `PATH="/usr/local/bin:$PATH" node node_modules/vitest/vitest.mjs run tests/boundary/process/androidSnapshotClose.test.ts tests/boundary/android/androidTargetSnapshot.test.ts tests/boundary/process/jadxHashCleanup.test.ts tests/boundary/process/jadxIntegration.test.ts tests/boundary/providers/kuna --maxWorkers 4` — 36 files, 385 tests passed. This run was before the format-only commit; oxfmt changed whitespace only. - `PATH="/usr/local/bin:$PATH" npm run check:fast` and `npx oxfmt --check` on the two edited files, then `vitest` on `androidSnapshotClose`, `androidTargetSnapshot`, `jadxHashCleanup`, and `jadxIntegration` — 4 files, 60 tests passed after recovering a snapshot hash nested in `RegularFileCancelled`. - `PATH="/usr/local/bin:$PATH" npm run check:fast`, `npx oxfmt --check` on the four edited files, then `vitest` on `androidSnapshotClose`, `jadxIntegration`, `kunaSpanCloseOwnership`, `kunaReaderCancellation`, and `kunaProjectReaderConcurrency` — 5 files, 71 tests passed after attaching a direct close cancellation's snapshot hash and returning the caller's abort reason when a completed span close succeeds. - GitHub Actions run [39834210977](https://github.com/morluto/rea/actions/runs/39834210977) on head `7c8bd59a7` failed **Static checks** and **Build package** while compiling the pull-request merge with the then-current `main`. `src/application/ReconstructionObligationCandidates.ts` called `uniqueBy`, which was not defined (`5d3762456`, #3826). This branch did not modify that file. The same merge checkout also failed source and portable tests in IDA, browser scenario diff, pcap, and reconstruction fixtures. - Merged `origin/main` at `7091be291` (#6375) in `225d2d742`. No conflicts. Android snapshot and Kuna span close-ownership commits are unchanged. After that merge: `PATH="/usr/local/bin:$PATH" npm run check:fast` passed; `npx oxfmt --check .` passed (5125 files); vitest on `androidSnapshotClose`, `jadxIntegration`, `kunaSpanCloseOwnership`, `kunaReaderCancellation`, and `kunaProjectReaderConcurrency` passed (5 files, 71 tests). GitHub CI on `225d2d742` had not finished when this was recorded. `npm run test:focused` was not run as a separate script. The vitest command above is the boundary-project run those tests use; they import `src/` directly. No real JADX or Kuna installation was used. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Callers that matched `execution_failure` for a snapshot or span close rejection now receive `cleanup_incomplete`, with the previous diagnosis or completed facts retained. Successful copies and span reads are unchanged when close succeeds. - Real Hopper/Ghidra, browser, or OS coverage: not exercised. Linux Node handles and the repository's JADX and Kuna fixtures only. - Package or release metadata impact: none. - Security, privacy, process, or containment review: no new process authority. Retained descriptors stay owned until their own retry confirms release. Workspace removal still follows descriptor release. ## Author readiness Human owner: @morluto - [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. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-778f29ba-1f64-58f8-a38f-8664d7d889de?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-778f29ba-1f64-58f8-a38f-8664d7d889de&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div> --- <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:55 +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#7309
No description provided.