* feat(artifacts): read Godot PCK packs Add a Godot Engine PCK artifact reader for standalone packs and packs embedded behind an executable trailer (formats 2 and 3). Members are uncompressed byte ranges verified against their declared MD5 on read. Encrypted directories, sparse bundles, patch removal entries, unknown flags and format 1 fail closed as unavailable; encrypted members are reported without being read. inspect-artifact and extract-artifact recognize standalone packs by their GDPC magic. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(artifacts): bound Godot PCK metadata and own member streams Cap member paths at 4096 bytes and the retained directory at 64 MiB before allocation. Read members with positional chunk reads through pipeline so cancellation is typed, abandoned consumers release their source, and the shared descriptor stays reader-owned. Retain the root descriptor for godot-pck inventory, as for ZIP and universal Mach-O. Co-Authored-By: Claude Opus 5.5 <[email protected]> * feat(artifacts): complete Godot PCK facts, integrity and selected views * fix(artifacts): preserve atomic-root inventory Evidence * fix(artifacts): bound aggregate PCK member expansion --------- Co-authored-by: Samucahub <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]> Co-authored-by: gensokyo-dev <[email protected]>
616 lines
20 KiB
TypeScript
616 lines
20 KiB
TypeScript
import { projectArtifactIntegrityDetails } from "./artifactIntegrity.js";
|
|
import { jsonValueSchema, type JsonValue } from "./jsonValue.js";
|
|
import { isImmutableJsonSnapshot } from "./immutableJson.js";
|
|
|
|
import {
|
|
analysisErrorCategory,
|
|
analysisErrorRemediationAction,
|
|
analysisErrorUserMessage,
|
|
assertKnownAnalysisErrorTag,
|
|
} from "./analysisErrorPresentation.js";
|
|
import {
|
|
AnalysisAccessDeniedError,
|
|
AnalysisArtifactChangedError,
|
|
AnalysisCancelledError,
|
|
AnalysisCapabilityUnavailableError,
|
|
AnalysisUnsupportedTargetError,
|
|
AnalysisInputError,
|
|
AnalysisOutputError,
|
|
AnalysisTimeoutError,
|
|
AnalysisResourceConstraintError,
|
|
} from "./analysisErrorCore.js";
|
|
import { ArtifactOperationError } from "./artifactOperationError.js";
|
|
import {
|
|
BinaryTargetError,
|
|
ConfigurationError,
|
|
} from "./configurationErrors.js";
|
|
import { BrowserObservationError } from "./browserObservationError.js";
|
|
import {
|
|
EvidenceFileError,
|
|
EvidenceIntegrityError,
|
|
EvidenceReferenceError,
|
|
} from "./evidenceErrors.js";
|
|
import {
|
|
HopperCancelledError,
|
|
HopperProcessError,
|
|
HopperRemoteError,
|
|
HopperStartError,
|
|
HopperTimeoutError,
|
|
} from "./hopperErrors.js";
|
|
import { ProviderAdapterError } from "./providerAdapterError.js";
|
|
import { ProviderSelectionError } from "./providerSelectionError.js";
|
|
import { UnknownRegistryError } from "./unknownRegistryError.js";
|
|
import { providerRetryAction } from "./providerOperationHealth.js";
|
|
import {
|
|
resolvedAnalysisError,
|
|
type AnalysisError,
|
|
type AnalysisErrorTag,
|
|
} from "./analysisErrorBase.js";
|
|
|
|
/** Project expected failures into exhaustive, secret-safe caller fields. */
|
|
export const projectAnalysisError = (
|
|
error: AnalysisError,
|
|
): AnalysisErrorProjection => {
|
|
const composed = error;
|
|
error = resolvedAnalysisError(error);
|
|
let diagnosticSource = error;
|
|
while (
|
|
diagnosticSource.diagnostics === undefined &&
|
|
diagnosticSource.cleanupPrimary !== undefined
|
|
)
|
|
diagnosticSource = diagnosticSource.cleanupPrimary;
|
|
const diagnostics = diagnosticSource.diagnostics;
|
|
const capturedOutput = composed.capturedOutput ?? error.capturedOutput;
|
|
const partialObservation =
|
|
composed.partialObservation ?? error.partialObservation;
|
|
assertKnownAnalysisErrorTag(error._tag);
|
|
const underlyingCode = underlyingErrorCode(error);
|
|
const code = error.cleanupIncomplete ? "cleanup_incomplete" : underlyingCode;
|
|
const primaryDetails = errorDetails(error);
|
|
const details = {
|
|
...primaryDetails,
|
|
...(composed === error || composed.cleanupReport === undefined
|
|
? {}
|
|
: { cleanup_report: jsonValueSchema.parse(composed.cleanupReport) }),
|
|
...(diagnostics === undefined ? {} : { diagnostics }),
|
|
...(composed === error || composed.diagnostics === undefined
|
|
? {}
|
|
: { cleanup_history: composed.diagnostics }),
|
|
...(error.cleanupIncomplete
|
|
? {
|
|
cleanup: "incomplete",
|
|
resources: [...error.cleanupResources],
|
|
...(error.cleanup === undefined
|
|
? {}
|
|
: { cleanup_reason: error.cleanup.reason }),
|
|
execution_failure:
|
|
primaryDetails?.execution_failure ?? underlyingCode,
|
|
}
|
|
: {}),
|
|
...(capturedOutput === undefined
|
|
? {}
|
|
: {
|
|
captured_output: {
|
|
...capturedOutput,
|
|
},
|
|
}),
|
|
...(partialObservation === undefined
|
|
? {}
|
|
: {
|
|
partial_observation: isImmutableJsonSnapshot(partialObservation)
|
|
? partialObservation
|
|
: jsonValueSchema.parse(partialObservation),
|
|
}),
|
|
};
|
|
return {
|
|
code,
|
|
category: analysisErrorCategory(error),
|
|
message: analysisErrorUserMessage(error),
|
|
retryable:
|
|
RETRYABLE_CODES.has(code) ||
|
|
(error instanceof AnalysisCapabilityUnavailableError &&
|
|
error.retryable) ||
|
|
(code === "resource_constraint" &&
|
|
error instanceof AnalysisResourceConstraintError &&
|
|
(error.retryable ?? error.resource === "capacity")),
|
|
remediation: {
|
|
action: analysisErrorRemediationAction(error),
|
|
},
|
|
...(Object.keys(details).length === 0 ? {} : { details }),
|
|
};
|
|
};
|
|
|
|
const underlyingErrorCode = (
|
|
error: AnalysisError,
|
|
): AnalysisErrorProjection["code"] => {
|
|
if (
|
|
error instanceof HopperRemoteError &&
|
|
error.diagnosticType === "invalid_request"
|
|
)
|
|
return "invalid_request";
|
|
if (error instanceof ProviderSelectionError)
|
|
return error.reason === "provider_unavailable"
|
|
? "provider_unavailable"
|
|
: "capability_unavailable";
|
|
if (error instanceof BrowserObservationError)
|
|
return error.userCategory === "cancelled"
|
|
? "cancelled"
|
|
: BROWSER_ERROR_CODES[error.reason];
|
|
if (error instanceof ArtifactOperationError)
|
|
return artifactOperationCode(error);
|
|
if (error instanceof BinaryTargetError)
|
|
return error.constraint === "load_selection_rejected"
|
|
? "invalid_request"
|
|
: error.systemCode === undefined
|
|
? "target_unavailable"
|
|
: "access_denied";
|
|
if (error instanceof EvidenceFileError) return evidenceFileCode(error.reason);
|
|
if (error instanceof UnknownRegistryError)
|
|
return unknownRegistryCode(error.reason);
|
|
if (error._tag === "ProcessCaptureError") return processCaptureCode(error);
|
|
return staticErrorCode(error._tag);
|
|
};
|
|
|
|
const BROWSER_ERROR_CODES: Readonly<
|
|
Record<BrowserObservationError["reason"], AnalysisErrorProjection["code"]>
|
|
> = {
|
|
endpoint_unreachable: "provider_unavailable",
|
|
invalid_endpoint_response: "unreadable_output",
|
|
target_not_found: "target_unavailable",
|
|
target_not_allowed: "target_unavailable",
|
|
service_worker_blocked: "target_unavailable",
|
|
target_changed: "target_unavailable",
|
|
protocol_error: "unreadable_output",
|
|
disconnected: "provider_unavailable",
|
|
payload_limit: "truncated",
|
|
window_not_found: "unreadable_output",
|
|
window_metadata_missing: "unreadable_output",
|
|
process_ownership_unavailable: "unreadable_output",
|
|
cleanup_failed: "execution_failure",
|
|
cancelled: "cancelled",
|
|
timeout: "provider_timeout",
|
|
secret_unavailable: "unreadable_output",
|
|
};
|
|
|
|
const artifactOperationCode = (
|
|
error: ArtifactOperationError,
|
|
): AnalysisErrorProjection["code"] => {
|
|
if (error.reason === "integrity" && error.artifactDetails !== undefined)
|
|
return "artifact_integrity_mismatch";
|
|
if (error.reason === "limit") return "truncated";
|
|
if (error.reason === "cancelled") return "cancelled";
|
|
return "artifact_operation_failed";
|
|
};
|
|
|
|
const evidenceFileCode = (
|
|
reason: EvidenceFileError["reason"],
|
|
): AnalysisErrorProjection["code"] => {
|
|
if (reason === "invalid-json") return "evidence_integrity_mismatch";
|
|
// A missing, non-file or already-existing path is the caller's selection.
|
|
if (reason === "io") return "execution_failure";
|
|
return "invalid_request";
|
|
};
|
|
|
|
const unknownRegistryCode = (
|
|
reason: UnknownRegistryError["reason"],
|
|
): AnalysisErrorProjection["code"] => {
|
|
if (reason === "revision-conflict" || reason === "already-exists")
|
|
return "revision_conflict";
|
|
if (reason === "limit") return "truncated";
|
|
if (reason === "integrity") return "evidence_integrity_mismatch";
|
|
return "execution_failure";
|
|
};
|
|
|
|
const processCaptureCode = (
|
|
error: AnalysisError,
|
|
): AnalysisErrorProjection["code"] => {
|
|
if (error.cleanupIncomplete) return "cleanup_incomplete";
|
|
if (error.userCategory === "cancelled") return "cancelled";
|
|
return "process_capture_failed";
|
|
};
|
|
|
|
type SpecializedErrorTag =
|
|
| "ArtifactOperationError"
|
|
| "BinaryTargetError"
|
|
| "BrowserObservationError"
|
|
| "EvidenceFileError"
|
|
| "ProcessCaptureError"
|
|
| "ProviderSelectionError"
|
|
| "UnknownRegistryError";
|
|
|
|
const STATIC_ERROR_CODES = {
|
|
AnalysisProtocolError: "unreadable_output",
|
|
AnalysisOutputError: "unreadable_output",
|
|
HopperProtocolError: "unreadable_output",
|
|
AnalysisInputError: "invalid_request",
|
|
AnalysisAccessDeniedError: "access_denied",
|
|
AnalysisArtifactChangedError: "artifact_changed",
|
|
AnalysisCapabilityUnavailableError: "capability_unavailable",
|
|
AnalysisUnsupportedTargetError: "unsupported_target",
|
|
AnalysisCancelledError: "cancelled",
|
|
HopperCancelledError: "cancelled",
|
|
AnalysisTimeoutError: "provider_timeout",
|
|
AnalysisResourceConstraintError: "resource_constraint",
|
|
HopperTimeoutError: "provider_timeout",
|
|
HopperProcessError: "provider_unavailable",
|
|
HopperStartError: "provider_unavailable",
|
|
ConfigurationError: "configuration_invalid",
|
|
NoBinaryOpenError: "target_unavailable",
|
|
EvidenceIntegrityError: "evidence_integrity_mismatch",
|
|
ProviderAdapterError: "execution_failure",
|
|
HopperRemoteError: "execution_failure",
|
|
} as const satisfies Readonly<
|
|
Record<
|
|
Exclude<AnalysisErrorTag, SpecializedErrorTag>,
|
|
AnalysisErrorProjection["code"]
|
|
>
|
|
>;
|
|
|
|
const staticErrorCode = (
|
|
tag: AnalysisErrorTag,
|
|
): AnalysisErrorProjection["code"] => {
|
|
switch (tag) {
|
|
case "ArtifactOperationError":
|
|
case "BinaryTargetError":
|
|
case "BrowserObservationError":
|
|
case "EvidenceFileError":
|
|
case "ProcessCaptureError":
|
|
case "ProviderSelectionError":
|
|
case "UnknownRegistryError":
|
|
throw new TypeError(`Unhandled specialized analysis error: ${tag}`);
|
|
default:
|
|
return STATIC_ERROR_CODES[tag];
|
|
}
|
|
};
|
|
|
|
const errorDetails = (
|
|
error: AnalysisError,
|
|
): Readonly<Record<string, JsonValue>> | undefined =>
|
|
requestErrorDetails(error) ??
|
|
artifactStateErrorDetails(error) ??
|
|
providerErrorDetails(error) ??
|
|
lifecycleErrorDetails(error);
|
|
|
|
const requestErrorDetails = (
|
|
error: AnalysisError,
|
|
): Readonly<Record<string, JsonValue>> | undefined => {
|
|
if (error instanceof AnalysisUnsupportedTargetError)
|
|
return {
|
|
operation: error.operation,
|
|
path: error.path,
|
|
reason: error.reason,
|
|
};
|
|
if (error instanceof AnalysisResourceConstraintError)
|
|
return {
|
|
operation: error.operation,
|
|
resource: error.resource,
|
|
reason: error.reason,
|
|
reported_limits: error.reportedLimits,
|
|
};
|
|
if (error instanceof AnalysisArtifactChangedError)
|
|
return {
|
|
operation: error.operation,
|
|
path: error.path,
|
|
reason: error.reason,
|
|
boundary: "stable-artifact-read",
|
|
};
|
|
if (error instanceof AnalysisAccessDeniedError)
|
|
return {
|
|
operation: error.operation,
|
|
path: error.path,
|
|
system_code: error.systemCode,
|
|
boundary: "filesystem-read",
|
|
};
|
|
if (error instanceof AnalysisOutputError)
|
|
return {
|
|
operation: error.operation,
|
|
reason: error.reason,
|
|
...(error.diagnostics === undefined
|
|
? {}
|
|
: { diagnostics: error.diagnostics }),
|
|
};
|
|
if (error instanceof AnalysisInputError && error.issues.length > 0)
|
|
return {
|
|
operation: error.operation,
|
|
issues: error.issues.map((issue) => ({
|
|
path: [...issue.path],
|
|
reason: issue.reason,
|
|
...(issue.message === undefined ? {} : { message: issue.message }),
|
|
...(issue.expected === undefined ? {} : { expected: issue.expected }),
|
|
...(issue.minimum === undefined ? {} : { minimum: issue.minimum }),
|
|
...(issue.maximum === undefined ? {} : { maximum: issue.maximum }),
|
|
})),
|
|
};
|
|
if (error instanceof EvidenceReferenceError)
|
|
return {
|
|
evidence_id: error.evidenceId,
|
|
reason: error.reason,
|
|
expected: error.expected,
|
|
actual: error.actual,
|
|
};
|
|
if (error instanceof EvidenceIntegrityError) return { reason: error.message };
|
|
return undefined;
|
|
};
|
|
|
|
const artifactStateErrorDetails = (
|
|
error: AnalysisError,
|
|
): Readonly<Record<string, JsonValue>> | undefined => {
|
|
if (error instanceof ArtifactOperationError && error.artifactDetails)
|
|
return projectArtifactIntegrityDetails(error.artifactDetails);
|
|
if (error instanceof ArtifactOperationError)
|
|
return {
|
|
operation: error.operation,
|
|
reason: error.reason,
|
|
...(error.reason === "limit" ? { truncated: true } : {}),
|
|
...(error.detail === undefined ? {} : { detail: error.detail }),
|
|
};
|
|
if (error instanceof UnknownRegistryError) return { reason: error.reason };
|
|
if (error instanceof EvidenceFileError)
|
|
return {
|
|
operation: error.operation,
|
|
reason: error.reason,
|
|
...(error.path === undefined ? {} : { path: error.path }),
|
|
...(error.published === undefined
|
|
? {}
|
|
: {
|
|
published: true,
|
|
bytes: error.published.bytes,
|
|
published_path: error.published.path,
|
|
}),
|
|
};
|
|
return undefined;
|
|
};
|
|
|
|
const providerErrorDetails = (
|
|
error: AnalysisError,
|
|
): Readonly<Record<string, JsonValue>> | undefined => {
|
|
if (error instanceof AnalysisCapabilityUnavailableError)
|
|
return {
|
|
provider_id: error.providerId,
|
|
operation: error.operation,
|
|
reason: error.reason,
|
|
};
|
|
if (error instanceof ProviderSelectionError)
|
|
return {
|
|
operation: error.operation,
|
|
selection_reason: error.reason,
|
|
requested_provider_id: error.requestedProviderId,
|
|
candidate_ids: [...error.candidateIds],
|
|
rejections: error.rejections.map((rejection) => ({
|
|
provider_id: rejection.providerId,
|
|
code: rejection.code,
|
|
reason: rejection.reason,
|
|
diagnostics: rejection.diagnostics,
|
|
})),
|
|
};
|
|
if (error instanceof ProviderAdapterError)
|
|
return {
|
|
provider_id: error.providerId,
|
|
operation: error.operation,
|
|
...(error.cleanupIncomplete
|
|
? {
|
|
cleanup: "incomplete",
|
|
resources: [...error.cleanupResources],
|
|
}
|
|
: {}),
|
|
};
|
|
if (error instanceof BrowserObservationError) {
|
|
const primaryReason = primaryBrowserFailureReason(error);
|
|
return {
|
|
operation: error.operation,
|
|
reason: error.reason,
|
|
...(error.cleanupIncomplete
|
|
? {
|
|
cleanup: "incomplete",
|
|
resources: [...error.cleanupResources],
|
|
...(primaryReason === undefined
|
|
? {}
|
|
: { primary_reason: primaryReason }),
|
|
}
|
|
: {}),
|
|
};
|
|
}
|
|
if (error instanceof HopperRemoteError)
|
|
return {
|
|
stage: "analysis",
|
|
provider_code: error.code,
|
|
diagnostic_type: error.diagnosticType,
|
|
...(error.operation === undefined ? {} : { operation: error.operation }),
|
|
...(error.requestId === undefined ? {} : { request_id: error.requestId }),
|
|
};
|
|
if (error instanceof HopperProcessError) {
|
|
const stage = error.stage;
|
|
return {
|
|
exit_code: error.exitCode,
|
|
stage,
|
|
provider_state: error.providerState,
|
|
retry_action: providerRetryAction(
|
|
error.providerState,
|
|
error.failureCode !== undefined || error.stage === "launch",
|
|
),
|
|
...(error.failureCode === undefined
|
|
? {}
|
|
: { failure_code: error.failureCode }),
|
|
...(error.operation === undefined ? {} : { operation: error.operation }),
|
|
...(error.requestId === undefined ? {} : { request_id: error.requestId }),
|
|
...(error.diagnostic === undefined
|
|
? {}
|
|
: { diagnostics: { ...error.diagnostic } }),
|
|
...(error.launcherFailure === undefined
|
|
? {}
|
|
: { launcher: error.launcherFailure }),
|
|
};
|
|
}
|
|
if (error instanceof HopperStartError)
|
|
return {
|
|
stage: "launch",
|
|
provider_state: "unknown",
|
|
...(error.launchRejection === undefined
|
|
? {}
|
|
: { launch_rejection: { ...error.launchRejection } }),
|
|
retry_action: error.ownerRunId === undefined ? "retry" : "unknown",
|
|
...(error.ownerRunId === undefined
|
|
? {}
|
|
: { owner_run_id: error.ownerRunId }),
|
|
...(error.launcherFailure === undefined
|
|
? {}
|
|
: { launcher: error.launcherFailure }),
|
|
};
|
|
return undefined;
|
|
};
|
|
|
|
const primaryBrowserFailureReason = (
|
|
error: BrowserObservationError,
|
|
): string | undefined => {
|
|
const aggregate = error.cause instanceof AggregateError;
|
|
const primary =
|
|
error.cause instanceof AggregateError ? error.cause.errors[0] : error.cause;
|
|
if (primary instanceof BrowserObservationError) return primary.reason;
|
|
if (primary instanceof AnalysisCancelledError) return "cancelled";
|
|
if (primary instanceof AnalysisTimeoutError) return "timeout";
|
|
if (typeof primary === "object" && primary !== null && "_tag" in primary)
|
|
return typeof primary._tag === "string"
|
|
? primary._tag
|
|
: "execution_failure";
|
|
return aggregate ? "execution_failure" : undefined;
|
|
};
|
|
|
|
const lifecycleErrorDetails = (
|
|
error: AnalysisError,
|
|
): Readonly<Record<string, JsonValue>> | undefined => {
|
|
if (error instanceof AnalysisCancelledError)
|
|
return {
|
|
operation: error.operation,
|
|
cleanup: error.cleanupIncomplete ? "incomplete" : "complete",
|
|
...(error.cleanup === undefined || !error.cleanupIncomplete
|
|
? {}
|
|
: {
|
|
cleanup_reason: error.cleanup.reason,
|
|
resources: [...error.cleanup.resources],
|
|
execution_failure: "cancelled",
|
|
}),
|
|
};
|
|
if (error instanceof HopperCancelledError)
|
|
return { operation: "hopper", cleanup: "complete" };
|
|
if (error instanceof AnalysisTimeoutError)
|
|
return {
|
|
operation: error.operation,
|
|
timeout_ms: error.timeoutMs,
|
|
...(error.cleanup === undefined || !error.cleanupIncomplete
|
|
? {}
|
|
: {
|
|
cleanup: "incomplete",
|
|
cleanup_reason: error.cleanup.reason,
|
|
resources: [...error.cleanup.resources],
|
|
}),
|
|
};
|
|
if (error instanceof HopperTimeoutError)
|
|
return {
|
|
stage: error.operation === undefined ? "startup" : error.stage,
|
|
timeout_ms: error.timeoutMs,
|
|
...(error.launcherOutcome === undefined
|
|
? {}
|
|
: { launcher: error.launcherOutcome }),
|
|
provider_state: error.providerState,
|
|
retry_action: error.providerState === "busy" ? "wait" : "retry",
|
|
...(error.operation === undefined ? {} : { operation: error.operation }),
|
|
...(error.requestId === undefined ? {} : { request_id: error.requestId }),
|
|
};
|
|
if (error._tag === "ProcessCaptureError" && error.cleanupIncomplete)
|
|
return {
|
|
cleanup: "incomplete",
|
|
resources: [...error.cleanupResources],
|
|
...(error.cleanupReport === undefined
|
|
? {}
|
|
: { cleanup_report: jsonValueSchema.parse(error.cleanupReport) }),
|
|
...(error.executionFailure === undefined
|
|
? {}
|
|
: { execution_failure: error.executionFailure }),
|
|
};
|
|
if (error._tag === "ProcessCaptureError") {
|
|
const details = {
|
|
...(error.userCategory === "cancelled"
|
|
? { operation: "process_capture", cleanup: "complete" }
|
|
: {}),
|
|
...(error.cleanupReport === undefined
|
|
? {}
|
|
: { cleanup_report: jsonValueSchema.parse(error.cleanupReport) }),
|
|
...(error.executionFailure === undefined
|
|
? {}
|
|
: { execution_failure: error.executionFailure }),
|
|
};
|
|
return Object.keys(details).length === 0 ? undefined : details;
|
|
}
|
|
if (error instanceof ConfigurationError && error.settings.length > 0)
|
|
return {
|
|
settings: error.settings.map(({ setting, constraint }) => ({
|
|
setting,
|
|
constraint,
|
|
})),
|
|
};
|
|
if (error instanceof BinaryTargetError)
|
|
return {
|
|
path: error.path,
|
|
reason: error.reason,
|
|
...(error.constraint === undefined
|
|
? {}
|
|
: { constraint: error.constraint }),
|
|
...(error.systemCode === undefined
|
|
? {}
|
|
: { system_code: error.systemCode, boundary: "filesystem-read" }),
|
|
};
|
|
return undefined;
|
|
};
|
|
|
|
const RETRYABLE_CODES: ReadonlySet<AnalysisErrorProjection["code"]> = new Set([
|
|
"artifact_changed",
|
|
"invalid_request",
|
|
"provider_timeout",
|
|
"cancelled",
|
|
"revision_conflict",
|
|
"provider_unavailable",
|
|
]);
|
|
|
|
export interface AnalysisErrorProjection extends Readonly<
|
|
Record<string, JsonValue>
|
|
> {
|
|
readonly code:
|
|
| "invalid_request"
|
|
| "access_denied"
|
|
| "artifact_changed"
|
|
| "unreadable_output"
|
|
| "capability_unavailable"
|
|
| "unsupported_target"
|
|
| "provider_unavailable"
|
|
| "provider_timeout"
|
|
| "resource_constraint"
|
|
| "cancelled"
|
|
| "artifact_integrity_mismatch"
|
|
| "artifact_operation_failed"
|
|
| "evidence_integrity_mismatch"
|
|
| "truncated"
|
|
| "process_capture_failed"
|
|
| "cleanup_incomplete"
|
|
| "revision_conflict"
|
|
| "configuration_invalid"
|
|
| "target_unavailable"
|
|
| "execution_failure";
|
|
readonly category:
|
|
| "invalid_input"
|
|
| "unsupported_provider"
|
|
| "unsupported_target"
|
|
| "integrity_mismatch"
|
|
| "truncated"
|
|
| "cancelled"
|
|
| "timeout"
|
|
| "resource_constraint"
|
|
| "unavailable"
|
|
| "execution_failure";
|
|
readonly message: string;
|
|
readonly retryable: boolean;
|
|
readonly remediation: Readonly<{
|
|
action: string;
|
|
}>;
|
|
readonly details?: Readonly<Record<string, JsonValue>>;
|
|
}
|