Review execution semantic-major changes without storage migration planning
This commit is contained in:
@@ -367,6 +367,36 @@ export const planEvolution = (
|
||||
...(next ? { candidate: next } : {}),
|
||||
});
|
||||
}
|
||||
const semanticReview = assessSemanticReviews(baseline, candidate, options.reviews ?? [], checkerVersion, [
|
||||
...nextRuntimes.values(),
|
||||
]);
|
||||
const reviews = semanticReview.reviews;
|
||||
blockers.push(...semanticReview.blockers);
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
baselineDigest: baseline ? contentDigest(baseline) : null,
|
||||
candidateDigest,
|
||||
checkerVersion,
|
||||
runtimeActions,
|
||||
storageChanges,
|
||||
migrationRequired: storageChanges.filter((entry) => entry.requiresMigration).map((entry) => entry.id),
|
||||
reviews,
|
||||
packageChecks: runtimeActions
|
||||
.filter((entry) => entry.candidate && entry.action !== "keep")
|
||||
.map((entry) => ({ groupId: entry.groupId, contractDigest: entry.candidate!.digest })),
|
||||
blockers,
|
||||
};
|
||||
};
|
||||
|
||||
/** Review dependency contracts, without making any storage or process-placement decision. */
|
||||
function assessSemanticReviews(
|
||||
baseline: WorkspaceRevision | null,
|
||||
candidate: WorkspaceRevision,
|
||||
receipts: readonly EvolutionReview[],
|
||||
checkerVersion: string,
|
||||
consumers: readonly RuntimeContract[],
|
||||
): Pick<EvolutionReport, "reviews" | "blockers"> {
|
||||
const blockers: string[] = [];
|
||||
const providers = (workspace: WorkspaceRevision) => [
|
||||
...workspace.packageImports.map((entry) => ({
|
||||
id: entry.packageId as string,
|
||||
@@ -393,7 +423,7 @@ export const planEvolution = (
|
||||
}
|
||||
if (!old[0] || old[0].major === provider.major) continue;
|
||||
if (provider.major < old[0].major) blockers.push(`Semantic major decreases for ${provider.id}`);
|
||||
for (const consumer of nextRuntimes.values()) {
|
||||
for (const consumer of consumers) {
|
||||
if (consumer.packageId === provider.id || !consumer.reviewProviders.includes(provider.id)) continue;
|
||||
const requirement = {
|
||||
consumerId: consumer.groupId,
|
||||
@@ -408,7 +438,7 @@ export const planEvolution = (
|
||||
consumer: consumer.digest,
|
||||
checkerVersion,
|
||||
});
|
||||
const accepted = (options.reviews ?? []).some(
|
||||
const accepted = receipts.some(
|
||||
(entry) =>
|
||||
entry.requirementDigest === requirementDigest &&
|
||||
["changed", "accepted-unchanged"].includes(entry.decision) &&
|
||||
@@ -419,18 +449,27 @@ export const planEvolution = (
|
||||
if (!accepted) blockers.push(`Semantic-major review required: ${consumer.groupId} consumes ${provider.id}`);
|
||||
}
|
||||
}
|
||||
return { reviews, blockers };
|
||||
}
|
||||
|
||||
export function reviewSemanticMajors(
|
||||
baseline: WorkspaceRevision | null,
|
||||
candidate: WorkspaceRevision,
|
||||
receipts: readonly EvolutionReview[] = [],
|
||||
) {
|
||||
for (const workspace of baseline ? [baseline, candidate] : [candidate]) {
|
||||
const issues = validateWorkspaceRevision(workspace);
|
||||
if (issues.length)
|
||||
throw new Error("Invalid semantic-review workspace: " + issues.map((issue) => issue.message).join("; "));
|
||||
}
|
||||
if (baseline && baseline.workspaceId !== candidate.workspaceId)
|
||||
throw new Error("Cannot review a different workspace");
|
||||
const checkerVersion = "quixos-semantic-review-v1";
|
||||
const report = assessSemanticReviews(baseline, candidate, receipts, checkerVersion, runtimeContracts(candidate));
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
baselineDigest: baseline ? contentDigest(baseline) : null,
|
||||
candidateDigest,
|
||||
checkerVersion,
|
||||
runtimeActions,
|
||||
storageChanges,
|
||||
migrationRequired: storageChanges.filter((entry) => entry.requiresMigration).map((entry) => entry.id),
|
||||
reviews,
|
||||
packageChecks: runtimeActions
|
||||
.filter((entry) => entry.candidate && entry.action !== "keep")
|
||||
.map((entry) => ({ groupId: entry.groupId, contractDigest: entry.candidate!.digest })),
|
||||
blockers,
|
||||
baselineDigest: baseline ? contentDigest(baseline) : null,
|
||||
candidateDigest: contentDigest(candidate),
|
||||
...report,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user