mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
refactor(javascript): unify application workflow ownership
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import {
|
||||
resolveEvidenceInput,
|
||||
type EvidenceLookup,
|
||||
} from "../EvidenceInputResolver.js";
|
||||
import { retainedEvidenceReferenceSchema } from "../../domain/evidenceReference.js";
|
||||
import type { ResolvedSourceToBundleReference } from "./SourceToBundleReference.js";
|
||||
import { z } from "zod";
|
||||
|
||||
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
|
||||
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import type { Evidence } from "../../domain/evidence.js";
|
||||
import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js";
|
||||
@@ -9,20 +13,26 @@ import { compareJavaScriptApplicationVersions } from "../../domain/javascript/ja
|
||||
import {
|
||||
compareApplicationVersionsInputSchema,
|
||||
applicationVersionIdentitiesSchema,
|
||||
type ApplicationVersionComparisonResult,
|
||||
} from "../../domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
|
||||
import { compareJavaScriptExportShapes } from "../../domain/javascript/javascriptExportShapeComparison.js";
|
||||
import {
|
||||
compareJavaScriptExportShapesInputSchema,
|
||||
javaScriptExportShapeIdentitiesSchema,
|
||||
type JavaScriptExportShapeComparisonResult,
|
||||
} from "../../domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { traceApplicationFeature } from "../../domain/javascript/javascriptFeatureTrace.js";
|
||||
import {
|
||||
traceApplicationFeatureInputSchema,
|
||||
applicationTraceIdentitiesSchema,
|
||||
type ApplicationFeatureTraceResult,
|
||||
} from "../../domain/javascript/javascriptFeatureTraceSchemas.js";
|
||||
import { err, ok, type Result } from "../../domain/result.js";
|
||||
import { compareSourceToBundle } from "../../domain/javascript/sourceToBundleComparison.js";
|
||||
import { compareSourceToBundleInputSchema } from "../../domain/javascript/sourceToBundleComparisonSchemas.js";
|
||||
import {
|
||||
compareSourceToBundleInputSchema,
|
||||
type SourceToBundleComparisonResult,
|
||||
} from "../../domain/javascript/sourceToBundleComparisonSchemas.js";
|
||||
import {
|
||||
applicationGraphEvidenceInputError,
|
||||
parseApplicationGraphEvidence,
|
||||
@@ -35,29 +45,61 @@ import {
|
||||
createSourceToBundleComparisonEvidence,
|
||||
} from "./JavaScriptApplicationWorkflowEvidence.js";
|
||||
|
||||
/** Completed workflow facts and authenticated sources retained for adapter delivery. */
|
||||
export interface ApplicationWorkflowExecution<Projection> {
|
||||
readonly evidence: Evidence;
|
||||
readonly result: Projection;
|
||||
readonly sources: readonly Evidence[];
|
||||
}
|
||||
|
||||
// Validate the request frame without cloning source payloads before their owner reads them.
|
||||
const featureTraceFrameSchema = z.strictObject({
|
||||
...traceApplicationFeatureInputSchema.shape,
|
||||
application: z.unknown().nonoptional(),
|
||||
native_observations: z.array(z.unknown()).default([]),
|
||||
});
|
||||
const versionComparisonFrameSchema = z.strictObject({
|
||||
...compareApplicationVersionsInputSchema.shape,
|
||||
left: z.unknown().nonoptional(),
|
||||
right: z.unknown().nonoptional(),
|
||||
left_native_observations: z.array(z.unknown()).default([]),
|
||||
right_native_observations: z.array(z.unknown()).default([]),
|
||||
});
|
||||
const exportShapeFrameSchema = z.strictObject({
|
||||
...compareJavaScriptExportShapesInputSchema.shape,
|
||||
left: z.unknown().nonoptional(),
|
||||
right: z.unknown().nonoptional(),
|
||||
});
|
||||
|
||||
const resolveWorkflowEvidence = (
|
||||
raw: unknown,
|
||||
lookup: EvidenceLookup | undefined,
|
||||
): Result<unknown, AnalysisError> => {
|
||||
const reference = retainedEvidenceReferenceSchema.safeParse(raw);
|
||||
return reference.success
|
||||
? resolveEvidenceInput(reference.data, lookup)
|
||||
: ok(raw);
|
||||
};
|
||||
|
||||
/** Authenticate Evidence and derive one bounded cross-layer feature trace. */
|
||||
export const traceApplicationFeatureEvidence = (
|
||||
rawInput: unknown,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
lookup?: EvidenceLookup,
|
||||
): Result<
|
||||
ApplicationWorkflowExecution<ApplicationFeatureTraceResult>,
|
||||
AnalysisError
|
||||
> => {
|
||||
const operation = "trace_application_feature";
|
||||
const parsed = traceApplicationFeatureInputSchema.safeParse(rawInput);
|
||||
if (!parsed.success)
|
||||
const request = featureTraceFrameSchema.safeParse(rawInput);
|
||||
if (!request.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, parsed.error.issues, rawInput),
|
||||
);
|
||||
return traceApplicationFeatureEvidenceValidated(parsed.data);
|
||||
};
|
||||
|
||||
/** Derive one feature trace from input parsed by a trusted adapter. */
|
||||
export const traceApplicationFeatureEvidenceValidated = (
|
||||
input: z.output<typeof traceApplicationFeatureInputSchema>,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
const operation = "trace_application_feature";
|
||||
const identities = applicationTraceIdentitiesSchema.safeParse(input);
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
analysisInputErrorFromIssues(operation, request.error.issues, rawInput, {
|
||||
cause: request.error,
|
||||
}),
|
||||
);
|
||||
const selected = resolveWorkflowEvidence(request.data.application, lookup);
|
||||
if (!selected.ok) return selected;
|
||||
const input = { ...request.data, application: selected.value };
|
||||
const sourceResult = parseApplicationGraphEvidence(input.application, [
|
||||
"application",
|
||||
]);
|
||||
@@ -73,55 +115,63 @@ export const traceApplicationFeatureEvidenceValidated = (
|
||||
return err(
|
||||
applicationGraphEvidenceInputError(operation, nativeResult.error),
|
||||
);
|
||||
try {
|
||||
const source = sourceResult.value;
|
||||
const nativeEvidence = nativeResult.value;
|
||||
const result = traceApplicationFeature({
|
||||
sourceEvidenceId: source.evidence.evidence_id,
|
||||
graph: source.graph,
|
||||
nativeEvidence,
|
||||
const source = sourceResult.value;
|
||||
const nativeEvidence = nativeResult.value;
|
||||
const identities = applicationTraceIdentitiesSchema.safeParse({
|
||||
native_observations: nativeEvidence,
|
||||
});
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
);
|
||||
const result = traceApplicationFeature({
|
||||
sourceEvidenceId: source.evidence.evidence_id,
|
||||
graph: source.graph,
|
||||
nativeEvidence,
|
||||
seed: input.seed,
|
||||
direction: input.direction,
|
||||
});
|
||||
const evidence = createApplicationFeatureTraceEvidence(
|
||||
{
|
||||
application_evidence_id: source.evidence.evidence_id,
|
||||
native_evidence_ids: nativeEvidence.map(({ evidence_id: id }) => id),
|
||||
seed: input.seed,
|
||||
direction: input.direction,
|
||||
});
|
||||
return ok(
|
||||
createApplicationFeatureTraceEvidence(
|
||||
{
|
||||
application_evidence_id: source.evidence.evidence_id,
|
||||
native_evidence_ids: nativeEvidence.map(({ evidence_id: id }) => id),
|
||||
seed: input.seed,
|
||||
direction: input.direction,
|
||||
},
|
||||
result,
|
||||
),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
return workflowFailure(operation, cause);
|
||||
}
|
||||
},
|
||||
result,
|
||||
);
|
||||
return ok({
|
||||
evidence,
|
||||
result,
|
||||
sources: [source.evidence, ...nativeEvidence],
|
||||
});
|
||||
};
|
||||
|
||||
/** Authenticate both graphs and derive a tiered cross-version change graph. */
|
||||
export const compareApplicationVersionsEvidence = (
|
||||
rawInput: unknown,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
lookup?: EvidenceLookup,
|
||||
): Result<
|
||||
ApplicationWorkflowExecution<ApplicationVersionComparisonResult>,
|
||||
AnalysisError
|
||||
> => {
|
||||
const operation = "compare_application_versions";
|
||||
const parsed = compareApplicationVersionsInputSchema.safeParse(rawInput);
|
||||
if (!parsed.success)
|
||||
const request = versionComparisonFrameSchema.safeParse(rawInput);
|
||||
if (!request.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, parsed.error.issues, rawInput),
|
||||
);
|
||||
return compareApplicationVersionsEvidenceValidated(parsed.data);
|
||||
};
|
||||
|
||||
/** Compare versions from input parsed by a trusted adapter. */
|
||||
export const compareApplicationVersionsEvidenceValidated = (
|
||||
input: z.output<typeof compareApplicationVersionsInputSchema>,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
const operation = "compare_application_versions";
|
||||
const identities = applicationVersionIdentitiesSchema.safeParse(input);
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
analysisInputErrorFromIssues(operation, request.error.issues, rawInput, {
|
||||
cause: request.error,
|
||||
}),
|
||||
);
|
||||
const selectedLeft = resolveWorkflowEvidence(request.data.left, lookup);
|
||||
if (!selectedLeft.ok) return selectedLeft;
|
||||
const selectedRight = resolveWorkflowEvidence(request.data.right, lookup);
|
||||
if (!selectedRight.ok) return selectedRight;
|
||||
const input = {
|
||||
...request.data,
|
||||
left: selectedLeft.value,
|
||||
right: selectedRight.value,
|
||||
};
|
||||
const leftResult = parseApplicationGraphEvidence(input.left, ["left"]);
|
||||
if (!leftResult.ok)
|
||||
return err(applicationGraphEvidenceInputError(operation, leftResult.error));
|
||||
@@ -146,48 +196,58 @@ export const compareApplicationVersionsEvidenceValidated = (
|
||||
return err(
|
||||
applicationGraphEvidenceInputError(operation, rightNativeResult.error),
|
||||
);
|
||||
try {
|
||||
const left = leftResult.value;
|
||||
const right = rightResult.value;
|
||||
const leftNative = leftNativeResult.value;
|
||||
const rightNative = rightNativeResult.value;
|
||||
const result = compareJavaScriptApplicationVersions({
|
||||
left: {
|
||||
evidenceId: left.evidence.evidence_id,
|
||||
rootArtifactSha256: left.rootArtifactSha256,
|
||||
graph: left.graph,
|
||||
},
|
||||
right: {
|
||||
evidenceId: right.evidence.evidence_id,
|
||||
rootArtifactSha256: right.rootArtifactSha256,
|
||||
graph: right.graph,
|
||||
},
|
||||
leftNativeEvidence: leftNative,
|
||||
rightNativeEvidence: rightNative,
|
||||
});
|
||||
return ok(
|
||||
createApplicationVersionComparisonEvidence(
|
||||
{
|
||||
left_evidence_id: left.evidence.evidence_id,
|
||||
right_evidence_id: right.evidence.evidence_id,
|
||||
left_native_evidence_ids: leftNative.map(({ evidence_id: id }) => id),
|
||||
right_native_evidence_ids: rightNative.map(
|
||||
({ evidence_id: id }) => id,
|
||||
),
|
||||
},
|
||||
result,
|
||||
),
|
||||
const left = leftResult.value;
|
||||
const right = rightResult.value;
|
||||
const leftNative = leftNativeResult.value;
|
||||
const rightNative = rightNativeResult.value;
|
||||
const identities = applicationVersionIdentitiesSchema.safeParse({
|
||||
left: left.evidence,
|
||||
right: right.evidence,
|
||||
left_native_observations: leftNative,
|
||||
right_native_observations: rightNative,
|
||||
});
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
return workflowFailure(operation, cause);
|
||||
}
|
||||
const result = compareJavaScriptApplicationVersions({
|
||||
left: {
|
||||
evidenceId: left.evidence.evidence_id,
|
||||
rootArtifactSha256: left.rootArtifactSha256,
|
||||
graph: left.graph,
|
||||
},
|
||||
right: {
|
||||
evidenceId: right.evidence.evidence_id,
|
||||
rootArtifactSha256: right.rootArtifactSha256,
|
||||
graph: right.graph,
|
||||
},
|
||||
leftNativeEvidence: leftNative,
|
||||
rightNativeEvidence: rightNative,
|
||||
});
|
||||
const evidence = createApplicationVersionComparisonEvidence(
|
||||
{
|
||||
left_evidence_id: left.evidence.evidence_id,
|
||||
right_evidence_id: right.evidence.evidence_id,
|
||||
left_native_evidence_ids: leftNative.map(({ evidence_id: id }) => id),
|
||||
right_native_evidence_ids: rightNative.map(({ evidence_id: id }) => id),
|
||||
},
|
||||
result,
|
||||
);
|
||||
return ok({
|
||||
evidence,
|
||||
result,
|
||||
sources: [left.evidence, right.evidence, ...leftNative, ...rightNative],
|
||||
});
|
||||
};
|
||||
|
||||
/** Compare source and bundle inputs already parsed by a trusted adapter. */
|
||||
export const compareSourceToBundleEvidenceValidated = (
|
||||
export const compareSourceToBundleEvidence = (
|
||||
input: ResolvedSourceToBundleReference &
|
||||
Pick<z.output<typeof compareSourceToBundleInputSchema>, "application">,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
): Result<
|
||||
ApplicationWorkflowExecution<SourceToBundleComparisonResult>,
|
||||
AnalysisError
|
||||
> => {
|
||||
const operation = "compare_source_to_bundle";
|
||||
const applicationResult = parseApplicationGraphEvidence(input.application, [
|
||||
"application",
|
||||
@@ -196,31 +256,26 @@ export const compareSourceToBundleEvidenceValidated = (
|
||||
return err(
|
||||
applicationGraphEvidenceInputError(operation, applicationResult.error),
|
||||
);
|
||||
try {
|
||||
const application = applicationResult.value;
|
||||
const result = compareSourceToBundle({
|
||||
reference: input.reference,
|
||||
application: {
|
||||
evidenceId: application.evidence.evidence_id,
|
||||
rootArtifactSha256: application.rootArtifactSha256,
|
||||
graph: application.graph,
|
||||
},
|
||||
});
|
||||
return ok(
|
||||
createSourceToBundleComparisonEvidence(
|
||||
{
|
||||
reference_root_sha256: input.reference.root_sha256,
|
||||
application_evidence_id: application.evidence.evidence_id,
|
||||
...(input.reference_source === undefined
|
||||
? {}
|
||||
: { reference_source: input.reference_source }),
|
||||
},
|
||||
result,
|
||||
),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
return workflowFailure(operation, cause);
|
||||
}
|
||||
const application = applicationResult.value;
|
||||
const result = compareSourceToBundle({
|
||||
reference: input.reference,
|
||||
application: {
|
||||
evidenceId: application.evidence.evidence_id,
|
||||
rootArtifactSha256: application.rootArtifactSha256,
|
||||
graph: application.graph,
|
||||
},
|
||||
});
|
||||
const evidence = createSourceToBundleComparisonEvidence(
|
||||
{
|
||||
reference_root_sha256: input.reference.root_sha256,
|
||||
application_evidence_id: application.evidence.evidence_id,
|
||||
...(input.reference_source === undefined
|
||||
? {}
|
||||
: { reference_source: input.reference_source }),
|
||||
},
|
||||
result,
|
||||
);
|
||||
return ok({ evidence, result, sources: [application.evidence] });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -229,26 +284,28 @@ export const compareSourceToBundleEvidenceValidated = (
|
||||
*/
|
||||
export const compareJavaScriptExportShapesEvidence = (
|
||||
rawInput: unknown,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
lookup?: EvidenceLookup,
|
||||
): Result<
|
||||
ApplicationWorkflowExecution<JavaScriptExportShapeComparisonResult>,
|
||||
AnalysisError
|
||||
> => {
|
||||
const operation = "compare_javascript_export_shapes";
|
||||
const parsed = compareJavaScriptExportShapesInputSchema.safeParse(rawInput);
|
||||
if (!parsed.success)
|
||||
const request = exportShapeFrameSchema.safeParse(rawInput);
|
||||
if (!request.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, parsed.error.issues, rawInput),
|
||||
);
|
||||
return compareJavaScriptExportShapesEvidenceValidated(parsed.data);
|
||||
};
|
||||
|
||||
/** Compare exact export shapes from input parsed by a trusted adapter. */
|
||||
export const compareJavaScriptExportShapesEvidenceValidated = (
|
||||
input: z.output<typeof compareJavaScriptExportShapesInputSchema>,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
const operation = "compare_javascript_export_shapes";
|
||||
const identities = javaScriptExportShapeIdentitiesSchema.safeParse(input);
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
analysisInputErrorFromIssues(operation, request.error.issues, rawInput, {
|
||||
cause: request.error,
|
||||
}),
|
||||
);
|
||||
const selectedLeft = resolveWorkflowEvidence(request.data.left, lookup);
|
||||
if (!selectedLeft.ok) return selectedLeft;
|
||||
const selectedRight = resolveWorkflowEvidence(request.data.right, lookup);
|
||||
if (!selectedRight.ok) return selectedRight;
|
||||
const input = {
|
||||
...request.data,
|
||||
left: selectedLeft.value,
|
||||
right: selectedRight.value,
|
||||
};
|
||||
const leftResult = parseApplicationGraphEvidence(input.left, ["left"]);
|
||||
if (!leftResult.ok)
|
||||
return err(applicationGraphEvidenceInputError(operation, leftResult.error));
|
||||
@@ -257,48 +314,40 @@ export const compareJavaScriptExportShapesEvidenceValidated = (
|
||||
return err(
|
||||
applicationGraphEvidenceInputError(operation, rightResult.error),
|
||||
);
|
||||
try {
|
||||
const left = leftResult.value;
|
||||
const right = rightResult.value;
|
||||
const result = compareJavaScriptExportShapes({
|
||||
left: {
|
||||
evidenceId: left.evidence.evidence_id,
|
||||
graph: left.graph,
|
||||
modulePath: input.left_module_path,
|
||||
exportName: input.left_export_name,
|
||||
},
|
||||
right: {
|
||||
evidenceId: right.evidence.evidence_id,
|
||||
graph: right.graph,
|
||||
modulePath: input.right_module_path,
|
||||
exportName: input.right_export_name,
|
||||
},
|
||||
});
|
||||
return ok(
|
||||
createJavaScriptExportShapeComparisonEvidence(
|
||||
{
|
||||
left_evidence_id: left.evidence.evidence_id,
|
||||
right_evidence_id: right.evidence.evidence_id,
|
||||
left_module_path: input.left_module_path,
|
||||
left_export_name: input.left_export_name,
|
||||
right_module_path: input.right_module_path,
|
||||
right_export_name: input.right_export_name,
|
||||
},
|
||||
result,
|
||||
),
|
||||
const left = leftResult.value;
|
||||
const right = rightResult.value;
|
||||
const identities = javaScriptExportShapeIdentitiesSchema.safeParse({
|
||||
left: left.evidence,
|
||||
right: right.evidence,
|
||||
});
|
||||
if (!identities.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(operation, identities.error.issues, input),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
return workflowFailure(operation, cause);
|
||||
}
|
||||
};
|
||||
|
||||
const workflowFailure = (
|
||||
operation: string,
|
||||
cause: unknown,
|
||||
): Result<never, AnalysisError> =>
|
||||
err(
|
||||
new AnalysisProtocolError(
|
||||
`JavaScript application workflow failed while producing ${operation}`,
|
||||
{ cause },
|
||||
),
|
||||
const result = compareJavaScriptExportShapes({
|
||||
left: {
|
||||
evidenceId: left.evidence.evidence_id,
|
||||
graph: left.graph,
|
||||
modulePath: input.left_module_path,
|
||||
exportName: input.left_export_name,
|
||||
},
|
||||
right: {
|
||||
evidenceId: right.evidence.evidence_id,
|
||||
graph: right.graph,
|
||||
modulePath: input.right_module_path,
|
||||
exportName: input.right_export_name,
|
||||
},
|
||||
});
|
||||
const evidence = createJavaScriptExportShapeComparisonEvidence(
|
||||
{
|
||||
left_evidence_id: left.evidence.evidence_id,
|
||||
right_evidence_id: right.evidence.evidence_id,
|
||||
left_module_path: input.left_module_path,
|
||||
left_export_name: input.left_export_name,
|
||||
right_module_path: input.right_module_path,
|
||||
right_export_name: input.right_export_name,
|
||||
},
|
||||
result,
|
||||
);
|
||||
return ok({ evidence, result, sources: [left.evidence, right.evidence] });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user