fix: keep the P2 fixture workspace ids in the P3 acceptance runner
This commit is contained in:
@@ -409,9 +409,9 @@ async function setupSecrets(ctx) {
|
|||||||
ctx.forbiddenValues = Object.values(values);
|
ctx.forbiddenValues = Object.values(values);
|
||||||
ctx.secretValues = values;
|
ctx.secretValues = values;
|
||||||
const paths = {
|
const paths = {
|
||||||
dwh: join(secretDir, "p3-dwh-api-key"),
|
dwh: join(secretDir, "p2-dwh-api-key"),
|
||||||
filesystemDwh: join(secretDir, "p3-filesystem-api-key"),
|
filesystemDwh: join(secretDir, "p2-filesystem-api-key"),
|
||||||
signed: join(secretDir, "p3-dwh-evidence-signed-urls.json"),
|
signed: join(secretDir, "p2-dwh-evidence-signed-urls.json"),
|
||||||
bundle: join(secretDir, "thothii.secrets"),
|
bundle: join(secretDir, "thothii.secrets"),
|
||||||
};
|
};
|
||||||
await atomicWrite(paths.dwh, scalarSecretBytes(values.dwhToken));
|
await atomicWrite(paths.dwh, scalarSecretBytes(values.dwhToken));
|
||||||
@@ -428,9 +428,9 @@ async function setupFixtures(ctx) {
|
|||||||
qdrant: await allocatePort(),
|
qdrant: await allocatePort(),
|
||||||
};
|
};
|
||||||
const dwhBaseUrl = `http://host.docker.internal:${ctx.fixturePorts.dwh}`;
|
const dwhBaseUrl = `http://host.docker.internal:${ctx.fixturePorts.dwh}`;
|
||||||
const evidenceProvenance = `http://host.docker.internal:${ctx.fixturePorts.evidence}/p3-dwh/guide.md`;
|
const evidenceProvenance = `http://host.docker.internal:${ctx.fixturePorts.evidence}/p2-dwh/guide.md`;
|
||||||
ctx.workspaceObjects = {
|
ctx.workspaceObjects = {
|
||||||
dwh: baseWorkspace("p3-dwh", {
|
dwh: baseWorkspace("p2-dwh", {
|
||||||
dwhBaseUrl,
|
dwhBaseUrl,
|
||||||
evidenceSource: {
|
evidenceSource: {
|
||||||
type: "http",
|
type: "http",
|
||||||
@@ -444,11 +444,11 @@ async function setupFixtures(ctx) {
|
|||||||
max_cache_bytes: 65536,
|
max_cache_bytes: 65536,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
filesystem: baseWorkspace("p3-filesystem", {
|
filesystem: baseWorkspace("p2-filesystem", {
|
||||||
dwhBaseUrl,
|
dwhBaseUrl,
|
||||||
evidenceSource: {
|
evidenceSource: {
|
||||||
type: "filesystem",
|
type: "filesystem",
|
||||||
uri: "p3-filesystem/evidence",
|
uri: "p2-filesystem/evidence",
|
||||||
patterns: ["**/*.md"],
|
patterns: ["**/*.md"],
|
||||||
max_bytes: 1048576,
|
max_bytes: 1048576,
|
||||||
},
|
},
|
||||||
@@ -609,7 +609,7 @@ async function startServers(ctx) {
|
|||||||
port: ctx.fixturePorts.evidence,
|
port: ctx.fixturePorts.evidence,
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
const url = new URL(req.url, `http://127.0.0.1:${ctx.fixturePorts.evidence}`);
|
const url = new URL(req.url, `http://127.0.0.1:${ctx.fixturePorts.evidence}`);
|
||||||
if (url.pathname !== "/p3-dwh/guide.md" || url.searchParams.get("token") !== ctx.evidenceState.token) {
|
if (url.pathname !== "/p2-dwh/guide.md" || url.searchParams.get("token") !== ctx.evidenceState.token) {
|
||||||
res.statusCode = 403;
|
res.statusCode = 403;
|
||||||
res.end("forbidden");
|
res.end("forbidden");
|
||||||
return;
|
return;
|
||||||
@@ -673,8 +673,8 @@ async function initializeGitAndRegistry(ctx) {
|
|||||||
const catalog = {
|
const catalog = {
|
||||||
schema_version: 1,
|
schema_version: 1,
|
||||||
workspaces: [
|
workspaces: [
|
||||||
{ id: "p3-dwh", name: ctx.workspaceObjects.dwh.workspace.name },
|
{ id: "p2-dwh", name: ctx.workspaceObjects.dwh.workspace.name },
|
||||||
{ id: "p3-filesystem", name: ctx.workspaceObjects.filesystem.workspace.name },
|
{ id: "p2-filesystem", name: ctx.workspaceObjects.filesystem.workspace.name },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
await writeFile(join(author, "thoth-workspaces.yaml"), yamlStringify(catalog, { lineWidth: 0, sortMapEntries: false }));
|
await writeFile(join(author, "thoth-workspaces.yaml"), yamlStringify(catalog, { lineWidth: 0, sortMapEntries: false }));
|
||||||
@@ -688,8 +688,8 @@ async function initializeGitAndRegistry(ctx) {
|
|||||||
await writeFile(join(author, "workspace-docs", pathId, "contract.env.example"), docs.envExample);
|
await writeFile(join(author, "workspace-docs", pathId, "contract.env.example"), docs.envExample);
|
||||||
await writeFile(join(author, "workspace-docs", pathId, "README.md"), docs.markdown);
|
await writeFile(join(author, "workspace-docs", pathId, "README.md"), docs.markdown);
|
||||||
}
|
}
|
||||||
await mkdir(join(author, "p3-filesystem", "evidence"), { recursive: true });
|
await mkdir(join(author, "p2-filesystem", "evidence"), { recursive: true });
|
||||||
await writeFile(join(author, "p3-filesystem", "evidence", "guide.md"), "# P2 Filesystem Evidence\n\nCommitted fixture.\n");
|
await writeFile(join(author, "p2-filesystem", "evidence", "guide.md"), "# P2 Filesystem Evidence\n\nCommitted fixture.\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
await writeWorkspaces();
|
await writeWorkspaces();
|
||||||
@@ -714,9 +714,9 @@ async function initializeGitAndRegistry(ctx) {
|
|||||||
|
|
||||||
async function mutateWorkspaceDescriptor(ctx, workspaceId, mutator, commitMessage) {
|
async function mutateWorkspaceDescriptor(ctx, workspaceId, mutator, commitMessage) {
|
||||||
const author = join(ctx.run.root, "author");
|
const author = join(ctx.run.root, "author");
|
||||||
const workspace = structuredClone(ctx.workspaceObjects[workspaceId === "p3-dwh" ? "dwh" : "filesystem"]);
|
const workspace = structuredClone(ctx.workspaceObjects[workspaceId === "p2-dwh" ? "dwh" : "filesystem"]);
|
||||||
mutator(workspace);
|
mutator(workspace);
|
||||||
ctx.workspaceObjects[workspaceId === "p3-dwh" ? "dwh" : "filesystem"] = workspace;
|
ctx.workspaceObjects[workspaceId === "p2-dwh" ? "dwh" : "filesystem"] = workspace;
|
||||||
await writeFile(join(author, workspaceId, "workspace.yaml"), descriptorYaml(workspace));
|
await writeFile(join(author, workspaceId, "workspace.yaml"), descriptorYaml(workspace));
|
||||||
const docs = ctx.workspaceModules.renderWorkspaceDocs(workspace);
|
const docs = ctx.workspaceModules.renderWorkspaceDocs(workspace);
|
||||||
await writeFile(join(author, "workspace-docs", workspaceId, "contract.env.example"), docs.envExample);
|
await writeFile(join(author, "workspace-docs", workspaceId, "contract.env.example"), docs.envExample);
|
||||||
@@ -741,11 +741,11 @@ async function writeInstallationFiles(ctx) {
|
|||||||
const bindings = [
|
const bindings = [
|
||||||
`THT_WS_P2_DWH_DWH_TRANSPORT=rest_api`,
|
`THT_WS_P2_DWH_DWH_TRANSPORT=rest_api`,
|
||||||
`THT_WS_P2_DWH_DWH_BASE_URL=http://host.docker.internal:${ctx.fixturePorts.dwh}`,
|
`THT_WS_P2_DWH_DWH_BASE_URL=http://host.docker.internal:${ctx.fixturePorts.dwh}`,
|
||||||
`THT_WS_P2_DWH_DWH_API_KEY_FILE=/run/secrets/p3-dwh-api-key`,
|
`THT_WS_P2_DWH_DWH_API_KEY_FILE=/run/secrets/p2-dwh-api-key`,
|
||||||
`THT_WS_P2_DWH_EVIDENCE_SIGNED_URLS_FILE=/run/secrets/p3-dwh-evidence-signed-urls`,
|
`THT_WS_P2_DWH_EVIDENCE_SIGNED_URLS_FILE=/run/secrets/p2-dwh-evidence-signed-urls`,
|
||||||
`THT_WS_P2_FILESYSTEM_DWH_TRANSPORT=rest_api`,
|
`THT_WS_P2_FILESYSTEM_DWH_TRANSPORT=rest_api`,
|
||||||
`THT_WS_P2_FILESYSTEM_DWH_BASE_URL=http://host.docker.internal:${ctx.fixturePorts.dwh}`,
|
`THT_WS_P2_FILESYSTEM_DWH_BASE_URL=http://host.docker.internal:${ctx.fixturePorts.dwh}`,
|
||||||
`THT_WS_P2_FILESYSTEM_DWH_API_KEY_FILE=/run/secrets/p3-filesystem-api-key`,
|
`THT_WS_P2_FILESYSTEM_DWH_API_KEY_FILE=/run/secrets/p2-filesystem-api-key`,
|
||||||
].join("\n") + "\n";
|
].join("\n") + "\n";
|
||||||
await atomicWrite(bindingsEnvPath, bindings);
|
await atomicWrite(bindingsEnvPath, bindings);
|
||||||
const operatorEnv = [
|
const operatorEnv = [
|
||||||
@@ -1127,8 +1127,8 @@ async function realChecks(ctx) {
|
|||||||
await startServers(ctx);
|
await startServers(ctx);
|
||||||
await initializeGitAndRegistry(ctx);
|
await initializeGitAndRegistry(ctx);
|
||||||
await startQdrant(ctx);
|
await startQdrant(ctx);
|
||||||
await preprovisionCollection(ctx, "p3-dwh");
|
await preprovisionCollection(ctx, "p2-dwh");
|
||||||
await preprovisionCollection(ctx, "p3-filesystem");
|
await preprovisionCollection(ctx, "p2-filesystem");
|
||||||
state.collectionsBefore = await listCollections(ctx);
|
state.collectionsBefore = await listCollections(ctx);
|
||||||
state.runningServices = await assertNoCoreFrontendRunning(ctx);
|
state.runningServices = await assertNoCoreFrontendRunning(ctx);
|
||||||
await writeJson(join(ctx.run.root, "logs", "collections-before.json"), state.collectionsBefore);
|
await writeJson(join(ctx.run.root, "logs", "collections-before.json"), state.collectionsBefore);
|
||||||
@@ -1147,12 +1147,12 @@ async function realChecks(ctx) {
|
|||||||
{
|
{
|
||||||
id: "effective_config_identity",
|
id: "effective_config_identity",
|
||||||
async run() {
|
async run() {
|
||||||
const response = await runThothctlJson(ctx, "inspect-p3-dwh", ["workspace", "inspect", "--workspace", "p3-dwh"], 0);
|
const response = await runThothctlJson(ctx, "inspect-p2-dwh", ["workspace", "inspect", "--workspace", "p2-dwh"], 0);
|
||||||
assert(typeof response.payload.effectiveConfigIdentity === "string" && response.payload.effectiveConfigIdentity.startsWith("workspace://p3-dwh@v1:"), "effective config identity missing");
|
assert(typeof response.payload.effectiveConfigIdentity === "string" && response.payload.effectiveConfigIdentity.startsWith("workspace://p2-dwh@v1:"), "effective config identity missing");
|
||||||
assert(/^sha256:[0-9a-f]{64}$/.test(response.payload.configFingerprint ?? ""), "config fingerprint missing");
|
assert(/^sha256:[0-9a-f]{64}$/.test(response.payload.configFingerprint ?? ""), "config fingerprint missing");
|
||||||
assert(/^sha256:[0-9a-f]{64}$/.test(response.payload.inputFingerprint ?? ""), "input fingerprint missing");
|
assert(/^sha256:[0-9a-f]{64}$/.test(response.payload.inputFingerprint ?? ""), "input fingerprint missing");
|
||||||
const snapshot = await loadWorkspaceSnapshot(ctx, "p3-dwh");
|
const snapshot = await loadWorkspaceSnapshot(ctx, "p2-dwh");
|
||||||
assert(response.payload.workspaceId === "p3-dwh", "inspect workspace id mismatch");
|
assert(response.payload.workspaceId === "p2-dwh", "inspect workspace id mismatch");
|
||||||
assert(response.payload.workspaceRevision === snapshot.active.head, "inspect revision mismatch");
|
assert(response.payload.workspaceRevision === snapshot.active.head, "inspect revision mismatch");
|
||||||
assert(`sha256:${sha256(snapshot.contents)}` === response.payload.descriptorBlob, "inspect descriptor mismatch");
|
assert(`sha256:${sha256(snapshot.contents)}` === response.payload.descriptorBlob, "inspect descriptor mismatch");
|
||||||
state.inspect = response.payload;
|
state.inspect = response.payload;
|
||||||
@@ -1162,10 +1162,10 @@ async function realChecks(ctx) {
|
|||||||
{
|
{
|
||||||
id: "dwh_processing",
|
id: "dwh_processing",
|
||||||
async run() {
|
async run() {
|
||||||
const first = await runThothctlJson(ctx, "preprocess-dwh-first", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh"], 0);
|
const first = await runThothctlJson(ctx, "preprocess-dwh-first", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh"], 0);
|
||||||
assert(first.payload.status === "succeeded" && first.payload.code === "ok", "dwh first run failed");
|
assert(first.payload.status === "succeeded" && first.payload.code === "ok", "dwh first run failed");
|
||||||
const rerun = await runThothctlJson(ctx, "preprocess-dwh-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh"], 0);
|
const rerun = await runThothctlJson(ctx, "preprocess-dwh-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh"], 0);
|
||||||
const resume = await runThothctlJson(ctx, "preprocess-dwh-resume", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh", "--resume", first.payload.runId], 0);
|
const resume = await runThothctlJson(ctx, "preprocess-dwh-resume", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh", "--resume", first.payload.runId], 0);
|
||||||
assert(["unchanged", "succeeded"].includes(rerun.payload.status), "dwh rerun not idempotent");
|
assert(["unchanged", "succeeded"].includes(rerun.payload.status), "dwh rerun not idempotent");
|
||||||
assert(["unchanged", "succeeded"].includes(resume.payload.status), "dwh resume failed");
|
assert(["unchanged", "succeeded"].includes(resume.payload.status), "dwh resume failed");
|
||||||
state.dwhRunId = first.payload.runId;
|
state.dwhRunId = first.payload.runId;
|
||||||
@@ -1177,34 +1177,34 @@ async function realChecks(ctx) {
|
|||||||
async run() {
|
async run() {
|
||||||
// FK suggestion consumes the workspace's own introspected physical schema and mines
|
// FK suggestion consumes the workspace's own introspected physical schema and mines
|
||||||
// approved SQL joins for candidates.
|
// approved SQL joins for candidates.
|
||||||
await runThothctlJson(ctx, "preprocess-dwh-filesystem", ["workspace", "preprocess", "dwh", "--workspace", "p3-filesystem"], 0);
|
await runThothctlJson(ctx, "preprocess-dwh-filesystem", ["workspace", "preprocess", "dwh", "--workspace", "p2-filesystem"], 0);
|
||||||
const sqlPath = join(ctx.run.root, "fixtures", "p3-filesystem.sql");
|
const sqlPath = join(ctx.run.root, "fixtures", "p2-filesystem.sql");
|
||||||
await atomicWrite(sqlPath, "SELECT v.id FROM dw.visits v JOIN dw.patients p ON v.patient_id = p.patient_id\n");
|
await atomicWrite(sqlPath, "SELECT v.id FROM dw.visits v JOIN dw.patients p ON v.patient_id = p.patient_id\n");
|
||||||
const suggest = await runThothctlJson(ctx, "schema-suggest-filesystem", ["workspace", "schema", "suggest-fks", "--workspace", "p3-filesystem", "--from-sql", sqlPath], 3);
|
const suggest = await runThothctlJson(ctx, "schema-suggest-filesystem", ["workspace", "schema", "suggest-fks", "--workspace", "p2-filesystem", "--from-sql", sqlPath], 3);
|
||||||
assert(suggest.payload.code === "manual_review_required", "suggest did not block");
|
assert(suggest.payload.code === "manual_review_required", "suggest did not block");
|
||||||
assert(typeof suggest.payload.suggestedFksYaml === "string" && suggest.payload.suggestedFksYaml.length > 0, "suggested FK YAML missing");
|
assert(typeof suggest.payload.suggestedFksYaml === "string" && suggest.payload.suggestedFksYaml.length > 0, "suggested FK YAML missing");
|
||||||
const digest = suggest.payload.artifactIdentities?.[0]?.digest;
|
const digest = suggest.payload.artifactIdentities?.[0]?.digest;
|
||||||
assert(/^sha256:[0-9a-f]{64}$/.test(digest ?? ""), "candidate digest missing");
|
assert(/^sha256:[0-9a-f]{64}$/.test(digest ?? ""), "candidate digest missing");
|
||||||
const candidatePath = join(ctx.run.root, "fixtures", "p3-filesystem.candidates.yaml");
|
const candidatePath = join(ctx.run.root, "fixtures", "p2-filesystem.candidates.yaml");
|
||||||
await atomicWrite(candidatePath, suggest.payload.suggestedFksYaml);
|
await atomicWrite(candidatePath, suggest.payload.suggestedFksYaml);
|
||||||
assert(`sha256:${sha256(suggest.payload.suggestedFksYaml)}` === digest, "candidate digest mismatch");
|
assert(`sha256:${sha256(suggest.payload.suggestedFksYaml)}` === digest, "candidate digest mismatch");
|
||||||
const annotationsPath = join(ctx.run.root, "fixtures", "p3-filesystem.annotations.yaml");
|
const annotationsPath = join(ctx.run.root, "fixtures", "p2-filesystem.annotations.yaml");
|
||||||
await atomicWrite(annotationsPath, "tables: {}\n");
|
await atomicWrite(annotationsPath, "tables: {}\n");
|
||||||
const checked = await runThothctlJson(ctx, "schema-check-filesystem", [
|
const checked = await runThothctlJson(ctx, "schema-check-filesystem", [
|
||||||
"workspace", "schema", "check", "--workspace", "p3-filesystem",
|
"workspace", "schema", "check", "--workspace", "p2-filesystem",
|
||||||
"--annotations", annotationsPath,
|
"--annotations", annotationsPath,
|
||||||
"--reviewed-candidates", digest,
|
"--reviewed-candidates", digest,
|
||||||
], 0);
|
], 0);
|
||||||
assert(checked.payload.status === "succeeded", "schema check failed");
|
assert(checked.payload.status === "succeeded", "schema check failed");
|
||||||
state.filesystemCandidateDigest = digest;
|
state.filesystemCandidateDigest = digest;
|
||||||
return { commands: ["thothctl"], artifacts: [...suggest.artifacts, ...checked.artifacts, await fileArtifact(ctx.run.root, "fixtures/p3-filesystem.candidates.yaml"), await fileArtifact(ctx.run.root, "fixtures/p3-filesystem.annotations.yaml"), await fileArtifact(ctx.run.root, "fixtures/p3-filesystem.sql")] };
|
return { commands: ["thothctl"], artifacts: [...suggest.artifacts, ...checked.artifacts, await fileArtifact(ctx.run.root, "fixtures/p2-filesystem.candidates.yaml"), await fileArtifact(ctx.run.root, "fixtures/p2-filesystem.annotations.yaml"), await fileArtifact(ctx.run.root, "fixtures/p2-filesystem.sql")] };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "schema_index",
|
id: "schema_index",
|
||||||
async run() {
|
async run() {
|
||||||
const first = await runThothctlJson(ctx, "index-schema-filesystem", ["workspace", "index-schema", "--workspace", "p3-filesystem"], 0);
|
const first = await runThothctlJson(ctx, "index-schema-filesystem", ["workspace", "index-schema", "--workspace", "p2-filesystem"], 0);
|
||||||
const second = await runThothctlJson(ctx, "index-schema-filesystem-rerun", ["workspace", "index-schema", "--workspace", "p3-filesystem"], 0);
|
const second = await runThothctlJson(ctx, "index-schema-filesystem-rerun", ["workspace", "index-schema", "--workspace", "p2-filesystem"], 0);
|
||||||
assert(["succeeded", "unchanged"].includes(first.payload.status), "index schema first failed");
|
assert(["succeeded", "unchanged"].includes(first.payload.status), "index schema first failed");
|
||||||
assert(["unchanged", "succeeded"].includes(second.payload.status), "index schema rerun failed");
|
assert(["unchanged", "succeeded"].includes(second.payload.status), "index schema rerun failed");
|
||||||
return { commands: ["thothctl"], artifacts: [...first.artifacts, ...second.artifacts] };
|
return { commands: ["thothctl"], artifacts: [...first.artifacts, ...second.artifacts] };
|
||||||
@@ -1215,27 +1215,27 @@ async function realChecks(ctx) {
|
|||||||
async run() {
|
async run() {
|
||||||
// Full-run FK checkpoint: the filesystem workspace already has mined FK candidates,
|
// Full-run FK checkpoint: the filesystem workspace already has mined FK candidates,
|
||||||
// so a full run must stop for human review before schema/Evidence writes.
|
// so a full run must stop for human review before schema/Evidence writes.
|
||||||
const full = await runThothctlJson(ctx, "preprocess-run-fs-blocked", ["workspace", "preprocess", "run", "--workspace", "p3-filesystem"], 3);
|
const full = await runThothctlJson(ctx, "preprocess-run-fs-blocked", ["workspace", "preprocess", "run", "--workspace", "p2-filesystem"], 3);
|
||||||
assert(full.payload.code === "manual_review_required", "full run did not block for review");
|
assert(full.payload.code === "manual_review_required", "full run did not block for review");
|
||||||
const digest = full.payload.artifactIdentities?.[0]?.digest;
|
const digest = full.payload.artifactIdentities?.[0]?.digest;
|
||||||
assert(/^sha256:[0-9a-f]{64}$/.test(digest ?? ""), "full run digest missing");
|
assert(/^sha256:[0-9a-f]{64}$/.test(digest ?? ""), "full run digest missing");
|
||||||
const reviewPath = join(ctx.run.root, "fixtures", "p3-filesystem.full-annotations.yaml");
|
const reviewPath = join(ctx.run.root, "fixtures", "p2-filesystem.full-annotations.yaml");
|
||||||
await atomicWrite(reviewPath, "tables: {}\n");
|
await atomicWrite(reviewPath, "tables: {}\n");
|
||||||
const reviewed = await runThothctlJson(ctx, "schema-check-fs-full", [
|
const reviewed = await runThothctlJson(ctx, "schema-check-fs-full", [
|
||||||
"workspace", "schema", "check", "--workspace", "p3-filesystem",
|
"workspace", "schema", "check", "--workspace", "p2-filesystem",
|
||||||
"--annotations", reviewPath,
|
"--annotations", reviewPath,
|
||||||
"--reviewed-candidates", digest,
|
"--reviewed-candidates", digest,
|
||||||
], 0);
|
], 0);
|
||||||
assert(reviewed.payload.status === "succeeded", "full-run review failed");
|
assert(reviewed.payload.status === "succeeded", "full-run review failed");
|
||||||
// Resume continues through index-schema and stops at filesystem Evidence materialization.
|
// Resume continues through index-schema and stops at filesystem Evidence materialization.
|
||||||
const resumed = await runThothctlJson(ctx, "preprocess-run-fs-resume", ["workspace", "preprocess", "run", "--workspace", "p3-filesystem", "--resume", full.payload.runId], 3);
|
const resumed = await runThothctlJson(ctx, "preprocess-run-fs-resume", ["workspace", "preprocess", "run", "--workspace", "p2-filesystem", "--resume", full.payload.runId], 3);
|
||||||
assert(resumed.payload.code === "evidence_materialization_required", "filesystem evidence did not block after review");
|
assert(resumed.payload.code === "evidence_materialization_required", "filesystem evidence did not block after review");
|
||||||
// HTTP Evidence on the p3-dwh workspace: dry-run, publish, unchanged rerun, mutation.
|
// HTTP Evidence on the p2-dwh workspace: dry-run, publish, unchanged rerun, mutation.
|
||||||
const dryRun = await runThothctlJson(ctx, "preprocess-evidence-dry-run", ["workspace", "preprocess", "evidence", "--workspace", "p3-dwh", "--dry-run"], 0);
|
const dryRun = await runThothctlJson(ctx, "preprocess-evidence-dry-run", ["workspace", "preprocess", "evidence", "--workspace", "p2-dwh", "--dry-run"], 0);
|
||||||
const publish = await runThothctlJson(ctx, "preprocess-evidence-publish", ["workspace", "preprocess", "evidence", "--workspace", "p3-dwh"], 0);
|
const publish = await runThothctlJson(ctx, "preprocess-evidence-publish", ["workspace", "preprocess", "evidence", "--workspace", "p2-dwh"], 0);
|
||||||
const rerun = await runThothctlJson(ctx, "preprocess-evidence-rerun", ["workspace", "preprocess", "evidence", "--workspace", "p3-dwh"], 0);
|
const rerun = await runThothctlJson(ctx, "preprocess-evidence-rerun", ["workspace", "preprocess", "evidence", "--workspace", "p2-dwh"], 0);
|
||||||
ctx.evidenceState.content = "# P2 Evidence\n\nSecond generation.\n";
|
ctx.evidenceState.content = "# P2 Evidence\n\nSecond generation.\n";
|
||||||
const mutated = await runThothctlJson(ctx, "preprocess-evidence-mutated", ["workspace", "preprocess", "evidence", "--workspace", "p3-dwh"], 0);
|
const mutated = await runThothctlJson(ctx, "preprocess-evidence-mutated", ["workspace", "preprocess", "evidence", "--workspace", "p2-dwh"], 0);
|
||||||
state.fullRunId = full.payload.runId;
|
state.fullRunId = full.payload.runId;
|
||||||
return { commands: ["thothctl"], artifacts: [
|
return { commands: ["thothctl"], artifacts: [
|
||||||
...full.artifacts, ...reviewed.artifacts, ...resumed.artifacts, ...dryRun.artifacts,
|
...full.artifacts, ...reviewed.artifacts, ...resumed.artifacts, ...dryRun.artifacts,
|
||||||
@@ -1247,8 +1247,8 @@ async function realChecks(ctx) {
|
|||||||
id: "content_only_reuse",
|
id: "content_only_reuse",
|
||||||
async run() {
|
async run() {
|
||||||
// A content-only Evidence change must NOT invalidate the prepared DWH generation.
|
// A content-only Evidence change must NOT invalidate the prepared DWH generation.
|
||||||
await mutateWorkspaceDescriptor(ctx, "p3-dwh", () => { ctx.evidenceState.content = "# P2 Evidence\n\nThird generation (content-only).\n"; }, "Content-only Evidence change");
|
await mutateWorkspaceDescriptor(ctx, "p2-dwh", () => { ctx.evidenceState.content = "# P2 Evidence\n\nThird generation (content-only).\n"; }, "Content-only Evidence change");
|
||||||
const rerun = await runThothctlJson(ctx, "p3-content-only-dwh-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh"], 0);
|
const rerun = await runThothctlJson(ctx, "p3-content-only-dwh-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh"], 0);
|
||||||
assert(rerun.payload.status === "unchanged", `content-only change forced DWH introspection: ${rerun.payload.status}`);
|
assert(rerun.payload.status === "unchanged", `content-only change forced DWH introspection: ${rerun.payload.status}`);
|
||||||
return { commands: ["thothctl"], artifacts: [...rerun.artifacts] };
|
return { commands: ["thothctl"], artifacts: [...rerun.artifacts] };
|
||||||
},
|
},
|
||||||
@@ -1256,11 +1256,11 @@ async function realChecks(ctx) {
|
|||||||
{
|
{
|
||||||
id: "dwh_change_fail_closed",
|
id: "dwh_change_fail_closed",
|
||||||
async run() {
|
async run() {
|
||||||
const before = await runThothctlJson(ctx, "p3-dwh-before-change", ["workspace", "inspect", "--workspace", "p3-dwh"], 0);
|
const before = await runThothctlJson(ctx, "p2-dwh-before-change", ["workspace", "inspect", "--workspace", "p2-dwh"], 0);
|
||||||
await mutateWorkspaceDescriptor(ctx, "p3-dwh", (workspace) => { workspace.dwh.schema = "dw2"; }, "Change DWH schema");
|
await mutateWorkspaceDescriptor(ctx, "p2-dwh", (workspace) => { workspace.dwh.schema = "dw2"; }, "Change DWH schema");
|
||||||
const after = await runThothctlJson(ctx, "p3-dwh-after-change", ["workspace", "inspect", "--workspace", "p3-dwh"], 0);
|
const after = await runThothctlJson(ctx, "p2-dwh-after-change", ["workspace", "inspect", "--workspace", "p2-dwh"], 0);
|
||||||
assert(before.payload.configFingerprint !== after.payload.configFingerprint, "DWH-affecting change kept the same config fingerprint");
|
assert(before.payload.configFingerprint !== after.payload.configFingerprint, "DWH-affecting change kept the same config fingerprint");
|
||||||
const rerun = await runThothctlJson(ctx, "p3-dwh-change-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh"], 0);
|
const rerun = await runThothctlJson(ctx, "p2-dwh-change-rerun", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh"], 0);
|
||||||
assert(["succeeded", "unchanged"].includes(rerun.payload.status), "DWH-affecting change did not regenerate");
|
assert(["succeeded", "unchanged"].includes(rerun.payload.status), "DWH-affecting change did not regenerate");
|
||||||
return { commands: ["thothctl"], artifacts: [...before.artifacts, ...after.artifacts, ...rerun.artifacts] };
|
return { commands: ["thothctl"], artifacts: [...before.artifacts, ...after.artifacts, ...rerun.artifacts] };
|
||||||
},
|
},
|
||||||
@@ -1268,7 +1268,7 @@ async function realChecks(ctx) {
|
|||||||
{
|
{
|
||||||
id: "memory_root",
|
id: "memory_root",
|
||||||
async run() {
|
async run() {
|
||||||
const manifests = join(ctx.run.root, "installation", "data", "sessions", "p3-dwh", "preprocessing", "runtime-config-manifests");
|
const manifests = join(ctx.run.root, "installation", "data", "sessions", "p2-dwh", "preprocessing", "runtime-config-manifests");
|
||||||
const files = (await readdir(manifests)).filter((name) => name.endsWith(".json"));
|
const files = (await readdir(manifests)).filter((name) => name.endsWith(".json"));
|
||||||
assert(files.length > 0, "no runtime config manifest");
|
assert(files.length > 0, "no runtime config manifest");
|
||||||
const manifest = JSON.parse(await readFile(join(manifests, files[0]), "utf8"));
|
const manifest = JSON.parse(await readFile(join(manifests, files[0]), "utf8"));
|
||||||
@@ -1281,7 +1281,7 @@ async function realChecks(ctx) {
|
|||||||
{
|
{
|
||||||
id: "revision_scoped_records",
|
id: "revision_scoped_records",
|
||||||
async run() {
|
async run() {
|
||||||
const collection = "p3-dwh";
|
const collection = "p2-dwh";
|
||||||
const base = `http://127.0.0.1:${ctx.fixturePorts.qdrant}`;
|
const base = `http://127.0.0.1:${ctx.fixturePorts.qdrant}`;
|
||||||
const scroll = await fetch(`${base}/collections/${collection}/points/scroll?limit=200`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ with_payload: true, with_vector: false }) });
|
const scroll = await fetch(`${base}/collections/${collection}/points/scroll?limit=200`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ with_payload: true, with_vector: false }) });
|
||||||
const body = await scroll.json();
|
const body = await scroll.json();
|
||||||
@@ -1298,17 +1298,17 @@ async function realChecks(ctx) {
|
|||||||
id: "negative_cases",
|
id: "negative_cases",
|
||||||
async run() {
|
async run() {
|
||||||
const missing = await runThothctlJson(ctx, "negative-missing-workspace", ["workspace", "inspect", "--workspace", "missing-workspace"], 1);
|
const missing = await runThothctlJson(ctx, "negative-missing-workspace", ["workspace", "inspect", "--workspace", "missing-workspace"], 1);
|
||||||
const resumeMismatch = await runThothctlJson(ctx, "negative-resume-mismatch", ["workspace", "preprocess", "dwh", "--workspace", "p3-dwh", "--resume", "0".repeat(32)], 1);
|
const resumeMismatch = await runThothctlJson(ctx, "negative-resume-mismatch", ["workspace", "preprocess", "dwh", "--workspace", "p2-dwh", "--resume", "0".repeat(32)], 1);
|
||||||
const annotationInvalid = await runThothctlJson(ctx, "negative-annotation-invalid", [
|
const annotationInvalid = await runThothctlJson(ctx, "negative-annotation-invalid", [
|
||||||
"workspace", "schema", "check", "--workspace", "p3-filesystem",
|
"workspace", "schema", "check", "--workspace", "p2-filesystem",
|
||||||
"--annotations", join(ctx.run.root, "fixtures", "p3-filesystem.annotations.yaml"),
|
"--annotations", join(ctx.run.root, "fixtures", "p2-filesystem.annotations.yaml"),
|
||||||
"--reviewed-candidates", `sha256:${"0".repeat(64)}`,
|
"--reviewed-candidates", `sha256:${"0".repeat(64)}`,
|
||||||
], 1);
|
], 1);
|
||||||
await mutateWorkspaceDescriptor(ctx, "p3-dwh", (workspace) => { delete workspace.evidence; }, "Remove P2 Evidence");
|
await mutateWorkspaceDescriptor(ctx, "p2-dwh", (workspace) => { delete workspace.evidence; }, "Remove P2 Evidence");
|
||||||
const noEvidence = await runThothctlJson(ctx, "negative-no-evidence-run", ["workspace", "preprocess", "evidence", "--workspace", "p3-dwh"], 0);
|
const noEvidence = await runThothctlJson(ctx, "negative-no-evidence-run", ["workspace", "preprocess", "evidence", "--workspace", "p2-dwh"], 0);
|
||||||
assert(["succeeded", "unchanged"].includes(noEvidence.payload.status), "no-evidence evidence did not skip");
|
assert(["succeeded", "unchanged"].includes(noEvidence.payload.status), "no-evidence evidence did not skip");
|
||||||
assert(Array.isArray(noEvidence.payload.warnings) && noEvidence.payload.warnings.length > 0, "no-evidence warning missing");
|
assert(Array.isArray(noEvidence.payload.warnings) && noEvidence.payload.warnings.length > 0, "no-evidence warning missing");
|
||||||
const conflict = await runThothctlJson(ctx, "negative-revision-conflict", ["workspace", "preprocess", "run", "--workspace", "p3-dwh", "--resume", state.fullRunId], 1);
|
const conflict = await runThothctlJson(ctx, "negative-revision-conflict", ["workspace", "preprocess", "run", "--workspace", "p2-dwh", "--resume", state.fullRunId], 1);
|
||||||
const after = await listCollections(ctx);
|
const after = await listCollections(ctx);
|
||||||
assert(sameSet(after, state.collectionsBefore), "product path created or removed a collection");
|
assert(sameSet(after, state.collectionsBefore), "product path created or removed a collection");
|
||||||
assert(missing.payload.code === "workspace_not_activatable" || missing.payload.code === "workspace_not_found", "missing workspace code mismatch");
|
assert(missing.payload.code === "workspace_not_activatable" || missing.payload.code === "workspace_not_found", "missing workspace code mismatch");
|
||||||
@@ -1329,8 +1329,8 @@ async function realChecks(ctx) {
|
|||||||
id: "secret_scan",
|
id: "secret_scan",
|
||||||
async run() {
|
async run() {
|
||||||
const virtualFiles = [];
|
const virtualFiles = [];
|
||||||
const qdrantDump = await dumpQdrantPayloads(ctx, "p3-dwh");
|
const qdrantDump = await dumpQdrantPayloads(ctx, "p2-dwh");
|
||||||
if (Buffer.byteLength(qdrantDump) <= MAX_SECRET_SCAN_VIRTUAL_BYTES) virtualFiles.push({ path: "virtual/qdrant-p3-dwh.json", bytes: qdrantDump });
|
if (Buffer.byteLength(qdrantDump) <= MAX_SECRET_SCAN_VIRTUAL_BYTES) virtualFiles.push({ path: "virtual/qdrant-p2-dwh.json", bytes: qdrantDump });
|
||||||
const findings = await scanSecrets({
|
const findings = await scanSecrets({
|
||||||
runRoot: ctx.run.root,
|
runRoot: ctx.run.root,
|
||||||
forbiddenValues: ctx.forbiddenValues,
|
forbiddenValues: ctx.forbiddenValues,
|
||||||
|
|||||||
Reference in New Issue
Block a user