mirror of
https://github.com/morluto/rea
synced 2026-10-28 06:46:47 -04:00
fix(mcp): keep a snapshot open ahead of later calls on the same connection (#3661)
open_binary read snapshot_path before it entered the session's lifecycle order, so a current_document or close_binary dispatched after it could run first: the read returned Evidence for the previous target and the close left the snapshot target open. The session now loads the snapshot inside the open's own turn. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
ce89706145
commit
73c72d5745
@@ -216,12 +216,12 @@ export class BinarySession
|
||||
options: BinarySessionOpenOptions = {},
|
||||
): Promise<Result<BinaryTarget, AnalysisError>> {
|
||||
return this.#open(
|
||||
() =>
|
||||
(admitted) =>
|
||||
resolveSessionOpen({
|
||||
router: this.#providerRouter,
|
||||
current: this.#active,
|
||||
path,
|
||||
options,
|
||||
options: admitted,
|
||||
stagedSnapshotMatches: (target, profile) =>
|
||||
this.matchesSnapshot(target, profile),
|
||||
}),
|
||||
@@ -250,12 +250,33 @@ export class BinarySession
|
||||
}
|
||||
|
||||
#open(
|
||||
resolve: () => Promise<Result<ResolvedSessionOpen, AnalysisError>>,
|
||||
options: Pick<BinarySessionOpenOptions, "signal" | "snapshot">,
|
||||
resolve: (
|
||||
admitted: BinarySessionOpenOptions,
|
||||
) => Promise<Result<ResolvedSessionOpen, AnalysisError>>,
|
||||
options: BinarySessionOpenOptions,
|
||||
): Promise<Result<BinaryTarget, AnalysisError>> {
|
||||
return this.#serialize((admittedThrough) =>
|
||||
this.#openWithinTransition(admittedThrough, resolve, options),
|
||||
);
|
||||
return this.#serialize(async (admittedThrough) => {
|
||||
const admitted = await this.#withLoadedSnapshot(options);
|
||||
if (!admitted.ok) return admitted;
|
||||
return this.#openWithinTransition(
|
||||
admittedThrough,
|
||||
() => resolve(admitted.value),
|
||||
admitted.value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/** Read the staged snapshot only after earlier lifecycle transitions have settled. */
|
||||
async #withLoadedSnapshot(
|
||||
options: BinarySessionOpenOptions,
|
||||
): Promise<Result<BinarySessionOpenOptions, AnalysisError>> {
|
||||
if (options.loadSnapshot === undefined) return ok(options);
|
||||
if (isAborted(options.signal))
|
||||
return err(new AnalysisCancelledError("open_binary"));
|
||||
const loaded = await options.loadSnapshot();
|
||||
if (!loaded.ok) return loaded;
|
||||
const { loadSnapshot: _loaded, ...rest } = options;
|
||||
return ok({ ...rest, snapshot: loaded.value });
|
||||
}
|
||||
|
||||
async #openWithinTransition(
|
||||
|
||||
@@ -19,6 +19,11 @@ import { err, type Result } from "../../domain/result.js";
|
||||
import type { SessionProviderRoute } from "./SessionProviderRouter.js";
|
||||
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
||||
|
||||
/** Read a staged snapshot once the open holds its place in the session order. */
|
||||
export type AnalysisSnapshotLoader = () => Promise<
|
||||
Result<AnalysisSnapshot, AnalysisError>
|
||||
>;
|
||||
|
||||
export interface BinarySessionOpenOptions {
|
||||
readonly signal?: AbortSignal;
|
||||
readonly targetKind?: BinaryTarget["kind"];
|
||||
@@ -26,6 +31,11 @@ export interface BinarySessionOpenOptions {
|
||||
readonly architecture?: BinaryArchitecture;
|
||||
readonly entryPoint?: string;
|
||||
readonly snapshot?: AnalysisSnapshot;
|
||||
/**
|
||||
* Load the snapshot inside the open's turn instead of before it, so calls
|
||||
* dispatched after the open cannot overtake its file read.
|
||||
*/
|
||||
readonly loadSnapshot?: AnalysisSnapshotLoader;
|
||||
readonly providerId?: AnalysisProviderSelector;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { AnalysisProviderSelector } from "../../contracts/providerSelection
|
||||
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import type { Result } from "../../domain/result.js";
|
||||
import type { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
|
||||
import type { AnalysisSnapshotLoader } from "./BinarySessionOpen.js";
|
||||
import type { WorkflowSnapshotRecordInput } from "./BinarySessionRecords.js";
|
||||
|
||||
import type {
|
||||
@@ -71,6 +72,7 @@ export interface BinarySessionPort
|
||||
readonly architecture?: BinaryArchitecture;
|
||||
readonly entryPoint?: string;
|
||||
readonly snapshot?: AnalysisSnapshot;
|
||||
readonly loadSnapshot?: AnalysisSnapshotLoader;
|
||||
readonly providerId?: AnalysisProviderSelector;
|
||||
},
|
||||
): Promise<Result<BinaryTarget, AnalysisError>>;
|
||||
|
||||
Reference in New Issue
Block a user