mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor(javascript): unify application workflow ownership
This commit is contained in:
1 parent
74ed67da7f
commit
da9a580a0d
18 files changed
+385
-315
No files matched your search
@@ -9,9 +9,6 @@ import {
|
||||
compareJavaScriptExportShapesEvidence,
|
||||
traceApplicationFeatureEvidence,
|
||||
} from "../../../dist/application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { applicationVersionComparisonResultSchema } from "../../../dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
|
||||
import { applicationFeatureTraceResultSchema } from "../../../dist/domain/javascript/javascriptFeatureTraceSchemas.js";
|
||||
import { javaScriptExportShapeComparisonResultSchema } from "../../../dist/domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import {
|
||||
completeVerifierRun,
|
||||
createVerifierRun,
|
||||
@@ -50,9 +47,7 @@ const [left, right] = await Promise.all([
|
||||
]);
|
||||
const comparison = compareApplicationVersionsEvidence({ left, right });
|
||||
if (!comparison.ok) throw comparison.error;
|
||||
const comparisonResult = applicationVersionComparisonResultSchema.parse(
|
||||
comparison.value.normalized_result,
|
||||
);
|
||||
const comparisonResult = comparison.value.result;
|
||||
const seedValue =
|
||||
options["seed-value"] ??
|
||||
left.normalized_result.graph.nodes.find(
|
||||
@@ -72,10 +67,7 @@ const trace =
|
||||
direction: "both",
|
||||
});
|
||||
if (trace !== null && !trace.ok) throw trace.error;
|
||||
const traceResult =
|
||||
trace === null
|
||||
? null
|
||||
: applicationFeatureTraceResultSchema.parse(trace.value.normalized_result);
|
||||
const traceResult = trace === null ? null : trace.value.result;
|
||||
const exportShapeSelector = resolveExportShapeSelector(left, right, options);
|
||||
const exportShapeComparison =
|
||||
exportShapeSelector === null
|
||||
@@ -88,17 +80,13 @@ const exportShapeComparison =
|
||||
if (exportShapeComparison !== null && !exportShapeComparison.ok)
|
||||
throw exportShapeComparison.error;
|
||||
const exportShapeResult =
|
||||
exportShapeComparison === null
|
||||
? null
|
||||
: javaScriptExportShapeComparisonResultSchema.parse(
|
||||
exportShapeComparison.value.normalized_result,
|
||||
);
|
||||
exportShapeComparison === null ? null : exportShapeComparison.value.result;
|
||||
|
||||
process.stdout.write(
|
||||
`${JSON.stringify({
|
||||
verifier_run: await completeVerifierRun(verifierRun),
|
||||
comparison_id: comparisonResult.comparison_id,
|
||||
evidence_id: comparison.value.evidence_id,
|
||||
evidence_id: comparison.value.evidence.evidence_id,
|
||||
left: comparisonResult.left,
|
||||
right: comparisonResult.right,
|
||||
summary: comparisonResult.summary,
|
||||
@@ -109,7 +97,7 @@ process.stdout.write(
|
||||
? null
|
||||
: {
|
||||
comparison_id: exportShapeResult.comparison_id,
|
||||
evidence_id: exportShapeComparison.value.evidence_id,
|
||||
evidence_id: exportShapeComparison.value.evidence.evidence_id,
|
||||
left: exportShapeResult.left,
|
||||
right: exportShapeResult.right,
|
||||
summary: exportShapeResult.summary,
|
||||
@@ -122,7 +110,7 @@ process.stdout.write(
|
||||
? null
|
||||
: {
|
||||
trace_id: traceResult.trace_id,
|
||||
evidence_id: trace.value.evidence_id,
|
||||
evidence_id: trace.value.evidence.evidence_id,
|
||||
seed: traceResult.seed,
|
||||
summary: traceResult.summary,
|
||||
coverage: traceResult.coverage,
|
||||
|
||||
@@ -202,10 +202,7 @@ try {
|
||||
direction: "incoming",
|
||||
});
|
||||
assert.equal(applicationTrace.ok, true);
|
||||
assert.equal(
|
||||
applicationTrace.value.normalized_result.summary.matched_seeds,
|
||||
1,
|
||||
);
|
||||
assert.equal(applicationTrace.value.result.summary.matched_seeds, 1);
|
||||
|
||||
const readyToRun = await fixture("r2r-x64.exe", {
|
||||
machine: 0x8664,
|
||||
|
||||
@@ -207,7 +207,7 @@ function verifyManagedAppManifestApplicationGraph({
|
||||
traced.ok,
|
||||
`application graph trace failed for method ${expectedTrace.method_token}`,
|
||||
);
|
||||
const matched = traced.value.normalized_result.summary.matched_seeds;
|
||||
const matched = traced.value.result.summary.matched_seeds;
|
||||
ensure(
|
||||
matched >= expectedTrace.min_matched_seeds,
|
||||
`application graph trace ${expectedTrace.seed} matched ${String(matched)} seeds, expected at least ${String(expectedTrace.min_matched_seeds)}`,
|
||||
@@ -218,7 +218,7 @@ function verifyManagedAppManifestApplicationGraph({
|
||||
method_token: expectedTrace.method_token,
|
||||
seed: expectedTrace.seed,
|
||||
matched_seeds: matched,
|
||||
trace_evidence_id: traced.value.evidence_id,
|
||||
trace_evidence_id: traced.value.evidence.evidence_id,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ const requireProvider = (
|
||||
);
|
||||
};
|
||||
|
||||
/** Parse unique, artifact-bound Evidence that may extend a native handoff. */
|
||||
/** Authenticate artifact-bound Evidence that may extend a native handoff. */
|
||||
export const parseNativeApplicationEvidence = (
|
||||
inputs: readonly unknown[],
|
||||
path: readonly (string | number)[] = [],
|
||||
@@ -336,13 +336,6 @@ export const parseNativeApplicationEvidence = (
|
||||
"subject",
|
||||
"Native handoff Evidence requires an artifact subject.",
|
||||
);
|
||||
const ids = parsed.map(({ evidence_id: id }) => id);
|
||||
if (new Set(ids).size !== ids.length)
|
||||
throw invalidEvidence(
|
||||
path,
|
||||
"evidence_id",
|
||||
"Native handoff Evidence must be unique.",
|
||||
);
|
||||
return parsed;
|
||||
});
|
||||
|
||||
|
||||
@@ -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] });
|
||||
};
|
||||
@@ -8,11 +8,8 @@ import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
||||
import type { AnalysisError } from "../domain/analysisErrorBase.js";
|
||||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import type { Logger } from "pino";
|
||||
import { traceApplicationFeatureInputSchema } from "../domain/javascript/javascriptFeatureTraceSchemas.js";
|
||||
import { traceJavaScriptSemanticsInputSchema } from "../domain/javascript/javascriptSemanticTraceSchemas.js";
|
||||
import { compareApplicationVersionsInputSchema } from "../domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
|
||||
import { registerSourceToBundleCommand } from "./sourceToBundleCommand.js";
|
||||
import { compareJavaScriptExportShapesInputSchema } from "../domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
||||
|
||||
type CliInstance = ReturnType<typeof Cli.create>;
|
||||
@@ -28,11 +25,12 @@ export const registerApplicationCommands = (
|
||||
name: CLI_COMMANDS.traceApplicationFeature,
|
||||
description:
|
||||
"Trace a typed seed through authenticated application Evidence JSON",
|
||||
inputSchema: traceApplicationFeatureInputSchema,
|
||||
inputSchema: z.unknown(),
|
||||
workflow: async (input) => {
|
||||
const { traceApplicationFeatureEvidenceValidated } =
|
||||
const { traceApplicationFeatureEvidence } =
|
||||
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
||||
return traceApplicationFeatureEvidenceValidated(input);
|
||||
const result = traceApplicationFeatureEvidence(input);
|
||||
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
||||
},
|
||||
});
|
||||
registerJsonCommand({
|
||||
@@ -54,11 +52,12 @@ export const registerApplicationCommands = (
|
||||
name: CLI_COMMANDS.compareApplicationVersions,
|
||||
description:
|
||||
"Compare two authenticated JavaScript Application Graph versions",
|
||||
inputSchema: compareApplicationVersionsInputSchema,
|
||||
inputSchema: z.unknown(),
|
||||
workflow: async (input) => {
|
||||
const { compareApplicationVersionsEvidenceValidated } =
|
||||
const { compareApplicationVersionsEvidence } =
|
||||
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
||||
return compareApplicationVersionsEvidenceValidated(input);
|
||||
const result = compareApplicationVersionsEvidence(input);
|
||||
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
||||
},
|
||||
});
|
||||
registerSourceToBundleCommand(cli, logger);
|
||||
@@ -68,11 +67,12 @@ export const registerApplicationCommands = (
|
||||
name: CLI_COMMANDS.compareJavaScriptExportShapes,
|
||||
description:
|
||||
"Compare exact static JavaScript export return shapes without execution",
|
||||
inputSchema: compareJavaScriptExportShapesInputSchema,
|
||||
inputSchema: z.unknown(),
|
||||
workflow: async (input) => {
|
||||
const { compareJavaScriptExportShapesEvidenceValidated } =
|
||||
const { compareJavaScriptExportShapesEvidence } =
|
||||
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
||||
return compareJavaScriptExportShapesEvidenceValidated(input);
|
||||
const result = compareJavaScriptExportShapesEvidence(input);
|
||||
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
||||
},
|
||||
});
|
||||
registerObligationLedgerCommand(cli, logger);
|
||||
|
||||
@@ -53,12 +53,15 @@ export const registerSourceToBundleCommand = (
|
||||
resources,
|
||||
);
|
||||
if (!reference.ok) return reference;
|
||||
const { compareSourceToBundleEvidenceValidated } =
|
||||
const { compareSourceToBundleEvidence } =
|
||||
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
||||
return compareSourceToBundleEvidenceValidated({
|
||||
const compared = compareSourceToBundleEvidence({
|
||||
...reference.value,
|
||||
application: parsed.data.application,
|
||||
});
|
||||
return compared.ok
|
||||
? { ok: true, value: compared.value.evidence }
|
||||
: compared;
|
||||
},
|
||||
resources,
|
||||
"javascript-application-workflow",
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type { EvidenceMcpServer } from "../EvidenceMcpServer.js";
|
||||
import { runAdmittedToolOperation } from "../admittedToolOperation.js";
|
||||
import { resolvePairedEvidenceRequest } from "../../application/EvidenceInputResolver.js";
|
||||
import { recordSessionEvidenceSources } from "../sessionEvidence.js";
|
||||
|
||||
import { compareJavaScriptExportShapesEvidenceValidated } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { compareJavaScriptExportShapesEvidence } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
||||
import { javaScriptExportShapeComparisonResultSchema } from "../../domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { logToolExecution } from "../toolLogging.js";
|
||||
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
|
||||
import { recordResult } from "./helpers.js";
|
||||
@@ -28,39 +26,33 @@ export const registerCompareJavaScriptExportShapesTool = (
|
||||
contract.name,
|
||||
context.mcpReq.signal,
|
||||
async () => {
|
||||
const resolved = resolvePairedEvidenceRequest(
|
||||
input,
|
||||
options.evidenceById,
|
||||
);
|
||||
if (!resolved.ok)
|
||||
return server.delivery.toCallToolResult(resolved, contract);
|
||||
const parsed = resolved.value;
|
||||
const result = await logToolExecution(
|
||||
options.logger,
|
||||
contract.name,
|
||||
() =>
|
||||
Promise.resolve(
|
||||
compareJavaScriptExportShapesEvidenceValidated(parsed),
|
||||
compareJavaScriptExportShapesEvidence(
|
||||
input,
|
||||
options.evidenceById,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!result.ok)
|
||||
return server.delivery.toCallToolResult(result, contract);
|
||||
const recorded = recordSessionEvidenceSources(
|
||||
options.recordEvidence,
|
||||
[parsed.left, parsed.right],
|
||||
result.value.sources,
|
||||
);
|
||||
if (!recorded.ok)
|
||||
return server.delivery.toCallToolResult(recorded, contract);
|
||||
const comparison = javaScriptExportShapeComparisonResultSchema.parse(
|
||||
result.value.normalized_result,
|
||||
);
|
||||
const comparison = result.value.result;
|
||||
const unknown =
|
||||
comparison.summary.unknown > 0 ||
|
||||
comparison.coverage.status !== "complete-within-inputs";
|
||||
return recordResult(
|
||||
{ ...options, delivery: server.delivery },
|
||||
contract,
|
||||
result.value,
|
||||
result.value.evidence,
|
||||
unknown ? "javascript-export-shape" : undefined,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -11,9 +11,8 @@ import { runAdmittedToolOperation } from "../admittedToolOperation.js";
|
||||
import { resolveApplicationEvidenceRequest } from "../../application/EvidenceInputResolver.js";
|
||||
import { recordSessionEvidenceSources } from "../sessionEvidence.js";
|
||||
|
||||
import { compareSourceToBundleEvidenceValidated } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { compareSourceToBundleEvidence } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
||||
import { sourceToBundleComparisonResultSchema } from "../../domain/javascript/sourceToBundleComparisonSchemas.js";
|
||||
import { logToolExecution } from "../toolLogging.js";
|
||||
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
|
||||
import { recordApplicationResult } from "./helpers.js";
|
||||
@@ -64,15 +63,12 @@ export const registerCompareSourceToBundleTool = (
|
||||
const result = await logToolExecution(
|
||||
options.logger,
|
||||
contract.name,
|
||||
() =>
|
||||
Promise.resolve(compareSourceToBundleEvidenceValidated(parsed)),
|
||||
() => Promise.resolve(compareSourceToBundleEvidence(parsed)),
|
||||
);
|
||||
if (!result.ok)
|
||||
return server.delivery.toCallToolResult(result, contract);
|
||||
const parent = result.value;
|
||||
const comparison = sourceToBundleComparisonResultSchema.parse(
|
||||
parent.normalized_result,
|
||||
);
|
||||
const parent = result.value.evidence;
|
||||
const comparison = result.value.result;
|
||||
// Stage the projection against the owned parent before committing any session facts.
|
||||
const selected =
|
||||
input.view === undefined
|
||||
@@ -102,7 +98,7 @@ export const registerCompareSourceToBundleTool = (
|
||||
return server.delivery.toCallToolResult(selected, contract);
|
||||
const recorded = recordSessionEvidenceSources(
|
||||
options.recordEvidence,
|
||||
[parsed.application],
|
||||
result.value.sources,
|
||||
);
|
||||
if (!recorded.ok)
|
||||
return server.delivery.toCallToolResult(recorded, contract);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type { EvidenceMcpServer } from "../EvidenceMcpServer.js";
|
||||
import { runAdmittedToolOperation } from "../admittedToolOperation.js";
|
||||
import { resolvePairedEvidenceRequest } from "../../application/EvidenceInputResolver.js";
|
||||
import { recordSessionEvidenceSources } from "../sessionEvidence.js";
|
||||
|
||||
import { compareApplicationVersionsEvidenceValidated } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { compareApplicationVersionsEvidence } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
||||
import { applicationVersionComparisonResultSchema } from "../../domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
|
||||
import { logToolExecution } from "../toolLogging.js";
|
||||
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
|
||||
import { recordResult } from "./helpers.js";
|
||||
@@ -28,43 +26,27 @@ export const registerCompareApplicationVersionsTool = (
|
||||
compareContract.name,
|
||||
context.mcpReq.signal,
|
||||
async () => {
|
||||
const resolved = resolvePairedEvidenceRequest(
|
||||
input,
|
||||
options.evidenceById,
|
||||
);
|
||||
if (!resolved.ok)
|
||||
return server.delivery.toCallToolResult(resolved, compareContract);
|
||||
const parsed = resolved.value;
|
||||
const result = await logToolExecution(
|
||||
options.logger,
|
||||
compareContract.name,
|
||||
() =>
|
||||
Promise.resolve(
|
||||
compareApplicationVersionsEvidenceValidated(parsed),
|
||||
compareApplicationVersionsEvidence(input, options.evidenceById),
|
||||
),
|
||||
);
|
||||
if (!result.ok)
|
||||
return server.delivery.toCallToolResult(result, compareContract);
|
||||
const sources = [
|
||||
parsed.left,
|
||||
parsed.right,
|
||||
...parsed.left_native_observations,
|
||||
...parsed.right_native_observations,
|
||||
];
|
||||
const recorded = recordSessionEvidenceSources(
|
||||
options.recordEvidence,
|
||||
sources,
|
||||
result.value.sources,
|
||||
);
|
||||
if (!recorded.ok)
|
||||
return server.delivery.toCallToolResult(recorded, compareContract);
|
||||
const comparison = applicationVersionComparisonResultSchema.parse(
|
||||
result.value.normalized_result,
|
||||
);
|
||||
const unknown = comparison.summary.unknown > 0;
|
||||
const unknown = result.value.result.summary.unknown > 0;
|
||||
return recordResult(
|
||||
{ ...options, delivery: server.delivery },
|
||||
compareContract,
|
||||
result.value,
|
||||
result.value.evidence,
|
||||
unknown ? "application-version-comparison" : undefined,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { EvidenceMcpServer } from "../EvidenceMcpServer.js";
|
||||
import { runAdmittedToolOperation } from "../admittedToolOperation.js";
|
||||
import { resolveApplicationEvidenceRequest } from "../../application/EvidenceInputResolver.js";
|
||||
import { recordSessionEvidenceSources } from "../sessionEvidence.js";
|
||||
|
||||
import { traceApplicationFeatureEvidenceValidated } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { traceApplicationFeatureEvidence } from "../../application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
||||
import { logToolExecution } from "../toolLogging.js";
|
||||
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
|
||||
@@ -27,32 +26,26 @@ export const registerTraceFeatureTool = (
|
||||
traceContract.name,
|
||||
context.mcpReq.signal,
|
||||
async () => {
|
||||
const resolved = resolveApplicationEvidenceRequest(
|
||||
input,
|
||||
options.evidenceById,
|
||||
);
|
||||
if (!resolved.ok)
|
||||
return server.delivery.toCallToolResult(resolved, traceContract);
|
||||
const parsed = resolved.value;
|
||||
const result = await logToolExecution(
|
||||
options.logger,
|
||||
traceContract.name,
|
||||
() =>
|
||||
Promise.resolve(traceApplicationFeatureEvidenceValidated(parsed)),
|
||||
Promise.resolve(
|
||||
traceApplicationFeatureEvidence(input, options.evidenceById),
|
||||
),
|
||||
);
|
||||
if (!result.ok)
|
||||
return server.delivery.toCallToolResult(result, traceContract);
|
||||
const sources = [parsed.application, ...parsed.native_observations];
|
||||
const recorded = recordSessionEvidenceSources(
|
||||
options.recordEvidence,
|
||||
sources,
|
||||
result.value.sources,
|
||||
);
|
||||
if (!recorded.ok)
|
||||
return server.delivery.toCallToolResult(recorded, traceContract);
|
||||
return recordResult(
|
||||
{ ...options, delivery: server.delivery },
|
||||
traceContract,
|
||||
result.value,
|
||||
result.value.evidence,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -206,6 +206,41 @@ const checkNativeObservationIdentities = async ({
|
||||
);
|
||||
};
|
||||
|
||||
const checkMalformedEvidenceBeforeIdentities = async ({
|
||||
cli,
|
||||
root,
|
||||
application,
|
||||
}: WorkflowContext) => {
|
||||
const malformed = {
|
||||
...application,
|
||||
provider: { ...application.provider, name: 3 },
|
||||
};
|
||||
for (const [command, input, path] of [
|
||||
[
|
||||
"compare-application-versions",
|
||||
{ left: application, right: malformed },
|
||||
["right", "provider", "name"],
|
||||
],
|
||||
[
|
||||
"compare-javascript-export-shapes",
|
||||
{ left: application, right: malformed, ...selectors },
|
||||
["right", "provider", "name"],
|
||||
],
|
||||
[
|
||||
"trace-application-feature",
|
||||
{ application, seed, native_observations: [malformed, application] },
|
||||
["native_observations", 0, "provider", "name"],
|
||||
],
|
||||
] as const) {
|
||||
const rejected = await runJson(cli, root, command, input);
|
||||
expect(rejected.exitCode).toBe(1);
|
||||
expect(rejected.json).toMatchObject({
|
||||
code: "invalid_request",
|
||||
details: { issues: [{ path, reason: "invalid_type" }] },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
cliTest(
|
||||
"preserves workflow identity validation through CLI and inline, retained and mixed MCP inputs",
|
||||
async ({ cli }) => {
|
||||
@@ -277,6 +312,7 @@ cliTest(
|
||||
};
|
||||
await checkComparisonIdentities(context);
|
||||
await checkNativeObservationIdentities(context);
|
||||
await checkMalformedEvidenceBeforeIdentities(context);
|
||||
const compared = await call("compare_application_versions", {
|
||||
left: reference,
|
||||
right: otherReference,
|
||||
|
||||
@@ -198,9 +198,7 @@ describe("complete comparison projections", () => {
|
||||
]);
|
||||
const compared = compareApplicationVersionsEvidence({ left, right });
|
||||
if (!compared.ok) throw compared.error;
|
||||
const result = applicationVersionComparisonResultSchema.parse(
|
||||
compared.value.normalized_result,
|
||||
);
|
||||
const result = compared.value.result;
|
||||
expectFullComparisonResultSchema(result);
|
||||
const modules = result.items.filter(
|
||||
({ node_kind: kind }) => kind === "javascript-module",
|
||||
@@ -261,9 +259,7 @@ describe("complete comparison projections", () => {
|
||||
]);
|
||||
const compared = compareApplicationVersionsEvidence({ left, right });
|
||||
if (!compared.ok) throw compared.error;
|
||||
const result = applicationVersionComparisonResultSchema.parse(
|
||||
compared.value.normalized_result,
|
||||
);
|
||||
const result = compared.value.result;
|
||||
expect(result.items).toContainEqual(
|
||||
expect.objectContaining({
|
||||
node_kind: "source-module",
|
||||
|
||||
@@ -5,11 +5,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { parseApplicationGraphEvidence } from "../../../src/application/javascript/JavaScriptApplicationEvidenceGraph.js";
|
||||
import { analyzeJavaScriptApplication } from "../../support/javascriptApplicationScope.js";
|
||||
import { compareJavaScriptExportShapesEvidence } from "../../../src/application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { parseEvidence } from "../../../src/domain/evidence.js";
|
||||
import {
|
||||
javaScriptExportShapeComparisonResultSchema,
|
||||
projectedExportReturnShapesSchema,
|
||||
} from "../../../src/domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { projectedExportReturnShapesSchema } from "../../../src/domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { writeFixtureFiles } from "../../support/javascriptApplicationFixture.js";
|
||||
|
||||
@@ -267,10 +263,8 @@ const compareEvidence = (left: Source, right: Source) => {
|
||||
right_export_name: "default",
|
||||
});
|
||||
if (!compared.ok) throw compared.error;
|
||||
const evidence = parseEvidence(compared.value);
|
||||
const result = javaScriptExportShapeComparisonResultSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
const evidence = compared.value.evidence;
|
||||
const result = compared.value.result;
|
||||
const evidenceLinks = [left.evidence.evidence_id, right.evidence.evidence_id];
|
||||
expect(evidence).toMatchObject({
|
||||
operation: "compare_javascript_export_shapes",
|
||||
|
||||
@@ -9,7 +9,6 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { analyzeJavaScriptApplication } from "../../support/javascriptApplicationScope.js";
|
||||
import { compareJavaScriptExportShapesEvidence } from "../../../src/application/javascript/JavaScriptApplicationWorkflowService.js";
|
||||
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
|
||||
import { javaScriptExportShapeComparisonResultSchema } from "../../../src/domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
|
||||
import { APPLICATION_TOOL_CONTRACTS } from "../../../src/contracts/applicationToolContracts.js";
|
||||
import { parseEvidence } from "../../../src/domain/evidence.js";
|
||||
@@ -516,7 +515,5 @@ const compareEvidence = (
|
||||
right_export_name: "default",
|
||||
});
|
||||
if (!compared.ok) throw compared.error;
|
||||
return javaScriptExportShapeComparisonResultSchema.parse(
|
||||
compared.value.normalized_result,
|
||||
);
|
||||
return compared.value.result;
|
||||
};
|
||||
@@ -209,7 +209,7 @@ describe("managed application graph projection", () => {
|
||||
true,
|
||||
);
|
||||
if (!trace.ok) throw new Error("trace failed");
|
||||
expect(trace.value.normalized_result).toMatchObject({
|
||||
expect(trace.value.result).toMatchObject({
|
||||
source_evidence_id: parsed.evidence_id,
|
||||
summary: { matched_seeds: 1 },
|
||||
});
|
||||
|
||||
@@ -39,6 +39,16 @@ import { processCaptureSchema } from "../../src/domain/process/processCapture.js
|
||||
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js";
|
||||
import { javascriptApplicationAnalysisResultSchema } from "../../src/domain/javascript/javascriptApplicationAnalysis.js";
|
||||
import { javaScriptSemanticQueryResultSchema } from "../../src/domain/javascript/javascriptSemanticQuerySchemas.js";
|
||||
import {
|
||||
JAVASCRIPT_FEATURE_TRACE_EXAMPLE,
|
||||
JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE,
|
||||
SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE,
|
||||
} from "../../src/contracts/javascript/javascriptApplicationWorkflowExamples.js";
|
||||
import { JAVASCRIPT_EXPORT_SHAPE_COMPARISON_EXAMPLE } from "../../src/contracts/javascript/javascriptExportShapeComparisonExample.js";
|
||||
import { applicationFeatureTraceResultSchema } from "../../src/domain/javascript/javascriptFeatureTraceSchemas.js";
|
||||
import { ownedApplicationVersionComparisonResultSchema } from "../../src/domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
|
||||
import { javaScriptExportShapeComparisonResultSchema } from "../../src/domain/javascript/javascriptExportShapeComparisonSchemas.js";
|
||||
import { sourceToBundleComparisonResultSchema } from "../../src/domain/javascript/sourceToBundleComparisonSchemas.js";
|
||||
|
||||
import { nativeFunctionMatchingSchema } from "../../src/domain/native/functionMatching.js";
|
||||
import { FunctionByteCoverage } from "../../src/domain/native/functionByteCoverage.js";
|
||||
@@ -72,6 +82,50 @@ const unexpectedResultFailures = [
|
||||
],
|
||||
] as const;
|
||||
|
||||
describe.each([
|
||||
{
|
||||
name: "trace_application_feature",
|
||||
input: JAVASCRIPT_FEATURE_TRACE_EXAMPLE,
|
||||
result: applicationFeatureTraceResultSchema,
|
||||
},
|
||||
{
|
||||
name: "compare_application_versions",
|
||||
input: JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE,
|
||||
result: ownedApplicationVersionComparisonResultSchema,
|
||||
},
|
||||
{
|
||||
name: "compare_javascript_export_shapes",
|
||||
input: JAVASCRIPT_EXPORT_SHAPE_COMPARISON_EXAMPLE,
|
||||
result: javaScriptExportShapeComparisonResultSchema,
|
||||
},
|
||||
{
|
||||
name: "compare_source_to_bundle",
|
||||
input: SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE,
|
||||
result: sourceToBundleComparisonResultSchema,
|
||||
},
|
||||
])("$name output failures through the public SDK", (workflow) => {
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
it.each(unexpectedResultFailures)(
|
||||
"preserves an unexpected %s without recording sources or derived Evidence",
|
||||
async (_kind, createFailure) => {
|
||||
await withSdk(async ({ client, session }) => {
|
||||
const failure = createFailure();
|
||||
vi.spyOn(workflow.result, "parse").mockImplementation(() => {
|
||||
throw failure;
|
||||
});
|
||||
const response = await client.callTool({
|
||||
name: workflow.name,
|
||||
arguments: workflow.input,
|
||||
});
|
||||
expectUnexpectedToolFailure(response, failure);
|
||||
expect(session.exportEvidenceBundle().records).toEqual([]);
|
||||
expect(session.exportEvidenceBundle().unknowns).toEqual([]);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const invalidFunctionOperationEvidence = () => {
|
||||
const left = FUNCTION_COMPARISON_EXAMPLE.left;
|
||||
if (left.subject === null) throw new Error("Expected a function subject");
|
||||
|
||||
@@ -122,15 +122,15 @@ it.each(["validation", "comparison"] as const)(
|
||||
const actual = await vi.importActual<typeof workflow>(
|
||||
"../../src/application/javascript/JavaScriptApplicationWorkflowService.js",
|
||||
);
|
||||
vi.mocked(
|
||||
workflow.compareSourceToBundleEvidenceValidated,
|
||||
).mockImplementationOnce((input) => {
|
||||
const compared = actual.compareSourceToBundleEvidenceValidated(input);
|
||||
setImmediate(() =>
|
||||
controller.abort(new Error("cancel during graph comparison")),
|
||||
);
|
||||
return compared;
|
||||
});
|
||||
vi.mocked(workflow.compareSourceToBundleEvidence).mockImplementationOnce(
|
||||
(input) => {
|
||||
const compared = actual.compareSourceToBundleEvidence(input);
|
||||
setImmediate(() =>
|
||||
controller.abort(new Error("cancel during graph comparison")),
|
||||
);
|
||||
return compared;
|
||||
},
|
||||
);
|
||||
}
|
||||
let settle: (() => void) | undefined;
|
||||
const settled = new Promise<void>((resolve) => {
|
||||
|
||||
Reference in new issue
Block a user