| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import { test } from "node:test"; |
| import assert from "node:assert/strict"; |
| import { eq } from "drizzle-orm"; |
|
|
| const SKIP = !process.env["DATABASE_URL"]; |
|
|
| test( |
| "dispatch-validation: ajv input_contract enforced + violations table", |
| { skip: SKIP && "DATABASE_URL not set" }, |
| async (t) => { |
| const { db, toolNetworks, networkVersions, networkDispatchViolations } = |
| await import("@workspace/db"); |
| const tn = await import("../tool-network.ts"); |
| const { newId } = await import("../ids.ts"); |
|
|
| const networkName = `b1_validation_${Math.random().toString(16).slice(2, 8)}`; |
| const inputContract = { |
| type: "object", |
| required: ["q", "top_k"], |
| properties: { |
| q: { type: "string" }, |
| top_k: { type: "integer", minimum: 1, maximum: 100 }, |
| }, |
| additionalProperties: false, |
| }; |
|
|
| |
| const networkId = newId("tnet"); |
| const variantId = newId("nver"); |
| await db.insert(toolNetworks).values({ |
| id: networkId, |
| name: networkName, |
| problemClassPath: "ligand.screening.binding", |
| description: "B1 dispatch-validation fixture", |
| inputContract, |
| outputContract: { type: "object" }, |
| internalGraph: { nodes: ["echo"] }, |
| capabilityTags: [], |
| builderModelTier: "strong", |
| status: "active", |
| }); |
| await db.insert(networkVersions).values({ |
| id: variantId, |
| networkId, |
| versionLabel: "v1", |
| internalGraph: { nodes: ["echo"] }, |
| config: {}, |
| status: "active", |
| builtBy: "system", |
| builderModelTier: "strong", |
| }); |
| await db |
| .update(toolNetworks) |
| .set({ activeVariantId: variantId }) |
| .where(eq(toolNetworks.id, networkId)); |
|
|
| |
| tn.registerNetworkRunner(networkName, async () => ({ |
| output: { ok: true }, |
| steps: [], |
| durationMs: 1, |
| })); |
|
|
| |
| const prev = process.env["DOATLAS_INPUT_CONTRACT_ENFORCE"]; |
| process.env["DOATLAS_INPUT_CONTRACT_ENFORCE"] = "true"; |
|
|
| t.after(async () => { |
| if (prev === undefined) delete process.env["DOATLAS_INPUT_CONTRACT_ENFORCE"]; |
| else process.env["DOATLAS_INPUT_CONTRACT_ENFORCE"] = prev; |
| await db.delete(networkDispatchViolations).where(eq(networkDispatchViolations.networkName, networkName)); |
| await db.update(toolNetworks).set({ activeVariantId: null }).where(eq(toolNetworks.id, networkId)); |
| await db.delete(networkVersions).where(eq(networkVersions.id, variantId)); |
| await db.delete(toolNetworks).where(eq(toolNetworks.id, networkId)); |
| }); |
|
|
| await t.test("legal args → matched, no violation row", async () => { |
| const r = await tn.dispatchNetworkTool( |
| `run_${networkName}`, |
| { q: "egfr", top_k: 10 }, |
| undefined, |
| 0, |
| ); |
| assert.equal(r.matched, true); |
| assert.equal(r.error, undefined); |
| const rows = await db |
| .select() |
| .from(networkDispatchViolations) |
| .where(eq(networkDispatchViolations.networkName, networkName)); |
| assert.equal(rows.length, 0, "no violation row for legal args"); |
| }); |
|
|
| await t.test("missing required field → INPUT_CONTRACT_VIOLATION", async () => { |
| const r = await tn.dispatchNetworkTool( |
| `run_${networkName}`, |
| { q: "egfr" }, |
| undefined, |
| 0, |
| ); |
| assert.equal(r.matched, true); |
| assert.ok(r.error, "must report error"); |
| assert.equal(r.error!.error_code, "INPUT_CONTRACT_VIOLATION"); |
| assert.match(r.error!.error, /top_k|required/); |
| }); |
|
|
| await t.test("wrong type → INPUT_CONTRACT_VIOLATION", async () => { |
| const r = await tn.dispatchNetworkTool( |
| `run_${networkName}`, |
| { q: 123, top_k: 5 }, |
| undefined, |
| 0, |
| ); |
| assert.equal(r.matched, true); |
| assert.equal(r.error?.error_code, "INPUT_CONTRACT_VIOLATION"); |
| }); |
|
|
| await t.test("additional property → INPUT_CONTRACT_VIOLATION", async () => { |
| const r = await tn.dispatchNetworkTool( |
| `run_${networkName}`, |
| { q: "x", top_k: 10, extra: true }, |
| undefined, |
| 0, |
| ); |
| assert.equal(r.matched, true); |
| assert.equal(r.error?.error_code, "INPUT_CONTRACT_VIOLATION"); |
| }); |
|
|
| await t.test("violations rows accumulate", async () => { |
| const rows = await db |
| .select() |
| .from(networkDispatchViolations) |
| .where(eq(networkDispatchViolations.networkName, networkName)); |
| assert.ok(rows.length >= 3, `expected ≥3 violations, got ${rows.length}`); |
| assert.ok(rows.every((r) => r.mode === "enforced")); |
| }); |
|
|
| await t.test("observed_only mode falls through and still dispatches", async () => { |
| process.env["DOATLAS_INPUT_CONTRACT_ENFORCE"] = "false"; |
| const r = await tn.dispatchNetworkTool( |
| `run_${networkName}`, |
| { q: 999, top_k: "no" }, |
| undefined, |
| 0, |
| ); |
| assert.equal(r.matched, true); |
| |
| assert.equal(r.error, undefined); |
| assert.ok(r.result, "runner result returned in observed_only mode"); |
| const rows = await db |
| .select() |
| .from(networkDispatchViolations) |
| .where(eq(networkDispatchViolations.networkName, networkName)); |
| assert.ok(rows.some((r) => r.mode === "observed_only")); |
| }); |
| }, |
| ); |
|
|