/** * The page tools, executed against a real Postgres. * * `test/chat-tools.test.ts` passes `{} as Database` and asserts on tool names, * which is the right shape for a selection test and no shape at all for the * five `execute` bodies underneath: every where clause, every `Number(gpuHours)` * coercion and every date comparison was covered by tsc alone. The defect that * prompted this suite — a headline quoting `list.length` from a capped query as * if it were a total — typechecks perfectly. * * It lives in `e2e/` rather than `test/` for one reason: the unit suite runs in * CI BEFORE the migration step, against a database with no tables. `test:e2e` * runs after migrate and seed, which is the only point at which a query here * can mean anything. * * Every assertion is a DELTA against a reading taken before the fixture is * inserted. The tools are book-wide by design — there is no tenant to scope * them to — so they see the seed, the demo book and whatever the API's own E2E * left behind. Absolute figures would be a test of the seed, not of the tool. */ import assert from 'node:assert/strict'; import { randomUUID } from 'node:crypto'; import test, { after, before } from 'node:test'; import { eq, inArray } from 'drizzle-orm'; import { accounts, allocations, capacityCommitments, contractObligations, contracts, createDatabase, demandDeals, type Database, } from '@pig/db'; import { createPagePigTools } from '../src/page-tools'; const databaseUrl = process.env.DATABASE_URL; if (!databaseUrl) throw new Error('DATABASE_URL is required for the Piggy page-tool E2E tests.'); const db: Database = createDatabase({ url: databaseUrl, max: 4 }); const MINUTE = 60_000; const HOUR = 3_600_000; const DAY = 86_400_000; /** Marks every fixture row so cleanup can never reach somebody else's data. */ const marker = `PIGGY-E2E-${randomUUID()}`; /** How many exemplars each result may carry — mirrors EXEMPLARS in page-tools. */ const EXEMPLARS = 8; interface Reading { headline: string; truncated?: unknown; [key: string]: unknown; } async function run(route: '/margin' | '/capacity' | '/demand' | '/calendar' | '/'): Promise { const [tool] = createPagePigTools(db, route); assert.ok(tool, `no tool for ${route}`); // The calendar tool is the only one taking input, and its default is 30. return (await tool.execute({})) as Reading; } const created = { accountId: '', contractId: '', commitmentId: '', dealIds: [] as string[], }; /** * The fixture is deliberately lopsided. * * Twenty obligations fall due inside the horizon and twelve are already late, * because the capped exemplar lists hold sixteen and eight — a headline that * reports the list length rather than the count cannot survive those numbers. */ const UPCOMING_OBLIGATIONS = 20; const OVERDUE_OBLIGATIONS = 12; let before30: Reading; let after30: Reading; let marginBefore: Reading; let marginAfter: Reading; let idleBefore: Reading; let idleAfter: Reading; let pipelineBefore: Reading; let pipelineAfter: Reading; let workspaceBefore: Reading; let workspaceAfter: Reading; before(async () => { const now = Date.now(); [before30, marginBefore, idleBefore, pipelineBefore, workspaceBefore] = await Promise.all([ run('/calendar'), run('/margin'), run('/capacity'), run('/demand'), run('/'), ]); const [account] = await db .insert(accounts) .values({ name: `${marker} counterparty`, side: 'supply' }) .returning(); assert.ok(account); created.accountId = account.id; const [contract] = await db .insert(contracts) .values({ accountId: account.id, type: 'msa', status: 'executed', side: 'demand', title: `${marker} master agreement`, // Inside the 30-day horizon, so the projection must emit a // contract_expiry — a kind the old two-table version could not see. expiresAt: new Date(now + 10 * DAY), // Auto-renewal with notice puts a renewal_notice inside the horizon too. isAutoRenew: true, noticeDays: 5, }) .returning(); assert.ok(contract); created.contractId = contract.id; await db.insert(contractObligations).values([ ...Array.from({ length: UPCOMING_OBLIGATIONS }, (_, i) => ({ contractId: contract.id, title: `${marker} upcoming ${i}`, kind: 'milestone', dueAt: new Date(now + (i + 1) * MINUTE), })), ...Array.from({ length: OVERDUE_OBLIGATIONS }, (_, i) => ({ contractId: contract.id, title: `${marker} overdue ${i}`, kind: 'milestone', // i = 0 lapsed a minute ago, i = 11 twelve minutes ago. dueAt: new Date(now - (i + 1) * MINUTE), })), { contractId: contract.id, title: `${marker} already done`, kind: 'milestone', dueAt: new Date(now + 2 * DAY), // Completed work is a dated fact, not a workload; it must not be counted. completedAt: new Date(now - DAY), }, ]); // 1,000 GPU-hours bought at 100c. Half sells at exactly cost, 100 more are // held; the block therefore loses money on the hours nobody bought, which is // the arithmetic PIG exists to keep honest. const [commitment] = await db .insert(capacityCommitments) .values({ accountId: account.id, name: `${marker} block`, gpuType: 'H100', gpuCount: 8, startsAt: new Date(now - DAY), endsAt: new Date(now + 20 * DAY), totalGpuHours: '1000.00', costPerGpuHourCents: 100, }) .returning(); assert.ok(commitment); created.commitmentId = commitment.id; const [openDeal, closingDeal] = await db .insert(demandDeals) .values([ { accountId: account.id, name: `${marker} open deal`, stage: 'proposal', acvCents: 1_000_000, tcvCents: 2_500_000, }, { accountId: account.id, name: `${marker} closing deal`, stage: 'procurement', acvCents: 4_000_000, tcvCents: 4_000_000, probability: '0.50', expectedCloseDate: new Date(now + 3 * DAY), }, ]) .returning(); assert.ok(openDeal && closingDeal); created.dealIds = [openDeal.id, closingDeal.id]; await db.insert(allocations).values([ { capacityCommitmentId: commitment.id, demandDealId: openDeal.id, gpuHours: '500.00', pricePerGpuHourCents: 100, startsAt: new Date(now - HOUR), endsAt: new Date(now + 10 * DAY), status: 'committed', }, { capacityCommitmentId: commitment.id, demandDealId: closingDeal.id, gpuHours: '100.00', pricePerGpuHourCents: 300, startsAt: new Date(now - HOUR), endsAt: new Date(now + 10 * DAY), status: 'planned', // A live hold: removed from availability, never revenue. Inside the // horizon, so it is also a hold_expiry event on the calendar. holdExpiresAt: new Date(now + 4 * DAY), }, ]); [after30, marginAfter, idleAfter, pipelineAfter, workspaceAfter] = await Promise.all([ run('/calendar'), run('/margin'), run('/capacity'), run('/demand'), run('/'), ]); }); after(async () => { if (created.commitmentId) { await db .delete(allocations) .where(eq(allocations.capacityCommitmentId, created.commitmentId)); await db.delete(capacityCommitments).where(eq(capacityCommitments.id, created.commitmentId)); } if (created.dealIds.length > 0) { await db.delete(demandDeals).where(inArray(demandDeals.id, created.dealIds)); } // Obligations cascade from the contract. if (created.contractId) await db.delete(contracts).where(eq(contracts.id, created.contractId)); if (created.accountId) await db.delete(accounts).where(eq(accounts.id, created.accountId)); await db.$client.end(); }); // --------------------------------------------------------------------------- // The calendar // --------------------------------------------------------------------------- interface CalendarReading extends Reading { exactTotals: { obligationsDue: number; dealsExpectedToClose: number }; upcoming: { count: number; byKind: Record; events: { startsAt: string }[] }; overdue: { count: number; byKind: Record; events: { title: string; startsAt: string }[]; }; } test('the calendar headline counts the whole set, not the capped exemplar list', () => { const from = before30 as CalendarReading; const to = after30 as CalendarReading; // The defect, pinned. Twenty obligations were added and the exemplar list // holds sixteen; a headline built from `list.length` reports sixteen. assert.equal( to.exactTotals.obligationsDue - from.exactTotals.obligationsDue, UPCOMING_OBLIGATIONS, ); assert.equal( (to.upcoming.byKind.obligation_due ?? 0) - (from.upcoming.byKind.obligation_due ?? 0), UPCOMING_OBLIGATIONS, ); assert.equal(to.upcoming.events.length, EXEMPLARS * 2); assert.ok(to.upcoming.count > to.upcoming.events.length); assert.match(to.headline, new RegExp(`${to.exactTotals.obligationsDue} obligation\\(s\\) due`)); assert.equal( (to.overdue.byKind.obligation_due ?? 0) - (from.overdue.byKind.obligation_due ?? 0), OVERDUE_OBLIGATIONS, ); assert.equal(to.overdue.events.length, EXEMPLARS); assert.ok(to.overdue.count > to.overdue.events.length); assert.match(to.headline, new RegExp(`${to.overdue.count} item\\(s\\) overdue`)); }); test('a completed obligation is a dated fact, not a workload', () => { const to = after30 as CalendarReading; const from = before30 as CalendarReading; // Twenty-one obligations were inserted inside the horizon; the completed one // is excluded from both the SQL total and the state-filtered list. assert.equal( to.exactTotals.obligationsDue - from.exactTotals.obligationsDue, UPCOMING_OBLIGATIONS, ); const states = (to.upcoming as unknown as { byState: Record }).byState; assert.equal(states.done, undefined); }); test('the projection reaches the kinds the old two-table version could not', () => { const to = after30 as CalendarReading; const from = before30 as CalendarReading; const gained = (kind: string): number => (to.upcoming.byKind[kind] ?? 0) - (from.upcoming.byKind[kind] ?? 0); assert.equal(gained('contract_expiry'), 1); assert.equal(gained('renewal_notice'), 1); assert.equal(gained('hold_expiry'), 1); assert.equal(gained('expected_close'), 1); // The commitment window overlaps the horizon on both edges. assert.ok(gained('capacity_window') >= 1); assert.ok(gained('allocation_window') >= 1); assert.equal(to.exactTotals.dealsExpectedToClose - from.exactTotals.dealsExpectedToClose, 1); }); test('overdue exemplars are the most recently lapsed, not the oldest in the book', () => { const to = after30 as CalendarReading; const dates = to.overdue.events.map((event) => event.startsAt); assert.deepEqual(dates, [...dates].sort().reverse(), 'overdue exemplars run newest first'); const titles = to.overdue.events.map((event) => event.title); // Lapsed one minute ago: present. Lapsed twelve minutes ago: cut, because // twelve rows were inserted and only eight are carried. assert.ok(titles.includes(`${marker} overdue 0`)); assert.ok(!titles.includes(`${marker} overdue ${OVERDUE_OBLIGATIONS - 1}`)); }); test('a book this size is not truncated, and says so', () => { assert.equal(after30.truncated, false); assert.doesNotMatch(after30.headline, /at least/); }); // --------------------------------------------------------------------------- // The book // --------------------------------------------------------------------------- interface MarginReading extends Reading { totals: { revenueCents: number; costCents: number; grossMarginCents: number }; liveCommitments: number; } test('margin charges cost against the full commitment and coerces numeric strings', () => { const from = marginBefore as MarginReading; const to = marginAfter as MarginReading; // 500 sold hours × 100c. The held 100 are not revenue. assert.equal(to.totals.revenueCents - from.totals.revenueCents, 50_000); // 1,000 committed hours × 100c — not the 500 that sold. assert.equal(to.totals.costCents - from.totals.costCents, 100_000); // Charging cost against the sold hours alone would report break-even here // instead of a 50,000c hole, which is the reading the rule forbids. assert.equal(to.totals.grossMarginCents - from.totals.grossMarginCents, -50_000); assert.equal(to.liveCommitments - from.liveCommitments, 1); // `gpuHours` arrives as a string. Concatenation would give "1000.00500.00" // and a revenue in the billions rather than a delta of exactly 50,000c. assert.ok(Number.isSafeInteger(to.totals.revenueCents)); }); test('the idle block appears with its break-even price', () => { const from = idleBefore as Reading & { totalIdleCostCents: number; blocks: unknown[] }; const to = idleAfter as Reading & { totalIdleCostCents: number; blocks: { name: string; idleGpuHours: number; breakEvenPricePerGpuHourCents: number }[]; }; // 50% unsold, well past the 25% threshold: 500 idle hours at 100c. assert.equal(to.totalIdleCostCents - from.totalIdleCostCents, 50_000); const mine = to.blocks.find((block) => block.name === `${marker} block`); assert.ok(mine, 'the fixture block is idle enough to be listed'); assert.equal(mine.idleGpuHours, 500); // The remaining 500 hours must fetch 100c each to cover the whole block. assert.equal(mine.breakEvenPricePerGpuHourCents, 100); }); // --------------------------------------------------------------------------- // The pipelines // --------------------------------------------------------------------------- interface PipelineReading extends Reading { demand: { openDeals: number; valueCents: number; byStage: Record }; supply: { openDeals: number }; } test('the pipeline totals TCV where it is known and reports open stages', () => { const from = pipelineBefore as PipelineReading; const to = pipelineAfter as PipelineReading; assert.equal(to.demand.openDeals - from.demand.openDeals, 2); // 2,500,000 + 4,000,000, both by TCV. assert.equal(to.demand.valueCents - from.demand.valueCents, 6_500_000); assert.equal((to.demand.byStage.proposal ?? 0) - (from.demand.byStage.proposal ?? 0), 1); assert.equal((to.demand.byStage.procurement ?? 0) - (from.demand.byStage.procurement ?? 0), 1); assert.deepEqual(to.truncated, { demandDeals: false, supplyDeals: false }); }); test('the workspace summary agrees with the tools it summarises', () => { const from = workspaceBefore as Reading & { book: { costCents: number }; openDemandDeals: number }; const to = workspaceAfter as Reading & { book: { costCents: number }; openDemandDeals: number }; assert.equal(to.book.costCents - from.book.costCents, 100_000); assert.equal(to.openDemandDeals - from.openDemandDeals, 2); assert.deepEqual(to.truncated, { commitments: false, demandDeals: false, supplyDeals: false, }); });