// The module's migrations are its own files, each exactly `schemaStatements()` over the entities it // added (decision AT-D20: the entity definition is the one source of a column). Forward-only: the // first file stays the run and step tables as first shipped; the second adds the step's recorded // tool result and the run's conversation table (`agent_thread`, TanStack AI's message store); the // third adds the run answer's provenance (EU AI Act Art. 50(2)). import { readFileSync } from "node:fs" import { AGENT_ENTITIES, agentRuns, agentSteps, agentThreads } from "@conusai-kit/agent" import { schemaStatements } from "@conusai-kit/data-kysely" import { describe, expect, it } from "vitest" import { agentModule } from "../index.js" function tablesOf(entities: Parameters[0]): string { const kernel = schemaStatements([]).length return `${schemaStatements(entities) .slice(kernel) .map((statement) => `${statement};`) .join("\n\n")}\n` } const migration = (name: string) => readFileSync(new URL(`../migrations/${name}`, import.meta.url), "utf8") const HEADER = "-- SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0\n" describe("the migrations of the agent module", () => { it("are the run and step tables as first shipped, then the step's result column", () => { const added = ',\n "result" jsonb\n' const provenance = ',\n "answer_provenance" jsonb\n' const generated = tablesOf([agentRuns, agentSteps]) expect(generated).toContain(added) expect(generated).toContain(provenance) expect(`${HEADER}${generated.replace(added, "\n").replace(provenance, "\n")}`).toBe(migration("0001_agent.sql")) expect(migration("0002_agent_thread.sql")).toContain( `${HEADER}alter table "agent_step" add column "result" jsonb;\n\n`, ) }) it("add the run's conversation table in the second file, exactly its table", async () => { await expect( `${HEADER}alter table "agent_step" add column "result" jsonb;\n\n${tablesOf([agentThreads])}`, ).toMatchFileSnapshot("../migrations/0002_agent_thread.sql") expect(AGENT_ENTITIES).toEqual([agentRuns, agentSteps, agentThreads]) }) it("add the run answer's provenance column in the third file, exactly that column", () => { expect(tablesOf([agentRuns])).toContain(',\n "answer_provenance" jsonb\n') expect(migration("0003_agent_answer_provenance.sql")).toBe( `${HEADER}alter table "agent_run" add column "answer_provenance" jsonb;\n`, ) }) it("are declared by the manifest, and every table is row-level secured", () => { expect(agentModule.migrations).toEqual({ postgres: "migrations" }) const sql = migration("0001_agent.sql") + migration("0002_agent_thread.sql") for (const table of ["agent_run", "agent_step", "agent_thread"]) { expect(sql).toContain(`create table "${table}"`) expect(sql).toContain(`alter table "${table}" force row level security`) } }) })