fix(errors): name fixed allowances in resource-constraint recovery (#5633)

* fix(errors): name fixed allowances in resource-constraint recovery

Fixed parser, count, report, input, and capture refusals inherited
host-memory, wait-and-retry, or retained-Evidence advice. Producers now
attach allowance-specific recovery, and deterministic capacity caps are
not retryable. IL2CPP reader occupancy stays retryable capacity.

Refs #5556, #5405, #5456, #5459, #5460, #5504, #5505, #5506, #5537, #5628, #5630, #5631, #5632

* fix(il2cpp): keep a closing metadata reader non-retryable

close() stops admission before the active inspection finishes. A second
inspect in that window was projected as retryable capacity. Closing and
closed readers now report capability_unavailable. Occupied readers that
remain open stay retryable.

* fix(errors): align fixed-cap recovery with retained facts

IL2CPP report refusals keep observed source facts instead of denying Evidence. Command-output caps use the capture allowance. Ghidra seed recovery names the limit that was exceeded.

* fix(errors): call byte caps a byte allowance

WASM representation limits and the IL2CPP Ghidra seed-file cap are byte budgets. Their recovery no longer says the exceeded allowance is a fixed count.

* test(ida): keep unresolved procedure lookups non-retryable

Main now treats an unchanged invalid request as non-retryable. The IDA lookup tests follow that projection.

* fix(errors): qualify capture recovery for live output

A fixed capture allowance still rejects the same output. Live captures such as adb logcat can change between requests, so recovery no longer says every unchanged request fails again.

* fix(adb): keep a truncated live capture retryable

Device output can shrink between calls, so an adb capture that exceeds the allowance stays retryable. Deterministic capture and version-output limits stay non-retryable.

* fix(adb): keep truncated mutations non-retryable

Only live observations opt into retrying a capture that exceeded the allowance. Push, install, uninstall, and other mutations stay non-retryable.

* fix(errors): keep live capture recovery off deterministic limits

Artifact-derived capture allowances again say the unchanged request fails. Only volatile adb observations use the live-output sentence.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
morluto
2026-10-21 03:45:34 +08:00
committed by GitHub
parent 53e0943223
commit ef59174c1e
40 changed files with 888 additions and 51 deletions
+41 -3
View File
@@ -27,6 +27,7 @@ import {
AnalysisAccessDeniedError,
AnalysisArtifactChangedError,
AnalysisCancelledError,
AnalysisCapabilityUnavailableError,
AnalysisInputError,
AnalysisOutputError,
AnalysisResourceConstraintError,
@@ -37,6 +38,7 @@ import {
type Il2cppMetadata,
type Il2cppMetadataProviderInput,
} from "../domain/il2cpp/il2cppMetadata.js";
import { fixedAllowanceOptions } from "../domain/fixedAllowanceRemediation.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
import { err, ok, type Result } from "../domain/result.js";
@@ -76,7 +78,13 @@ const failureForPrimary = (
cause.reason === "native-type-text-capacity" ? "memory" : "capacity",
cause.message,
{},
{ cause },
{
cause,
...fixedAllowanceOptions(
"The IL2CPP native-link allowance",
cause.reason === "native-type-text-capacity" ? "parser" : "count",
),
},
);
if (
cause instanceof Il2cppBinaryFormatFailure ||
@@ -112,7 +120,10 @@ const failureForPrimary = (
"file-size",
cause.message,
{ maximum_input_bytes: maximum },
{ cause },
{
cause,
...fixedAllowanceOptions("the fixed IL2CPP input allowance", "input"),
},
);
if (cause.reason === "path")
return new AnalysisInputError(OPERATION, { cause }, [
@@ -220,12 +231,20 @@ const binaryReport = (
method_addresses: link.method_addresses,
});
/**
* Source facts stay on the refusal. The shared report sentence would deny an
* Evidence record that this reader attaches and MCP retains.
*/
const completeReportRecovery =
"The IL2CPP complete-report allowance is a fixed report allowance. No complete metadata inventory is retained. Source facts already observed stay with this refusal, and complete CLI JSON does not raise the allowance. Repeating the unchanged request fails the same way.";
const reportLimit = (path: string, maximumBytes: number) =>
new AnalysisResourceConstraintError(
OPERATION,
"memory",
`Complete IL2CPP metadata for ${path} exceeds the retained report budget; no complete inventory is retained.`,
{ maximum_report_bytes: maximumBytes },
{ retryable: false, remediationAction: completeReportRecovery },
);
const sourceArtifact = (path: string, snapshot: StableArtifactSnapshot) => ({
@@ -316,6 +335,8 @@ export class Il2cppMetadataProvider implements Il2cppMetadataPort {
readonly identity = IL2CPP_METADATA_PROVIDER_IDENTITY;
readonly #resources = new ArtifactResourceScope();
#inspecting = false;
/** `close()` stops admission permanently, including while an inspection is active. */
#admissionStopped = false;
/** `outputBytes` exists so tests can reach the guard with small files. */
constructor(
@@ -324,6 +345,7 @@ export class Il2cppMetadataProvider implements Il2cppMetadataPort {
) {}
async close(): Promise<void> {
this.#admissionStopped = true;
try {
await this.#resources.close();
} catch (cause: unknown) {
@@ -352,13 +374,29 @@ export class Il2cppMetadataProvider implements Il2cppMetadataPort {
return err(
new AnalysisCancelledError(OPERATION, { cause: options.signal.reason }),
);
if (this.#admissionStopped)
return err(
new AnalysisCapabilityUnavailableError(
IL2CPP_METADATA_PROVIDER_IDENTITY.id,
OPERATION,
"IL2CPP metadata reader is closed",
{
remediationAction:
"This reader has stopped admitting inspections. Create a new IL2CPP metadata reader to inspect again. Repeating the request on this reader fails the same way.",
},
),
);
if (this.#inspecting)
return err(
new AnalysisResourceConstraintError(
OPERATION,
"memory",
"capacity",
"Only one IL2CPP metadata inspection is admitted per reader.",
{ maximum_concurrent_inspections: 1 },
{
remediationAction:
"Retry after the active IL2CPP metadata inspection on this reader completes.",
},
),
);
this.#inspecting = true;