[GH-ISSUE #4635] [Bug] Cutter command admission treats typed abort reasons as provider failures #2414

Closed
opened 2026-10-17 21:04:20 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

  • Searched open and closed Cutter descriptor/operation/cancellation and abort-reason reports. #4607 concerns status replies; #4471 concerns descriptor admission/cleanup, rather than these request identities.
  • No credentials or private target data included.

Area

Native analysis or decompilation

Observed behavior

Cancellation arriving during command admission can return the caller's abort-reason object as an expected provider failure. A caller-supplied AnalysisInputError becomes the command result; a caller-supplied ProviderCleanupError exposes caller-owned resource metadata and cleanupIncomplete=true, although the Cutter command owns no such resource.

Reproduction

Use an actual CutterBridgeService(new CutterBridgeClient({REA_CUTTER_BRIDGE_DIR: emptyPrivateDirectory})). Call service.execute({session_id,expected_generation:0,command:'ij'}, {signal}). Queue a microtask that aborts with either new AnalysisInputError('opaque caller metadata') or new ProviderCleanupError('caller-owned',['opaque caller resource'],{reason:'caller metadata'}). Await the command. Both new controls in tests/boundary/providers/CutterCommandCancellation.test.ts failed on unchanged main.

Executed with the descriptor lifetime controls: four new failures, seven existing passes; two failures concern this report.

Expected behavior

Return AnalysisCancelledError('cutter_command') with the exact reason retained as cause, no inferred cleanup ownership, and no dispatch. A reason's class must not turn caller metadata into a producer observation. Genuine independent physical failures must keep their existing precedence.

Impact and scope

P2: structured cancellation can falsely become invalid input or unresolved cleanup. Two deterministic admission controls reproduced once each. No actual leak or command effect established. NOT_ENOUGH_INFO: real Cutter incidence and public transport consequences. The issue requires a local caller choosing a typed reason and cancellation during the asynchronous admission gap.

Target and artifact context

Empty private descriptor directory; no target or bridge is required. The real client stops at its admission checkpoint before descriptor acquisition.

REA version

6.5.0; main 5c0472c571. Only new regression files were changed during reproduction; production source was unchanged.

Runtime and platform

Node 24.18.0, Darwin arm64. No native Cutter engine or target execution.

Interface

Other: production client/service boundary; no public CLI/MCP reproduction claimed for this report.

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

The foreign cleanup reason was returned unchanged:

expected: AnalysisCancelledError, operation=cutter_command, cleanupIncomplete=false
actual: ProviderCleanupError, operation=close_binary, cleanupIncomplete=true

Source: CutterBridgeClient.execute uses signal.throwIfAborted() at command checkpoints; CutterBridgeService.execute preserves any AnalysisError thrown by the client. The source guard cannot distinguish a genuine typed producer error from a raw abort reason thrown by these checkpoints. Discovery already handles this concern separately.

Typed outcome or recovery expected

Normalize cancellation at the command checkpoint producer, preserving the opaque reason as cause. Do not infer cancellation from an arbitrary physical error's class or equal reason value downstream.

Analysis or suspected cause

Source-derived: raw reason values cross a typed-error boundary without a producer-owned cancellation representation.

Additional context

Found during the #4607 consumer audit. Related #4610 repairs a similar boundary for regular-file workflows; this report concerns Cutter's own raw command checkpoints.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4635 ### Before submitting - [x] Searched open and closed Cutter descriptor/operation/cancellation and abort-reason reports. #4607 concerns status replies; #4471 concerns descriptor admission/cleanup, rather than these request identities. - [x] No credentials or private target data included. ### Area Native analysis or decompilation ### Observed behavior Cancellation arriving during command admission can return the caller's abort-reason object as an expected provider failure. A caller-supplied AnalysisInputError becomes the command result; a caller-supplied ProviderCleanupError exposes caller-owned resource metadata and cleanupIncomplete=true, although the Cutter command owns no such resource. ### Reproduction Use an actual CutterBridgeService(new CutterBridgeClient({REA_CUTTER_BRIDGE_DIR: emptyPrivateDirectory})). Call service.execute({session_id,expected_generation:0,command:'ij'}, {signal}). Queue a microtask that aborts with either new AnalysisInputError('opaque caller metadata') or new ProviderCleanupError('caller-owned',['opaque caller resource'],{reason:'caller metadata'}). Await the command. Both new controls in tests/boundary/providers/CutterCommandCancellation.test.ts failed on unchanged main. Executed with the descriptor lifetime controls: four new failures, seven existing passes; two failures concern this report. ### Expected behavior Return AnalysisCancelledError('cutter_command') with the exact reason retained as cause, no inferred cleanup ownership, and no dispatch. A reason's class must not turn caller metadata into a producer observation. Genuine independent physical failures must keep their existing precedence. ### Impact and scope P2: structured cancellation can falsely become invalid input or unresolved cleanup. Two deterministic admission controls reproduced once each. No actual leak or command effect established. NOT_ENOUGH_INFO: real Cutter incidence and public transport consequences. The issue requires a local caller choosing a typed reason and cancellation during the asynchronous admission gap. ### Target and artifact context Empty private descriptor directory; no target or bridge is required. The real client stops at its admission checkpoint before descriptor acquisition. ### REA version 6.5.0; main 5c0472c571cd27a812013650624893aefa446209. Only new regression files were changed during reproduction; production source was unchanged. ### Runtime and platform Node 24.18.0, Darwin arm64. No native Cutter engine or target execution. ### Interface Other: production client/service boundary; no public CLI/MCP reproduction claimed for this report. ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence The foreign cleanup reason was returned unchanged: ```text expected: AnalysisCancelledError, operation=cutter_command, cleanupIncomplete=false actual: ProviderCleanupError, operation=close_binary, cleanupIncomplete=true ``` Source: CutterBridgeClient.execute uses signal.throwIfAborted() at command checkpoints; CutterBridgeService.execute preserves any AnalysisError thrown by the client. The source guard cannot distinguish a genuine typed producer error from a raw abort reason thrown by these checkpoints. Discovery already handles this concern separately. ### Typed outcome or recovery expected Normalize cancellation at the command checkpoint producer, preserving the opaque reason as cause. Do not infer cancellation from an arbitrary physical error's class or equal reason value downstream. ### Analysis or suspected cause Source-derived: raw reason values cross a typed-error boundary without a producer-owned cancellation representation. ### Additional context Found during the #4607 consumer audit. Related #4610 repairs a similar boundary for regular-file workflows; this report concerns Cutter's own raw command checkpoints.
Author
Owner

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

Implemented and pushed to main in two separate commits:

  • #4634: 199396f61c passes the requesting operation into the descriptor failure owner. Discovery retains list_cutter_sessions; command execution and completion confirmation retain cutter_command, without changing exact cleanup dependencies.
  • #4635: 71929ed37c normalizes all three command checkpoints into AnalysisCancelledError with the exact opaque reason as cause. The service still preserves independent typed producer errors; it does not guess from reason equality.

Validation executed:

  • Before repair, four new controls failed on unchanged main (two descriptor operation controls, two typed opaque-reason admission races); seven existing controls passed.
  • The descriptor commit passed 61 focused tests across five files. The completed batch passed 72 tests across nine files, including denied and successful exact-descriptor retry, original discovery behavior, actual client/service admission races, same-object physical-error controls, pre-aborted direct-client behavior, capacity, CLI status proof, MCP cancellation and cleanup recovery.
  • Typecheck/lint, docs checks, five documentation conformance controls, normal commit hooks and normal pre-push checks passed. Source review found no blocker. The direct-client assertion now requires typed cancellation and the exact original AbortError as cause.

Bounded completed-task comparison against main 5c0472c57: two alternating warm repeats per build, plus separately recorded first processes. Cancellation at admission: baseline/candidate elapsed 0.08803/0.08755 seconds, CPU 0.07983/0.08056 seconds, sampled peak process-family RSS 60,456,960/60,588,032 bytes, raw projected-error tokens 44/55 (cl100k_base). Descriptor read, denied close, denied retry and successful exact release: elapsed 0.08734/0.08723 seconds, CPU 0.08319/0.08119 seconds, RSS 60,637,184/60,743,680 bytes, median tokens 147.5/147; per-run resource paths vary. No speed, memory or token reduction claimed. True cold, whole-agent, CLI/MCP/catalog/request/retry transport and native-engine costs remain unmeasured.

Scope: descriptor controls use real file handles with controlled close faults; cancellation races use the actual client/service and an empty private directory. Same-object physical controls use a controlled provider port. Existing public CLI/MCP regressions passed; the new defects were reproduced at the production provider boundary, not through public transport or a native Cutter engine. No native-engine verification or support claim added. Heavy Qodo/profiler jobs were not restarted.

<!-- gh-comment-id:6227930430 --> @morluto commented on GitHub (Oct 17, 2026): Implemented and pushed to main in two separate commits: - #4634: 199396f61c8f61da326d059606a992304a760147 passes the requesting operation into the descriptor failure owner. Discovery retains list_cutter_sessions; command execution and completion confirmation retain cutter_command, without changing exact cleanup dependencies. - #4635: 71929ed37cdc560b6b8aa62b5f7182e417c8a850 normalizes all three command checkpoints into AnalysisCancelledError with the exact opaque reason as cause. The service still preserves independent typed producer errors; it does not guess from reason equality. Validation executed: - Before repair, four new controls failed on unchanged main (two descriptor operation controls, two typed opaque-reason admission races); seven existing controls passed. - The descriptor commit passed 61 focused tests across five files. The completed batch passed 72 tests across nine files, including denied and successful exact-descriptor retry, original discovery behavior, actual client/service admission races, same-object physical-error controls, pre-aborted direct-client behavior, capacity, CLI status proof, MCP cancellation and cleanup recovery. - Typecheck/lint, docs checks, five documentation conformance controls, normal commit hooks and normal pre-push checks passed. Source review found no blocker. The direct-client assertion now requires typed cancellation and the exact original AbortError as cause. Bounded completed-task comparison against main 5c0472c57: two alternating warm repeats per build, plus separately recorded first processes. Cancellation at admission: baseline/candidate elapsed 0.08803/0.08755 seconds, CPU 0.07983/0.08056 seconds, sampled peak process-family RSS 60,456,960/60,588,032 bytes, raw projected-error tokens 44/55 (cl100k_base). Descriptor read, denied close, denied retry and successful exact release: elapsed 0.08734/0.08723 seconds, CPU 0.08319/0.08119 seconds, RSS 60,637,184/60,743,680 bytes, median tokens 147.5/147; per-run resource paths vary. No speed, memory or token reduction claimed. True cold, whole-agent, CLI/MCP/catalog/request/retry transport and native-engine costs remain unmeasured. Scope: descriptor controls use real file handles with controlled close faults; cancellation races use the actual client/service and an empty private directory. Same-object physical controls use a controlled provider port. Existing public CLI/MCP regressions passed; the new defects were reproduced at the production provider boundary, not through public transport or a native Cutter engine. No native-engine verification or support claim added. Heavy Qodo/profiler jobs were not restarted.
Author
Owner

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

Closing as fixed on main after reconciling this report with the landed owner/consumer changes.

  • 71929ed37: fix(cutter): normalize command checkpoint cancellation. Validated 72 focused tests across nine files, static checks, docs and five conformance controls, including real client/service admission races and matching physical-error controls. No native Cutter engine or new public-transport reproduction claimed.

Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.

<!-- gh-comment-id:6255995566 --> @morluto commented on GitHub (Oct 18, 2026): <!-- rea-backlog-reconciliation-2026-10-19-4635 --> Closing as fixed on `main` after reconciling this report with the landed owner/consumer changes. - [71929ed37](https://github.com/morluto/rea/commit/71929ed37cdc560b6b8aa62b5f7182e417c8a850): fix(cutter): normalize command checkpoint cancellation. Validated 72 focused tests across nine files, static checks, docs and five conformance controls, including real client/service admission races and matching physical-error controls. No native Cutter engine or new public-transport reproduction claimed. Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.
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#2414
No description provided.