mirror of
https://github.com/morluto/rea
synced 2026-10-28 06:46:47 -04:00
fix(readers): preserve completed snapshots through cleanup retries
Retain exact completed file path, digest and length in Python pyc and Erlang BEAM failure observations. Translate Python close failures at the provider boundary and bind them to the retained descriptor cleanup leases so later successful retries resolve prior errors. Exercise actual services and file handles with completed reads, cancellation during finalization and physical read failure followed by cancellation. Assert no fabricated snapshot on early failure and resolution of every prior cleanup report. Validation: six focused descriptor regressions plus existing filesystem, parser and MCP coverage passed; build and static checks passed. Authored format fixtures establish portable reader behavior, not CPython/Erlang runtime execution.
This commit is contained in:
@@ -6,9 +6,13 @@ import {
|
||||
bindArtifactFileCleanup,
|
||||
} from "../artifacts/ArtifactFileOperation.js";
|
||||
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
||||
import { readStableArtifact } from "../artifacts/readStableArtifact.js";
|
||||
import {
|
||||
completedStableArtifact,
|
||||
readStableArtifact,
|
||||
} from "../artifacts/readStableArtifact.js";
|
||||
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
||||
import { analysisErrorWithCleanupFailure } from "../domain/analysisErrorCleanup.js";
|
||||
import { fileSnapshotPartialObservationSchema } from "../domain/fileSnapshotObservation.js";
|
||||
import type { PythonPycPort } from "../application/python/PythonPycPort.js";
|
||||
import type { ExecutionOptions } from "../application/AnalysisProvider.js";
|
||||
import { AnalysisError } from "../domain/analysisErrorBase.js";
|
||||
@@ -164,6 +168,16 @@ const failureForPrimary = (
|
||||
|
||||
const failureFor = (cause: unknown, input: InspectPythonPycInput) => {
|
||||
const primary = failureForPrimary(artifactFilePrimaryFacts(cause), input);
|
||||
const snapshot = completedStableArtifact(cause);
|
||||
if (snapshot !== undefined)
|
||||
primary.retainPartialObservation(
|
||||
fileSnapshotPartialObservationSchema.parse({
|
||||
kind: "file-snapshot-hash",
|
||||
path: input.path,
|
||||
sha256: snapshot.sha256,
|
||||
bytes: snapshot.bytes.length,
|
||||
}),
|
||||
);
|
||||
if (!(cause instanceof ArtifactReaderFailure) || cause.cleanup === undefined)
|
||||
return primary;
|
||||
const cleanup = new ProviderCleanupError(
|
||||
@@ -182,8 +196,24 @@ export class PythonPycProvider implements PythonPycPort {
|
||||
readonly identity = PYTHON_PYC_PROVIDER_IDENTITY;
|
||||
readonly #resources = new ArtifactResourceScope();
|
||||
|
||||
close(): Promise<void> {
|
||||
return this.#resources.close();
|
||||
async close(): Promise<void> {
|
||||
try {
|
||||
await this.#resources.close();
|
||||
} catch (cause: unknown) {
|
||||
if (
|
||||
!(cause instanceof ArtifactReaderFailure) ||
|
||||
cause.cleanup === undefined
|
||||
)
|
||||
throw cause;
|
||||
const error = new ProviderCleanupError(
|
||||
PYTHON_PYC_PROVIDER_IDENTITY.id,
|
||||
cause.cleanup.resources,
|
||||
{ reason: cause.cleanup.reason },
|
||||
{ cause, operation: OPERATION },
|
||||
);
|
||||
bindArtifactFileCleanup(cause, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async inspect(input: InspectPythonPycInput, options?: ExecutionOptions) {
|
||||
|
||||
Reference in New Issue
Block a user