Use execution workspace review semantics during bottom-up pin upgrades
This commit is contained in:
@@ -5,9 +5,89 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { execFile as callback } from "node:child_process";
|
||||
import { planPinUpgrades, applyPinUpgrades, type UpgradeEffects } from "../src/capability-language/pin-upgrades.js";
|
||||
import {
|
||||
planPinUpgrades,
|
||||
applyPinUpgrades,
|
||||
reviewUpgradeCandidate,
|
||||
type UpgradeEffects,
|
||||
} from "../src/capability-language/pin-upgrades.js";
|
||||
import { capabilityId } from "../src/capability-model/index.js";
|
||||
import { makeValidCapabilityWorkspace } from "./fixtures/capability-model.js";
|
||||
const execFile = promisify(callback);
|
||||
|
||||
test("execution pin upgrades accept unchanged shared attachments without legacy migration planning", async (context) => {
|
||||
const artifact = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-execution-review-"));
|
||||
context.after(() => fs.rm(artifact, { recursive: true, force: true }));
|
||||
await fs.writeFile(path.join(artifact, "execution-plan.json"), "{}");
|
||||
const baseline = makeValidCapabilityWorkspace();
|
||||
assert.ok(baseline.sharedAttachments.length);
|
||||
const candidate = structuredClone(baseline);
|
||||
candidate.sourceRootCommit = "f".repeat(40);
|
||||
const { filename, review } = await reviewUpgradeCandidate({ artifact, baseline, candidate });
|
||||
assert.equal(filename, "semantic-review.json");
|
||||
assert.equal(review.checkerVersion, "quixos-semantic-review-v1");
|
||||
assert.deepEqual(review.blockers, []);
|
||||
assert.equal("migrationRequired" in review, false);
|
||||
assert.equal("runtimeActions" in review, false);
|
||||
});
|
||||
|
||||
test("execution pin upgrades require exact semantic-major receipts and reject foreign workspaces", async (context) => {
|
||||
const artifact = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-semantic-review-"));
|
||||
context.after(() => fs.rm(artifact, { recursive: true, force: true }));
|
||||
await fs.writeFile(path.join(artifact, "execution-plan.json"), "{}");
|
||||
const baseline = makeValidCapabilityWorkspace();
|
||||
baseline.conformances[0]!.id = capabilityId.conformance("conformance:project:named");
|
||||
const candidate = structuredClone(baseline);
|
||||
candidate.conformances[0]!.semanticMajor = 2;
|
||||
const { review } = await reviewUpgradeCandidate({ artifact, baseline, candidate });
|
||||
assert.equal(review.reviews.length, 1);
|
||||
assert.equal(review.reviews[0]!.accepted, false);
|
||||
assert.match(review.blockers[0]!, /Semantic-major review required/);
|
||||
const receipt = {
|
||||
requirementDigest: review.reviews[0]!.requirementDigest,
|
||||
decision: "accepted-unchanged" as const,
|
||||
rationale: "Reviewed the consumer against the provider's unchanged label behavior",
|
||||
agentId: "upgrade-fixture-agent",
|
||||
};
|
||||
assert.deepEqual(
|
||||
(await reviewUpgradeCandidate({ artifact, baseline, candidate, reviews: [receipt] })).review.blockers,
|
||||
[],
|
||||
);
|
||||
candidate.packageImports[0]!.source.commit = "f".repeat(40);
|
||||
assert.equal(
|
||||
(await reviewUpgradeCandidate({ artifact, baseline, candidate, reviews: [receipt] })).review.reviews[0]!.accepted,
|
||||
false,
|
||||
);
|
||||
candidate.workspaceId = capabilityId.workspace("workspace:foreign");
|
||||
await assert.rejects(() => reviewUpgradeCandidate({ artifact, baseline, candidate }), /different workspace/);
|
||||
});
|
||||
|
||||
test("nonexecution pin upgrades retain their evolution checks", async (context) => {
|
||||
const artifact = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-evolution-review-"));
|
||||
context.after(() => fs.rm(artifact, { recursive: true, force: true }));
|
||||
const baseline = makeValidCapabilityWorkspace();
|
||||
const { filename, review } = await reviewUpgradeCandidate({
|
||||
artifact,
|
||||
baseline,
|
||||
candidate: structuredClone(baseline),
|
||||
});
|
||||
assert.equal(filename, "evolution.json");
|
||||
assert.equal(review.checkerVersion, "quixos-evolution-v1");
|
||||
assert.ok(review.blockers.some((message) => message.includes("legacy workspace-shared attachments")));
|
||||
assert.equal("migrationRequired" in review, true);
|
||||
});
|
||||
|
||||
test("unexpected artifact access failures do not select nonexecution checks", async (context) => {
|
||||
const directory = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-review-failure-"));
|
||||
context.after(() => fs.rm(directory, { recursive: true, force: true }));
|
||||
const artifact = path.join(directory, "not-a-directory");
|
||||
await fs.writeFile(artifact, "not an artifact");
|
||||
const candidate = makeValidCapabilityWorkspace();
|
||||
await assert.rejects(() => reviewUpgradeCandidate({ artifact, baseline: candidate, candidate }), {
|
||||
code: "ENOTDIR",
|
||||
});
|
||||
});
|
||||
|
||||
test(
|
||||
"real jj snapshots and immutable Git publication propagate a changed interface into the root",
|
||||
{ skip: !process.env.QX_CHECK_GENERATOR },
|
||||
|
||||
Reference in New Issue
Block a user