mirror of
https://github.com/morluto/rea
synced 2026-10-28 06:46:47 -04:00
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:
@@ -5,8 +5,10 @@ import { join } from "node:path";
|
||||
import { afterEach, expect, it, vi } from "vitest";
|
||||
import {
|
||||
AnalysisCancelledError,
|
||||
AnalysisCapabilityUnavailableError,
|
||||
AnalysisResourceConstraintError,
|
||||
} from "../../../src/domain/analysisErrorCore.js";
|
||||
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
|
||||
import { Il2cppMetadataProvider } from "../../../src/il2cpp/Il2cppMetadataProvider.js";
|
||||
import {
|
||||
createElfFixture,
|
||||
@@ -188,6 +190,41 @@ it("admits a report whose escaped names fit the budget exactly", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps observed source facts with a complete-report refusal", async () => {
|
||||
const root = await createTestTempDirectory("rea-il2cpp-report-evidence-");
|
||||
const path = join(root, "global-metadata.dat");
|
||||
const bytes = createIl2cppMetadataFixture().bytes;
|
||||
await writeFile(path, bytes);
|
||||
const result = await inspectMetadata(path, 256);
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) throw new Error("Expected report allowance refusal");
|
||||
expect(result.error).toBeInstanceOf(AnalysisResourceConstraintError);
|
||||
expect(result.error.partialObservation).toMatchObject({
|
||||
operation: "observe_il2cpp_metadata_source",
|
||||
normalized_result: {
|
||||
artifact: {
|
||||
path,
|
||||
sha256: createHash("sha256").update(bytes).digest("hex"),
|
||||
bytes: bytes.length,
|
||||
},
|
||||
inventory_status: "not-returned-as-complete",
|
||||
},
|
||||
});
|
||||
const projected = projectAnalysisError(result.error);
|
||||
expect(projected.retryable).toBe(false);
|
||||
expect(projected.code).toBe("resource_constraint");
|
||||
expect(projected.remediation.action).toContain(
|
||||
"No complete metadata inventory is retained",
|
||||
);
|
||||
expect(projected.remediation.action).toContain(
|
||||
"Source facts already observed stay with this refusal",
|
||||
);
|
||||
expect(projected.remediation.action).not.toMatch(
|
||||
/does not leave a completed report or Evidence record/u,
|
||||
);
|
||||
expect(projected.remediation.action).not.toMatch(/worker memory/u);
|
||||
});
|
||||
|
||||
it("refuses from row counts before decoding any row", async () => {
|
||||
const root = await createTestTempDirectory("rea-il2cpp-provider-counts-");
|
||||
const path = join(root, "global-metadata.dat");
|
||||
@@ -288,8 +325,17 @@ it("bounds concurrent snapshots and retains active decoding until close complete
|
||||
try {
|
||||
const refused = await provider.inspect({ path });
|
||||
expect(refused.ok).toBe(false);
|
||||
if (!refused.ok)
|
||||
expect(refused.error).toBeInstanceOf(AnalysisResourceConstraintError);
|
||||
if (!refused.ok) {
|
||||
expect(refused.error).toBeInstanceOf(AnalysisCapabilityUnavailableError);
|
||||
expect(projectAnalysisError(refused.error)).toMatchObject({
|
||||
code: "capability_unavailable",
|
||||
retryable: false,
|
||||
details: { reason: "IL2CPP metadata reader is closed" },
|
||||
});
|
||||
expect(
|
||||
projectAnalysisError(refused.error).remediation.action,
|
||||
).not.toMatch(/retry/i);
|
||||
}
|
||||
await setImmediate();
|
||||
expect(closed).toBe(false);
|
||||
} finally {
|
||||
@@ -298,7 +344,53 @@ it("bounds concurrent snapshots and retains active decoding until close complete
|
||||
}
|
||||
expect((await active).ok).toBe(true);
|
||||
expect(closed).toBe(true);
|
||||
expect((await provider.inspect({ path })).ok).toBe(false);
|
||||
const afterClose = await provider.inspect({ path });
|
||||
expect(afterClose.ok).toBe(false);
|
||||
if (!afterClose.ok) {
|
||||
expect(afterClose.error).toBeInstanceOf(AnalysisCapabilityUnavailableError);
|
||||
expect(projectAnalysisError(afterClose.error).retryable).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps occupied capacity retryable while the reader remains open", async () => {
|
||||
const root = await createTestTempDirectory("rea-il2cpp-provider-occupied-");
|
||||
const path = join(root, "global-metadata.dat");
|
||||
await writeFile(path, createIl2cppMetadataFixture().bytes);
|
||||
let markEntered!: () => void;
|
||||
const entered = new Promise<void>((resolve) => {
|
||||
markEntered = resolve;
|
||||
});
|
||||
let resume!: () => void;
|
||||
const release = new Promise<void>((resolve) => {
|
||||
resume = resolve;
|
||||
});
|
||||
const provider = new Il2cppMetadataProvider(undefined, () => {
|
||||
markEntered();
|
||||
return release;
|
||||
});
|
||||
const active = provider.inspect({ path });
|
||||
await entered;
|
||||
try {
|
||||
const refused = await provider.inspect({ path });
|
||||
expect(refused.ok).toBe(false);
|
||||
if (!refused.ok) {
|
||||
expect(refused.error).toBeInstanceOf(AnalysisResourceConstraintError);
|
||||
expect(projectAnalysisError(refused.error)).toMatchObject({
|
||||
retryable: true,
|
||||
details: {
|
||||
resource: "capacity",
|
||||
reported_limits: { maximum_concurrent_inspections: 1 },
|
||||
},
|
||||
remediation: {
|
||||
action: expect.stringContaining("active IL2CPP metadata inspection"),
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
resume();
|
||||
await active;
|
||||
await provider.close();
|
||||
}
|
||||
});
|
||||
|
||||
it.each([false, true])(
|
||||
|
||||
Reference in New Issue
Block a user