[GH-ISSUE #4910] [Bug] Standalone registration helpers discard failed-close ownership #3048

Closed
opened 2026-10-31 00:35:28 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

  • Searched open/closed registration cleanup ownership reports.
  • No credentials or sensitive target data included.

Area

Setup, packaging, or upgrade

Observed behavior

Standalone registration/maintenance helpers lose the exact cleanup owner when a configuration or Gemini policy descriptor refuses close and no ArtifactResourceScope was supplied. They return statuses, scope, or a maintenance plan instead of transferring the still-open descriptor capability. Calls with a supplied scope retain ownership correctly.

Reproduction

Executed npm run test:focused -- tests/boundary/filesystem/setupClientConfigCleanupOwnership.test.ts on main abb54ce37:8new controls failed,8existing/scoped controls passed. Each opens owned inert temporary JSON, injects close refusal on its real FileHandle, and invokes inspections/status projection/maintenance scope/maintenance planning without an external scope. Cross-product covers registration and policy sources. Expected typed RegularFileCleanupFailure with exact owner; actual normal return. The harness releases every held descriptor in finally. No real agent config, package install or provider ran.

Expected behavior

AGENTS.md requires failed cleanup ownership to survive boundaries. Preserve the typed failure with its exact descriptor and completed/failed operation outcome until an owner can retry it. Do not serialize an unretained capability into a diagnostic string or ordinary plan. Keep supplied-scope ownership and diagnostics behavior.

Impact and scope

Observed at shared application boundaries with deterministic native-file/close-seam controls. This report is about exported standalone helpers; production doctor/update host factories supply a scope, so this is not a claim that their normal scoped CLI path leaks. Native OS close-fault frequency and Windows/Linux behavior: NOT_ENOUGH_INFO.

REA version

6.5.0; source abb54ce374.

Runtime and platform

Node24.18.0, macOS arm64; real temporary descriptors with injected close rejection.

Target and artifact context

Inert JSON registration/policy fixtures only. No engine or target execution.

Interface / Earliest failure stage

Shared registration discovery and maintenance planning; final read cleanup before result projection.

Relevant output or evidence

Eight assertions expected {kind:"threw",cause:RegularFileCleanupFailure} and received {kind:"returned"}. ClientConfigurationFileError retains cleanupFailure, but ClientRegistrationStatus converts it into status and its catch also serializes typed failures. UpdateMaintenance.planIntegrationMaintenance catches every thrown value and returns unavailable text.

Analysis

Source-derived: semantic diagnostics were produced without first retaining or transferring cleanup authority. Propagate original typed cleanup failures when no caller resource owner exists; supplied scopes already retain failures at the read boundary. Verify exact descriptor retry after pathname replacement and no maintenance execution on unresolved cleanup.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4910 ### Before submitting - [x] Searched open/closed registration cleanup ownership reports. - [x] No credentials or sensitive target data included. ### Area Setup, packaging, or upgrade ### Observed behavior Standalone registration/maintenance helpers lose the exact cleanup owner when a configuration or Gemini policy descriptor refuses close and no ArtifactResourceScope was supplied. They return statuses, scope, or a maintenance plan instead of transferring the still-open descriptor capability. Calls with a supplied scope retain ownership correctly. ### Reproduction Executed `npm run test:focused -- tests/boundary/filesystem/setupClientConfigCleanupOwnership.test.ts` on main abb54ce37:8new controls failed,8existing/scoped controls passed. Each opens owned inert temporary JSON, injects close refusal on its real FileHandle, and invokes inspections/status projection/maintenance scope/maintenance planning without an external scope. Cross-product covers registration and policy sources. Expected typed RegularFileCleanupFailure with exact owner; actual normal return. The harness releases every held descriptor in finally. No real agent config, package install or provider ran. ### Expected behavior AGENTS.md requires failed cleanup ownership to survive boundaries. Preserve the typed failure with its exact descriptor and completed/failed operation outcome until an owner can retry it. Do not serialize an unretained capability into a diagnostic string or ordinary plan. Keep supplied-scope ownership and diagnostics behavior. ### Impact and scope Observed at shared application boundaries with deterministic native-file/close-seam controls. This report is about exported standalone helpers; production doctor/update host factories supply a scope, so this is not a claim that their normal scoped CLI path leaks. Native OS close-fault frequency and Windows/Linux behavior: NOT_ENOUGH_INFO. ### REA version 6.5.0; source abb54ce3743dd51a54304833a6e081b89243a5e8. ### Runtime and platform Node24.18.0, macOS arm64; real temporary descriptors with injected close rejection. ### Target and artifact context Inert JSON registration/policy fixtures only. No engine or target execution. ### Interface / Earliest failure stage Shared registration discovery and maintenance planning; final read cleanup before result projection. ### Relevant output or evidence Eight assertions expected `{kind:"threw",cause:RegularFileCleanupFailure}` and received `{kind:"returned"}`. ClientConfigurationFileError retains cleanupFailure, but ClientRegistrationStatus converts it into status and its catch also serializes typed failures. UpdateMaintenance.planIntegrationMaintenance catches every thrown value and returns unavailable text. ### Analysis Source-derived: semantic diagnostics were produced without first retaining or transferring cleanup authority. Propagate original typed cleanup failures when no caller resource owner exists; supplied scopes already retain failures at the read boundary. Verify exact descriptor retry after pathname replacement and no maintenance execution on unresolved cleanup.
bsakaguchi 2026-10-31 00:35:28 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

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

Fixed in 823521085a28f825e7fee1929d852d420042d1f7 and pushed to main.

Registration inspection now transfers the original typed cleanup failure when it has no supplied resource scope, for both configuration and Gemini policy errors. Status projection and maintenance scope preserve that exception; maintenance planning no longer converts an unretained cleanup capability into unavailable text. Caller-supplied scopes keep the existing diagnostics and exact retained owner. No new owner, lease, path-based repair or duplicate parser was introduced.

Executed 79 focused tests across four files on macOS arm64 / Node24.18.0. The final baseline at abb54ce37 fails all16 ownership-transfer controls, with eight existing/scoped controls passing. Controls cover all four exported consumers × configuration/policy × completed/malformedUTF8 read, preserve the original outcome and exact descriptor, refuse one more cleanup attempt, replace the pathname, then close only the original owner without touching the replacement or executing maintenance. Supplied-scope retry and doctor lifecycle checks pass. Typecheck/lint, formatting, discovery(1563files exactly once), pre-push and scoped source review passed.

Six completed isolated public doctor comparisons retain identical aligned replies and byte-identical configs. Two warm-repeat medians per build: elapsed 1.2201→1.2266s; wait4 CPU 1.2641→1.2518s;10ms sampled process-family RSS 500.8→497.0MiB. Estimated cl100k request/reply/progress tokens25/121/0 unchanged. Separate first processes recorded; no speedup, significance, true-cold or whole-agent token claim, and no claim that fault-task performance was measured. Family sampling may miss transients/reparenting.

Scope: real temporary descriptors with injected close rejection, not native OS close faults. Native Windows/Linux, actual user installations and provider/target execution remain unverified. Production doctor/update factories already supply scopes; this resolves the standalone-helper ownership loss, without claiming a leak in their normal scoped path. Heavy profiler/test remain stopped.

<!-- gh-comment-id:6243019178 --> @morluto commented on GitHub (Oct 17, 2026): Fixed in `823521085a28f825e7fee1929d852d420042d1f7` and pushed to main. Registration inspection now transfers the original typed cleanup failure when it has no supplied resource scope, for both configuration and Gemini policy errors. Status projection and maintenance scope preserve that exception; maintenance planning no longer converts an unretained cleanup capability into unavailable text. Caller-supplied scopes keep the existing diagnostics and exact retained owner. No new owner, lease, path-based repair or duplicate parser was introduced. Executed **79 focused tests across four files** on macOS arm64 / Node24.18.0. The final baseline at abb54ce37 fails all16 ownership-transfer controls, with eight existing/scoped controls passing. Controls cover all four exported consumers × configuration/policy × completed/malformedUTF8 read, preserve the original outcome and exact descriptor, refuse one more cleanup attempt, replace the pathname, then close only the original owner without touching the replacement or executing maintenance. Supplied-scope retry and doctor lifecycle checks pass. Typecheck/lint, formatting, discovery(1563files exactly once), pre-push and scoped source review passed. Six completed isolated public doctor comparisons retain identical aligned replies and byte-identical configs. Two warm-repeat medians per build: elapsed 1.2201→1.2266s; wait4 CPU 1.2641→1.2518s;10ms sampled process-family RSS 500.8→497.0MiB. Estimated cl100k request/reply/progress tokens25/121/0 unchanged. Separate first processes recorded; no speedup, significance, true-cold or whole-agent token claim, and no claim that fault-task performance was measured. Family sampling may miss transients/reparenting. Scope: real temporary descriptors with injected close rejection, not native OS close faults. Native Windows/Linux, actual user installations and provider/target execution remain unverified. Production doctor/update factories already supply scopes; this resolves the standalone-helper ownership loss, without claiming a leak in their normal scoped path. Heavy profiler/test remain stopped.
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#3048
No description provided.