fix(errors): stop recommending retries for non-retryable failures (#1869)

* fix(errors): stop recommending retries for non-retryable failures

Unreadable output and provider adapter failures project retryable=false,
but their standard message and remediation said "Retry once", so a
firmware run whose expected report was never published told callers to
repeat a non-retryable operation. Point those failures at `rea doctor`
and the reported details instead, leaving retryability decided once by
the projected error code.

Fixes #1855

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(errors): align Hopper remote failure guidance with retryability

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kaoru0822
2026-10-11 08:17:35 -07:00
committed by GitHub
parent 96547d373f
commit fb94d9dde0
5 changed files with 44 additions and 12 deletions
+6 -6
View File
@@ -1,10 +1,10 @@
harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implementation_status,verification_result
1,src/domain/errors.ts:AnalysisCapabilityUnavailableError,Requested analysis unavailable,"Provider {providerId} cannot execute {operation}: {reason}",Exposes provider and internal operation/reason,"This analysis is unavailable for the current target. Choose another analysis or target.",implemented,focused assertions passed; full `npm run check` passed
2,src/domain/errors.ts:ProviderAdapterError,Provider adapter fails,"Provider {providerId} adapter failed during {operation}",Exposes provider and implementation boundary,"Analysis could not complete. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
3,src/domain/errors.ts:HopperRemoteError,Remote analysis request fails,"Hopper request failed ({code}): {safeMessage}",Exposes provider name code and upstream text,"Analysis could not complete. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
4,src/domain/errors.ts:HopperProtocolError,Malformed provider protocol result,Raw constructor message,Can expose provider protocol and implementation details,"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
5,src/domain/errors.ts:AnalysisOutputError,Analysis output fails parsing,"Invalid analysis output for {operation}: {reason}",Exposes internal operation and parser reason,"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
6,src/domain/errors.ts:AnalysisProtocolError,Application protocol fails,Raw constructor message,Can expose protocol internals,"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
2,src/domain/errors.ts:ProviderAdapterError,Provider adapter fails,"Provider {providerId} adapter failed during {operation}",Exposes provider and implementation boundary,"Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
3,src/domain/errors.ts:HopperRemoteError,Remote analysis request fails,"Hopper request failed ({code}): {safeMessage}",Exposes provider name code and upstream text,"Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
4,src/domain/errors.ts:HopperProtocolError,Malformed provider protocol result,Raw constructor message,Can expose provider protocol and implementation details,"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
5,src/domain/errors.ts:AnalysisOutputError,Analysis output fails parsing,"Invalid analysis output for {operation}: {reason}",Exposes internal operation and parser reason,"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
6,src/domain/errors.ts:AnalysisProtocolError,Application protocol fails,Raw constructor message,Can expose protocol internals,"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
7,src/domain/errors.ts:HopperProcessError,Analysis subprocess stops,"Hopper bridge stopped unexpectedly with code {exitCode}",Exposes provider bridge and process code,"Analysis could not start or stopped unexpectedly. Run `rea doctor`, then try again.",implemented,focused assertions passed; full `npm run check` passed
8,src/domain/errors.ts:HopperStartError,Analysis subprocess cannot start,Hopper application bridge could not be started,Exposes provider and bridge implementation,"Analysis could not start or stopped unexpectedly. Run `rea doctor`, then try again.",implemented,focused assertions passed; full `npm run check` passed
9,src/domain/errors.ts:BinaryTargetError,Target cannot open,"Cannot open artifact: {reason}",May expose raw reason and lacks checks,"Preserve the target admission reason; directories name analyze_javascript_application and rea analyze as available alternatives.",implemented,focused assertions passed; full `npm run check` passed
@@ -21,7 +21,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
21,src/domain/errors.ts:AnalysisCancelledError,Caller cancels analysis,"Analysis operation was cancelled: {operation}",Exposes operation identifier,"Analysis was cancelled. Start it again when ready.",implemented,focused assertions passed; full `npm run check` passed
22,src/domain/errors.ts:HopperCancelledError,Caller cancels provider request,Hopper operation was cancelled,Exposes provider name,"Analysis was cancelled. Start it again when ready.",implemented,focused assertions passed; full `npm run check` passed
23,src/domain/errors.ts:NoBinaryOpenError,Analysis requested without target,"No app is open. Ask the user which app to investigate, then call open_binary with its local path.",Low risk; already supplies agent recovery,Keep current copy,implemented,focused assertions passed; full `npm run check` passed
24,src/server/toolResult.ts:successResult,Successful value violates public output schema,AnalysisOutputError: Analysis output does not match the tool contract,Exposes internal error tag and contract implementation,"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",implemented,focused assertions passed; full `npm run check` passed
24,src/server/toolResult.ts:successResult,Successful value violates public output schema,AnalysisOutputError: Analysis output does not match the tool contract,Exposes internal error tag and contract implementation,"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",implemented,focused assertions passed; full `npm run check` passed
24.5,src/server/registerOfficialTools.ts:capability unknown,Approved unknown tracking records an unavailable analysis,"TOOL_NAME is unavailable: PROVIDER_REASON",Exposes an internal tool identifier and provider diagnostic in persistent user-visible evidence,"The requested analysis is unavailable for the current target.",implemented,verified by focused MCP integration test
24.6,src/application/ReferenceSourceImportEntries.ts:failed entry,A partial reference import contains an unreadable entry,Low-level reader diagnostic stored in entry limitations,Can persist filesystem or reader implementation details,"Code- and entry-specific safe guidance with a retry, limit, exclusion, or platform recovery step.",implemented,verified by exhaustive focused projection test
24.7,src/server/registerSessionTools.ts:process residual,Capture records a residual unknown linked to capture Evidence,SCOPE: RAW_REASON,Persists adapter diagnostic and implementation wording,"Was SCOPE behavior fully observed during capture?",implemented,verified by focused session MCP test
1 harm_rank location trigger current_copy user_risk proposed_replacement implementation_status verification_result
2 1 src/domain/errors.ts:AnalysisCapabilityUnavailableError Requested analysis unavailable Provider {providerId} cannot execute {operation}: {reason} Exposes provider and internal operation/reason This analysis is unavailable for the current target. Choose another analysis or target. implemented focused assertions passed; full `npm run check` passed
3 2 src/domain/errors.ts:ProviderAdapterError Provider adapter fails Provider {providerId} adapter failed during {operation} Exposes provider and implementation boundary Analysis could not complete. Retry once; if it continues, run `rea doctor`. Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
4 3 src/domain/errors.ts:HopperRemoteError Remote analysis request fails Hopper request failed ({code}): {safeMessage} Exposes provider name code and upstream text Analysis could not complete. Retry once; if it continues, run `rea doctor`. Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
5 4 src/domain/errors.ts:HopperProtocolError Malformed provider protocol result Raw constructor message Can expose provider protocol and implementation details Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`. Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
6 5 src/domain/errors.ts:AnalysisOutputError Analysis output fails parsing Invalid analysis output for {operation}: {reason} Exposes internal operation and parser reason Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`. Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
7 6 src/domain/errors.ts:AnalysisProtocolError Application protocol fails Raw constructor message Can expose protocol internals Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`. Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
8 7 src/domain/errors.ts:HopperProcessError Analysis subprocess stops Hopper bridge stopped unexpectedly with code {exitCode} Exposes provider bridge and process code Analysis could not start or stopped unexpectedly. Run `rea doctor`, then try again. implemented focused assertions passed; full `npm run check` passed
9 8 src/domain/errors.ts:HopperStartError Analysis subprocess cannot start Hopper application bridge could not be started Exposes provider and bridge implementation Analysis could not start or stopped unexpectedly. Run `rea doctor`, then try again. implemented focused assertions passed; full `npm run check` passed
10 9 src/domain/errors.ts:BinaryTargetError Target cannot open Cannot open artifact: {reason} May expose raw reason and lacks checks Preserve the target admission reason; directories name analyze_javascript_application and rea analyze as available alternatives. implemented focused assertions passed; full `npm run check` passed
21 21 src/domain/errors.ts:AnalysisCancelledError Caller cancels analysis Analysis operation was cancelled: {operation} Exposes operation identifier Analysis was cancelled. Start it again when ready. implemented focused assertions passed; full `npm run check` passed
22 22 src/domain/errors.ts:HopperCancelledError Caller cancels provider request Hopper operation was cancelled Exposes provider name Analysis was cancelled. Start it again when ready. implemented focused assertions passed; full `npm run check` passed
23 23 src/domain/errors.ts:NoBinaryOpenError Analysis requested without target No app is open. Ask the user which app to investigate, then call open_binary with its local path. Low risk; already supplies agent recovery Keep current copy implemented focused assertions passed; full `npm run check` passed
24 24 src/server/toolResult.ts:successResult Successful value violates public output schema AnalysisOutputError: Analysis output does not match the tool contract Exposes internal error tag and contract implementation Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`. Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. implemented focused assertions passed; full `npm run check` passed
25 24.5 src/server/registerOfficialTools.ts:capability unknown Approved unknown tracking records an unavailable analysis TOOL_NAME is unavailable: PROVIDER_REASON Exposes an internal tool identifier and provider diagnostic in persistent user-visible evidence The requested analysis is unavailable for the current target. implemented verified by focused MCP integration test
26 24.6 src/application/ReferenceSourceImportEntries.ts:failed entry A partial reference import contains an unreadable entry Low-level reader diagnostic stored in entry limitations Can persist filesystem or reader implementation details Code- and entry-specific safe guidance with a retry, limit, exclusion, or platform recovery step. implemented verified by exhaustive focused projection test
27 24.7 src/server/registerSessionTools.ts:process residual Capture records a residual unknown linked to capture Evidence SCOPE: RAW_REASON Persists adapter diagnostic and implementation wording Was SCOPE behavior fully observed during capture? implemented verified by focused session MCP test
+3 -3
View File
@@ -66,7 +66,7 @@ export const analysisErrorRemediationAction = (
if (error instanceof HopperRemoteError)
return error.diagnosticType === "invalid_request"
? "Correct the reported address, document, or arguments and retry."
: "Review the Hopper diagnostic details; correct the request or retry if the failure was transient.";
: "Review the Hopper diagnostic details and correct the request or target; run `rea doctor` if the provider itself is failing. Repeating the unchanged request is not expected to succeed.";
if (error instanceof EvidenceReferenceError)
return "Use an exact Evidence reference retained by this session, supply the complete inline Evidence, re-run its producer, or import its Evidence bundle. close_binary clears retained records.";
if (
@@ -282,7 +282,7 @@ const hopperProcessMessage = (error: HopperProcessError): string => {
const standardErrorMessage = (tag: AnalysisErrorTag): string | undefined => {
if (UNREADABLE_OUTPUT_TAGS.has(tag))
return "Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.";
return "Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.";
if (UNSUPPORTED_PROVIDER_TAGS.has(tag))
return "This analysis is unavailable for the current target. Choose another analysis or target.";
if (CANCELLED_TAGS.has(tag))
@@ -290,7 +290,7 @@ const standardErrorMessage = (tag: AnalysisErrorTag): string | undefined => {
if (TIMEOUT_TAGS.has(tag))
return "Analysis took too long. Try a smaller request, then run `rea doctor` if it continues.";
if (ADAPTER_FAILURE_TAGS.has(tag))
return "Analysis could not complete. Retry once; if it continues, run `rea doctor`.";
return "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.";
if (START_FAILURE_TAGS.has(tag))
return "Analysis could not start or stopped unexpectedly. Run `rea doctor`, then try again.";
return undefined;
@@ -384,6 +384,38 @@ describe("analysis error projection: provider failures", () => {
});
});
describe("analysis error projection: retry guidance", () => {
it.each([
[
"unreadable output",
new AnalysisOutputError("inspect_firmware_regions", "report missing"),
"unreadable_output",
],
[
"adapter failure",
new ProviderAdapterError("firmware", "inspect_firmware_regions"),
"execution_failure",
],
[
"Hopper remote failure",
new HopperRemoteError(7, "Hopper analysis failed", {
diagnosticType: "bridge_exception",
operation: "trace_feature",
}),
"execution_failure",
],
])(
"does not recommend an unchanged retry for non-retryable %s",
(_name, error, code) => {
const projected = projectAnalysisError(error);
expect(projected).toMatchObject({ code, retryable: false });
for (const text of [projected.message, projected.remediation.action])
expect(text).not.toMatch(/\bretry\b/iu);
},
);
});
describe("analysis error projection: caller contract", () => {
it("preserves the reported output constraint without exposing its internal cause", () => {
const projected = projectAnalysisError(
@@ -44,7 +44,7 @@ describe("enhanced MCP tools", () => {
error: {
category: "execution_failure",
message:
"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",
"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",
},
},
],
@@ -96,11 +96,11 @@ describe("enhanced MCP tools", () => {
category: "execution_failure",
details: { operation: "decompile", reason: "failed" },
message:
"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",
"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",
retryable: false,
remediation: {
action:
"Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`.",
"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",
},
},
},