mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 17:28:08 +00:00
fix(evidence)!: report storage publication limits (#7887)
* fix(evidence): report storage publication limits * test(evidence): cover staged storage failure cleanup
This commit is contained in:
1 parent
539a494d25
commit
bf115be2cd
6 files changed
+187
-12
No files matched your search
@@ -411,16 +411,16 @@ const writeTextPartsOwned = async (
|
||||
}),
|
||||
cause.lease,
|
||||
);
|
||||
const failure = classifyWriteFailure(cause.outcome.error);
|
||||
return stagedCleanupFailure(
|
||||
new EvidenceFileError(
|
||||
"write",
|
||||
fileAccessFailureReason(cause.outcome.error),
|
||||
{
|
||||
cause,
|
||||
path: requestedPath,
|
||||
cleanup,
|
||||
},
|
||||
),
|
||||
new EvidenceFileError("write", failure.reason, {
|
||||
cause,
|
||||
path: requestedPath,
|
||||
cleanup,
|
||||
...(failure.systemCode === undefined
|
||||
? {}
|
||||
: { systemCode: failure.systemCode }),
|
||||
}),
|
||||
cause.lease,
|
||||
);
|
||||
}
|
||||
@@ -437,15 +437,32 @@ const writeTextPartsOwned = async (
|
||||
path: requestedPath,
|
||||
}),
|
||||
);
|
||||
const failure = classifyWriteFailure(cause);
|
||||
return err(
|
||||
new EvidenceFileError("write", fileAccessFailureReason(cause), {
|
||||
new EvidenceFileError("write", failure.reason, {
|
||||
cause,
|
||||
path: requestedPath,
|
||||
...(failure.systemCode === undefined
|
||||
? {}
|
||||
: { systemCode: failure.systemCode }),
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/** Recognize only host codes that establish a publication resource refusal. */
|
||||
const classifyWriteFailure = (
|
||||
cause: unknown,
|
||||
): {
|
||||
readonly reason: EvidenceFileError["reason"];
|
||||
readonly systemCode?: "EFBIG" | "ENOSPC" | "EDQUOT";
|
||||
} => {
|
||||
const code = fileErrorCode(cause);
|
||||
return code === "EFBIG" || code === "ENOSPC" || code === "EDQUOT"
|
||||
? { reason: "storage-limit", systemCode: code }
|
||||
: { reason: fileAccessFailureReason(cause) };
|
||||
};
|
||||
|
||||
/** The retained staging lease clears this error only when a retry confirms release. */
|
||||
const stagedCleanupFailure = <
|
||||
Failure extends EvidenceFileError | AnalysisCancelledError,
|
||||
|
||||
@@ -260,7 +260,10 @@ export const analysisErrorCategory = (
|
||||
return "unavailable";
|
||||
if (error instanceof ArtifactOperationError)
|
||||
return artifactErrorCategory(error.reason);
|
||||
if (error instanceof EvidenceFileError && error.reason === "path-limit")
|
||||
if (
|
||||
error instanceof EvidenceFileError &&
|
||||
(error.reason === "path-limit" || error.reason === "storage-limit")
|
||||
)
|
||||
return "resource_constraint";
|
||||
if (
|
||||
error instanceof EvidenceFileError &&
|
||||
@@ -565,11 +568,18 @@ const evidenceFileMessage = ({
|
||||
operation,
|
||||
reason,
|
||||
published,
|
||||
systemCode,
|
||||
}: EvidenceFileError): string => {
|
||||
if (published !== undefined)
|
||||
return "The output file was published, but staging cleanup remains incomplete.";
|
||||
if (reason === "path-limit")
|
||||
return "Filesystem path-length constraints prevented reading or atomic publication at the selected path. Choose a shorter local path.";
|
||||
if (reason === "storage-limit")
|
||||
return systemCode === "EFBIG"
|
||||
? "The host file-size limit prevented Evidence publication. Increase the inherited file-size allowance and retry."
|
||||
: systemCode === undefined
|
||||
? "A host filesystem resource limit prevented Evidence publication. Check the file-size allowance, filesystem space and quota before retrying."
|
||||
: "The filesystem lacks space or quota for Evidence publication. Free space or increase quota and retry.";
|
||||
if (reason === "symlink-traversal")
|
||||
return "The selected path cannot be resolved because its symbolic-link chain loops or exceeds the host traversal limit. Repair the chain or select another path.";
|
||||
if (reason === "missing")
|
||||
|
||||
@@ -236,7 +236,8 @@ const evidenceFileCode = (
|
||||
reason: EvidenceFileError["reason"],
|
||||
): AnalysisErrorProjection["code"] => {
|
||||
if (reason === "invalid-json") return "evidence_integrity_mismatch";
|
||||
if (reason === "path-limit") return "resource_constraint";
|
||||
if (reason === "path-limit" || reason === "storage-limit")
|
||||
return "resource_constraint";
|
||||
// A missing, non-file or already-existing path is the caller's selection.
|
||||
if (reason === "io") return "execution_failure";
|
||||
return "invalid_request";
|
||||
@@ -418,6 +419,9 @@ const artifactStateErrorDetails = (
|
||||
operation: error.operation,
|
||||
reason: error.reason,
|
||||
...(error.reason === "path-limit" ? { boundary: "filesystem-path" } : {}),
|
||||
...(error.systemCode === undefined
|
||||
? {}
|
||||
: { system_code: error.systemCode }),
|
||||
...(error.path === undefined ? {} : { path: error.path }),
|
||||
...(error.contentIssues === undefined
|
||||
? {}
|
||||
|
||||
@@ -60,6 +60,7 @@ export class EvidenceFileError extends AnalysisError {
|
||||
readonly published: PublishedEvidenceFileObservation | undefined;
|
||||
/** Schema issues relative to the selected file's JSON root, never the request envelope. */
|
||||
readonly contentIssues: readonly AnalysisInputIssue[] | undefined;
|
||||
readonly systemCode: "EFBIG" | "ENOSPC" | "EDQUOT" | undefined;
|
||||
|
||||
constructor(
|
||||
readonly operation: "read" | "write",
|
||||
@@ -70,6 +71,7 @@ export class EvidenceFileError extends AnalysisError {
|
||||
| "invalid-json"
|
||||
| "missing"
|
||||
| "path-limit"
|
||||
| "storage-limit"
|
||||
| "symlink-traversal"
|
||||
| "io",
|
||||
options?: AnalysisErrorOptions & {
|
||||
@@ -77,6 +79,7 @@ export class EvidenceFileError extends AnalysisError {
|
||||
readonly published?: PublishedEvidenceFileObservation;
|
||||
readonly userMessage?: string;
|
||||
readonly contentIssues?: readonly AnalysisInputIssue[];
|
||||
readonly systemCode?: "EFBIG" | "ENOSPC" | "EDQUOT";
|
||||
},
|
||||
) {
|
||||
super(`Evidence bundle ${operation} failed: ${reason}`, options);
|
||||
@@ -84,5 +87,6 @@ export class EvidenceFileError extends AnalysisError {
|
||||
this.published = options?.published;
|
||||
this.userMessage = options?.userMessage;
|
||||
this.contentIssues = options?.contentIssues;
|
||||
this.systemCode = options?.systemCode;
|
||||
}
|
||||
}
|
||||
@@ -189,6 +189,10 @@ const redactFailure = (
|
||||
const publishedPath = identity(error.published?.path);
|
||||
return new EvidenceFileError(error.operation, error.reason, {
|
||||
...context,
|
||||
...(error.systemCode === undefined ||
|
||||
text(error.systemCode) !== error.systemCode
|
||||
? {}
|
||||
: { systemCode: error.systemCode }),
|
||||
...(retainedPath === undefined ? {} : { path: retainedPath }),
|
||||
...(error.userMessage === undefined
|
||||
? {}
|
||||
|
||||
Reference in new issue
Block a user