fix: generate FK candidates through the full run before schema accept (P5)

This commit is contained in:
2026-08-13 11:38:00 +02:00
parent 239d1c634f
commit ccc3dc772e
+10 -16
View File
@@ -1216,30 +1216,24 @@ async function realChecks(ctx) {
{ {
id: "accept_happy_path", id: "accept_happy_path",
async run() { async run() {
// 1) introspect the physical schema, then mine FK candidates from SQL. // 1) a fresh full run introspects the DWH, mines FK candidates, and blocks for review.
await runThothctlJson(ctx, "preprocess-dwh-filesystem", ["workspace", "preprocess", "dwh", "--workspace", "p2-filesystem"], 0); const full = await runThothctlJson(ctx, "preprocess-run-fs-blocked", ["workspace", "preprocess", "run", "--workspace", "p2-filesystem"], 3);
const sqlPath = join(ctx.run.root, "fixtures", "p2-filesystem.sql"); assert(full.payload.code === "manual_review_required", `full run did not block: ${full.payload.code}`);
await atomicWrite(sqlPath, "SELECT v.id FROM dw.visits v JOIN dw.patients p ON v.patient_id = p.patient_id\n"); const digest = full.payload.artifactIdentities?.[0]?.digest;
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(typeof suggest.payload.suggestedFksYaml === "string" && suggest.payload.suggestedFksYaml.length > 0, "suggested FK YAML missing");
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");
assert(`sha256:${sha256(suggest.payload.suggestedFksYaml)}` === digest, "candidate digest mismatch"); state.runId = full.payload.runId;
state.runId = suggest.payload.runId; assert(/^[0-9a-f]{32}$/.test(state.runId ?? ""), "run id missing");
assert(/^[0-9a-f]{32}$/.test(state.runId ?? ""), "suggest run id missing");
// 2) The curator's reviewed blob is already the committed empty set (no approved FKs); the // 2) the operator records the human review with the explicit accept command.
// operator records the human review with the explicit accept command.
const accepted = await runThothctlJson(ctx, "schema-accept-filesystem", ["workspace", "schema", "accept", "--workspace", "p2-filesystem", "--run", state.runId, "--yes"], 0); const accepted = await runThothctlJson(ctx, "schema-accept-filesystem", ["workspace", "schema", "accept", "--workspace", "p2-filesystem", "--run", state.runId, "--yes"], 0);
assert(accepted.payload.status === "succeeded" && accepted.payload.code === "ok", "schema accept failed"); assert(accepted.payload.status === "succeeded" && accepted.payload.code === "ok", "schema accept failed");
assert(Array.isArray(accepted.payload.artifactIdentities), "accept artifact identities missing"); assert(Array.isArray(accepted.payload.artifactIdentities), "accept artifact identities missing");
// 3) Same-revision resume continues through the FK gate and stops at filesystem Evidence. // 3) same-revision resume continues through the FK gate and stops at filesystem Evidence.
const resumed = await runThothctlJson(ctx, "preprocess-run-fs-resume", ["workspace", "preprocess", "run", "--workspace", "p2-filesystem", "--resume", state.runId], 3); const resumed = await runThothctlJson(ctx, "preprocess-run-fs-resume", ["workspace", "preprocess", "run", "--workspace", "p2-filesystem", "--resume", state.runId], 3);
assert(resumed.payload.code === "evidence_materialization_required", "resume did not pass the FK gate and block on filesystem Evidence"); assert(resumed.payload.code === "evidence_materialization_required", `resume code mismatch: ${resumed.payload.code}`);
state.acceptedCommit = state.initialCommit; state.acceptedCommit = state.initialCommit;
return { commands: ["thothctl"], artifacts: [...suggest.artifacts, ...accepted.artifacts, ...resumed.artifacts, await fileArtifact(ctx.run.root, "fixtures/p2-filesystem.sql")] }; return { commands: ["thothctl"], artifacts: [...full.artifacts, ...accepted.artifacts, ...resumed.artifacts] };
}, },
}, },
{ {