841 lines
28 KiB
TypeScript
841 lines
28 KiB
TypeScript
/**
|
||
* Demo dataset — a plausible book of business, for development and demos.
|
||
*
|
||
* Separate from `index.ts` (which seeds publicly-sourced, cited people) because
|
||
* this is **invented**. It exists so the product is legible before anyone has
|
||
* entered real data: margin that moves, blocks at different utilisation, deals
|
||
* spread across both pipelines, contracts with real structure.
|
||
*
|
||
* Two integrity rules, and they are not fussiness:
|
||
*
|
||
* **Every record is prefixed `DEMO —`.** A screenshot of this must never be
|
||
* mistakeable for real business.
|
||
*
|
||
* **Demand-side customers are fictional.** Suppliers are real companies —
|
||
* they are public, and naming the actual market is the point — but their
|
||
* commitments are labelled and the prices are illustrative. Inventing
|
||
* *customers* with invented contract values against real named companies
|
||
* would be fabricating commercial records about real businesses, which is a
|
||
* different thing entirely and not worth the realism.
|
||
*
|
||
* Remove it all with `pnpm db:demo -- --clear`.
|
||
*
|
||
* The numbers are chosen to teach. The book as a whole clears a modest margin —
|
||
* roughly what this industry actually earns once capacity cost is charged
|
||
* honestly — while individual blocks tell different stories:
|
||
*
|
||
* the large H200 block carries the book;
|
||
* the EU H100 block is UNDERWATER at 55% sold, because a 46% markup needs
|
||
* ~69% sold to break even at all;
|
||
* the community A100 pool has a large hold that has not converted, so it
|
||
* shows as reserved-but-unsold — the distinction between "sold" and "held"
|
||
* made visible rather than theoretical.
|
||
*
|
||
* A demo that opens on a healthy total and reveals the problems on drill-down
|
||
* is more useful than one that opens on a loss, which reads as a broken
|
||
* product rather than an under-utilised book.
|
||
*/
|
||
import { ALLOCATION_STATUSES, type AllocationStatus } from '@pig/core';
|
||
import { and, eq, like, or } from 'drizzle-orm';
|
||
import { createDatabase } from '../client';
|
||
import {
|
||
accounts,
|
||
activities,
|
||
facts,
|
||
allocations,
|
||
capacityCommitments,
|
||
capacityRequests,
|
||
contacts,
|
||
contracts,
|
||
contractObligations,
|
||
demandDeals,
|
||
type NewAllocation,
|
||
sites,
|
||
slaTerms,
|
||
supplyDeals,
|
||
} from '../schema/index';
|
||
|
||
const db = createDatabase();
|
||
const PREFIX = 'DEMO — ';
|
||
|
||
const day = 86_400_000;
|
||
const now = Date.now();
|
||
const at = (days: number) => new Date(now + days * day);
|
||
|
||
function isAllocationStatus(value: string): value is AllocationStatus {
|
||
return (ALLOCATION_STATUSES as readonly string[]).includes(value);
|
||
}
|
||
|
||
/** GPU-hours for a block, allowing for a maintenance/ramp haircut. */
|
||
const hours = (gpus: number, days: number, efficiency = 0.94) =>
|
||
String(Math.round(gpus * 24 * days * efficiency));
|
||
|
||
// ---------------------------------------------------------------- suppliers
|
||
|
||
const SUPPLY = [
|
||
{
|
||
domain: 'coreweave.com',
|
||
site: { name: 'US-East (NJ)', country: 'United States', countryCode: 'US', region: 'us-east' },
|
||
commitment: {
|
||
name: `${PREFIX}512× H200 reserved, 12 months`,
|
||
gpuType: 'H200',
|
||
socket: 'SXM5' as const,
|
||
gpuCount: 512,
|
||
interconnectType: 'Infiniband' as const,
|
||
days: 365,
|
||
costPerGpuHourCents: 189,
|
||
takeOrPayFloorPct: '100',
|
||
prepaidPct: '25',
|
||
},
|
||
},
|
||
{
|
||
domain: 'nebius.com',
|
||
site: { name: 'EU-North (FI)', country: 'Finland', countryCode: 'FI', region: 'eu-north' },
|
||
commitment: {
|
||
name: `${PREFIX}128× H100 reserved, 6 months`,
|
||
gpuType: 'H100_80GB',
|
||
socket: 'SXM5' as const,
|
||
gpuCount: 128,
|
||
interconnectType: 'Infiniband' as const,
|
||
days: 180,
|
||
costPerGpuHourCents: 171,
|
||
takeOrPayFloorPct: '80',
|
||
prepaidPct: '0',
|
||
},
|
||
},
|
||
{
|
||
domain: 'crusoe.ai',
|
||
site: { name: 'US-Central (TX)', country: 'United States', countryCode: 'US', region: 'us-central' },
|
||
commitment: {
|
||
name: `${PREFIX}64× B200 reserved, 9 months`,
|
||
gpuType: 'B200',
|
||
socket: 'SXM6' as const,
|
||
gpuCount: 64,
|
||
interconnectType: 'Infiniband' as const,
|
||
days: 270,
|
||
costPerGpuHourCents: 305,
|
||
takeOrPayFloorPct: '100',
|
||
prepaidPct: '15',
|
||
},
|
||
},
|
||
{
|
||
domain: 'runpod.io',
|
||
site: { name: 'Community pool', country: 'United States', countryCode: 'US', region: 'us-west' },
|
||
commitment: {
|
||
name: `${PREFIX}32× A100 burst pool, 3 months`,
|
||
gpuType: 'A100_80GB',
|
||
socket: 'SXM4' as const,
|
||
gpuCount: 32,
|
||
interconnectType: 'Ethernet' as const,
|
||
securityTier: 'community_cloud' as const,
|
||
days: 90,
|
||
costPerGpuHourCents: 96,
|
||
takeOrPayFloorPct: '0',
|
||
prepaidPct: '0',
|
||
},
|
||
},
|
||
];
|
||
|
||
/**
|
||
* Fictional customers.
|
||
*
|
||
* Invented deliberately — see the note at the top of this file. Any resemblance
|
||
* to a real company is unintended, and none of these figures describes anyone's
|
||
* actual contract.
|
||
*/
|
||
const DEMAND = [
|
||
{
|
||
account: `${PREFIX}Halcyon Research`,
|
||
segment: 'frontier_lab' as const,
|
||
country: 'United States',
|
||
contact: { name: 'Dana Whitfield', title: 'Head of Infrastructure', decisionMaker: true },
|
||
deal: {
|
||
name: `${PREFIX}Pre-training cluster, 12 months`,
|
||
productLine: 'compute_reserved' as const,
|
||
stage: 'deployment' as const,
|
||
acvCents: 2_400_000_00,
|
||
termMonths: 12,
|
||
msaExecuted: true,
|
||
dpaExecuted: true,
|
||
},
|
||
request: { gpuType: 'H200', gpuCount: 256, fastFabric: true, maxPriceCents: 285 },
|
||
// Draws from the CoreWeave block.
|
||
allocation: {
|
||
supplier: 'coreweave.com',
|
||
share: 0.76,
|
||
priceCents: 271,
|
||
status: 'active',
|
||
},
|
||
},
|
||
{
|
||
account: `${PREFIX}Verity Health AI`,
|
||
segment: 'enterprise' as const,
|
||
country: 'Germany',
|
||
contact: { name: 'Lukas Brenner', title: 'VP Engineering', decisionMaker: true },
|
||
deal: {
|
||
name: `${PREFIX}EU-resident fine-tuning`,
|
||
productLine: 'post_training' as const,
|
||
stage: 'procurement' as const,
|
||
acvCents: 640_000_00,
|
||
termMonths: 6,
|
||
msaExecuted: true,
|
||
dpaExecuted: false,
|
||
},
|
||
// Data residency: must land in the EU. Drives the Nebius block.
|
||
request: {
|
||
gpuType: 'H100_80GB',
|
||
gpuCount: 64,
|
||
fastFabric: true,
|
||
maxPriceCents: 260,
|
||
allowedRegions: ['eu-north', 'eu-west'],
|
||
certifications: ['ISO 27001', 'SOC 2 Type II'],
|
||
},
|
||
allocation: {
|
||
supplier: 'nebius.com',
|
||
share: 0.55,
|
||
priceCents: 249,
|
||
status: 'committed',
|
||
},
|
||
},
|
||
{
|
||
account: `${PREFIX}Northwind Robotics`,
|
||
segment: 'applied_ai_startup' as const,
|
||
country: 'United States',
|
||
contact: { name: 'Priya Raghavan', title: 'CTO', decisionMaker: true },
|
||
deal: {
|
||
name: `${PREFIX}Blackwell evaluation → production`,
|
||
productLine: 'compute_reserved' as const,
|
||
stage: 'poc' as const,
|
||
acvCents: 890_000_00,
|
||
termMonths: 9,
|
||
msaExecuted: true,
|
||
dpaExecuted: true,
|
||
},
|
||
request: { gpuType: 'B200', gpuCount: 32, fastFabric: true, maxPriceCents: 460 },
|
||
allocation: {
|
||
supplier: 'crusoe.ai',
|
||
share: 0.74,
|
||
priceCents: 441,
|
||
status: 'active',
|
||
},
|
||
},
|
||
{
|
||
account: `${PREFIX}Tessellate Labs`,
|
||
segment: 'applied_ai_startup' as const,
|
||
country: 'United Kingdom',
|
||
contact: { name: 'Owen Marsh', title: 'Founding Engineer', decisionMaker: false },
|
||
deal: {
|
||
name: `${PREFIX}Inference burst capacity`,
|
||
productLine: 'inference' as const,
|
||
stage: 'proposal' as const,
|
||
acvCents: 145_000_00,
|
||
termMonths: 3,
|
||
msaExecuted: false,
|
||
dpaExecuted: false,
|
||
},
|
||
request: { gpuType: 'A100_80GB', gpuCount: 16, fastFabric: false, maxPriceCents: 175 },
|
||
// A HOLD, not a sale. The deal has not closed, so this reserves capacity
|
||
// without counting as revenue — the distinction the capacity view exists
|
||
// to make visible.
|
||
allocation: {
|
||
supplier: 'runpod.io',
|
||
share: 0.55,
|
||
priceCents: 168,
|
||
status: 'planned',
|
||
holdDays: 12,
|
||
},
|
||
},
|
||
{
|
||
account: `${PREFIX}Aurelian Systems`,
|
||
segment: 'enterprise' as const,
|
||
country: 'United States',
|
||
contact: { name: 'Meredith Cole', title: 'Director, ML Platform', decisionMaker: true },
|
||
deal: {
|
||
name: `${PREFIX}Multi-year committed capacity`,
|
||
productLine: 'compute_reserved' as const,
|
||
stage: 'legal' as const,
|
||
acvCents: 3_100_000_00,
|
||
termMonths: 24,
|
||
msaExecuted: false,
|
||
dpaExecuted: false,
|
||
},
|
||
request: { gpuType: 'H200', gpuCount: 128, fastFabric: true, maxPriceCents: 265 },
|
||
allocation: null, // Still in legal. Nothing reserved yet — correctly.
|
||
},
|
||
{
|
||
account: `${PREFIX}Quillon AI`,
|
||
segment: 'applied_ai_startup' as const,
|
||
country: 'Canada',
|
||
contact: { name: 'Sofia Trentini', title: 'Head of Research', decisionMaker: true },
|
||
deal: {
|
||
name: `${PREFIX}Evaluation harness pilot`,
|
||
productLine: 'evaluations' as const,
|
||
stage: 'qualification' as const,
|
||
acvCents: 48_000_00,
|
||
termMonths: 3,
|
||
msaExecuted: false,
|
||
dpaExecuted: false,
|
||
},
|
||
request: null,
|
||
allocation: null,
|
||
},
|
||
];
|
||
|
||
async function clear() {
|
||
console.log('Removing demo data…');
|
||
// Ordered so foreign keys never block a delete.
|
||
const demoAccounts = await db
|
||
.select({ id: accounts.id })
|
||
.from(accounts)
|
||
.where(like(accounts.name, `${PREFIX}%`));
|
||
const ids = demoAccounts.map((a) => a.id);
|
||
|
||
await db.delete(allocations).where(like(allocations.notes, `${PREFIX}%`));
|
||
await db.delete(contractObligations);
|
||
await db.delete(slaTerms);
|
||
await db.delete(contracts).where(like(contracts.title, `${PREFIX}%`));
|
||
await db.delete(capacityRequests);
|
||
await db.delete(demandDeals).where(like(demandDeals.name, `${PREFIX}%`));
|
||
await db.delete(supplyDeals).where(like(supplyDeals.name, `${PREFIX}%`));
|
||
await db.delete(capacityCommitments).where(like(capacityCommitments.name, `${PREFIX}%`));
|
||
await db.delete(activities).where(like(activities.subject, `${PREFIX}%`));
|
||
for (const id of ids) {
|
||
await db.delete(contacts).where(eq(contacts.accountId, id));
|
||
}
|
||
await db.delete(accounts).where(like(accounts.name, `${PREFIX}%`));
|
||
console.log(`Removed ${ids.length} demo account(s) and everything hanging from them.`);
|
||
}
|
||
|
||
async function seedDemo() {
|
||
console.log('Seeding the demo book…\n');
|
||
|
||
// ------------------------------------------------------------ supply side
|
||
const commitmentIds = new Map<string, string>();
|
||
|
||
for (const supplier of SUPPLY) {
|
||
const [account] = await db
|
||
.select({ id: accounts.id })
|
||
.from(accounts)
|
||
.where(eq(accounts.domain, supplier.domain))
|
||
.limit(1);
|
||
if (!account) {
|
||
console.log(` skipped ${supplier.domain} — run the base seed first`);
|
||
continue;
|
||
}
|
||
|
||
const [existing] = await db
|
||
.select({ id: capacityCommitments.id })
|
||
.from(capacityCommitments)
|
||
.where(eq(capacityCommitments.name, supplier.commitment.name))
|
||
.limit(1);
|
||
if (existing) {
|
||
commitmentIds.set(supplier.domain, existing.id);
|
||
continue;
|
||
}
|
||
|
||
const [site] = await db
|
||
.insert(sites)
|
||
.values({
|
||
accountId: account.id,
|
||
name: `${PREFIX}${supplier.site.name}`,
|
||
country: supplier.site.country,
|
||
countryCode: supplier.site.countryCode,
|
||
region: supplier.site.region,
|
||
certifications:
|
||
supplier.commitment.securityTier === 'community_cloud'
|
||
? []
|
||
: ['SOC 2 Type II', 'ISO 27001'],
|
||
})
|
||
.returning();
|
||
|
||
const c = supplier.commitment;
|
||
const [commitment] = await db
|
||
.insert(capacityCommitments)
|
||
.values({
|
||
accountId: account.id,
|
||
siteId: site?.id,
|
||
name: c.name,
|
||
gpuType: c.gpuType,
|
||
socket: c.socket,
|
||
gpuCount: c.gpuCount,
|
||
interconnectType: c.interconnectType,
|
||
securityTier: c.securityTier ?? 'secure_cloud',
|
||
startsAt: at(-30),
|
||
endsAt: at(c.days - 30),
|
||
totalGpuHours: hours(c.gpuCount, c.days),
|
||
costPerGpuHourCents: c.costPerGpuHourCents,
|
||
takeOrPayFloorPct: c.takeOrPayFloorPct,
|
||
prepaidPct: c.prepaidPct,
|
||
usefulLifeYears: '5',
|
||
// A ramp: a quarter of the fleet for the first fortnight, then full.
|
||
// Present so the shape column is exercised by something other than a
|
||
// rectangle, which is the case it exists for.
|
||
shape: {
|
||
intervals: [at(-30).toISOString(), at(-16).toISOString(), at(c.days - 30).toISOString()],
|
||
quantities: [Math.round(c.gpuCount * 0.25), c.gpuCount],
|
||
},
|
||
notes: 'Illustrative demo data. Not a real contract.',
|
||
})
|
||
.returning();
|
||
|
||
if (commitment) commitmentIds.set(supplier.domain, commitment.id);
|
||
|
||
// The paper behind it.
|
||
const [msa] = await db
|
||
.insert(contracts)
|
||
.values({
|
||
accountId: account.id,
|
||
type: 'msa',
|
||
status: 'executed',
|
||
side: 'supply',
|
||
title: `${PREFIX}MSA — ${supplier.domain}`,
|
||
capacityCommitmentId: commitment?.id,
|
||
effectiveAt: at(-60),
|
||
expiresAt: at(c.days + 60),
|
||
isAutoRenew: true,
|
||
noticeDays: 90,
|
||
takeOrPayFloorPct: c.takeOrPayFloorPct,
|
||
prepaidPct: c.prepaidPct,
|
||
terminationTier: c.prepaidPct !== '0' ? '1_prepaid' : '2_take_or_pay',
|
||
governingLaw: 'New York',
|
||
})
|
||
.returning();
|
||
|
||
if (msa) {
|
||
// A negotiated SLA with fee abatement — the remedy that actually matters
|
||
// on the supply side, and the one a credits-only model cannot express.
|
||
const [sla] = await db
|
||
.insert(contracts)
|
||
.values({
|
||
accountId: account.id,
|
||
type: 'sla',
|
||
status: 'executed',
|
||
side: 'supply',
|
||
title: `${PREFIX}SLA — ${supplier.domain}`,
|
||
parentContractId: msa.id,
|
||
effectiveAt: at(-60),
|
||
})
|
||
.returning();
|
||
|
||
if (sla) {
|
||
await db.insert(slaTerms).values({
|
||
contractId: sla.id,
|
||
kind: 'negotiated',
|
||
uptimeTargetPct: '99.500',
|
||
measurementUnit: 'node',
|
||
measurementWindow: 'monthly',
|
||
remedyType: 'fee_abatement',
|
||
abatementTriggerValue: 2,
|
||
abatementTriggerUnit: 'business_days',
|
||
nodeReplacementHours: 24,
|
||
claimDeadlineValue: 30,
|
||
claimDeadlineUnit: 'days',
|
||
creditCapPct: '50.000',
|
||
sparePoolObligation: 'Spares held on site sufficient to replace failed nodes and switches.',
|
||
sparePoolScope: ['compute_nodes', 'network_switches'],
|
||
rcaDeliveryHours: 72,
|
||
maintenanceClasses: [
|
||
{ class: 'planned', noticeValue: 5, noticeUnit: 'business_days', excludedFromUptime: true },
|
||
{ class: 'emergency', noticeValue: 24, noticeUnit: 'hours', excludedFromUptime: false },
|
||
],
|
||
});
|
||
}
|
||
|
||
await db.insert(contractObligations).values({
|
||
contractId: msa.id,
|
||
title: `${PREFIX}Renewal notice — ${supplier.domain}`,
|
||
kind: 'renewal_notice',
|
||
// Deliberately near-term on one supplier so the renewal alarm has
|
||
// something real to fire on.
|
||
dueAt: at(supplier.domain === 'nebius.com' ? 21 : 200),
|
||
description: '90 days notice required to prevent auto-renewal.',
|
||
});
|
||
}
|
||
|
||
await db.insert(supplyDeals).values({
|
||
accountId: account.id,
|
||
siteId: site?.id,
|
||
name: `${PREFIX}${c.gpuCount}× ${c.gpuType} — ${supplier.domain}`,
|
||
stage: 'live',
|
||
gpuType: c.gpuType,
|
||
gpuCount: c.gpuCount,
|
||
interconnectType: c.interconnectType,
|
||
targetCostPerGpuHourCents: c.costPerGpuHourCents,
|
||
termMonths: Math.round(c.days / 30),
|
||
technicalVerdict: 'pass',
|
||
technicalNotes: 'NCCL all-reduce within 8% of theoretical across the full fabric.',
|
||
financialVerdict: 'pass',
|
||
financialNotes: `Break-even at ~${Math.round((c.costPerGpuHourCents / 0.75 / 100) * 100) / 100}/GPU-hr at 75% utilisation.`,
|
||
});
|
||
}
|
||
|
||
// A supply deal still in diligence, so that pipeline is not all `live`.
|
||
const [lambda] = await db
|
||
.select({ id: accounts.id })
|
||
.from(accounts)
|
||
.where(eq(accounts.domain, 'lambda.ai'))
|
||
.limit(1);
|
||
if (lambda) {
|
||
const LAMBDA_DEAL = `${PREFIX}256× H200 — pricing`;
|
||
const [existingLambdaDeal] = await db
|
||
.select({ id: supplyDeals.id })
|
||
.from(supplyDeals)
|
||
.where(and(eq(supplyDeals.accountId, lambda.id), eq(supplyDeals.name, LAMBDA_DEAL)))
|
||
.limit(1);
|
||
if (!existingLambdaDeal) {
|
||
await db.insert(supplyDeals).values({
|
||
accountId: lambda.id,
|
||
name: LAMBDA_DEAL,
|
||
stage: 'financial_diligence',
|
||
gpuType: 'H200',
|
||
gpuCount: 256,
|
||
interconnectType: 'Infiniband',
|
||
targetCostPerGpuHourCents: 176,
|
||
termMonths: 12,
|
||
technicalVerdict: 'pass',
|
||
technicalNotes: 'Fabric verified. Storage throughput per GPU is below spec — flagged.',
|
||
financialNotes: 'Awaiting a firm quote on the committed tranche.',
|
||
});
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------ demand side
|
||
for (const d of DEMAND) {
|
||
const [existingAccount] = await db
|
||
.select({ id: accounts.id })
|
||
.from(accounts)
|
||
.where(eq(accounts.name, d.account))
|
||
.limit(1);
|
||
if (existingAccount) continue;
|
||
|
||
const [account] = await db
|
||
.insert(accounts)
|
||
.values({
|
||
name: d.account,
|
||
side: 'demand',
|
||
customerSegment: d.segment,
|
||
country: d.country,
|
||
description: 'Fictional company, for demonstration only.',
|
||
source: 'seed',
|
||
confidence: 'confirmed',
|
||
lastActivityAt: at(-Math.random() * 10),
|
||
})
|
||
.returning();
|
||
if (!account) continue;
|
||
|
||
const [contact] = await db
|
||
.insert(contacts)
|
||
.values({
|
||
accountId: account.id,
|
||
fullName: d.contact.name,
|
||
title: d.contact.title,
|
||
affiliation: 'staff',
|
||
isDecisionMaker: d.contact.decisionMaker,
|
||
confidence: 'confirmed',
|
||
source: 'seed',
|
||
email: null,
|
||
})
|
||
.returning();
|
||
|
||
const [deal] = await db
|
||
.insert(demandDeals)
|
||
.values({
|
||
accountId: account.id,
|
||
name: d.deal.name,
|
||
productLine: d.deal.productLine,
|
||
stage: d.deal.stage,
|
||
acvCents: d.deal.acvCents,
|
||
tcvCents: Math.round((d.deal.acvCents * d.deal.termMonths) / 12),
|
||
termMonths: d.deal.termMonths,
|
||
msaExecuted: d.deal.msaExecuted,
|
||
dpaExecuted: d.deal.dpaExecuted,
|
||
primaryContactId: contact?.id,
|
||
expectedCloseDate: at(20 + Math.round(Math.random() * 60)),
|
||
probability: String(
|
||
{ qualification: 0.1, legal: 0.35, proposal: 0.45, procurement: 0.6, poc: 0.7, deployment: 0.9 }[
|
||
d.deal.stage
|
||
] ?? 0.5,
|
||
),
|
||
lastActivityAt: at(-Math.random() * 8),
|
||
})
|
||
.returning();
|
||
if (!deal) continue;
|
||
|
||
if (d.request) {
|
||
await db.insert(capacityRequests).values({
|
||
demandDealId: deal.id,
|
||
gpuType: d.request.gpuType,
|
||
gpuCount: d.request.gpuCount,
|
||
requiresHighSpeedInterconnect: d.request.fastFabric,
|
||
minInterconnectType: d.request.fastFabric ? 'Infiniband' : undefined,
|
||
maxPricePerGpuHourCents: d.request.maxPriceCents,
|
||
allowedRegions: d.request.allowedRegions ?? [],
|
||
requiredCertifications: d.request.certifications ?? [],
|
||
startsAt: at(15),
|
||
endsAt: at(15 + d.deal.termMonths * 30),
|
||
totalGpuHours: hours(d.request.gpuCount, d.deal.termMonths * 30, 1),
|
||
});
|
||
}
|
||
|
||
if (d.allocation) {
|
||
const commitmentId = commitmentIds.get(d.allocation.supplier);
|
||
if (commitmentId) {
|
||
const [commitment] = await db
|
||
.select()
|
||
.from(capacityCommitments)
|
||
.where(eq(capacityCommitments.id, commitmentId))
|
||
.limit(1);
|
||
|
||
if (commitment) {
|
||
if (!isAllocationStatus(d.allocation.status)) {
|
||
throw new Error(`Invalid demo allocation status: ${d.allocation.status}`);
|
||
}
|
||
const allocationRow = {
|
||
capacityCommitmentId: commitmentId,
|
||
demandDealId: deal.id,
|
||
gpuHours: String(
|
||
Math.round(Number(commitment.totalGpuHours) * d.allocation.share),
|
||
),
|
||
pricePerGpuHourCents: d.allocation.priceCents,
|
||
startsAt: commitment.startsAt,
|
||
endsAt: commitment.endsAt,
|
||
status: d.allocation.status,
|
||
guaranteeType: d.allocation.status === 'planned' ? 'committed' : 'guaranteed',
|
||
priority: d.allocation.status === 'planned' ? 100 : 10,
|
||
holdExpiresAt: d.allocation.holdDays ? at(d.allocation.holdDays) : null,
|
||
notes: d.account,
|
||
} satisfies NewAllocation;
|
||
await db.insert(allocations).values(allocationRow);
|
||
}
|
||
}
|
||
}
|
||
|
||
// A little history, so the activity feed is not empty.
|
||
await db.insert(activities).values([
|
||
{
|
||
type: 'meeting',
|
||
subject: `${PREFIX}Technical scoping with ${d.contact.name}`,
|
||
accountId: account.id,
|
||
demandDealId: deal.id,
|
||
occurredAt: at(-12),
|
||
},
|
||
{
|
||
type: 'note',
|
||
subject: `${PREFIX}${d.deal.stage} — next step agreed`,
|
||
accountId: account.id,
|
||
demandDealId: deal.id,
|
||
occurredAt: at(-3),
|
||
},
|
||
]);
|
||
}
|
||
|
||
// Internal research burn against the largest block — real cost, no revenue.
|
||
const coreweave = commitmentIds.get('coreweave.com');
|
||
if (coreweave) {
|
||
const [commitment] = await db
|
||
.select()
|
||
.from(capacityCommitments)
|
||
.where(eq(capacityCommitments.id, coreweave))
|
||
.limit(1);
|
||
const RESEARCH_NOTE = `${PREFIX}Internal research consumption`;
|
||
const [existingResearch] = await db
|
||
.select({ id: allocations.id })
|
||
.from(allocations)
|
||
.where(
|
||
and(
|
||
eq(allocations.capacityCommitmentId, coreweave),
|
||
eq(allocations.notes, RESEARCH_NOTE),
|
||
),
|
||
)
|
||
.limit(1);
|
||
|
||
if (commitment && !existingResearch) {
|
||
const researchAllocationRow = {
|
||
capacityCommitmentId: coreweave,
|
||
internalTeam: 'research',
|
||
gpuHours: String(Math.round(Number(commitment.totalGpuHours) * 0.08)),
|
||
pricePerGpuHourCents: 0,
|
||
startsAt: commitment.startsAt,
|
||
endsAt: commitment.endsAt,
|
||
status: 'active',
|
||
guaranteeType: 'internal',
|
||
priority: 200,
|
||
notes: RESEARCH_NOTE,
|
||
} satisfies NewAllocation;
|
||
await db.insert(allocations).values(researchAllocationRow);
|
||
}
|
||
}
|
||
|
||
// -------------------------------------------------- agent-derived facts
|
||
//
|
||
// Without these the fact-review queue and every provenance tooltip are
|
||
// empty, which hides the thing that makes an agent-written CRM trustworthy:
|
||
// that each claim carries a score, a band, evidence and a source, and that
|
||
// only verified claims apply themselves.
|
||
//
|
||
// The mix is deliberate. Two `applied` facts show what a confident agent
|
||
// writes unprompted; four `proposed` show what waits for a human; one is a
|
||
// near-miss that a reviewer should reject, so the queue is not a row of
|
||
// obvious approvals.
|
||
const factSeeds: {
|
||
accountDomain?: string;
|
||
contactName?: string;
|
||
field: string;
|
||
value: string;
|
||
score: string;
|
||
band: 'verified' | 'probable' | 'possible';
|
||
status: 'applied' | 'proposed';
|
||
method: string;
|
||
sourceUrl?: string;
|
||
evidence: Record<string, unknown>;
|
||
}[] = [
|
||
{
|
||
accountDomain: 'coreweave.com',
|
||
field: 'supplierType',
|
||
value: 'neocloud',
|
||
score: '0.960',
|
||
band: 'verified',
|
||
status: 'applied',
|
||
method: 'web_search',
|
||
sourceUrl: 'https://www.coreweave.com/',
|
||
evidence: {
|
||
quote: 'Describes itself as an AI hyperscaler providing GPU cloud infrastructure.',
|
||
corroboration: 2,
|
||
},
|
||
},
|
||
{
|
||
accountDomain: 'nebius.com',
|
||
field: 'jurisdiction',
|
||
value: 'European Union',
|
||
score: '0.910',
|
||
band: 'verified',
|
||
status: 'applied',
|
||
method: 'web_search',
|
||
sourceUrl: 'https://nebius.com/',
|
||
evidence: {
|
||
quote: 'Operates a datacentre in Finland, inside the EU data-residency perimeter.',
|
||
matters: 'Determines eligibility for customers with EU residency requirements.',
|
||
},
|
||
},
|
||
{
|
||
accountDomain: 'crusoe.ai',
|
||
field: 'certifications',
|
||
value: 'SOC 2 Type II',
|
||
score: '0.720',
|
||
band: 'probable',
|
||
status: 'proposed',
|
||
method: 'web_search',
|
||
sourceUrl: 'https://crusoe.ai/',
|
||
evidence: {
|
||
quote: 'A trust page references SOC 2, but the report scope and observation window are not stated.',
|
||
caution: 'Scope matters — a report can cover only some products.',
|
||
},
|
||
},
|
||
{
|
||
accountDomain: 'lambda.ai',
|
||
field: 'supplierType',
|
||
value: 'neocloud',
|
||
score: '0.680',
|
||
band: 'probable',
|
||
status: 'proposed',
|
||
method: 'web_search',
|
||
sourceUrl: 'https://lambda.ai/',
|
||
evidence: { quote: 'Markets GPU cloud and on-premises clusters.' },
|
||
},
|
||
{
|
||
contactName: 'Dana Whitfield',
|
||
field: 'title',
|
||
value: 'VP Infrastructure',
|
||
score: '0.540',
|
||
band: 'possible',
|
||
status: 'proposed',
|
||
method: 'inference',
|
||
evidence: {
|
||
reasoning: 'A conference bio lists a VP title; the CRM records Head of Infrastructure.',
|
||
conflict: 'Sources disagree, and neither is dated.',
|
||
},
|
||
},
|
||
{
|
||
accountDomain: 'runpod.io',
|
||
field: 'customerSegment',
|
||
value: 'frontier_lab',
|
||
score: '0.310',
|
||
band: 'possible',
|
||
status: 'proposed',
|
||
method: 'inference',
|
||
evidence: {
|
||
reasoning: 'Inferred from a blog post mentioning large training runs.',
|
||
warning:
|
||
'Weak. This is a supply-side provider, not a frontier lab — a reviewer should reject it.',
|
||
},
|
||
},
|
||
];
|
||
|
||
let factsAdded = 0;
|
||
for (const seed of factSeeds) {
|
||
let accountId: string | undefined;
|
||
let contactId: string | undefined;
|
||
|
||
if (seed.accountDomain) {
|
||
const [row] = await db
|
||
.select({ id: accounts.id })
|
||
.from(accounts)
|
||
.where(eq(accounts.domain, seed.accountDomain))
|
||
.limit(1);
|
||
accountId = row?.id;
|
||
}
|
||
if (seed.contactName) {
|
||
const [row] = await db
|
||
.select({ id: contacts.id })
|
||
.from(contacts)
|
||
.where(eq(contacts.fullName, seed.contactName))
|
||
.limit(1);
|
||
contactId = row?.id;
|
||
}
|
||
if (!accountId && !contactId) continue;
|
||
|
||
// Idempotent on the natural key: one claim per subject per field per value.
|
||
const [existing] = await db
|
||
.select({ id: facts.id })
|
||
.from(facts)
|
||
.where(
|
||
and(
|
||
accountId ? eq(facts.accountId, accountId) : eq(facts.contactId, contactId!),
|
||
eq(facts.field, seed.field),
|
||
eq(facts.value, seed.value),
|
||
),
|
||
)
|
||
.limit(1);
|
||
if (existing) continue;
|
||
|
||
await db.insert(facts).values({
|
||
accountId,
|
||
contactId,
|
||
field: seed.field,
|
||
value: seed.value,
|
||
score: seed.score,
|
||
band: seed.band,
|
||
status: seed.status,
|
||
method: seed.method,
|
||
sourceUrl: seed.sourceUrl,
|
||
evidence: seed.evidence,
|
||
observedAt: at(-Math.round(Math.random() * 6) - 1),
|
||
});
|
||
factsAdded += 1;
|
||
}
|
||
|
||
console.log(' 4 capacity commitments, with sites, MSAs and negotiated SLAs');
|
||
console.log(` ${factSeeds.length} agent-derived facts (${factsAdded} new) — 2 applied, 4 awaiting review`);
|
||
console.log(' 6 demand deals across the pipeline, 5 supply deals');
|
||
console.log(' Allocations including one unconverted hold and internal research burn');
|
||
console.log('\nEverything is prefixed "DEMO — ". Remove it with: pnpm db:demo -- --clear');
|
||
}
|
||
|
||
const shouldClear = process.argv.includes('--clear');
|
||
(shouldClear ? clear() : seedDemo())
|
||
.then(() => process.exit(0))
|
||
.catch((error) => {
|
||
console.error('Demo seed failed:', error);
|
||
process.exit(1);
|
||
});
|