mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
d0253c99d6
Replace configuration-specific write-file-atomic delegation with a verified input snapshot, exclusive private staging, and an explicit canonical-parent destination. Existing files publish by rename; first-run files use an exclusive link so a newly created destination is retained. Both consumers read back the publication owner's selected path. Retain descriptor and staging cleanup capabilities through recovery and host retry. Preserve mode and ownership, remove temporary permission handoffs, and use positional restoration writes. Keep UTF-8 diagnostics with failed cleanup. Validation: 284 focused tests passed, one skipped across 14 files; check:fast, format:check, docs:check (including five consistency tests), two source reviews, and 12 completed isolated public CLI setup/uninstall cost controls passed. Native Windows/Linux, real editor concurrency, and providers were not verified. Final-check/publication races and same-inode concurrent writers remain unexcluded. Fixes #4904
114 lines
3.8 KiB
TypeScript
114 lines
3.8 KiB
TypeScript
import {
|
|
ArtifactResourceRetryFailure,
|
|
type ArtifactResourceOwner,
|
|
type ArtifactResourceScope,
|
|
} from "../artifacts/ArtifactResourceScope.js";
|
|
import type { AnalysisCleanupLease } from "../artifacts/AnalysisCleanupLease.js";
|
|
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
|
import type { AnalysisCleanupObservation } from "../domain/analysisErrorBase.js";
|
|
import type { RegularFileOperationOutcome } from "../filesystem/OwnedRegularFile.js";
|
|
import {
|
|
RegularFileCleanupFailure,
|
|
retryRegularFileCleanupFailures,
|
|
} from "./RegularFileRead.js";
|
|
|
|
/** Completion and exact staging owner retained when publication cleanup fails. */
|
|
export class ClientConfigurationPublicationFailure<
|
|
Value = unknown,
|
|
> extends ArtifactResourceRetryFailure {
|
|
constructor(
|
|
readonly path: string,
|
|
readonly outcome: RegularFileOperationOutcome<Value>,
|
|
readonly cleanupCause: unknown,
|
|
readonly owner: Extract<
|
|
ArtifactResourceOwner,
|
|
{ readonly kind: "staged-output" }
|
|
>,
|
|
readonly cleanupLease: AnalysisCleanupLease,
|
|
) {
|
|
super(
|
|
[{ owner, lease: cleanupLease }],
|
|
"Configuration publication cleanup remains incomplete",
|
|
{
|
|
cause: new AggregateError(
|
|
[...(outcome.kind === "failed" ? [outcome.cause] : []), cleanupCause],
|
|
"Configuration operation and staging cleanup failures",
|
|
),
|
|
cleanup: ArtifactReaderFailure.cleanupObservation(
|
|
cleanupCause,
|
|
owner.resource,
|
|
),
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
type ClientConfigurationCleanupFailure =
|
|
| RegularFileCleanupFailure
|
|
| ClientConfigurationPublicationFailure;
|
|
|
|
export const isClientConfigurationCleanupFailure = (
|
|
cause: unknown,
|
|
): cause is ClientConfigurationCleanupFailure =>
|
|
cause instanceof RegularFileCleanupFailure ||
|
|
cause instanceof ClientConfigurationPublicationFailure;
|
|
|
|
/** Adopt only capabilities carried by explicit operation outcomes, never opaque causes. */
|
|
export const retryClientConfigurationCleanup = async (
|
|
failure: ClientConfigurationCleanupFailure,
|
|
resources: ArtifactResourceScope,
|
|
): Promise<{
|
|
readonly primary: unknown;
|
|
readonly failures: readonly RegularFileCleanupFailure[];
|
|
readonly cleanup?: AnalysisCleanupObservation;
|
|
}> => {
|
|
const failures: RegularFileCleanupFailure[] = [];
|
|
const observations: AnalysisCleanupObservation[] = [];
|
|
let current = failure;
|
|
let primary: unknown;
|
|
for (;;) {
|
|
let nested: unknown;
|
|
if (current instanceof RegularFileCleanupFailure) {
|
|
const retried = await retryRegularFileCleanupFailures(current, resources);
|
|
failures.push(...retried.failures);
|
|
if (retried.cleanup !== undefined) observations.push(retried.cleanup);
|
|
primary = retried.primary;
|
|
const last = retried.failures.at(-1)!;
|
|
nested = last.outcome.kind === "failed" ? last.outcome.cause : undefined;
|
|
} else {
|
|
const released = await resources.release({
|
|
kind: "lease",
|
|
resource: current.owner.resource,
|
|
lease: current.cleanupLease,
|
|
});
|
|
if (released.kind === "failed")
|
|
observations.push(
|
|
ArtifactReaderFailure.cleanupObservation(
|
|
released.cause,
|
|
current.owner.resource,
|
|
),
|
|
);
|
|
primary =
|
|
current.outcome.kind === "failed"
|
|
? current.outcome.cause
|
|
: current.cleanupCause;
|
|
nested =
|
|
current.outcome.kind === "failed" ? current.outcome.cause : undefined;
|
|
}
|
|
if (!isClientConfigurationCleanupFailure(nested)) break;
|
|
current = nested;
|
|
}
|
|
return {
|
|
primary,
|
|
failures,
|
|
...(observations.length === 0
|
|
? {}
|
|
: {
|
|
cleanup: {
|
|
reason: observations.map(({ reason }) => reason).join("; "),
|
|
resources: observations.flatMap(({ resources }) => resources),
|
|
},
|
|
}),
|
|
};
|
|
};
|