From e7801483055352171d6b033a61563cbb8c1987c6 Mon Sep 17 00:00:00 2001
From: morluto <76467478+morluto@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:07:11 +0800
Subject: [PATCH] fix(cutter): preserve producer failure and cancellation facts
---
docs/reverse-engineering-tools.md | 6 +-
src/cutter/CutterBridgeClient.ts | 408 ++++++++++--------
src/cutter/CutterBridgeService.ts | 45 +-
.../mcp/cutterCancellationMcp.test.ts | 122 ++++++
.../providers/CutterBridgeClient.test.ts | 39 +-
.../providers/CutterBridgeService.test.ts | 132 ++++--
.../CutterCommandCancellation.test.ts | 72 ++++
.../providers/cutterBridgeProducer.test.ts | 11 +-
8 files changed, 599 insertions(+), 236 deletions(-)
diff --git a/docs/reverse-engineering-tools.md b/docs/reverse-engineering-tools.md
index 0bd27ef2bb..ab2e0c83ed 100644
--- a/docs/reverse-engineering-tools.md
+++ b/docs/reverse-engineering-tools.md
@@ -88,7 +88,11 @@ identify `cutter_command` and retain `status` in
`details.diagnostics.auxiliary_operation`; malformed proof still blocks dispatch.
Descriptor failures likewise retain the requesting operation through cleanup.
Command admission reports typed cancellation and treats the caller's abort reason
-as opaque metadata, without inferring cleanup ownership from it.
+as opaque metadata, without inferring cleanup ownership from it. A generation
+mismatch is an input correction only when the authenticated reply confirms
+`not_started`. Missing or ambiguous execution state retains the command's
+completion uncertainty until terminal proof arrives, even if the reply names a
+generation error.
## Configuration and coverage
diff --git a/src/cutter/CutterBridgeClient.ts b/src/cutter/CutterBridgeClient.ts
index c02c3b5eb2..1085a829e7 100644
--- a/src/cutter/CutterBridgeClient.ts
+++ b/src/cutter/CutterBridgeClient.ts
@@ -20,6 +20,7 @@ import { z } from "zod";
import {
AnalysisCapabilityUnavailableError,
+ AnalysisInputError,
AnalysisOutputError,
AnalysisResourceConstraintError,
} from "../domain/analysisErrorCore.js";
@@ -180,9 +181,12 @@ class CutterBridgeResponseFrames {
}
}
-const assertCommandActive = (signal: AbortSignal | undefined): void => {
+const assertBridgeActive = (
+ signal: AbortSignal | undefined,
+ operation: "cutter_command" | "list_cutter_sessions",
+): void => {
if (signal?.aborted)
- throw new AnalysisCancelledError("cutter_command", {
+ throw new AnalysisCancelledError(operation, {
cause: signal.reason,
});
};
@@ -190,9 +194,9 @@ const assertCommandActive = (signal: AbortSignal | undefined): void => {
const mapDiscovery = async (
inputs: readonly Input[],
operation: (input: Input) => Promise