mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
refactor(javascript): group domain semantics and contracts (#907)
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { emptyArraySchema } from "../emptyArraySchema.js";
|
||||
import { evidenceSchema } from "../evidence.js";
|
||||
import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js";
|
||||
import { JAVASCRIPT_APPLICATION_NODE_KINDS } from "./javascriptApplicationGraphSchemas.js";
|
||||
import { prefixedDigestSchema } from "../digests.js";
|
||||
|
||||
const evidenceIdSchema = prefixedDigestSchema("ev");
|
||||
const nodeIdSchema = prefixedDigestSchema("jag_node");
|
||||
const textSchema = z.string().min(1);
|
||||
|
||||
/** Two authenticated application versions and their native observations. */
|
||||
export const compareApplicationVersionsInputSchema = z
|
||||
.strictObject({
|
||||
left: evidenceSchema,
|
||||
right: evidenceSchema,
|
||||
left_native_observations: z.array(evidenceSchema).default([]),
|
||||
right_native_observations: z.array(evidenceSchema).default([]),
|
||||
})
|
||||
.superRefine((input, context) => {
|
||||
if (input.left.evidence_id === input.right.evidence_id)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["right"],
|
||||
message: "Application version Evidence must be distinct",
|
||||
});
|
||||
for (const side of [
|
||||
"left_native_observations",
|
||||
"right_native_observations",
|
||||
] as const) {
|
||||
const ids = input[side].map(({ evidence_id: id }) => id);
|
||||
if (new Set(ids).size !== ids.length)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: [side],
|
||||
message: "Native observations must be unique on each side",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const emptyCandidateNodesSchema = emptyArraySchema;
|
||||
const candidateNodesSchema = z.tuple([nodeIdSchema]).rest(nodeIdSchema);
|
||||
const exactMatchSchema = z.strictObject({
|
||||
status: z.literal("matched"),
|
||||
basis: z.enum([
|
||||
"exact-node-identity",
|
||||
"exact-content-digest",
|
||||
"exact-module-source-digest",
|
||||
]),
|
||||
confidence: z.literal("exact"),
|
||||
candidate_left_node_ids: emptyCandidateNodesSchema,
|
||||
candidate_right_node_ids: emptyCandidateNodesSchema,
|
||||
});
|
||||
const sourceMapMatchSchema = z.strictObject({
|
||||
status: z.literal("matched"),
|
||||
basis: z.literal("source-map-identity"),
|
||||
confidence: z.literal("high"),
|
||||
candidate_left_node_ids: emptyCandidateNodesSchema,
|
||||
candidate_right_node_ids: emptyCandidateNodesSchema,
|
||||
});
|
||||
const inferredMatchSchema = z.strictObject({
|
||||
status: z.literal("matched"),
|
||||
basis: z.enum(["structural-fingerprint", "semantic-key"]),
|
||||
confidence: z.literal("medium"),
|
||||
candidate_left_node_ids: emptyCandidateNodesSchema,
|
||||
candidate_right_node_ids: emptyCandidateNodesSchema,
|
||||
});
|
||||
const matchedItemMatchSchema = z.union([
|
||||
exactMatchSchema,
|
||||
sourceMapMatchSchema,
|
||||
inferredMatchSchema,
|
||||
]);
|
||||
const unmatchedItemMatchSchema = z.strictObject({
|
||||
status: z.literal("unmatched"),
|
||||
basis: z.literal("none"),
|
||||
confidence: z.literal("unknown"),
|
||||
candidate_left_node_ids: emptyCandidateNodesSchema,
|
||||
candidate_right_node_ids: emptyCandidateNodesSchema,
|
||||
});
|
||||
const leftAmbiguousMatchSchema = z.strictObject({
|
||||
status: z.literal("ambiguous"),
|
||||
basis: z.literal("none"),
|
||||
confidence: z.literal("unknown"),
|
||||
candidate_left_node_ids: emptyCandidateNodesSchema,
|
||||
candidate_right_node_ids: candidateNodesSchema,
|
||||
});
|
||||
const rightAmbiguousMatchSchema = z.strictObject({
|
||||
status: z.literal("ambiguous"),
|
||||
basis: z.literal("none"),
|
||||
confidence: z.literal("unknown"),
|
||||
candidate_left_node_ids: candidateNodesSchema,
|
||||
candidate_right_node_ids: emptyCandidateNodesSchema,
|
||||
});
|
||||
|
||||
const comparisonItemContextShape = {
|
||||
item_id: prefixedDigestSchema("javc_item"),
|
||||
node_kind: z.enum(JAVASCRIPT_APPLICATION_NODE_KINDS),
|
||||
dimensions: z.array(
|
||||
z.enum([
|
||||
"content",
|
||||
"location",
|
||||
"properties",
|
||||
"relationships",
|
||||
"availability",
|
||||
"coverage",
|
||||
]),
|
||||
),
|
||||
evidence_links: z.array(evidenceIdSchema).min(2),
|
||||
limitations: z.array(textSchema),
|
||||
};
|
||||
|
||||
const comparisonItemSchema = z.union([
|
||||
z.strictObject({
|
||||
...comparisonItemContextShape,
|
||||
status: z.enum(["unchanged", "changed", "unknown"]),
|
||||
left_node_id: nodeIdSchema,
|
||||
right_node_id: nodeIdSchema,
|
||||
match: matchedItemMatchSchema,
|
||||
}),
|
||||
z.strictObject({
|
||||
...comparisonItemContextShape,
|
||||
status: z.enum(["removed", "unknown"]),
|
||||
left_node_id: nodeIdSchema,
|
||||
right_node_id: z.null(),
|
||||
match: unmatchedItemMatchSchema,
|
||||
}),
|
||||
z.strictObject({
|
||||
...comparisonItemContextShape,
|
||||
status: z.enum(["added", "unknown"]),
|
||||
left_node_id: z.null(),
|
||||
right_node_id: nodeIdSchema,
|
||||
match: unmatchedItemMatchSchema,
|
||||
}),
|
||||
z.strictObject({
|
||||
...comparisonItemContextShape,
|
||||
status: z.literal("unknown"),
|
||||
left_node_id: nodeIdSchema,
|
||||
right_node_id: z.null(),
|
||||
match: leftAmbiguousMatchSchema,
|
||||
}),
|
||||
z.strictObject({
|
||||
...comparisonItemContextShape,
|
||||
status: z.literal("unknown"),
|
||||
left_node_id: z.null(),
|
||||
right_node_id: nodeIdSchema,
|
||||
match: rightAmbiguousMatchSchema,
|
||||
}),
|
||||
]);
|
||||
|
||||
const comparisonCoverageSchema = z.strictObject({
|
||||
left_graph_status: z.enum(["complete", "partial", "unknown", "unavailable"]),
|
||||
right_graph_status: z.enum(["complete", "partial", "unknown", "unavailable"]),
|
||||
left_graph_omitted_count: z.number().int().min(0).nullable(),
|
||||
right_graph_omitted_count: z.number().int().min(0).nullable(),
|
||||
status: z.enum(["complete-within-inputs", "partial", "truncated"]),
|
||||
});
|
||||
|
||||
/** Tiered module/entity matching plus its complete cross-version change graph. */
|
||||
export const applicationVersionComparisonResultSchema = z
|
||||
.strictObject({
|
||||
comparison_id: prefixedDigestSchema("javc"),
|
||||
left: z.strictObject({
|
||||
evidence_id: evidenceIdSchema,
|
||||
graph_id: prefixedDigestSchema("jag"),
|
||||
root_artifact_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
||||
}),
|
||||
right: z.strictObject({
|
||||
evidence_id: evidenceIdSchema,
|
||||
graph_id: prefixedDigestSchema("jag"),
|
||||
root_artifact_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
||||
}),
|
||||
summary: z.strictObject({
|
||||
unchanged: z.number().int().min(0),
|
||||
added: z.number().int().min(0),
|
||||
removed: z.number().int().min(0),
|
||||
changed: z.number().int().min(0),
|
||||
unknown: z.number().int().min(0),
|
||||
}),
|
||||
matching: z.strictObject({
|
||||
exact_node_identity: z.number().int().min(0),
|
||||
exact_content_digest: z.number().int().min(0),
|
||||
exact_module_source_digest: z.number().int().min(0),
|
||||
source_map_identity: z.number().int().min(0),
|
||||
structural_fingerprint: z.number().int().min(0),
|
||||
semantic_key: z.number().int().min(0),
|
||||
ambiguous: z.number().int().min(0),
|
||||
unmatched: z.number().int().min(0),
|
||||
}),
|
||||
items: z.array(comparisonItemSchema),
|
||||
graph: javascriptApplicationGraphSchema,
|
||||
coverage: comparisonCoverageSchema,
|
||||
evidence_links: z.array(evidenceIdSchema).min(2),
|
||||
limitations: z.array(textSchema),
|
||||
})
|
||||
.superRefine((result, context) => {
|
||||
const sourceGraphsComplete =
|
||||
result.coverage.left_graph_status === "complete" &&
|
||||
result.coverage.right_graph_status === "complete";
|
||||
if (
|
||||
(result.coverage.status === "complete-within-inputs") !==
|
||||
sourceGraphsComplete
|
||||
)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["coverage", "status"],
|
||||
message: "Comparison coverage must match source graph completeness",
|
||||
});
|
||||
});
|
||||
|
||||
export type ApplicationVersionComparisonItem = z.infer<
|
||||
typeof comparisonItemSchema
|
||||
>;
|
||||
export type ApplicationVersionComparisonResult = z.infer<
|
||||
typeof applicationVersionComparisonResultSchema
|
||||
>;
|
||||
Reference in New Issue
Block a user