mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 22:36:08 +00:00
fix(session): align resource-only status and snapshot recovery (#7896)
* fix(session): align resource-only status and snapshot recovery * fix(session): report independent workflows during resource sessions * test(mcp): honor SQLite runtime availability * test: compare resource snapshot guidance with its formatter Assert projected error codes and the owning remediation action for resource-session snapshot refusals, and type MCP error text as a closed content item. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
1 parent
bf115be2cd
commit
845080aef6
8 files changed
+260
-23
No files matched your search
@@ -64,7 +64,7 @@ import { analysisErrorWithCancellation } from "../../domain/analysisErrorCancell
|
||||
import { ProviderAdapterError } from "../../domain/providerAdapterError.js";
|
||||
import { profilelessNativeDispatchProfile } from "./ProfilelessNativeWorkflowSnapshot.js";
|
||||
import type { AnalysisSnapshot } from "../../domain/analysisSnapshot.js";
|
||||
import { AnalysisSnapshotMismatchError } from "../../domain/evidenceErrors.js";
|
||||
import { ResourceSnapshotMismatchError } from "../../domain/evidenceErrors.js";
|
||||
import {
|
||||
parseBinaryTarget,
|
||||
type BinaryTargetResolverOptions,
|
||||
@@ -1149,21 +1149,13 @@ export class BinarySession
|
||||
|
||||
override exportAnalysisSnapshot() {
|
||||
if (this.#activeBundleResources !== undefined)
|
||||
return err(
|
||||
new AnalysisSnapshotMismatchError(
|
||||
"Analysis snapshots do not apply to a resource-only app session because it has no executable identity or replay binding.",
|
||||
),
|
||||
);
|
||||
return err(new ResourceSnapshotMismatchError("export"));
|
||||
return super.exportAnalysisSnapshot();
|
||||
}
|
||||
|
||||
override importAnalysisSnapshot(snapshot: AnalysisSnapshot) {
|
||||
if (this.#activeBundleResources !== undefined)
|
||||
return err(
|
||||
new AnalysisSnapshotMismatchError(
|
||||
"Analysis snapshots do not apply to a resource-only app session because it has no executable identity or replay binding.",
|
||||
),
|
||||
);
|
||||
return err(new ResourceSnapshotMismatchError("import"));
|
||||
return super.importAnalysisSnapshot(snapshot);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,10 @@ import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
|
||||
import { BinarySession } from "./BinarySession.js";
|
||||
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
||||
import { bundleResourceRootSchema } from "../../domain/apple/bundleResourceRoot.js";
|
||||
import { AnalysisSnapshotMismatchError } from "../../domain/evidenceErrors.js";
|
||||
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import { analysisErrorRemediationAction } from "../../domain/analysisErrorPresentation.js";
|
||||
import { projectAnalysisError } from "../../domain/analysisErrorProjection.js";
|
||||
import { ResourceSnapshotMismatchError } from "../../domain/evidenceErrors.js";
|
||||
import type { AnalysisSnapshot } from "../../domain/analysisSnapshot.js";
|
||||
import { ProviderCleanupError } from "../../domain/providerCleanupError.js";
|
||||
import { ProviderAdapterError } from "../../domain/providerAdapterError.js";
|
||||
@@ -36,6 +39,24 @@ const binaryIdentity: ProviderIdentity = {
|
||||
};
|
||||
const temporaryDirectories: string[] = [];
|
||||
|
||||
const expectResourceSnapshotRefusal = (
|
||||
error: AnalysisError,
|
||||
operation: "export" | "import",
|
||||
): void => {
|
||||
expect(error).toBeInstanceOf(ResourceSnapshotMismatchError);
|
||||
expect(error).toMatchObject({
|
||||
_tag: "EvidenceIntegrityError",
|
||||
operation,
|
||||
});
|
||||
const projected = projectAnalysisError(error);
|
||||
expect(projected.code).toBe("evidence_integrity_mismatch");
|
||||
expect(projected.category).toBe("integrity_mismatch");
|
||||
expect(projected.retryable).toBe(false);
|
||||
expect(projected.remediation).toEqual({
|
||||
action: analysisErrorRemediationAction(error),
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
temporaryDirectories
|
||||
@@ -137,13 +158,17 @@ it("opens a resource-only bundle without executable identity and keeps snapshot
|
||||
resource_root: { canonical_path: opened.value.canonicalPath },
|
||||
});
|
||||
const snapshot = session.exportAnalysisSnapshot();
|
||||
expect(snapshot.ok).toBe(false);
|
||||
if (!snapshot.ok)
|
||||
expect(snapshot.error).toBeInstanceOf(AnalysisSnapshotMismatchError);
|
||||
if (snapshot.ok)
|
||||
throw new Error("resource session exported a binary snapshot");
|
||||
expectResourceSnapshotRefusal(snapshot.error, "export");
|
||||
const imported = session.importAnalysisSnapshot({} as AnalysisSnapshot);
|
||||
expect(imported.ok).toBe(false);
|
||||
if (!imported.ok)
|
||||
expect(imported.error).toBeInstanceOf(AnalysisSnapshotMismatchError);
|
||||
if (imported.ok)
|
||||
throw new Error("resource session imported a binary snapshot");
|
||||
expectResourceSnapshotRefusal(imported.error, "import");
|
||||
expect(await session.status()).toMatchObject({
|
||||
open: true,
|
||||
session_kind: "bundle_resources",
|
||||
});
|
||||
const closedResult = await session.close();
|
||||
expect(closedResult.ok).toBe(true);
|
||||
expect(closed).toBe(true);
|
||||
|
||||
@@ -24,6 +24,13 @@ export const BUNDLE_RESOURCE_OPERATIONS = new Set<AnalysisOperation>([
|
||||
...BUNDLE_ARTIFACT_RESOURCE_OPERATIONS,
|
||||
]);
|
||||
|
||||
/** Share the dispatch owner's resource-session operation policy with discovery. */
|
||||
export const isBundleResourceOperation = (name: string): boolean => {
|
||||
for (const operation of BUNDLE_RESOURCE_OPERATIONS)
|
||||
if (operation === name) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Provider-specific owner of the four read-only app-resource operations. */
|
||||
export interface BundleResourceClientFactory {
|
||||
createClient(
|
||||
|
||||
Reference in new issue
Block a user