fix(evidence): retain owner finalization reports across cleanup envelopes
This commit is contained in:
1 parent
c2cc81927a
commit
640a0cf423
3 files changed
+54
-3
No files matched your search
+3
-1
@@ -195,7 +195,9 @@ providers need not expose identical state machines.
|
||||
owner's recovery instructions. While cleanup remains unconfirmed, canonical
|
||||
errors keep `cleanup_incomplete` and live resources while taking category,
|
||||
operation and failure details from the retained typed primary. Nested cleanup
|
||||
composition does not replace that semantic identity. CLI adapters should reuse
|
||||
composition does not replace that semantic identity. Finalization reports
|
||||
remain attached to their owning envelope while cleanup is pending and after
|
||||
confirmed release. CLI adapters should reuse
|
||||
[`finishAnalysisCommand`](https://github.com/morluto/rea/blob/main/src/cli/finishAnalysisCommand.ts) where its contract
|
||||
applies rather than duplicate close/finally handling.
|
||||
- Give descriptor-backed reads an owner before opening the file. A rejected
|
||||
|
||||
@@ -318,3 +318,43 @@ it("retains an observation attached to the composite after the primary failed",
|
||||
details: { partial_observation: observation },
|
||||
});
|
||||
});
|
||||
|
||||
it("retains an owner's finalization report independently of pending primary semantics", () => {
|
||||
const report = {
|
||||
owned_process_group: { state: "not_required" as const, reason: null },
|
||||
terminal_renderer: { state: "not_required" as const, reason: null },
|
||||
temporary_root: { state: "cleaned" as const, reason: null },
|
||||
};
|
||||
class ReportedCleanup extends ProviderCleanupError {
|
||||
override readonly cleanupReport = report;
|
||||
}
|
||||
const primary = new AnalysisInputError("inspect");
|
||||
const finalized = new ReportedCleanup(
|
||||
"fixture",
|
||||
["input"],
|
||||
{},
|
||||
{
|
||||
cleanupPrimary: primary,
|
||||
},
|
||||
);
|
||||
const later = new ProviderCleanupError("fixture", ["workspace"], {});
|
||||
const outer = analysisErrorWithCleanupFailure(
|
||||
finalized,
|
||||
later,
|
||||
).bindCleanupDependencies([finalized, later]);
|
||||
const assertReport = (error: typeof outer) => {
|
||||
expect(projectAnalysisError(error)).toMatchObject({
|
||||
category: "invalid_input",
|
||||
details: { operation: "inspect", cleanup_report: report },
|
||||
});
|
||||
};
|
||||
assertReport(finalized);
|
||||
assertReport(outer);
|
||||
expect(outer.cleanupIncomplete).toBe(true);
|
||||
later.resolveCleanup();
|
||||
assertReport(outer);
|
||||
expect(outer.cleanupIncomplete).toBe(true);
|
||||
finalized.resolveCleanup();
|
||||
assertReport(outer);
|
||||
expect(outer.cleanupIncomplete).toBe(false);
|
||||
});
|
||||
@@ -75,6 +75,15 @@ const projectError = (
|
||||
const capturedOutput = composed.capturedOutput ?? error.capturedOutput;
|
||||
const partialObservation =
|
||||
composed.partialObservation ?? error.partialObservation;
|
||||
// A finalizer can add a report above the semantic primary, including while
|
||||
// its cleanup is pending or beneath another cleanup composition.
|
||||
let cleanupReport = composed.cleanupReport;
|
||||
for (
|
||||
let owner = composed.cleanupPrimary;
|
||||
cleanupReport === undefined && owner !== undefined;
|
||||
owner = owner.cleanupPrimary
|
||||
)
|
||||
cleanupReport = owner.cleanupReport;
|
||||
assertKnownAnalysisErrorTag(error._tag);
|
||||
const primary = primaryAnalysisError(error);
|
||||
assertKnownAnalysisErrorTag(primary._tag);
|
||||
@@ -83,9 +92,9 @@ const projectError = (
|
||||
const primaryDetails = errorDetails(primary);
|
||||
const details = {
|
||||
...primaryDetails,
|
||||
...(composed === error || composed.cleanupReport === undefined
|
||||
...(cleanupReport === undefined
|
||||
? {}
|
||||
: { cleanup_report: jsonValueSchema.parse(composed.cleanupReport) }),
|
||||
: { cleanup_report: jsonValueSchema.parse(cleanupReport) }),
|
||||
...(diagnostics === undefined
|
||||
? {}
|
||||
: {
|
||||
|
||||
Reference in new issue
Block a user