fix: exercise catalog metadata mismatch on a pending slot

This commit is contained in:
2026-08-11 16:21:08 +02:00
parent 412c0d8715
commit e06d31aeac
+15 -6
View File
@@ -403,7 +403,13 @@ async function initializeGit(ctx) {
await git(ctx, ["clone", join(ctx.run.root, "remote.git"), author], { cwd: ctx.run.root }); await git(ctx, ["clone", join(ctx.run.root, "remote.git"), author], { cwd: ctx.run.root });
await git(ctx, ["config", "user.name", "P1 Fixture Curator"], { cwd: author }); await git(ctx, ["config", "user.name", "P1 Fixture Curator"], { cwd: author });
await git(ctx, ["config", "user.email", "p1-curator@example.invalid"], { cwd: author }); await git(ctx, ["config", "user.email", "p1-curator@example.invalid"], { cwd: author });
const catalogBytes = `${JSON.stringify(catalog(ctx.descriptors), null, 2)}\n`; const catalogBytes = `${JSON.stringify({
schema_version: 1,
workspaces: [
...catalog(ctx.descriptors).workspaces,
{ id: "p11-pending", name: "P1.1 pending", description: "Catalog-only slot awaiting bootstrap" },
],
}, null, 2)}\n`;
await atomicWrite(join(author, "thoth-workspaces.yaml"), catalogBytes, 0o644); await atomicWrite(join(author, "thoth-workspaces.yaml"), catalogBytes, 0o644);
const evidenceRoot = join(author, "p11-filesystem", "evidence"); const evidenceRoot = join(author, "p11-filesystem", "evidence");
await mkdir(join(evidenceRoot, "domain"), { recursive: true }); await mkdir(join(evidenceRoot, "domain"), { recursive: true });
@@ -583,7 +589,7 @@ async function productionChecks(ctx) {
const status = await request(ctx, "registry-status", "GET", "/workspace-registry/status"); const status = await request(ctx, "registry-status", "GET", "/workspace-registry/status");
assert(status.status === 200 && status.body.head === ctx.bootstrapCommit, "status head mismatch"); assert(status.status === 200 && status.body.head === ctx.bootstrapCommit, "status head mismatch");
const listed = await request(ctx, "workspace-list-initial", "GET", "/workspaces"); const listed = await request(ctx, "workspace-list-initial", "GET", "/workspaces");
assert(listed.status === 200 && listed.body.length === 3, "catalog listing failed"); assert(listed.status === 200 && listed.body.length === 4, "catalog listing failed");
assert(listed.body.every((entry) => entry.configurationState === "configuration_required"), "catalog entries were not configuration_required"); assert(listed.body.every((entry) => entry.configurationState === "configuration_required"), "catalog entries were not configuration_required");
ctx.baseCommit = status.body.head; ctx.baseCommit = status.body.head;
return await check("catalog_only_listing", { head: status.body.head, ids: listed.body.map((entry) => entry.id), allConfigurationRequired: true }); return await check("catalog_only_listing", { head: status.body.head, ids: listed.body.map((entry) => entry.id), allConfigurationRequired: true });
@@ -601,8 +607,9 @@ async function productionChecks(ctx) {
} }
ctx.publishHead = base; ctx.publishHead = base;
const listed = await request(ctx, "workspace-list-ready", "GET", "/workspaces"); const listed = await request(ctx, "workspace-list-ready", "GET", "/workspaces");
assert(listed.body.every((entry) => entry.configurationState === "ready"), "bootstrap did not activate all entries"); assert(listed.body.filter((entry) => entry.configurationState === "ready").length === 3, "bootstrap did not activate all published entries");
return await check("bootstrap_create_once", { head: base, readyIds: listed.body.map((entry) => entry.id) }); assert(listed.body.find((entry) => entry.id === "p11-pending")?.configurationState === "configuration_required", "pending slot was not left unconfigured");
return await check("bootstrap_create_once", { head: base, readyIds: listed.body.filter((entry) => entry.configurationState === "ready").map((entry) => entry.id) });
} }, } },
{ id: "api_curator_boundary", run: async () => { { id: "api_curator_boundary", run: async () => {
const author = join(ctx.run.root, "author"); const author = join(ctx.run.root, "author");
@@ -740,8 +747,10 @@ async function productionChecks(ctx) {
unknown.workspace.id = "p11-unknown"; unknown.workspace.id = "p11-unknown";
const unknownPublish = await request(ctx, "unknown-catalog-id", "POST", "/workspaces/publish", { action: "create", workspace: unknown, baseCommit: baseline.head }); const unknownPublish = await request(ctx, "unknown-catalog-id", "POST", "/workspaces/publish", { action: "create", workspace: unknown, baseCommit: baseline.head });
safeErrorEnvelope(unknownPublish, "workspace_invalid", 400); safeErrorEnvelope(unknownPublish, "workspace_invalid", 400);
const mismatch = structuredClone(ctx.descriptors[1]); const mismatch = structuredClone(ctx.descriptors[0]);
mismatch.workspace.name = "Mismatched name"; mismatch.workspace.id = "p11-pending";
mismatch.workspace.name = "Mismatched pending name";
mismatch.semantic_index.vector_store.collection = "p11-pending";
const mismatchPublish = await request(ctx, "catalog-metadata-mismatch", "POST", "/workspaces/publish", { action: "create", workspace: mismatch, baseCommit: baseline.head }); const mismatchPublish = await request(ctx, "catalog-metadata-mismatch", "POST", "/workspaces/publish", { action: "create", workspace: mismatch, baseCommit: baseline.head });
safeErrorEnvelope(mismatchPublish, "workspace_invalid", 400); safeErrorEnvelope(mismatchPublish, "workspace_invalid", 400);
const after = await registryState(ctx); const after = await registryState(ctx);