From e06d31aeac3cb83b103bd4623595bfe41ad971e3 Mon Sep 17 00:00:00 2001 From: mptyl Date: Tue, 11 Aug 2026 16:21:08 +0200 Subject: [PATCH] fix: exercise catalog metadata mismatch on a pending slot --- backend/scripts/p11-acceptance.mjs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/backend/scripts/p11-acceptance.mjs b/backend/scripts/p11-acceptance.mjs index 686a2c4f..adf4ee8c 100644 --- a/backend/scripts/p11-acceptance.mjs +++ b/backend/scripts/p11-acceptance.mjs @@ -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, ["config", "user.name", "P1 Fixture Curator"], { 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); const evidenceRoot = join(author, "p11-filesystem", "evidence"); 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"); assert(status.status === 200 && status.body.head === ctx.bootstrapCommit, "status head mismatch"); 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"); ctx.baseCommit = status.body.head; 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; const listed = await request(ctx, "workspace-list-ready", "GET", "/workspaces"); - assert(listed.body.every((entry) => entry.configurationState === "ready"), "bootstrap did not activate all entries"); - return await check("bootstrap_create_once", { head: base, readyIds: listed.body.map((entry) => entry.id) }); + assert(listed.body.filter((entry) => entry.configurationState === "ready").length === 3, "bootstrap did not activate all published entries"); + 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 () => { const author = join(ctx.run.root, "author"); @@ -740,8 +747,10 @@ async function productionChecks(ctx) { unknown.workspace.id = "p11-unknown"; const unknownPublish = await request(ctx, "unknown-catalog-id", "POST", "/workspaces/publish", { action: "create", workspace: unknown, baseCommit: baseline.head }); safeErrorEnvelope(unknownPublish, "workspace_invalid", 400); - const mismatch = structuredClone(ctx.descriptors[1]); - mismatch.workspace.name = "Mismatched name"; + const mismatch = structuredClone(ctx.descriptors[0]); + 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 }); safeErrorEnvelope(mismatchPublish, "workspace_invalid", 400); const after = await registryState(ctx);