Rebuild Piggy's interface, and give the demo book a business to describe
CI / verify (push) Successful in 4m57s
CI / publish (push) Has been skipped

Piggy answered in raw markdown, threw away every tool result it streamed,
and fought the reader's scroll on every token. The three surfaces that
made it worth having — what it read, how it reasoned, what it cost — were
all on the wire and none of them reached the screen.

The transcript is now composed of five parts under components/piggy:
answers render through streamdown, the container sticks to the bottom
without pinning the reader there, tool steps say what they read and link
to the record, and each turn carries its model and token count. Three
lifecycle bugs went with them: Stop left a permanent spinner, a truncated
stream was indistinguishable from thinking, and a failed send destroyed
the message it failed to send.

Underneath, the inference path grew timeouts, jittered retries on 429 and
5xx, tolerance of the malformed frames a 30B model emits, and an
agent_runs row per turn so chat spend is observable. The system prompt now
states that a field ending in Cents is cents — without it nemotron renders
costPerGpuHourCents: 189 as "$189 per GPU-hour", which is a 100x error on
the most scrutinised number in the room.

The demo book was arithmetically incoherent: every deal's value
contradicted its own allocation revenue by up to 3.6x, nothing had ever
closed, no customer had any paper, and the marketplace was empty. Deal
value is now derived from the allocation, the book clears 5.3% across five
blocks with one deliberately underwater, and the renewal, compliance and
agent-provenance machinery finally has rows to act on. A --clear that
deleted every obligation, SLA term and capacity request in the database
regardless of origin is scoped to the demo's own ids.

Around that: accounts have a detail page, ⌘K searches the book, Settings
can mint the API keys it always claimed to, and deploy.sh actually ships
the agent instead of silently skipping its compose profile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude
2026-08-14 00:33:41 -07:00
parent 76e3caa1cb
commit 99d165b5e5
81 changed files with 21780 additions and 2250 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+867
View File
@@ -0,0 +1,867 @@
/**
* Piggy's operating history: the queue, the runs, the actions, and the
* evidence-bearing facts that came out of them.
*
* Without the facts the 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.
*
* Without the runs behind them the facts are worse than empty — they are
* unattributed. `facts.agent_run_id` exists so a claim can be traced to the
* execution that produced it, and a demo in which every claim arrives from
* nowhere argues against the product rather than for it. So this module seeds
* the whole chain the schema defends: a task was queued, a worker leased it, a
* run spent tokens against a priced model, an idempotency-keyed action was
* written, and only then did a fact appear.
*
* The mix is deliberate.
*
* Two `applied` facts show what a confident agent writes unprompted, and
* four `proposed` show what waits for a human — one of them a near-miss
* whose own evidence does not support it, so the review queue is not a row
* of obvious approvals.
*
* One task was rate-limited on its first attempt and succeeded on its
* second, because an agent with a perfect record is the least believable
* thing that could be shown here. Its failed run is kept: cost was spent and
* the ledger says so.
*
* One task is still queued with a future `dueAt`, so the queue has a state
* other than finished.
*
* Every run is one task's work on one subject. That is not decoration: the
* `pig_record_fact` tool refuses any claim about a record the task did not
* name, so a run that produced facts about two different accounts could not
* have happened, and seeding one would teach a reader something false about
* how the agent is allowed to behave.
*/
import { createHash } from 'node:crypto';
import { and, eq, inArray, like } from 'drizzle-orm';
import { CONSUMING_ALLOCATION_STATUSES, breakEvenPricePerGpuHourCents } from '@pig/core';
import {
accounts,
agentActions,
agentRuns,
agentTasks,
allocations,
capacityCommitments,
contacts,
facts,
users,
} from '../../schema/index';
import type { DemoContext } from './index';
/** The model Piggy runs on by default; see `PIGGY_MODEL`. */
const MODEL = 'nvidia/nemotron-3-nano-30b-a3b';
/**
* The published price of that model, in cents per million tokens.
*
* Deliberately the same numbers as `PIGGY_PRICE_INPUT_CENTS_PER_MTOK` and
* `PIGGY_PRICE_OUTPUT_CENTS_PER_MTOK`, and deliberately the same arithmetic as
* `costMicroCents` in the chat server: cents-per-million multiplied by tokens
* is already micro-cents, so the whole calculation stays in integers instead of
* rounding a fraction of a cent per run and drifting. A demo cost that does not
* reproduce from the token counts beside it is worse than no cost at all.
*/
const INPUT_CENTS_PER_MTOK = 5;
const OUTPUT_CENTS_PER_MTOK = 20;
function costMicroCents(inputTokens: number, outputTokens: number): number {
return Math.round(inputTokens * INPUT_CENTS_PER_MTOK + outputTokens * OUTPUT_CENTS_PER_MTOK);
}
/**
* Fixed ids, because `agent_runs` and `agent_tasks` have no natural key to
* dedupe on — a run is an event, and two identical events are two rows. Seeding
* them with constant ids and `ON CONFLICT DO NOTHING` is what makes a second
* `db:demo` a no-op rather than a second fortnight of invented history.
*/
const TASK_ID = {
coreweave: 'a1c0f7e2-0001-4a00-8a00-000000000001',
nebius: 'a1c0f7e2-0001-4a00-8a00-000000000002',
crusoe: 'a1c0f7e2-0001-4a00-8a00-000000000003',
lambda: 'a1c0f7e2-0001-4a00-8a00-000000000004',
dana: 'a1c0f7e2-0001-4a00-8a00-000000000005',
runpod: 'a1c0f7e2-0001-4a00-8a00-000000000006',
renewal: 'a1c0f7e2-0001-4a00-8a00-000000000007',
} as const;
const RUN_ID = {
coreweave: 'a1c0f7e2-0002-4a00-8a00-000000000001',
nebius: 'a1c0f7e2-0002-4a00-8a00-000000000002',
crusoeRateLimited: 'a1c0f7e2-0002-4a00-8a00-000000000003',
crusoe: 'a1c0f7e2-0002-4a00-8a00-000000000004',
lambda: 'a1c0f7e2-0002-4a00-8a00-000000000005',
dana: 'a1c0f7e2-0002-4a00-8a00-000000000006',
runpod: 'a1c0f7e2-0002-4a00-8a00-000000000007',
} as const;
/**
* One action row per claim, with a fixed id.
*
* The idempotency key cannot serve as that anchor here even though it is
* unique: it hashes the subject's id, and `--clear` followed by a reseed gives
* the demo accounts new ids. Keyed only on the digest, every teardown would
* leave last week's action row behind pointing at a record that no longer
* exists. The id pins the row; the key is still written exactly as
* `pig_record_fact` would compute it.
*/
const ACTION_ID = {
coreweave: 'a1c0f7e2-0003-4a00-8a00-000000000001',
nebius: 'a1c0f7e2-0003-4a00-8a00-000000000002',
crusoe: 'a1c0f7e2-0003-4a00-8a00-000000000003',
lambda: 'a1c0f7e2-0003-4a00-8a00-000000000004',
dana: 'a1c0f7e2-0003-4a00-8a00-000000000005',
runpod: 'a1c0f7e2-0003-4a00-8a00-000000000006',
} as const;
type TaskKey = keyof typeof TASK_ID;
/** The tasks that produced a claim; `watch_renewal` has not run yet. */
type FactTaskKey = keyof typeof ACTION_ID;
const minute = 60_000;
const after = (from: Date, minutes: number) => new Date(from.getTime() + minutes * minute);
/** What the task named, resolved to an id before anything is written. */
type Subject =
| { kind: 'account'; domain: string }
| { kind: 'contact'; fullName: string };
interface RunSeed {
id: string;
/** Minutes after the task's own start, so a retry lands after its failure. */
startsAfter: number;
endsAfter: number;
inputTokens: number;
outputTokens: number;
toolCallCount: number;
summary: string;
/** Set only on the run that did not finish its work. */
error?: string;
}
interface WorkSeed {
task: TaskKey;
kind: 'enrich_account' | 'enrich_contact' | 'research_supplier';
subject: Subject;
reason: string;
priority: number;
/** One per lease taken, so a retried task shows two. */
attempts: number;
daysAgo: number;
runs: RunSeed[];
}
/**
* A fortnight of routine enrichment.
*
* Prefixed like every other invented record: a screenshot of a Piggy run
* summary must not be mistakeable for something the agent really did.
*/
function workSeeds(prefix: string): WorkSeed[] {
return [
{
task: 'coreweave',
kind: 'research_supplier',
subject: { kind: 'account', domain: 'coreweave.com' },
reason: `${prefix}Supply deal opened against an account with no supplier classification.`,
priority: 5,
attempts: 1,
daysAgo: -13,
runs: [
{
id: RUN_ID.coreweave,
startsAfter: 0,
endsAfter: 3,
inputTokens: 9_900,
outputTokens: 1_240,
toolCallCount: 3,
summary:
`${prefix}Read coreweave.com and two secondary descriptions of the same business. ` +
'All three describe GPU cloud infrastructure sold as a service, so supplierType=neocloud ' +
'at 0.96 — verified, and applied without review.',
},
],
},
{
task: 'nebius',
kind: 'research_supplier',
subject: { kind: 'account', domain: 'nebius.com' },
reason: `${prefix}EU-resident demand cannot be quoted against a block whose owner has no jurisdiction on record.`,
priority: 6,
attempts: 1,
daysAgo: -12,
runs: [
{
id: RUN_ID.nebius,
startsAfter: 0,
endsAfter: 2,
inputTokens: 8_700,
outputTokens: 980,
toolCallCount: 2,
summary:
`${prefix}Confirmed from nebius.com that the Finnish site sits inside the EU ` +
'data-residency perimeter. jurisdiction=European Union at 0.91 — verified, and applied.',
},
],
},
{
task: 'crusoe',
kind: 'research_supplier',
subject: { kind: 'account', domain: 'crusoe.ai' },
reason: `${prefix}A regulated buyer asked for the SOC 2 position on this block before signing.`,
priority: 7,
// Two leases: the first run died on an upstream rate limit, the queue
// backed off for a minute (`retryBackoffMs(1)`) and the second claimed it.
attempts: 2,
daysAgo: -9,
runs: [
{
id: RUN_ID.crusoeRateLimited,
startsAfter: 0,
endsAfter: 1,
inputTokens: 6_300,
outputTokens: 410,
toolCallCount: 1,
summary: `${prefix}Abandoned before any claim was recorded.`,
error:
'Inference upstream returned 429: rate limit on the shared key. Two tool calls were ' +
'already paid for; retrying after backoff.',
},
{
id: RUN_ID.crusoe,
startsAfter: 2,
endsAfter: 5,
inputTokens: 10_400,
outputTokens: 1_320,
toolCallCount: 4,
summary:
`${prefix}Re-ran once the rate limit cleared. crusoe.ai publishes a trust page citing ` +
'SOC 2, but states neither the report scope nor the observation window, so the claim is ' +
'0.72 — probable, and queued for a human rather than applied.',
},
],
},
{
task: 'lambda',
kind: 'enrich_account',
subject: { kind: 'account', domain: 'lambda.ai' },
reason: `${prefix}Supply deal in financial diligence against a thin firmographic record.`,
priority: 4,
attempts: 1,
daysAgo: -7,
runs: [
{
id: RUN_ID.lambda,
startsAfter: 0,
endsAfter: 4,
inputTokens: 11_300,
outputTokens: 1_460,
toolCallCount: 4,
summary:
`${prefix}Enriched lambda.ai from its own site. It markets both GPU cloud and hardware ` +
'sold outright, which weakens the neocloud reading to 0.68 — below the bar to apply itself.',
},
],
},
{
task: 'dana',
kind: 'enrich_contact',
subject: { kind: 'contact', fullName: 'Dana Whitfield' },
reason: `${prefix}Two internal documents disagree on the title of the Halcyon decision maker.`,
priority: 3,
attempts: 1,
daysAgo: -5,
runs: [
{
id: RUN_ID.dana,
startsAfter: 0,
endsAfter: 2,
inputTokens: 7_400,
outputTokens: 890,
toolCallCount: 3,
summary:
`${prefix}Read the Halcyon Research account brief: it names Dana Whitfield as VP ` +
'Infrastructure where the record says Head of Infrastructure. Neither source is dated, ' +
'so 0.54 — possible, and queued.',
},
],
},
{
task: 'runpod',
kind: 'enrich_account',
subject: { kind: 'account', domain: 'runpod.io' },
reason: `${prefix}Customer segment was blank on an account with a live burst pool behind it.`,
priority: 2,
attempts: 1,
daysAgo: -3,
runs: [
{
id: RUN_ID.runpod,
startsAfter: 0,
endsAfter: 2,
inputTokens: 6_800,
outputTokens: 1_540,
toolCallCount: 3,
summary:
`${prefix}Proposed customerSegment=frontier_lab for runpod.io at 0.31 on the strength of ` +
'marketing copy about large training runs. The excerpt does not name the account as the ' +
'party doing the training, and the same account is a supplier on this book — the queue is ' +
'holding a claim that should be rejected.',
},
],
},
];
}
interface FactSeed {
accountDomain?: string;
contactName?: string;
/** The task whose run recorded it; the tool refuses any other subject. */
task: FactTaskKey;
runId: string;
field: string;
value: string;
score: string;
band: 'verified' | 'probable' | 'possible';
status: 'applied' | 'proposed';
method: string;
sourceUrl: string;
/**
* Required, not optional. `recordFactInput` rejects a claim without both a
* source URL and an evidence excerpt, and a seeded fact that could not have
* been written through that tool is a demo of a rule the product does not
* have.
*/
excerpt: string;
/** Merged into `evidence` beside the excerpt. */
notes?: Record<string, unknown>;
}
function factSeeds(): FactSeed[] {
return [
{
accountDomain: 'coreweave.com',
task: 'coreweave',
runId: RUN_ID.coreweave,
field: 'supplierType',
value: 'neocloud',
score: '0.960',
band: 'verified',
status: 'applied',
method: 'web_search',
sourceUrl: 'https://www.coreweave.com/',
excerpt: 'Describes itself as an AI hyperscaler providing GPU cloud infrastructure.',
notes: { corroboration: 2 },
},
{
accountDomain: 'nebius.com',
task: 'nebius',
runId: RUN_ID.nebius,
field: 'jurisdiction',
value: 'European Union',
score: '0.910',
band: 'verified',
status: 'applied',
method: 'web_search',
sourceUrl: 'https://nebius.com/',
excerpt: 'Operates a datacentre in Finland, inside the EU data-residency perimeter.',
notes: { matters: 'Determines eligibility for customers with EU residency requirements.' },
},
{
accountDomain: 'crusoe.ai',
task: 'crusoe',
runId: RUN_ID.crusoe,
field: 'certifications',
value: 'SOC 2 Type II',
score: '0.720',
band: 'probable',
status: 'proposed',
method: 'web_search',
sourceUrl: 'https://crusoe.ai/',
excerpt:
'A trust page references SOC 2, but the report scope and observation window are not stated.',
notes: { caution: 'Scope matters — a report can cover only some products.' },
},
{
accountDomain: 'lambda.ai',
task: 'lambda',
runId: RUN_ID.lambda,
field: 'supplierType',
value: 'neocloud',
score: '0.680',
band: 'probable',
status: 'proposed',
method: 'web_search',
sourceUrl: 'https://lambda.ai/',
excerpt: 'Markets GPU cloud and on-premises clusters.',
},
{
contactName: 'Dana Whitfield',
task: 'dana',
runId: RUN_ID.dana,
field: 'title',
value: 'VP Infrastructure',
score: '0.540',
band: 'possible',
status: 'proposed',
// The source is an invented internal document about an invented company,
// which is the only kind of document this seed is entitled to quote.
method: 'document',
sourceUrl: 'https://demo.pig.invalid/documents/halcyon-research-account-brief',
excerpt:
'Account brief, attendee list: "Dana Whitfield, VP Infrastructure, Halcyon Research".',
notes: {
conflict: 'The CRM records Head of Infrastructure. Sources disagree, and neither is dated.',
},
},
{
accountDomain: 'runpod.io',
task: 'runpod',
runId: RUN_ID.runpod,
field: 'customerSegment',
value: 'frontier_lab',
score: '0.310',
band: 'possible',
status: 'proposed',
method: 'inference',
sourceUrl: 'https://runpod.io/',
// The excerpt does not support the claim, which is the point: the review
// queue is where a reader learns to check the evidence rather than the
// score. A weak model produces exactly this shape of near-miss.
excerpt: 'Marketing copy refers to customers running large training jobs.',
notes: {
warning:
'Weak. Nothing here says this account trains frontier models, and it is a supply-side ' +
'provider on this book — a reviewer should reject it.',
},
},
];
}
/**
* The idempotency key `pig_record_fact` would have written for this claim.
*
* Reproduced rather than invented, digest and all, so the mechanism the schema
* is most careful about is demonstrated by rows a reader can recompute.
*/
function factIdempotencyKey(
taskId: string,
input: {
targetType: 'account' | 'contact';
targetId: string;
field: string;
value: string;
sourceUrl: string;
evidenceExcerpt: string;
},
): string {
const digest = createHash('sha256')
.update(
JSON.stringify([
input.targetType,
input.targetId,
input.field,
input.value,
input.sourceUrl,
input.evidenceExcerpt,
]),
)
.digest('hex');
return `piggy:fact:${taskId}:${digest}`;
}
export async function seedFacts(context: DemoContext): Promise<{
total: number;
added: number;
runs: number;
tasks: number;
actions: number;
costMicroCents: number;
}> {
const { db, prefix, at } = context;
// The principal every queued task ran on behalf of. Resolved here rather
// than threaded in, so this module keeps its single-parameter shape.
const [owner] = await db.select({ id: users.id }).from(users).limit(1);
const ownerUserId = owner?.id ?? null;
const work = workSeeds(prefix);
const subjectIds = new Map<TaskKey, string>();
for (const item of work) {
const id =
item.subject.kind === 'account'
? (
await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.domain, item.subject.domain))
.limit(1)
)[0]?.id
: (
await db
.select({ id: contacts.id })
.from(contacts)
.where(eq(contacts.fullName, item.subject.fullName))
.limit(1)
)[0]?.id;
if (id) subjectIds.set(item.task, id);
}
/*
* Which of these rows are already here.
*
* The upserts below rewrite rather than skip, because the subject of a task
* is an account or contact id and `--clear` gives the demo book new ids on
* every teardown: a row that merely survived would keep pointing at a record
* that no longer exists. Counting from this snapshot rather than from
* `RETURNING` is what still distinguishes a fresh seed from a reseed once the
* write became an update.
*/
const existingTasks = new Set(
(
await db
.select({ id: agentTasks.id })
.from(agentTasks)
.where(inArray(agentTasks.id, Object.values(TASK_ID)))
).map((row) => row.id),
);
const existingRuns = new Set(
(
await db
.select({ id: agentRuns.id })
.from(agentRuns)
.where(inArray(agentRuns.id, Object.values(RUN_ID)))
).map((row) => row.id),
);
const existingActions = new Set(
(
await db
.select({ id: agentActions.id })
.from(agentActions)
.where(inArray(agentActions.id, Object.values(ACTION_ID)))
).map((row) => row.id),
);
let tasksAdded = 0;
let runsAdded = 0;
let spentMicroCents = 0;
for (const item of work) {
const subjectId = subjectIds.get(item.task);
if (!subjectId) continue;
const queuedAt = at(item.daysAgo);
const started = after(queuedAt, 5 + item.runs[0]!.startsAfter);
const lastRun = item.runs[item.runs.length - 1]!;
const finished = after(queuedAt, 5 + lastRun.endsAfter);
const payload = { source: 'demo', subjectKind: item.subject.kind };
await db
.insert(agentTasks)
.values({
id: TASK_ID[item.task],
kind: item.kind,
subject: subjectId,
reason: item.reason,
payload,
priority: item.priority,
budget: 4,
attempts: item.attempts,
maxAttempts: 3,
dueAt: queuedAt,
// Null on both, because `AgentTaskQueue.succeed` clears the lease when
// it stamps the outcome. A finished task holding a lease would be a
// row no worker in this codebase could have written.
leasedUntil: null,
leasedBy: null,
startedAt: started,
finishedAt: finished,
outcome: 'succeeded',
// Also cleared: the queue nulls the previous attempt's error when the
// task is re-claimed, so the rate-limited attempt survives on its run
// rather than here.
error: null,
requestedByUserId: ownerUserId,
createdAt: queuedAt,
})
.onConflictDoUpdate({
target: agentTasks.id,
set: { subject: subjectId, reason: item.reason, payload, requestedByUserId: ownerUserId },
});
if (!existingTasks.has(TASK_ID[item.task])) tasksAdded += 1;
for (const run of item.runs) {
const cost = costMicroCents(run.inputTokens, run.outputTokens);
spentMicroCents += cost;
const input = {
kind: item.kind,
subject: subjectId,
reason: item.reason,
payload,
};
await db
.insert(agentRuns)
.values({
id: run.id,
agentTaskId: TASK_ID[item.task],
agent: 'piggy',
principalUserId: ownerUserId,
status: run.error ? 'failed' : 'succeeded',
model: MODEL,
inputTokens: run.inputTokens,
outputTokens: run.outputTokens,
costMicroCents: cost,
input,
result: { toolCallCount: run.toolCallCount },
summary: run.summary,
error: run.error ?? null,
startedAt: after(queuedAt, 5 + run.startsAfter),
finishedAt: after(queuedAt, 5 + run.endsAfter),
})
.onConflictDoUpdate({
target: agentRuns.id,
set: { input, principalUserId: ownerUserId },
});
if (!existingRuns.has(run.id)) runsAdded += 1;
}
}
const seeds = factSeeds();
let factsAdded = 0;
let actionsAdded = 0;
for (const [index, seed] of seeds.entries()) {
const targetId = subjectIds.get(seed.task);
if (!targetId) continue;
const targetType = seed.accountDomain ? 'account' : 'contact';
const evidence: Record<string, unknown> = {
excerpt: seed.excerpt,
taskId: TASK_ID[seed.task],
taskReason: work.find((item) => item.task === seed.task)?.reason,
...seed.notes,
};
// 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(
targetType === 'account'
? eq(facts.accountId, targetId)
: eq(facts.contactId, targetId),
eq(facts.field, seed.field),
eq(facts.value, seed.value),
),
)
.limit(1);
let factId = existing?.id;
if (existing) {
// Converges a database seeded before the runs existed: the claim is
// already there, its provenance is what was missing.
await db
.update(facts)
.set({
agentRunId: seed.runId,
sourceUrl: seed.sourceUrl,
method: seed.method,
evidence,
})
.where(eq(facts.id, existing.id));
} else {
const [row] = await db
.insert(facts)
.values({
...(targetType === 'account' ? { accountId: targetId } : { contactId: targetId }),
field: seed.field,
value: seed.value,
score: seed.score,
band: seed.band,
status: seed.status,
method: seed.method,
sourceUrl: seed.sourceUrl,
evidence,
agentRunId: seed.runId,
observedAt: at(-1 - (index % 6)),
})
.returning({ id: facts.id });
factId = row?.id;
factsAdded += 1;
}
if (!factId) continue;
const idempotencyKey = factIdempotencyKey(TASK_ID[seed.task], {
targetType,
targetId,
field: seed.field,
value: seed.value,
sourceUrl: seed.sourceUrl,
evidenceExcerpt: seed.excerpt,
});
const metadata = { taskId: TASK_ID[seed.task], field: seed.field, factId };
await db
.insert(agentActions)
.values({
id: ACTION_ID[seed.task],
agentRunId: seed.runId,
type: 'record_fact',
targetType,
targetId,
summary: `${seed.field}: ${seed.value}`.slice(0, 500),
idempotencyKey,
status: 'completed',
externalId: factId,
metadata,
})
// A reseed, like a retried task, must leave one action per claim. The
// unique key does that job in the product; here the id does it, because
// the key itself moves when the subject is recreated with a new id.
.onConflictDoUpdate({
target: agentActions.id,
set: { targetId, idempotencyKey, externalId: factId, metadata },
});
if (!existingActions.has(ACTION_ID[seed.task])) actionsAdded += 1;
}
const watch = await seedRenewalWatch(context, ownerUserId);
if (watch) tasksAdded += 1;
return {
total: seeds.length,
added: factsAdded,
runs: runsAdded,
tasks: tasksAdded,
actions: actionsAdded,
costMicroCents: spentMicroCents,
};
}
/**
* The one task that has not run yet.
*
* Its reason is computed from the ledger rather than written by hand, because
* the whole argument for `watch_renewal` is that the agent is reading the same
* arithmetic the margin page shows. A hand-typed sell-through would go stale
* the moment somebody changed an allocation, and a wrong number here would be a
* demonstration of the agent being confidently wrong.
*/
async function seedRenewalWatch(
context: DemoContext,
ownerUserId: string | null,
): Promise<boolean> {
const { db, prefix, at } = context;
// The EU H100 block: the one that is underwater, and therefore the one worth
// watching to expiry.
const [block] = await db
.select({
id: capacityCommitments.id,
name: capacityCommitments.name,
endsAt: capacityCommitments.endsAt,
totalGpuHours: capacityCommitments.totalGpuHours,
costPerGpuHourCents: capacityCommitments.costPerGpuHourCents,
})
.from(capacityCommitments)
.innerJoin(accounts, eq(capacityCommitments.accountId, accounts.id))
.where(
and(
eq(accounts.domain, 'nebius.com'),
eq(capacityCommitments.gpuType, 'H100_80GB'),
// Scoped to the demo book and ordered, because the base seed and other
// fixtures put their own blocks on these accounts: an unordered pick
// would watch a different commitment on a different day.
like(capacityCommitments.name, `${prefix}%`),
),
)
.orderBy(capacityCommitments.startsAt)
.limit(1);
if (!block) return false;
const sold = await db
.select({
gpuHours: allocations.gpuHours,
pricePerGpuHourCents: allocations.pricePerGpuHourCents,
})
.from(allocations)
.where(
and(
eq(allocations.capacityCommitmentId, block.id),
inArray(allocations.status, [...CONSUMING_ALLOCATION_STATUSES]),
),
);
const committedHours = Number(block.totalGpuHours);
const priced = sold.map((row) => ({
gpuHours: Number(row.gpuHours),
pricePerGpuHourCents: row.pricePerGpuHourCents,
}));
const soldHours = priced.reduce((sum, row) => sum + row.gpuHours, 0);
const soldPct = committedHours > 0 ? Math.round((soldHours / committedHours) * 100) : 0;
const breakEvenCents = breakEvenPricePerGpuHourCents(
{ gpuHours: committedHours, costPerGpuHourCents: block.costPerGpuHourCents ?? 0 },
priced,
);
const daysToExpiry = Math.round((block.endsAt.getTime() - Date.now()) / 86_400_000);
const breakEven =
breakEvenCents === null
? 'nothing left to price'
: `the remaining hours must fetch $${(breakEvenCents / 100).toFixed(2)}/GPU-hr to cover the block`;
const [already] = await db
.select({ id: agentTasks.id })
.from(agentTasks)
.where(eq(agentTasks.id, TASK_ID.renewal))
.limit(1);
const reason =
`${prefix}${block.name.replace(prefix, '')} lapses in ${daysToExpiry} days at ` +
`${soldPct}% sold; ${breakEven}. Re-check weekly until it is re-let or written down.`;
const payload = {
capacityCommitmentId: block.id,
soldPct,
daysToExpiry,
breakEvenPricePerGpuHourCents: breakEvenCents === null ? null : Math.round(breakEvenCents),
};
await db
.insert(agentTasks)
.values({
id: TASK_ID.renewal,
kind: 'watch_renewal',
subject: block.id,
reason,
payload,
// Above the enrichment work: a block running out of term is time-boxed in
// a way that a blank firmographic field is not.
priority: 8,
budget: 4,
attempts: 0,
maxAttempts: 3,
dueAt: at(2),
// Unclaimed and unstarted, which is the state the queue leaves a row in
// until a worker leases it.
leasedUntil: null,
leasedBy: null,
startedAt: null,
finishedAt: null,
outcome: null,
requestedByUserId: ownerUserId,
createdAt: at(-1),
})
.onConflictDoUpdate({
target: agentTasks.id,
// The block is re-created with a new id by `--clear`, and the sell-through
// moves whenever an allocation does. Both belong on the row a worker would
// read, not on the row that happened to be written first.
set: { subject: block.id, reason, payload, requestedByUserId: ownerUserId, dueAt: at(2) },
});
return !already;
}
+164
View File
@@ -0,0 +1,164 @@
/**
* Calendar entries.
*
* The only rows the calendar owns. Everything else on it is projected from
* a record that already carries the date; these are the human-owned items
* that have nowhere else to live. So nothing here restates a deadline that a
* contract, an obligation or an authorisation already holds — an entry is the
* WORK before the date, which is the half a deal desk actually schedules.
*
* Placement is by quarter fraction rather than by a fixed offset wherever the
* item has to be visible. The page opens on the current quarter, and an entry
* pinned to `at(+45)` spends a third of the year in a quarter nobody is looking
* at. The two genuinely urgent items keep their day offsets, because "before
* the hold lapses" is a claim about this week, not about the quarter.
*/
import { eq } from 'drizzle-orm';
import { accounts, calendarEntries } from '../../schema/index';
import type { DemoContext } from './index';
export async function seedCalendar(
context: DemoContext,
ownerUserId: string | null,
): Promise<{ total: number; added: number }> {
const { db, prefix, at, quarterAt } = context;
const accountIdByName = async (name: string): Promise<string | null> => {
const [row] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, name))
.limit(1);
return row?.id ?? null;
};
const halcyonId = await accountIdByName(`${prefix}Halcyon Research`);
const tessellateId = await accountIdByName(`${prefix}Tessellate Labs`);
const meridianId = await accountIdByName(`${prefix}Meridian Sovereign Cloud`);
/*
* Ahead of the export licence, whichever way the licence date resolved.
*
* The licence in `compliance.ts` expires at the earlier of +24 days and 93%
* through the quarter; taking the earlier of +10 days and 80% of the quarter
* is before it under both branches, without either file having to know which
* branch the other took.
*/
const beforeTheLicenceLapses = (): Date => {
const target = at(10);
const lastCall = quarterAt(0, 0.8);
return target < lastCall ? target : lastCall;
};
const CALENDAR_ENTRIES = [
{
title: `${prefix}Q business review — Halcyon Research`,
kind: 'qbr' as const,
description: 'Utilisation against the reserved block, and the expansion case.',
startsAt: quarterAt(0, 0.7),
durationMinutes: 90,
accountId: halcyonId,
},
{
title: `${prefix}Renewal check-in — Nebius`,
kind: 'meeting' as const,
// A fortnight ahead of the +21 renewal notice obligation, which is the
// point: the reminder has to land before the deadline, not on it.
description: 'Decide whether to give notice before the 90-day window closes.',
startsAt: at(7),
durationMinutes: 45,
accountId: null,
},
{
title: `${prefix}Export-control review — Tessellate ownership change`,
kind: 'meeting' as const,
// The one determination on the book sitting at `needs_review`. The hold
// it blocks lapses inside a fortnight, so this is the meeting that either
// converts the deal or releases the capacity to someone else.
description:
'Counsel on the Hong Kong holding structure and whether the community pool ' +
'can evidence physical control. The hold lapses before the month is out.',
startsAt: at(4),
durationMinutes: 60,
accountId: tessellateId,
},
{
title: `${prefix}Licence renewal — Meridian Sovereign Cloud`,
kind: 'meeting' as const,
description:
'The export licence everything sold to this account rests on expires this ' +
'quarter. Open the renewal, and evidence the end-use reporting condition.',
startsAt: beforeTheLicenceLapses(),
durationMinutes: 60,
accountId: meridianId,
},
{
title: `${prefix}Renewal decision — H200 anchor block`,
kind: 'internal' as const,
// Not the notice deadline itself, which lives on the MSA as an obligation
// and is projected from there. This is the meeting at which renew, resize
// or exit is actually chosen, which has to happen while notice is still
// possible.
description:
'Renew, resize or exit the anchor block. Needs the utilisation and margin ' +
'numbers in the room, and it has to conclude while notice can still be served.',
startsAt: quarterAt(0, 0.6),
durationMinutes: 60,
accountId: null,
},
{
title: `${prefix}True-up preparation — take-or-pay shortfall`,
kind: 'reminder' as const,
// The true-up date itself is a contract obligation. What has no home is
// the week of reconciliation before it, which is when a disputed number
// can still be fixed rather than argued about after the invoice.
description:
'Reconcile hours drawn against the 100% floor before the true-up falls due. ' +
'Unsold hours are already paid for; the shortfall is what becomes payable.',
startsAt: quarterAt(0, 0.85),
durationMinutes: 30,
accountId: null,
},
{
title: `${prefix}Pipeline review — next quarter commit`,
kind: 'internal' as const,
description: 'Weighted pipeline against the number, before the quarter opens.',
startsAt: quarterAt(1, 0.02),
durationMinutes: 60,
accountId: null,
},
{
title: `${prefix}Blackwell availability campaign`,
kind: 'campaign' as const,
description: 'Outbound week against accounts waiting on B200 capacity.',
startsAt: quarterAt(0, 0.45),
// A span, not a point — the calendar must render both.
durationMinutes: 5 * 24 * 60,
accountId: null,
},
];
let entriesAdded = 0;
for (const entry of CALENDAR_ENTRIES) {
const [existingEntry] = await db
.select({ id: calendarEntries.id })
.from(calendarEntries)
.where(eq(calendarEntries.title, entry.title))
.limit(1);
if (existingEntry) continue;
await db.insert(calendarEntries).values({
title: entry.title,
description: entry.description,
kind: entry.kind,
startsAt: entry.startsAt,
endsAt: new Date(entry.startsAt.getTime() + entry.durationMinutes * 60_000),
allDay: entry.durationMinutes >= 24 * 60,
accountId: entry.accountId,
ownerUserId,
createdByUserId: ownerUserId,
});
entriesAdded += 1;
}
return { total: CALENDAR_ENTRIES.length, added: entriesAdded };
}
+113
View File
@@ -0,0 +1,113 @@
/**
* `--clear`: take the invented book back out again.
*
* Everything the demo seed writes is either prefixed `DEMO — ` or hangs off a
* row that is, so every delete here is scoped to one of those two things. A
* teardown that runs against a database with real records in it is exactly the
* situation this command is for — someone demoing on top of their own data —
* and it must leave that data untouched.
*/
import { eq, inArray, like } from 'drizzle-orm';
import { unstampDemoActivity } from './activities';
import {
accounts,
activities,
allocations,
calendarEntries,
capacityCommitments,
capacityRequests,
complianceArtifacts,
contacts,
contractObligations,
contracts,
demandDeals,
exportAuthorizations,
learnResources,
slaTerms,
teamMemberships,
users,
supplyDeals,
} from '../../schema/index';
import type { DemoContext } from './index';
export async function clear(context: DemoContext): Promise<void> {
const { db, prefix } = context;
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);
/*
* The children of the demo paper and the demo deals, named explicitly.
*
* These three deletes — obligations, SLA terms, capacity requests — used to
* run with NO WHERE CLAUSE. `pnpm db:demo -- --clear` is a documented
* command, so anyone who ran the demo book on top of their own data lost
* every renewal deadline, every negotiated SLA term and every customer
* capacity request in the database along with it: the three tables whose
* rows are hardest to reconstruct, because they record what was negotiated
* rather than what can be re-imported. Scoping them by parent id keeps the
* blast radius inside the demo book and keeps the delete order valid, since
* each of the three is a child of a row deleted a few lines further down.
*/
const demoContracts = await db
.select({ id: contracts.id })
.from(contracts)
.where(like(contracts.title, `${prefix}%`));
const contractIds = demoContracts.map((c) => c.id);
const demoDemandDeals = await db
.select({ id: demandDeals.id })
.from(demandDeals)
.where(like(demandDeals.name, `${prefix}%`));
const demandDealIds = demoDemandDeals.map((d) => d.id);
await db.delete(calendarEntries).where(like(calendarEntries.title, `${prefix}%`));
await db.delete(learnResources).where(like(learnResources.title, `${prefix}%`));
await db.delete(allocations).where(like(allocations.notes, `${prefix}%`));
// Guarded rather than relying on `inArray` with an empty list, which is a
// condition different drivers have historically disagreed about.
if (contractIds.length > 0) {
await db.delete(contractObligations).where(inArray(contractObligations.contractId, contractIds));
await db.delete(slaTerms).where(inArray(slaTerms.contractId, contractIds));
}
await db.delete(contracts).where(like(contracts.title, `${prefix}%`));
if (demandDealIds.length > 0) {
await db.delete(capacityRequests).where(inArray(capacityRequests.demandDealId, demandDealIds));
}
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}%`));
// Before the rows go: the supplier accounts are real and survive `--clear`,
// but their lastActivityAt is computed from demo correspondence. Recompute it
// from whatever non-demo activity remains first — once the activities are
// deleted there is no way to tell which accounts the demo book had touched.
await unstampDemoActivity(context);
await db.delete(activities).where(like(activities.subject, `${prefix}%`));
for (const id of ids) {
// Compliance rows cascade on the account anyway; deleted explicitly so the
// order of removal stays readable rather than relying on the constraint.
await db.delete(exportAuthorizations).where(eq(exportAuthorizations.accountId, id));
await db.delete(complianceArtifacts).where(eq(complianceArtifacts.accountId, id));
await db.delete(contacts).where(eq(contacts.accountId, id));
}
await db.delete(accounts).where(like(accounts.name, `${prefix}%`));
// The invented sellers the demand book creates to own its records. Their
// foreign keys are `on delete set null`, so leaving them behind corrupts
// nothing — but a teardown that leaves four fictional colleagues in the team
// list has not finished the job.
const demoSellers = await db.select({ id: users.id }).from(users).where(like(users.name, `${prefix}%`));
if (demoSellers.length > 0) {
const sellerIds = demoSellers.map((seller) => seller.id);
await db.delete(teamMemberships).where(inArray(teamMemberships.userId, sellerIds));
await db.delete(users).where(inArray(users.id, sellerIds));
}
console.log(`Removed ${ids.length} demo account(s) and everything hanging from them.`);
}
+625
View File
@@ -0,0 +1,625 @@
/**
* Export control, ownership, and the evidence behind both.
*
* `schema/compliance.ts` spends its opening page on one regulatory fact —
* country of incorporation is not a valid key, because the licence test reaches
* through the corporate tree to the ULTIMATE PARENT — and the demo book used to
* exercise none of it: no ownership on any account, no decision anywhere, one
* authorisation and one artefact on the same account. A distinctive idea that
* renders as an empty panel teaches nobody anything.
*
* So this file seeds the argument rather than a sample row:
*
* an ordinary US counterparty that clears cleanly, on a live allocation;
* a UK counterparty whose ultimate parent moved to Hong Kong between the
* proposal and the hold, which is the case the doctrine exists for and the
* only one on the book that needs a person to look at it;
* an enquiry closed at qualification, before any allocation existed, because
* the Singapore incorporation did not change where the parent sits;
* a sovereign buyer operating under a named licence that expires this
* quarter, and a research institute whose case-by-case authorisation has
* ALREADY LAPSED and which nobody has noticed.
*
* Two boundaries hold throughout.
*
* **Only invented, prefixed accounts carry any of this.** The supply side of
* this book is real, named companies. Fabricating a corporate parent, a licence
* or a lapsed certification against a real business is worse than fabricating a
* contract value: it is an allegation. Real accounts are left exactly as the
* base seed found them.
*
* **Nothing here is a legal determination.** `decision` is set by a named
* person under a stated `ruleVersion`, with the three coordinates it turned on
* recorded beside it, which is what makes it auditable two years later.
*/
import { and, eq, inArray } from 'drizzle-orm';
import {
accounts,
allocations,
capacityRequests,
complianceArtifacts,
complianceDecisions,
contacts,
demandDeals,
exportAuthorizations,
users,
} from '../../schema/index';
import type { DemoContext } from './index';
/**
* The revision of the check every determination below was taken under.
*
* It doubles as the idempotency key: re-running the seed must not record a
* second determination for the same counterparty under the same rules, which
* is also the real-world rule — a decision is superseded, never duplicated.
*/
const RULE_VERSION = 'hq-test/2026.02';
/**
* Counted the way the calendar slice counts: `total` is what the book asks for,
* `added` what this run actually wrote. A summary that reported only the new
* rows would print zero on every re-run, which reads as a failure rather than
* as idempotency working.
*/
export interface ComplianceSummary {
authorizations: { total: number; added: number };
artifacts: { total: number; added: number };
decisions: { total: number; added: number };
}
/**
* Ownership for the invented demand book.
*
* `ultimateParentName` is set even where the counterparty is its own ultimate
* parent: "verified, nothing above it" and "nobody has looked" are different
* states, and only the first is safe to sell against. Quillon is deliberately
* left blank — it is still at qualification, and a CRM that quietly fills in an
* unverified ownership chain is worse than one that admits the gap.
*/
function ownershipBook(prefix: string) {
return [
{
account: `${prefix}Halcyon Research`,
jurisdiction: 'Delaware, United States',
ultimateParentName: `${prefix}Halcyon Research, Inc.`,
ultimateParentCountry: 'United States',
verifiedDaysAgo: 58,
},
{
account: `${prefix}Verity Health AI`,
jurisdiction: 'Germany',
ultimateParentName: `${prefix}Verity Health AG`,
ultimateParentCountry: 'Germany',
verifiedDaysAgo: 96,
},
{
account: `${prefix}Northwind Robotics`,
jurisdiction: 'Delaware, United States',
ultimateParentName: `${prefix}Northwind Robotics, Inc.`,
ultimateParentCountry: 'United States',
verifiedDaysAgo: 140,
},
{
// The account the doctrine exists for. Incorporated in England, and on
// `country` alone indistinguishable from any other British startup — but
// a Series A extension moved voting control to a Hong Kong holding
// company, and the headquarters test follows the parent, not the paper.
account: `${prefix}Tessellate Labs`,
jurisdiction: 'England & Wales',
ultimateParentName: `${prefix}Tessellate Holdings (HK) Limited`,
ultimateParentCountry: 'Hong Kong SAR, China',
verifiedDaysAgo: 6,
},
{
// Verified two quarters before a 24-month commitment went to legal, which
// is exactly the staleness the column exists to make visible.
account: `${prefix}Aurelian Systems`,
jurisdiction: 'Delaware, United States',
ultimateParentName: `${prefix}Aurelian Industries, Inc.`,
ultimateParentCountry: 'United States',
verifiedDaysAgo: 210,
},
];
}
/**
* Counterparties that exist in this book because of compliance rather than in
* spite of it, and the two segments nothing else seeds.
*
* A sovereign programme and a research institute are not decoration: they buy
* differently — procurement measured in quarters, named end uses, authorisation
* conditions written into the order form — and they are where export control
* stops being theoretical. The third is the enquiry that never became a deal.
*/
function complianceAccounts(prefix: string) {
return [
{
name: `${prefix}Meridian Sovereign Cloud`,
segment: 'sovereign' as const,
country: 'United Arab Emirates',
region: 'Abu Dhabi',
jurisdiction: 'United Arab Emirates',
ultimateParentName: `${prefix}Meridian National Holdings PJSC`,
ultimateParentCountry: 'United Arab Emirates',
verifiedDaysAgo: 33,
lastActivityDaysAgo: 4,
description:
'Fictional national compute programme, for demonstration only. Buys under a ' +
'named export licence with conditions on end use and physical access.',
contact: { name: 'Nadia Al-Farsi', title: 'Head of Procurement' },
},
{
name: `${prefix}Calderwood Institute for Computational Science`,
segment: 'research_institution' as const,
country: 'United Kingdom',
region: 'Cambridge',
jurisdiction: 'England & Wales',
ultimateParentName: `${prefix}University of Calderwood`,
ultimateParentCountry: 'United Kingdom',
verifiedDaysAgo: 260,
lastActivityDaysAgo: 31,
description:
'Fictional research institute, for demonstration only. Mixed-nationality ' +
'research staff, so end use and access are conditions rather than notes.',
contact: { name: 'Dr Rhiannon Vale', title: 'Director of Research Computing' },
},
{
// No deal, no contact, no allocation — and that is the record. An enquiry
// screened out at qualification still has to leave evidence behind, or
// the next seller to meet them starts the same conversation from nothing.
name: `${prefix}Sable Ridge Analytics`,
segment: 'enterprise' as const,
country: 'Singapore',
region: 'Singapore',
jurisdiction: 'Singapore',
ultimateParentName: `${prefix}Sable Ridge Group Holdings`,
ultimateParentCountry: 'China',
verifiedDaysAgo: 12,
lastActivityDaysAgo: 12,
description:
'Fictional company, for demonstration only. Enquiry closed at qualification ' +
'on the ultimate-parent test.',
contact: null,
},
];
}
export async function seedCompliance(context: DemoContext): Promise<ComplianceSummary> {
const { db, prefix, at, quarterAt } = context;
/**
* Near-term, but never past the quarter the calendar opens on.
*
* A plain `at(24)` spends a quarter of the year pointing into the NEXT
* quarter, and the export-authorisation lane is then empty for whoever opens
* the page today — which is precisely how the one seeded authorisation
* managed to be invisible for half of every quarter.
*/
const soonInThisQuarter = (days: number): Date => {
const target = at(days);
const lastCall = quarterAt(0, 0.93);
return target < lastCall ? target : lastCall;
};
/** Whoever signs the demo book's determinations. A decision needs a decider. */
const [decider] = await db.select({ id: users.id }).from(users).orderBy(users.createdAt).limit(1);
const decidedByUserId = decider?.id ?? null;
const accountIdByName = async (name: string): Promise<string | null> => {
const [row] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, name))
.limit(1);
return row?.id ?? null;
};
// ------------------------------------------------------------- ownership
for (const owner of ownershipBook(prefix)) {
await db
.update(accounts)
.set({
jurisdiction: owner.jurisdiction,
ultimateParentName: owner.ultimateParentName,
ultimateParentCountry: owner.ultimateParentCountry,
ownershipVerifiedAt: at(-owner.verifiedDaysAgo),
})
.where(eq(accounts.name, owner.account));
}
for (const candidate of complianceAccounts(prefix)) {
const existingId = await accountIdByName(candidate.name);
const [inserted] = existingId
? []
: await db
.insert(accounts)
.values({
name: candidate.name,
side: 'demand',
customerSegment: candidate.segment,
country: candidate.country,
region: candidate.region,
jurisdiction: candidate.jurisdiction,
ultimateParentName: candidate.ultimateParentName,
ultimateParentCountry: candidate.ultimateParentCountry,
ownershipVerifiedAt: at(-candidate.verifiedDaysAgo),
description: candidate.description,
source: 'seed',
confidence: 'confirmed',
lastActivityAt: at(-candidate.lastActivityDaysAgo),
})
.returning({ id: accounts.id });
const accountId = existingId ?? inserted?.id;
if (!accountId || !candidate.contact) continue;
const [existingContact] = await db
.select({ id: contacts.id })
.from(contacts)
.where(
and(eq(contacts.accountId, accountId), eq(contacts.fullName, candidate.contact.name)),
)
.limit(1);
if (existingContact) continue;
await db.insert(contacts).values({
accountId,
fullName: candidate.contact.name,
title: candidate.contact.title,
affiliation: 'staff',
isDecisionMaker: true,
confidence: 'confirmed',
source: 'seed',
email: null,
});
}
// ------------------------------------------------- jurisdiction constraints
/*
* An excluded jurisdiction is a commercial constraint, not a preference, and
* both of these narrow the inventory that can lawfully or contractually
* serve the deal.
*
* Verity's is data protection rather than export control: a German health
* customer excluding US-jurisdiction operators is refusing the reach of the
* CLOUD Act over its processor, which no `allowedRegions` list can express —
* a US-owned operator running an EU region is still a US-jurisdiction
* operator. It is also what forces the deal onto the Finnish block.
*
* Halcyon's is the frontier-lab posture on model weights, which is about
* where the machines and their operators sit rather than where the data does.
*/
const exclusionBook = [
{ account: `${prefix}Verity Health AI`, jurisdictions: ['United States'] },
{
account: `${prefix}Halcyon Research`,
jurisdictions: ['China', 'Hong Kong SAR, China', 'Russia'],
},
];
for (const exclusion of exclusionBook) {
const accountId = await accountIdByName(exclusion.account);
if (!accountId) continue;
const dealIds = (
await db
.select({ id: demandDeals.id })
.from(demandDeals)
.where(eq(demandDeals.accountId, accountId))
).map((deal) => deal.id);
if (dealIds.length === 0) continue;
await db
.update(capacityRequests)
.set({ excludedJurisdictions: exclusion.jurisdictions })
.where(inArray(capacityRequests.demandDealId, dealIds));
}
// -------------------------------------------------------- authorisations
const verityId = await accountIdByName(`${prefix}Verity Health AI`);
const meridianId = await accountIdByName(`${prefix}Meridian Sovereign Cloud`);
const calderwoodId = await accountIdByName(`${prefix}Calderwood Institute for Computational Science`);
const halcyonId = await accountIdByName(`${prefix}Halcyon Research`);
const tessellateId = await accountIdByName(`${prefix}Tessellate Labs`);
const sableRidgeId = await accountIdByName(`${prefix}Sable Ridge Analytics`);
const authorizationBook = [
{
accountId: verityId,
authorizationType: 'dc_veu',
reference: `${prefix}DC-VEU-2026-0417`,
scopeNotes:
'Illustrative demo record. Covers EU-resident training workloads only; ' +
'inference in other regions is out of scope.',
issuedAt: at(-320),
// A month out, but never past the quarter the calendar opens on — the
// previous fixed +45 days spent half of every quarter out of view.
expiresAt: soonInThisQuarter(34),
evidenceUrl: 'https://example.invalid/demo-authorisation',
verifiedAt: at(-40),
// Rules in flux for this counterparty: re-verify, do not trust the date.
volatile: true,
},
{
// The sovereign programme's licence to exist as a customer at all. Ninety
// per cent through the quarter or three weeks out, whichever comes first:
// a renewal this close is the most expensive thing on the calendar to
// miss, because everything sold under it stops being lawful on the day.
accountId: meridianId,
authorizationType: 'licence',
reference: `${prefix}EXP-L-2026-08841`,
scopeNotes:
'Illustrative demo record. Named facility only, capped at 4,096 covered ' +
'accelerators, conditioned on no foreign-national physical access and on ' +
'quarterly end-use reporting. Resale outside the named facility voids it.',
issuedAt: at(-155),
expiresAt: soonInThisQuarter(24),
evidenceUrl: 'https://example.invalid/demo-licence',
verifiedAt: at(-21),
volatile: true,
},
{
// Lapsed, and nobody has noticed — which is the entire argument for
// indexing and alerting on this column. A fixed offset rather than a
// quarter fraction because "already expired" is a claim about today, not
// about the quarter; it lands in the current quarter most of the year.
accountId: calderwoodId,
authorizationType: 'case_by_case',
reference: `${prefix}CBC-2025-1179`,
scopeNotes:
'Illustrative demo record. Capped at 5,000 GPU-hours per quarter for one ' +
'named research programme, with no deemed-export cover for non-UK staff. ' +
'EXPIRED: the successor application is still with counsel.',
issuedAt: at(-400),
expiresAt: at(-26),
evidenceUrl: 'https://example.invalid/demo-case-by-case',
verifiedAt: at(-400),
volatile: false,
},
];
let authorizationsPlanned = 0;
let authorizationsAdded = 0;
for (const authorization of authorizationBook) {
if (!authorization.accountId) continue;
authorizationsPlanned += 1;
const [existing] = await db
.select({ id: exportAuthorizations.id })
.from(exportAuthorizations)
.where(eq(exportAuthorizations.reference, authorization.reference))
.limit(1);
if (existing) continue;
await db.insert(exportAuthorizations).values({
accountId: authorization.accountId,
authorizationType: authorization.authorizationType,
reference: authorization.reference,
scopeNotes: authorization.scopeNotes,
issuedAt: authorization.issuedAt,
expiresAt: authorization.expiresAt,
evidenceUrl: authorization.evidenceUrl,
verifiedByUserId: decidedByUserId,
verifiedAt: authorization.verifiedAt,
volatile: authorization.volatile,
});
authorizationsAdded += 1;
}
// ------------------------------------------------------------- artefacts
const artifactBook = [
{
accountId: verityId,
claim: 'soc2',
scope: `${prefix}EU training platform`,
// A true certification, not an alignment claim — the distinction the
// column exists for, and the one procurement actually gates on.
isCertified: true,
soc2Type: 'type_ii',
observationWindowStart: at(-365),
observationWindowEnd: at(-10),
auditFirm: 'Demo Assurance LLP',
// Carved out, so the colocation provider's physical controls are NOT
// attested by this report however it reads in the covering letter.
carveOutMethod: 'carve_out',
productsInScope: ['training', 'managed inference'],
evidenceUrl: 'https://example.invalid/demo-soc2',
// Inside the current quarter and ahead of the deal it gates: a report
// that lapses mid-procurement stalls the procurement.
expiresAt: quarterAt(0, 0.72),
},
{
accountId: meridianId,
claim: 'iso27001',
scope: `${prefix}Sovereign region — dedicated tenancy`,
isCertified: true,
// No observation window: an ISO certificate has a validity period rather
// than an audited period, and inventing one would misdescribe it.
soc2Type: null,
observationWindowStart: null,
observationWindowEnd: null,
auditFirm: 'Demo Certification Bureau',
carveOutMethod: null,
productsInScope: ['dedicated capacity', 'managed inference'],
evidenceUrl: 'https://example.invalid/demo-iso27001',
// In this quarter but behind the licence, so the two deadlines on this
// account read as a sequence rather than as one crowded week.
expiresAt: soonInThisQuarter(45),
},
{
// Not a certification at all, and flagged as such. A penetration test is
// routinely presented alongside certifications as though it were one,
// and its scope is usually the narrower half of the story.
accountId: calderwoodId,
claim: 'pentest',
scope: `${prefix}Research computing — external perimeter only`,
isCertified: false,
soc2Type: null,
observationWindowStart: null,
observationWindowEnd: null,
auditFirm: 'Demo Offensive Security Ltd',
carveOutMethod: null,
productsInScope: ['research computing'],
evidenceUrl: 'https://example.invalid/demo-pentest',
// Next quarter, so the artefact lane does not empty the moment this one
// closes. An annual test is stale before it is expired.
expiresAt: quarterAt(1, 0.25),
},
];
let artifactsPlanned = 0;
let artifactsAdded = 0;
for (const artifact of artifactBook) {
if (!artifact.accountId) continue;
artifactsPlanned += 1;
const [existing] = await db
.select({ id: complianceArtifacts.id })
.from(complianceArtifacts)
.where(
and(
eq(complianceArtifacts.accountId, artifact.accountId),
eq(complianceArtifacts.claim, artifact.claim),
),
)
.limit(1);
if (existing) continue;
await db.insert(complianceArtifacts).values({
accountId: artifact.accountId,
claim: artifact.claim,
scope: artifact.scope,
isCertified: artifact.isCertified,
soc2Type: artifact.soc2Type,
observationWindowStart: artifact.observationWindowStart,
observationWindowEnd: artifact.observationWindowEnd,
auditFirm: artifact.auditFirm,
carveOutMethod: artifact.carveOutMethod,
productsInScope: artifact.productsInScope,
evidenceUrl: artifact.evidenceUrl,
verifiedByUserId: decidedByUserId,
verifiedAt: at(-12),
expiresAt: artifact.expiresAt,
});
artifactsAdded += 1;
}
// ------------------------------------------------------------- decisions
/**
* The allocation a determination was made against, where there is one.
*
* The predicate is on the allocation edge — a buyer matched to specific
* capacity in a specific jurisdiction — so a decision that points at nothing
* is a decision about a counterparty in the abstract. Both exist here: two of
* the three below hang off a real allocation, and the third is an enquiry
* refused before any capacity was ever reserved.
*/
const allocationForAccount = async (accountId: string): Promise<string | null> => {
const [row] = await db
.select({ id: allocations.id })
.from(allocations)
.innerJoin(demandDeals, eq(demandDeals.id, allocations.demandDealId))
.where(eq(demandDeals.accountId, accountId))
.limit(1);
return row?.id ?? null;
};
const decisionBook = [
{
accountId: halcyonId,
withAllocation: true,
beneficialOwnerName: `${prefix}Halcyon Research, Inc.`,
ultimateParentCountry: 'United States',
physicalJurisdiction: 'United States',
endUse: 'Frontier model pre-training on the customers own corpus.',
decision: 'allow',
rationale:
'Counterparty, ultimate parent and physical capacity are all US. No licence ' +
'requirement arises, and the site is one we hold under our own MSA rather ' +
'than resold. Ownership re-verified against the cap table, not the website.',
decidedDaysAgo: 58,
// Even a clean allow is conditional. Reselling the block or the parent
// changing are the two events that would make this answer wrong without
// anything about the deal appearing to change.
reEvaluationTriggers: ['resale', 'ownership_change'],
},
{
accountId: tessellateId,
withAllocation: true,
beneficialOwnerName: `${prefix}Tessellate Holdings (HK) Limited`,
ultimateParentCountry: 'Hong Kong SAR, China',
physicalJurisdiction: 'United States',
endUse: 'Burst inference for a consumer product. End customer not disclosed.',
decision: 'needs_review',
rationale:
'The Series A extension moved 62% of voting rights to a Hong Kong holding ' +
'company, so the headquarters test reaches through the English entity and ' +
'the counterpartys own country does not settle the question. Two things ' +
'are open: whether a licence is required for the covered items at this ' +
'scale, and whether a community-pool tenancy can evidence the physical ' +
'control any licence would condition on. The hold stands; it does not ' +
'convert until counsel answers both.',
decidedDaysAgo: 5,
reEvaluationTriggers: ['ownership_change', 'migration', 'authorization_expiry'],
},
{
accountId: sableRidgeId,
withAllocation: false,
beneficialOwnerName: `${prefix}Sable Ridge Group Holdings`,
ultimateParentCountry: 'China',
physicalJurisdiction: 'United States',
endUse: 'Undisclosed. Described only as "training for a customer of ours".',
decision: 'block',
rationale:
'Singapore incorporation, ultimate parent headquartered in a jurisdiction ' +
'for which covered advanced-computing items require a licence. The place of ' +
'incorporation does not change that analysis. No licence or listed-entity ' +
'authorisation on file, and the end use was not disclosed on request, so the ' +
'enquiry is closed rather than progressed. Reopen only against a granted ' +
'licence naming this entity.',
decidedDaysAgo: 12,
reEvaluationTriggers: ['ownership_change'],
},
];
let decisionsPlanned = 0;
let decisionsAdded = 0;
for (const determination of decisionBook) {
if (!determination.accountId) continue;
decisionsPlanned += 1;
const [existing] = await db
.select({ id: complianceDecisions.id })
.from(complianceDecisions)
.where(
and(
eq(complianceDecisions.accountId, determination.accountId),
eq(complianceDecisions.ruleVersion, RULE_VERSION),
),
)
.limit(1);
if (existing) continue;
await db.insert(complianceDecisions).values({
accountId: determination.accountId,
allocationId: determination.withAllocation
? await allocationForAccount(determination.accountId)
: null,
beneficialOwnerName: determination.beneficialOwnerName,
ultimateParentCountry: determination.ultimateParentCountry,
physicalJurisdiction: determination.physicalJurisdiction,
endUse: determination.endUse,
decision: determination.decision,
rationale: determination.rationale,
ruleVersion: RULE_VERSION,
decidedByUserId,
decidedAt: at(-determination.decidedDaysAgo),
reEvaluationTriggers: determination.reEvaluationTriggers,
});
decisionsAdded += 1;
}
return {
authorizations: { total: authorizationsPlanned, added: authorizationsAdded },
artifacts: { total: artifactsPlanned, added: artifactsAdded },
decisions: { total: decisionsPlanned, added: decisionsAdded },
};
}
+815
View File
@@ -0,0 +1,815 @@
/**
* The paper on both sides of the book.
*
* Upstream: an MSA per supplier, a negotiated SLA hanging off it, and the
* dated obligations that are what actually get missed. Downstream: the
* customer paper — master agreements, DPAs and order forms — which is where
* the renewal machinery lives, because the lifecycle service reads contracts
* with `side = 'demand'` and nothing else.
*/
import { and, desc, eq } from 'drizzle-orm';
import {
accounts,
allocations,
contractObligations,
contracts,
demandDeals,
slaMetricTargets,
slaTerms,
} from '../../schema/index';
import type { DemoContext } from './index';
/**
* Dated obligations per supplier, spread deliberately across the year.
*
* `kind` is one of the five the schema allows. The near-term Nebius notice is
* kept so the renewal alarm still has something to fire on today.
*/
const OBLIGATION_SCHEDULE: Record<
string,
{ title: string; kind: 'renewal_notice' | 'payment' | 'true_up'; inDays: number; description: string }[]
> = {
'nebius.com': [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: 21,
description: '90 days notice required to prevent auto-renewal.',
},
{
title: 'Quarterly instalment',
kind: 'payment',
inDays: 75,
description: 'Committed spend invoiced quarterly in arrears.',
},
],
'coreweave.com': [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: 95,
description: '90 days notice required to prevent auto-renewal.',
},
{
title: 'Prepayment drawdown reconciliation',
kind: 'payment',
inDays: 40,
description: 'Reconcile the 25% prepayment against hours actually drawn.',
},
{
title: 'Take-or-pay true-up',
kind: 'true_up',
inDays: 130,
// The obligation that turns idle capacity from a metric into an invoice.
description: 'Shortfall against the 100% floor becomes payable at the true-up date.',
},
],
'crusoe.ai': [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: 160,
description: '90 days notice required to prevent auto-renewal.',
},
],
'runpod.io': [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: 250,
description: '90 days notice required to prevent auto-renewal.',
},
],
};
/** What the supply slice knows about a block, and all this one needs of it. */
export interface SupplyPaper {
accountId: string;
domain: string;
/** Absent only if the commitment insert returned nothing. */
capacityCommitmentId: string | undefined;
days: number;
takeOrPayFloorPct: string;
prepaidPct: string;
}
/**
* Write the MSA, the SLA beneath it, its terms, and the obligation schedule.
*
* Called from inside the supplier loop rather than in a pass of its own,
* because the SLA and the obligations are children of the MSA and the MSA is a
* child of the commitment that was just written.
*/
export async function seedSupplyPaper(context: DemoContext, supply: SupplyPaper): Promise<void> {
const { db, prefix, at } = context;
const [msa] = await db
.insert(contracts)
.values({
accountId: supply.accountId,
type: 'msa',
status: 'executed',
side: 'supply',
title: `${prefix}MSA — ${supply.domain}`,
capacityCommitmentId: supply.capacityCommitmentId,
// The anchor tenant's paper predates the block by months. Without one
// contract genuinely in the past, every `contract_effective` event on
// the calendar sits in the same fortnight and the view teaches nothing.
effectiveAt: supply.domain === 'coreweave.com' ? at(-150) : at(-60),
expiresAt: at(supply.days + 60),
isAutoRenew: true,
noticeDays: 90,
takeOrPayFloorPct: supply.takeOrPayFloorPct,
prepaidPct: supply.prepaidPct,
terminationTier: supply.prepaidPct !== '0' ? '1_prepaid' : '2_take_or_pay',
governingLaw: 'New York',
})
.returning();
if (!msa) return;
// 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: supply.accountId,
type: 'sla',
status: 'executed',
side: 'supply',
title: `${prefix}SLA — ${supply.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 },
],
});
}
/*
* Obligations spread across the year rather than bunched.
*
* Three of the four used to fall on the same day at +200, which made
* every quarter after this one look empty and the current one look
* uneventful. They are the dated things most likely to be missed, so a
* demo that cannot show one falling due in each quarter is not showing
* the feature at all. Payment and true-up dates are here for the same
* reason: a renewal notice is not the only deadline that costs money.
*/
const obligationsFor = OBLIGATION_SCHEDULE[supply.domain] ?? [];
for (const obligation of obligationsFor) {
await db.insert(contractObligations).values({
contractId: msa.id,
title: `${prefix}${obligation.title}${supply.domain}`,
kind: obligation.kind,
dueAt: at(obligation.inDays),
description: obligation.description,
});
}
}
/* -------------------------------------------------------------------------
* The customer paper.
* ---------------------------------------------------------------------- */
type PaperStatus =
| 'draft'
| 'in_review'
| 'in_negotiation'
| 'out_for_signature'
| 'executed';
interface PaperObligation {
title: string;
/** One of the five the schema allows. */
kind: 'renewal_notice' | 'milestone' | 'payment' | 'review' | 'true_up';
inDays: number;
description: string;
}
/** Service levels as an exhibit, plus any additional committed metrics. */
interface PaperSla {
terms: Omit<typeof slaTerms.$inferInsert, 'contractId'>;
metrics?: Omit<typeof slaMetricTargets.$inferInsert, 'slaTermId'>[];
}
interface Paper {
/** Stable within an account; how a child names its parent. */
key: string;
type: 'msa' | 'dpa' | 'order_form';
status: PaperStatus;
/** Goes between the prefix and the account name to make the title. */
label: string;
parent?: string;
effectiveInDays?: number;
expiresInDays?: number;
isAutoRenew?: boolean;
noticeDays?: number;
takeOrPayFloorPct?: string;
prepaidPct?: string;
terminationTier?: string;
assignableOnDefault?: boolean;
assignmentDeadlineBusinessDays?: number;
externalReference?: string;
contractingPartyName?: string;
/** Order forms carry the money; a master agreement has no value of its own. */
carriesDealValue?: boolean;
/** Point the order form at the block that fulfils it. See the schema note. */
linksCommitment?: boolean;
notes?: string;
sla?: PaperSla;
obligations?: PaperObligation[];
}
interface AccountPaper {
/** Account name without the prefix; the lookup adds it back. */
account: string;
governingLaw: string;
paper: Paper[];
}
/**
* Every demo contract says so on its face, on both sides of the book.
*/
const DEMO_CONTRACT_NOTE = 'Illustrative demo data. Not a real contract.';
/**
* What we grant a customer is not what we hold from a supplier, and the demo
* has to show the gap.
*
* Upstream from CoreWeave we hold fee abatement capped at 50% with 24-hour
* node replacement (see `seedSupplyPaper`). Downstream to the customer on the
* same capacity we grant service credits capped at 25% with 48 hours. That
* spread is the risk the business is actually paid to carry, and it is only
* legible if both ends of it are in the database.
*/
const HALCYON_SLA: PaperSla = {
terms: {
kind: 'negotiated',
uptimeTargetPct: '99.000',
measurementUnit: 'node',
measurementWindow: 'monthly',
remedyType: 'service_credit',
nodeReplacementHours: 48,
mttrHours: 8,
supportResponseHours: 1,
claimDeadlineValue: 30,
claimDeadlineUnit: 'days',
creditExpiryMonths: 12,
isSoleRemedy: true,
rcaDeliveryHours: 96,
creditSchedule: [
{ belowPct: 99, creditPct: 5 },
{ belowPct: 97, creditPct: 10 },
{ belowPct: 95, creditPct: 25 },
],
creditCapPct: '25.000',
maintenanceClasses: [
{ class: 'planned', noticeValue: 7, noticeUnit: 'business_days', allowancePerPeriodHours: 8, excludedFromUptime: true },
{ class: 'emergency', noticeValue: 4, noticeUnit: 'hours', excludedFromUptime: false },
],
exclusions: 'Planned maintenance within the monthly allowance, force majeure, and faults in customer-supplied images or code.',
},
// A rack-scale cluster is sold at two levels at once. Recording only the
// headline node figure would misstate what was promised.
metrics: [
{ metric: 'node_availability_pct', targetValue: '99.000', unit: 'percent' },
{ metric: 'uptime_pct', targetValue: '95.000', unit: 'percent_per_rack' },
{ metric: 'support_response_hours', targetValue: '1.000', unit: 'hours' },
],
};
/**
* The other shape entirely: a reliability tier with credits, sitting at master
* level so the order form beneath it inherits rather than restates it.
*
* `kind` is `credits_policy` deliberately. There is a published target figure
* and there is no uptime guarantee behind it, and the schema is emphatic that
* the two must not be shown as the same thing.
*/
const NORTHWIND_SLA: PaperSla = {
terms: {
kind: 'credits_policy',
uptimeTargetPct: '99.500',
measurementUnit: 'instance',
measurementWindow: 'monthly',
remedyType: 'service_credit',
supportResponseHours: 8,
claimDeadlineValue: 10,
claimDeadlineUnit: 'days',
creditExpiryMonths: 6,
isSoleRemedy: true,
creditSchedule: [
{ belowPct: 99.5, creditPct: 5 },
{ belowPct: 98, creditPct: 10 },
],
creditCapPct: '10.000',
exclusions: 'Maintenance windows, force majeure, customer-caused faults, and any capacity drawn from the community tier.',
},
};
/**
* The demand book's paper, keyed by the account names `demand.ts` writes.
*
* Read alongside that file: `msaExecuted` and `dpaExecuted` on each deal are
* assertions, and these rows are the evidence behind them. Where a deal says
* the DPA is not executed, the DPA here is genuinely unsigned — Verity's sits
* in review, which is why an EU deal in procurement has not deployed.
*
* Dates are chosen so the renewal machinery has all three of its states to
* show at once: a notice deadline already missed, one about to open, and paper
* whose term runs with the capacity behind it and needs nothing yet.
*
* Built from the prefix rather than declared with it baked in, for the reason
* given on `DemoContext`.
*/
function demandPaperBook(prefix: string): AccountPaper[] {
return [
{
account: 'Halcyon Research',
governingLaw: 'Delaware',
paper: [
{
key: 'msa',
type: 'msa',
status: 'executed',
label: 'MSA',
externalReference: 'HAL-MSA-0114',
// The master term is annual and renews itself; the order form
// beneath it runs with the block, which is why the two expiries
// differ. Effective 313 days ago, so a 365-day term leaves 52 days
// to run and a 60-day notice deadline that passed eight days ago.
// Missing that deadline is not a missed reminder: the term has
// renewed for another year unless the customer agrees otherwise.
effectiveInDays: -313,
expiresInDays: 52,
isAutoRenew: true,
noticeDays: 60,
// A frontier lab negotiates step-in. The link that makes it
// enforceable is `capacityCommitmentId` on the order form below.
assignableOnDefault: true,
assignmentDeadlineBusinessDays: 10,
obligations: [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: -8,
description:
'Sixty days written notice to stop the master term renewing for a further twelve months. The date has passed.',
},
{
title: 'Quarterly service review',
kind: 'review',
inDays: 26,
description:
'Contractual review of utilisation and incident history; the report is owed five business days beforehand.',
},
],
},
{
key: 'dpa',
type: 'dpa',
status: 'executed',
label: 'DPA',
parent: 'msa',
externalReference: 'HAL-DPA-0114',
// Coterminous with the master, and renewing with it. The notice
// that governs both is on the MSA, so this carries none of its own.
effectiveInDays: -313,
expiresInDays: 52,
isAutoRenew: true,
},
{
key: 'order_form',
type: 'order_form',
status: 'executed',
label: 'Order form — H200 reserved cluster',
parent: 'msa',
externalReference: 'HAL-OF-0221',
// Dated to the block it draws on, not to the master term.
effectiveInDays: -30,
expiresInDays: 335,
isAutoRenew: false,
takeOrPayFloorPct: '90',
prepaidPct: '20',
terminationTier: '1_prepaid',
carriesDealValue: true,
linksCommitment: true,
sla: HALCYON_SLA,
obligations: [
{
title: 'Quarterly instalment',
kind: 'payment',
inDays: 12,
description:
'Committed fees invoiced quarterly in advance; the 20% prepayment is credited against the final quarter.',
},
{
title: 'Committed-hours true-up',
kind: 'true_up',
inDays: 44,
// The floor is what makes the backlog real: unused hours are
// still owed, exactly as they are to the supplier upstream.
description:
'Draw below the 90% committed floor becomes payable at the true-up date.',
},
],
},
],
},
{
account: 'Northwind Robotics',
governingLaw: 'Delaware',
paper: [
{
key: 'msa',
type: 'msa',
status: 'executed',
label: 'MSA',
externalReference: 'NWR-MSA-0908',
// 287 days in, so 78 days left and the 60-day notice deadline opens
// in 18: the state a deal desk should be acting on now rather than
// discovering later.
effectiveInDays: -287,
expiresInDays: 78,
isAutoRenew: true,
noticeDays: 60,
sla: NORTHWIND_SLA,
obligations: [
{
title: 'Renewal notice',
kind: 'renewal_notice',
inDays: 18,
description:
'Sixty days notice to stop the master term renewing. The successor MSA is already out for signature.',
},
{
title: 'Annual security review',
kind: 'review',
inDays: 132,
description:
'Customer right to review the hosting environment; the evidence pack is owed within 30 days of request.',
},
],
},
{
key: 'dpa',
type: 'dpa',
status: 'executed',
label: 'DPA',
parent: 'msa',
externalReference: 'NWR-DPA-0908',
effectiveInDays: -287,
expiresInDays: 78,
isAutoRenew: true,
},
{
key: 'order_form',
type: 'order_form',
status: 'executed',
label: 'Order form — B200 evaluation cluster',
parent: 'msa',
externalReference: 'NWR-OF-0114',
effectiveInDays: -30,
expiresInDays: 240,
isAutoRenew: false,
// An evaluation, so no floor and a short exit — the opposite end of
// the backlog-quality scale from Halcyon, and the reason the two
// cannot be summed unweighted.
takeOrPayFloorPct: '0',
terminationTier: '3_cancellable',
carriesDealValue: true,
linksCommitment: true,
obligations: [
{
title: 'Production conversion decision',
kind: 'milestone',
inDays: 75,
description:
'The evaluation converts to the production rate at this date or the order form lapses.',
},
],
},
{
key: 'renewal_msa',
type: 'msa',
status: 'out_for_signature',
label: 'MSA renewal — successor term',
externalReference: 'NWR-MSA-0908-R1',
// Starts the day the current term ends. Out for signature is where
// most renewals actually sit, and nothing in the demo showed it.
effectiveInDays: 78,
expiresInDays: 443,
isAutoRenew: true,
noticeDays: 60,
notes: 'Signature blocks with the customer; commercial terms agreed.',
},
],
},
{
account: 'Verity Health AI',
governingLaw: 'Germany',
paper: [
{
key: 'msa',
type: 'msa',
status: 'executed',
label: 'MSA',
externalReference: 'VER-MSA-0512',
// Signed, well inside its term, and deliberately not up for renewal:
// if every account showed a renewal signal the facet would be
// telling nobody anything.
effectiveInDays: -96,
expiresInDays: 269,
isAutoRenew: false,
// The affiliate that signs is not the account. Assuming otherwise
// misfiles the counterparty on exactly the deals large enough to
// matter, which is why the column exists.
contractingPartyName: `${prefix}Verity Health AI GmbH`,
obligations: [
{
title: 'Data residency attestation',
kind: 'review',
inDays: 58,
description:
'Written attestation each quarter that no personal data left the EU processing region.',
},
],
},
{
key: 'dpa',
type: 'dpa',
status: 'in_review',
label: 'DPA and sub-processor schedule',
parent: 'msa',
// `dpaExecuted: false` on the deal in demand.ts is an assertion, and
// this is the row behind it. Unsigned paper carries no dates.
notes: 'With the customer privacy team. EU processing cannot start until this is executed.',
obligations: [
{
title: 'Sub-processor schedule review',
kind: 'review',
inDays: 9,
description:
'Customer privacy review of the sub-processor list; the committed EU allocation is dated from execution.',
},
],
},
],
},
{
account: 'Aurelian Systems',
governingLaw: 'Delaware',
paper: [
{
key: 'msa',
type: 'msa',
status: 'in_negotiation',
label: 'MSA',
// The account sitting in the `legal` stage. No effective date and no
// expiry, because neither exists until it is signed — and because a
// dated unsigned contract would fire the expiry alarm on paper
// nobody has agreed to.
assignableOnDefault: true,
assignmentDeadlineBusinessDays: 10,
notes: 'Third redline exchange. Open points: liability cap, step-in rights, audit frequency.',
obligations: [
{
title: 'Redlines returned to counsel',
kind: 'milestone',
inDays: 5,
description: 'Customer counsel expects our mark-up of the liability and indemnity clauses.',
},
{
title: 'Security questionnaire response',
kind: 'review',
inDays: 11,
description: 'Vendor security assessment; the deal cannot leave legal until it is returned.',
},
],
},
{
key: 'order_form',
type: 'order_form',
status: 'draft',
label: 'Order form — 24-month committed capacity',
parent: 'msa',
takeOrPayFloorPct: '85',
terminationTier: '2_take_or_pay',
carriesDealValue: true,
notes: 'Drafted against the current proposal. Not issued until the MSA is executed.',
},
],
},
{
account: 'Tessellate Labs',
governingLaw: 'England and Wales',
paper: [
{
key: 'msa',
type: 'msa',
status: 'draft',
label: 'MSA',
// Why the hold on the A100 pool cannot convert: there is no paper.
notes: 'Standard terms issued; the customer has not returned comments.',
},
],
},
];
}
/**
* Write the customer paper, and the obligations that make it actionable.
*
* Runs as a pass of its own after the demand book, rather than inside its
* loop, because it is written per account rather than per deal and because
* `demand.ts` skips an account it has already seeded — which would leave the
* paper unwritten on a second run against a half-seeded database.
*
* Every insert checks for its own row first. A contract is identified by its
* account and its title, an obligation by its contract and its title, so a
* repeat run adds nothing even if an earlier one stopped halfway.
*/
export async function seedDemandPaper(context: DemoContext): Promise<void> {
const { db, prefix, at } = context;
let contractsPresent = 0;
let contractsAdded = 0;
let obligationsPresent = 0;
let obligationsAdded = 0;
for (const entry of demandPaperBook(prefix)) {
const accountName = `${prefix}${entry.account}`;
const [account] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, accountName))
.limit(1);
if (!account) {
console.log(` skipped paper for ${entry.account} — no such demo account`);
continue;
}
/*
* The deal is read rather than passed in, and the money is taken from it
* rather than restated here. An order form is the commercial specifics
* under a master agreement, so its value is the deal's own term value; a
* figure typed in twice is a figure that will disagree with itself the
* first time the demand book is retuned.
*/
const [deal] = await db
.select({ id: demandDeals.id, acvCents: demandDeals.acvCents, tcvCents: demandDeals.tcvCents })
.from(demandDeals)
.where(eq(demandDeals.accountId, account.id))
.orderBy(desc(demandDeals.acvCents))
.limit(1);
// Which block fulfils the order form. Looked up through the allocation
// because that is where the demand book records the choice.
const [allocation] = deal
? await db
.select({ capacityCommitmentId: allocations.capacityCommitmentId })
.from(allocations)
.where(eq(allocations.demandDealId, deal.id))
.limit(1)
: [];
const idByKey = new Map<string, string>();
for (const paper of entry.paper) {
const title = `${prefix}${paper.label}${entry.account}`;
const [existing] = await db
.select({ id: contracts.id })
.from(contracts)
.where(and(eq(contracts.accountId, account.id), eq(contracts.title, title)))
.limit(1);
let contractId = existing?.id;
if (!contractId) {
const effectiveAt = paper.effectiveInDays == null ? null : at(paper.effectiveInDays);
const [inserted] = await db
.insert(contracts)
.values({
accountId: account.id,
type: paper.type,
status: paper.status,
side: 'demand',
title,
externalReference: paper.externalReference,
demandDealId: deal?.id,
capacityCommitmentId: paper.linksCommitment
? (allocation?.capacityCommitmentId ?? undefined)
: undefined,
parentContractId: paper.parent ? idByKey.get(paper.parent) : undefined,
contractingPartyName: paper.contractingPartyName,
takeOrPayFloorPct: paper.takeOrPayFloorPct,
prepaidPct: paper.prepaidPct,
terminationTier: paper.terminationTier,
assignableOnDefault: paper.assignableOnDefault ?? false,
assignmentDeadlineBusinessDays: paper.assignmentDeadlineBusinessDays,
effectiveAt,
expiresAt: paper.expiresInDays == null ? null : at(paper.expiresInDays),
// Executed paper was signed the day it took effect, or on the day
// of the run for anything effective in the future.
executedAt:
paper.status === 'executed' && effectiveAt
? new Date(Math.min(effectiveAt.getTime(), at(0).getTime()))
: null,
isAutoRenew: paper.isAutoRenew ?? false,
noticeDays: paper.noticeDays,
valueCents: paper.carriesDealValue ? (deal?.tcvCents ?? deal?.acvCents) : undefined,
governingLaw: entry.governingLaw,
notes: paper.notes ? `${paper.notes} ${DEMO_CONTRACT_NOTE}` : DEMO_CONTRACT_NOTE,
})
.returning({ id: contracts.id });
contractId = inserted?.id;
if (contractId) contractsAdded += 1;
}
if (!contractId) continue;
contractsPresent += 1;
idByKey.set(paper.key, contractId);
if (paper.sla) {
const [existingSla] = await db
.select({ id: slaTerms.id })
.from(slaTerms)
.where(eq(slaTerms.contractId, contractId))
.limit(1);
let slaTermId = existingSla?.id;
if (!slaTermId) {
const [insertedSla] = await db
.insert(slaTerms)
.values({ ...paper.sla.terms, contractId })
.returning({ id: slaTerms.id });
slaTermId = insertedSla?.id;
}
if (slaTermId) {
for (const metric of paper.sla.metrics ?? []) {
const [existingMetric] = await db
.select({ id: slaMetricTargets.id })
.from(slaMetricTargets)
.where(
and(
eq(slaMetricTargets.slaTermId, slaTermId),
eq(slaMetricTargets.metric, metric.metric),
),
)
.limit(1);
if (!existingMetric) {
await db.insert(slaMetricTargets).values({ ...metric, slaTermId });
}
}
}
}
for (const obligation of paper.obligations ?? []) {
const obligationTitle = `${prefix}${obligation.title}${entry.account}`;
const [existingObligation] = await db
.select({ id: contractObligations.id })
.from(contractObligations)
.where(
and(
eq(contractObligations.contractId, contractId),
eq(contractObligations.title, obligationTitle),
),
)
.limit(1);
obligationsPresent += 1;
if (existingObligation) continue;
await db.insert(contractObligations).values({
contractId,
title: obligationTitle,
kind: obligation.kind,
dueAt: at(obligation.inDays),
description: obligation.description,
});
obligationsAdded += 1;
}
}
}
console.log(
` ${contractsPresent} demand-side contracts (${contractsAdded} new) and ` +
`${obligationsPresent} obligations (${obligationsAdded} new) — ` +
'one renewal notice already missed, one opening within the month',
);
}
+977
View File
@@ -0,0 +1,977 @@
/**
* The demand side of the demo book: customers, the people inside them, who on
* our side owns each account, the deals, what was asked for, and what has been
* reserved against a block.
*
* Every account here is INVENTED — see the integrity note in `./index.ts`.
*
* Three rules hold across the whole file, and they are what stop the numbers on
* screen from contradicting one another.
*
* **A deal's value is derived, never asserted.** TCV is the money the hours
* actually fetch — allocated hours × the price on the allocation, or requested
* hours × the price we have quoted — and ACV is that annualised. An earlier
* version wrote the two halves independently, and every deal's stated value
* disagreed with the revenue implied by its own allocation by between 1.7× and
* 3.6×. That is the kind of error a reader finds with a calculator in the first
* minute of a demonstration.
*
* **A sell price sits between what the block cost and what the hardware
* actually fetches.** The spread on this book, against the costs `supply.ts`
* committed to:
*
* H200 CoreWeave cost 1.89 sold 2.39 +26% (Halcyon, 12-month reserved)
* H100 Nebius EU cost 1.71 sold 2.19 +28% (Verity, EU-resident, certified)
* B200 Crusoe cost 3.05 sold 3.75 +23% (Northwind, 9-month block)
* A100 RunPod cost 0.96 sold 1.25 +30% (Tessellate, community pool)
*
* Twenty-something per cent on the hour is what a capacity intermediary can
* defend in this market; the 43% the first draft carried is not, and it made
* the flagship account look like a rounding error had been left in.
*
* **Cost is charged against the whole block, so the spread is not the margin.**
* After idle hours and research burn — both already paid for — the book clears
* roughly 5%, which is the number a brokerage actually lives on. The blocks
* disagree with each other underneath it: the H200 block is 95% sold and makes
* money, the EU block is 55% sold and does not, and the A100 pool has sold
* nothing at all. That contrast is the point of the dataset.
*/
import {
ALLOCATION_STATUSES,
type AllocationStatus,
type CustomerSegment,
type DemandStage,
type ProductLine,
type SecurityTier,
type Team,
type TeamRole,
} from '@pig/core';
import { and, eq } from 'drizzle-orm';
import {
accounts,
activities,
allocations,
capacityCommitments,
capacityRequests,
contacts,
dealContacts,
demandDeals,
teamMemberships,
users,
type NewAllocation,
} from '../../schema/index';
import { accountLastActivityAt, dealLastActivityAt, seedDealActivities } from './activities';
import type { DemoContext } from './index';
function isAllocationStatus(value: string): value is AllocationStatus {
return (ALLOCATION_STATUSES as readonly string[]).includes(value);
}
// ---------------------------------------------------------------- our people
/**
* The sellers, and the fact that a record belongs to one of them.
*
* `ownerUserId` is indexed on accounts, contacts and deals, and until now the
* demo book left all three null — so every owner column rendered empty and the
* owner filter on the calendar could only ever return nothing. These four are
* invented, exactly like the customers, and none of them is a platform admin:
* the development user stays the only administrator, because a demo dataset
* that quietly grants administration is a trap rather than a convenience.
*
* Addresses are on a `.invalid` domain, which the DNS root guarantees can never
* resolve. The base seed refuses to infer an address for a real person; the
* least this file can do is make sure its invented ones can never reach one.
*/
interface DemoUser {
readonly key: string;
readonly name: string;
readonly email: string;
readonly handle: string;
readonly title: string;
readonly lastSeenDaysAgo: number;
readonly teams: readonly { team: Team; role: TeamRole; primary?: boolean }[];
}
function demoUsers(prefix: string): readonly DemoUser[] {
return [
{
key: 'ines',
name: `${prefix}Ines Fabre`,
email: 'ines.fabre@demo.pig.invalid',
handle: 'demo-ines',
title: 'Account executive — labs and research',
lastSeenDaysAgo: 0,
teams: [{ team: 'demand', role: 'lead', primary: true }],
},
{
key: 'marcus',
name: `${prefix}Marcus Oyelaran`,
email: 'marcus.oyelaran@demo.pig.invalid',
handle: 'demo-marcus',
title: 'Account executive — enterprise, EMEA',
lastSeenDaysAgo: 1,
teams: [{ team: 'demand', role: 'member', primary: true }],
},
{
// Both teams, deliberately. `teamMemberships` is a join table precisely
// because in a company this size the person who sources the community
// pool is also the person who sells burst capacity out of it.
key: 'wren',
name: `${prefix}Wren Abbot`,
email: 'wren.abbot@demo.pig.invalid',
handle: 'demo-wren',
title: 'Capacity partnerships',
lastSeenDaysAgo: 2,
teams: [
{ team: 'supply', role: 'lead', primary: true },
{ team: 'demand', role: 'member' },
],
},
{
key: 'rosalind',
name: `${prefix}Rosalind Achebe`,
email: 'rosalind.achebe@demo.pig.invalid',
handle: 'demo-rosalind',
title: 'Research programme lead',
lastSeenDaysAgo: 4,
teams: [{ team: 'research', role: 'lead', primary: true }],
},
];
}
// ------------------------------------------------------------- the book
/** Roles as `schema/demand.ts` documents them on `deal_contacts`. */
type BuyingRole =
| 'economic buyer'
| 'champion'
| 'technical evaluator'
| 'procurement'
| 'legal'
| 'blocker';
interface ContactSpec {
readonly name: string;
readonly title: string;
readonly decisionMaker?: boolean;
}
interface RequestSpec {
readonly gpuType: string;
readonly gpuCount: number;
readonly fastFabric: boolean;
/** The ceiling the customer has told us about. The other half of the spread. */
readonly maxPriceCents: number;
/**
* What we have quoted for these hours. Present only where nothing is
* reserved yet, because it is then the only honest basis for the deal value.
*/
readonly quotedPriceCents?: number;
readonly allowedRegions?: readonly string[];
readonly certifications?: readonly string[];
readonly minSecurityTier?: SecurityTier;
}
interface AllocationSpec {
/** Supplier domain, which is how `seedSupply` keys the block it returned. */
readonly supplier: string;
/** Share of the block's hours. Cross-checked against the request below. */
readonly share: number;
readonly priceCents: number;
readonly status: string;
readonly holdDays?: number;
}
interface DealSpec {
/** Stable handle, so a child deal can name its parent. */
readonly key: string;
readonly name: string;
readonly productLine: ProductLine;
readonly stage: DemandStage;
readonly termMonths: number;
readonly msaExecuted: boolean;
readonly dpaExecuted: boolean;
readonly close: { readonly quarter: -1 | 0 | 1; readonly fraction: number };
/** Set on `closed_won` and `closed_lost`; drives `closedAt`/`closedReason`. */
readonly closedReason?: string;
/** The deal this one grew out of. Must appear earlier in the account's list. */
readonly parent?: string;
readonly owner?: string;
readonly primaryContact: string;
readonly buyingGroup: readonly { readonly contact: string; readonly role: BuyingRole }[];
readonly request?: RequestSpec;
readonly allocation?: AllocationSpec;
/**
* Hours already delivered, for a deal that closed before the blocks in this
* book existed. Still hours × price — a closed deal's value is not exempt
* from the rule, it simply has no live allocation to read it from.
*/
readonly delivered?: { readonly gpuHours: number; readonly priceCents: number };
}
interface AccountSpec {
readonly account: string;
readonly segment: CustomerSegment;
readonly country: string;
/** Key into `demoUsers`. Carried down to the account's contacts and deals. */
readonly owner: string;
readonly contacts: readonly ContactSpec[];
readonly deals: readonly DealSpec[];
}
/**
* Fictional customers.
*
* Invented deliberately — see the note at the top of `./index.ts`. Any
* resemblance to a real company is unintended, and none of these figures
* describes anyone's actual contract.
*
* Built from the prefix rather than declared with it baked in, for the reason
* given on `DemoContext`: this module must not read a value out of `./index.ts`
* while that module is still evaluating.
*/
function demandBook(prefix: string): readonly AccountSpec[] {
return [
{
account: `${prefix}Halcyon Research`,
segment: 'frontier_lab',
country: 'United States',
owner: 'ines',
contacts: [
{ name: 'Dana Whitfield', title: 'Head of Infrastructure', decisionMaker: true },
{ name: 'Marisol Baptiste', title: 'VP Finance', decisionMaker: true },
{ name: 'Tobias Lind', title: 'Staff Research Engineer' },
],
deals: [
{
// The land. Won last quarter, and the reason the block beneath it
// exists at all: a lab buys a quarter before it buys a year.
key: 'halcyon-burst',
name: `${prefix}H100 burst — pre-training run`,
productLine: 'compute_reserved',
stage: 'closed_won',
termMonths: 3,
msaExecuted: true,
dpaExecuted: true,
close: { quarter: -1, fraction: 0.3 },
closedReason:
'Won. First paid run for this counterparty; the 12-month H200 block was signed off the back of it.',
primaryContact: 'Dana Whitfield',
buyingGroup: [{ contact: 'Dana Whitfield', role: 'champion' }],
// 96 GPUs for 90 days at 2.34, on capacity that has since ended.
delivered: { gpuHours: 96 * 90 * 24, priceCents: 234 },
},
{
key: 'halcyon-cluster',
name: `${prefix}Pre-training cluster, 12 months`,
productLine: 'compute_reserved',
stage: 'deployment',
termMonths: 12,
msaExecuted: true,
dpaExecuted: true,
// Slipped: the close date is in the quarter just gone while the deal
// is still open, so the calendar has a genuinely overdue item.
close: { quarter: -1, fraction: 0.62 },
parent: 'halcyon-burst',
primaryContact: 'Dana Whitfield',
buyingGroup: [
{ contact: 'Dana Whitfield', role: 'champion' },
{ contact: 'Marisol Baptiste', role: 'economic buyer' },
{ contact: 'Tobias Lind', role: 'technical evaluator' },
],
// 400 GPUs continuously for a year, which is a cluster a lab
// genuinely rents from a third party. The 256 this once said made
// the largest account on the book smaller than a Series A's fleet.
request: { gpuType: 'H200', gpuCount: 400, fastFabric: true, maxPriceCents: 259 },
// 87% of the CoreWeave block: 424 GPUs' worth of delivered hours
// against a 400-GPU ask, which is the headroom a 94%-availability
// fleet needs to keep 400 of them lit.
allocation: { supplier: 'coreweave.com', share: 0.87, priceCents: 239, status: 'active' },
},
{
// Managed post-training, priced above raw capacity because it carries
// our engineering rather than only our hours.
key: 'halcyon-post-training',
name: `${prefix}Managed post-training run`,
productLine: 'post_training',
stage: 'poc',
termMonths: 3,
msaExecuted: true,
dpaExecuted: true,
close: { quarter: 0, fraction: 0.66 },
primaryContact: 'Tobias Lind',
buyingGroup: [
{ contact: 'Tobias Lind', role: 'technical evaluator' },
{ contact: 'Dana Whitfield', role: 'champion' },
],
request: {
gpuType: 'H200',
gpuCount: 32,
fastFabric: true,
maxPriceCents: 320,
quotedPriceCents: 289,
},
},
],
},
{
account: `${prefix}Verity Health AI`,
segment: 'enterprise',
country: 'Germany',
owner: 'marcus',
contacts: [
{ name: 'Lukas Brenner', title: 'VP Engineering', decisionMaker: true },
{ name: 'Annika Voss', title: 'Head of IT Procurement', decisionMaker: true },
// The reason `dpaExecuted` is false on the deal below. A data
// protection officer is a named blocker with a job title, not an
// unexplained flag.
{ name: 'Dr Elif Sahin', title: 'Data Protection Officer' },
],
deals: [
{
key: 'verity-fine-tuning',
name: `${prefix}EU-resident fine-tuning`,
productLine: 'post_training',
stage: 'procurement',
termMonths: 6,
msaExecuted: true,
dpaExecuted: false,
close: { quarter: 0, fraction: 0.55 },
primaryContact: 'Lukas Brenner',
buyingGroup: [
{ contact: 'Lukas Brenner', role: 'champion' },
{ contact: 'Annika Voss', role: 'procurement' },
{ contact: 'Dr Elif Sahin', role: 'legal' },
],
// 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: 219, status: 'committed' },
},
{
// The one open request the idle half of the EU block could actually
// serve: same region, same certifications, and 103,680 hours against
// the ~234,000 sitting unsold on that commitment.
key: 'verity-inference',
name: `${prefix}EU inference endpoint`,
productLine: 'inference',
stage: 'scoping',
termMonths: 6,
msaExecuted: true,
dpaExecuted: false,
close: { quarter: 1, fraction: 0.3 },
primaryContact: 'Lukas Brenner',
buyingGroup: [{ contact: 'Lukas Brenner', role: 'champion' }],
request: {
gpuType: 'H100_80GB',
gpuCount: 24,
fastFabric: false,
maxPriceCents: 235,
quotedPriceCents: 209,
allowedRegions: ['eu-north', 'eu-west'],
certifications: ['ISO 27001'],
},
},
],
},
{
account: `${prefix}Northwind Robotics`,
segment: 'applied_ai_startup',
country: 'United States',
owner: 'marcus',
contacts: [
{ name: 'Priya Raghavan', title: 'CTO', decisionMaker: true },
{ name: 'Jonah Reyes', title: 'Head of ML Infrastructure' },
],
deals: [
{
// The land-and-expand root. Both deals below hang off it, which is
// what `parentDealId` is for and what makes the motion visible.
key: 'northwind-pilot',
name: `${prefix}A100 inference pilot`,
productLine: 'inference',
stage: 'closed_won',
termMonths: 3,
msaExecuted: true,
dpaExecuted: true,
close: { quarter: -1, fraction: 0.55 },
closedReason:
'Won. Delivered inside the customers evaluation window; the Blackwell block was signed off the back of it.',
primaryContact: 'Priya Raghavan',
buyingGroup: [{ contact: 'Priya Raghavan', role: 'economic buyer' }],
delivered: { gpuHours: 16 * 90 * 24, priceCents: 129 },
},
{
key: 'northwind-production',
name: `${prefix}Blackwell production block`,
productLine: 'compute_reserved',
stage: 'deployment',
termMonths: 9,
msaExecuted: true,
dpaExecuted: true,
close: { quarter: 0, fraction: 0.82 },
parent: 'northwind-pilot',
primaryContact: 'Priya Raghavan',
buyingGroup: [
{ contact: 'Priya Raghavan', role: 'economic buyer' },
{ contact: 'Jonah Reyes', role: 'technical evaluator' },
],
request: { gpuType: 'B200', gpuCount: 48, fastFabric: true, maxPriceCents: 410 },
allocation: { supplier: 'crusoe.ai', share: 0.86, priceCents: 375, status: 'active' },
},
{
// The expansion, and nothing on the book can cover it: the Crusoe
// block is 86% sold. This is the demand that justifies the 256× H200
// supply deal sitting in financial diligence.
key: 'northwind-expansion',
name: `${prefix}Fleet expansion — 32× B200`,
productLine: 'compute_reserved',
stage: 'expansion',
termMonths: 9,
msaExecuted: true,
dpaExecuted: true,
close: { quarter: 1, fraction: 0.45 },
parent: 'northwind-pilot',
primaryContact: 'Priya Raghavan',
buyingGroup: [
{ contact: 'Priya Raghavan', role: 'economic buyer' },
{ contact: 'Jonah Reyes', role: 'technical evaluator' },
],
request: {
gpuType: 'B200',
gpuCount: 32,
fastFabric: true,
maxPriceCents: 410,
// No volume discount on an increment; the blended rate is what the
// customer negotiates at renewal, not now.
quotedPriceCents: 379,
},
},
],
},
{
account: `${prefix}Tessellate Labs`,
segment: 'applied_ai_startup',
country: 'United Kingdom',
owner: 'wren',
// Single-threaded on a founding engineer who cannot sign. Deliberately
// the only account with one contact: it is why the deal is at proposal
// with an unreturned MSA, and the buying-group view should show it.
contacts: [
{ name: 'Owen Marsh', title: 'Founding Engineer' },
],
deals: [
{
key: 'tessellate-burst',
name: `${prefix}Inference burst capacity`,
productLine: 'inference',
stage: 'proposal',
termMonths: 3,
msaExecuted: false,
dpaExecuted: false,
close: { quarter: 0, fraction: 0.34 },
primaryContact: 'Owen Marsh',
buyingGroup: [{ contact: 'Owen Marsh', role: 'champion' }],
request: {
gpuType: 'A100_80GB',
gpuCount: 16,
fastFabric: false,
maxPriceCents: 175,
// States what the pool actually is. A request that silently demands
// secure_cloud cannot lawfully be served by the community block it
// is held against, and the matcher is right to say so.
minSecurityTier: 'community_cloud',
},
// 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: 125,
status: 'planned',
holdDays: 12,
},
},
],
},
{
account: `${prefix}Aurelian Systems`,
segment: 'enterprise',
country: 'United States',
owner: 'ines',
contacts: [
{ name: 'Meredith Cole', title: 'Director, ML Platform', decisionMaker: true },
{ name: 'Gregory Nkemdirim', title: 'Deputy General Counsel' },
{ name: 'Sandra Ipsen', title: 'VP Information Security' },
],
deals: [
{
key: 'aurelian-committed',
name: `${prefix}Multi-year committed capacity`,
productLine: 'compute_reserved',
stage: 'legal',
termMonths: 24,
msaExecuted: false,
dpaExecuted: false,
close: { quarter: 1, fraction: 0.38 },
primaryContact: 'Meredith Cole',
buyingGroup: [
{ contact: 'Meredith Cole', role: 'champion' },
{ contact: 'Gregory Nkemdirim', role: 'legal' },
{ contact: 'Sandra Ipsen', role: 'blocker' },
],
// Quoted under Halcyon's rate: 24 months of committed volume is worth
// a better number than 12, and this is the deal that would justify
// the next block. Nothing is reserved — it is still in legal, which
// is correct: capacity does not move before paper does.
request: {
gpuType: 'H200',
gpuCount: 128,
fastFabric: true,
maxPriceCents: 245,
quotedPriceCents: 229,
},
},
],
},
{
account: `${prefix}Quillon AI`,
segment: 'applied_ai_startup',
country: 'Canada',
owner: 'rosalind',
contacts: [
{ name: 'Sofia Trentini', title: 'Head of Research', decisionMaker: true },
],
deals: [
{
// The loss, with the reason a seller would actually write down.
// Recorded rather than deleted: a book with no losses in it has no
// win rate, and the next person to meet this account starts blind.
key: 'quillon-reserved',
name: `${prefix}Reserved H100 block — 12 months`,
productLine: 'compute_reserved',
stage: 'closed_lost',
termMonths: 12,
msaExecuted: false,
dpaExecuted: false,
close: { quarter: -1, fraction: 0.8 },
closedReason:
'Lost on price. A hyperscalers committed-use discount landed 19% under our quote; matching it would have put the hours below the cost we pay upstream for the block.',
primaryContact: 'Sofia Trentini',
buyingGroup: [{ contact: 'Sofia Trentini', role: 'economic buyer' }],
delivered: { gpuHours: 64 * 360 * 24, priceCents: 209 },
},
{
// The consolation, and how the relationship stayed alive.
key: 'quillon-evaluations',
name: `${prefix}Evaluation harness pilot`,
productLine: 'evaluations',
stage: 'qualification',
termMonths: 3,
msaExecuted: false,
dpaExecuted: false,
close: { quarter: 1, fraction: 0.74 },
primaryContact: 'Sofia Trentini',
buyingGroup: [{ contact: 'Sofia Trentini', role: 'economic buyer' }],
// Sixteen L40S for the harness itself — small, cheap and nothing like
// the block they bought elsewhere.
request: {
gpuType: 'L40S',
gpuCount: 16,
fastFabric: false,
maxPriceCents: 115,
quotedPriceCents: 98,
},
},
],
},
];
}
/**
* Forecast confidence by stage.
*
* A closed deal forecasts at certainty or at nothing, whatever its stage would
* otherwise imply. `expansion` is deliberately mid-table rather than late:
* this pipeline puts it after `deployment`, but an expansion is a fresh
* opportunity with a warm start, not a deal about to sign.
*/
const STAGE_PROBABILITY: Record<DemandStage, number> = {
qualification: 0.1,
legal: 0.35,
scoping: 0.4,
proposal: 0.45,
procurement: 0.6,
poc: 0.7,
deployment: 0.9,
expansion: 0.5,
closed_won: 1,
closed_lost: 0,
};
/** ACV is the term value annualised. TCV is what the hours actually fetch. */
function annualise(tcvCents: number, termMonths: number): { acvCents: number; tcvCents: number } {
return { acvCents: Math.round((tcvCents * 12) / termMonths), tcvCents };
}
/** What a block reservation is worth, resolved before the deal is written. */
interface Reservation {
readonly commitmentId: string;
readonly gpuHours: number;
readonly revenueCents: number;
readonly startsAt: Date;
readonly endsAt: Date;
}
/**
* Resolve the allocation before the deal row is inserted.
*
* The lookup used to run after the insert, which is how the two halves came to
* be written independently in the first place: the deal was already in the
* database by the time anyone knew what its hours were worth. Hoisting it is
* what makes a derived value possible at all.
*/
async function reserve(
context: DemoContext,
commitmentIds: Map<string, string>,
spec: AllocationSpec,
): Promise<Reservation | null> {
const commitmentId = commitmentIds.get(spec.supplier);
if (!commitmentId) return null;
const [commitment] = await context.db
.select()
.from(capacityCommitments)
.where(eq(capacityCommitments.id, commitmentId))
.limit(1);
if (!commitment) return null;
const gpuHours = Math.round(Number(commitment.totalGpuHours) * spec.share);
return {
commitmentId,
gpuHours,
revenueCents: gpuHours * spec.priceCents,
startsAt: commitment.startsAt,
endsAt: commitment.endsAt,
};
}
/**
* Seed the demand book against the blocks the supply slice bought.
*
* `commitmentIds` is handed in rather than looked up: an allocation must point
* at the block this run created, and re-querying by name would silently pick up
* a commitment from an earlier run whose hours no longer match.
*/
export async function seedDemand(
context: DemoContext,
commitmentIds: Map<string, string>,
): Promise<void> {
const { db, prefix, at, hours, quarterAt } = context;
const ownerIds = await seedDemoUsers(context);
const book = demandBook(prefix);
// Parent ids by deal key. A child must be inserted after its parent, which
// for this book means later in the same account's list; anything else is a
// mistake worth failing loudly on rather than writing a null and moving on.
const dealIdByKey = new Map<string, string>();
let dealIndex = 0;
for (const [accountIndex, entry] of book.entries()) {
const [existingAccount] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, entry.account))
.limit(1);
if (existingAccount) continue;
const accountOwnerId = ownerIds.get(entry.owner) ?? null;
const [account] = await db
.insert(accounts)
.values({
name: entry.account,
side: 'demand',
customerSegment: entry.segment,
country: entry.country,
description: 'Fictional company, for demonstration only.',
source: 'seed',
confidence: 'confirmed',
ownerUserId: accountOwnerId,
lastActivityAt: accountLastActivityAt(context, accountIndex),
})
.returning();
if (!account) continue;
const contactIdByName = new Map<string, string>();
for (const person of entry.contacts) {
const [contact] = await db
.insert(contacts)
.values({
accountId: account.id,
fullName: person.name,
title: person.title,
affiliation: 'staff',
isDecisionMaker: person.decisionMaker ?? false,
confidence: 'confirmed',
source: 'seed',
ownerUserId: accountOwnerId,
email: null,
})
.returning();
if (contact) contactIdByName.set(person.name, contact.id);
}
for (const spec of entry.deals) {
const reservation = spec.allocation
? await reserve(context, commitmentIds, spec.allocation)
: null;
/*
* The one place a deal's money is decided.
*
* Reserved hours price themselves; a request we have quoted against
* prices itself from the quote; a deal that closed before these blocks
* existed carries the hours it actually delivered. There is no fourth
* case, and a deal that reaches one is a deal whose value nobody can
* check against anything.
*/
const quoted = spec.request?.quotedPriceCents;
const termValueCents = reservation
? reservation.revenueCents
: spec.request && quoted != null
? Number(hours(spec.request.gpuCount, spec.termMonths * 30, 1)) * quoted
: spec.delivered
? spec.delivered.gpuHours * spec.delivered.priceCents
: null;
if (termValueCents === null) {
throw new Error(`Demo deal ${spec.key} has no basis for its value.`);
}
const isClosed = spec.stage === 'closed_won' || spec.stage === 'closed_lost';
const closedAt = isClosed ? quarterAt(spec.close.quarter, spec.close.fraction) : null;
const parentDealId = spec.parent ? dealIdByKey.get(spec.parent) : undefined;
if (spec.parent && !parentDealId) {
throw new Error(`Demo deal ${spec.key} names a parent (${spec.parent}) not yet seeded.`);
}
const [deal] = await db
.insert(demandDeals)
.values({
accountId: account.id,
name: spec.name,
productLine: spec.productLine,
stage: spec.stage,
// A closed deal stopped moving on the day it closed. Leaving this at
// its default would date every historic deal to the seed run and make
// time-in-stage nonsense; the open ones are spread rather than stamped
// together for the same reason.
stageChangedAt: closedAt ?? at(-9 - dealIndex * 4),
...annualise(termValueCents, spec.termMonths),
termMonths: spec.termMonths,
msaExecuted: spec.msaExecuted,
dpaExecuted: spec.dpaExecuted,
ownerUserId: ownerIds.get(spec.owner ?? entry.owner) ?? accountOwnerId,
primaryContactId: contactIdByName.get(spec.primaryContact),
parentDealId,
expectedCloseDate: quarterAt(spec.close.quarter, spec.close.fraction),
closedAt,
closedReason: spec.closedReason,
probability: String(STAGE_PROBABILITY[spec.stage]),
lastActivityAt: closedAt ?? dealLastActivityAt(context, dealIndex),
})
.returning();
if (!deal) continue;
dealIdByKey.set(spec.key, deal.id);
dealIndex += 1;
for (const member of spec.buyingGroup) {
const contactId = contactIdByName.get(member.contact);
if (!contactId) continue;
await db.insert(dealContacts).values({
demandDealId: deal.id,
contactId,
role: member.role,
});
}
if (spec.request) {
await db.insert(capacityRequests).values({
demandDealId: deal.id,
gpuType: spec.request.gpuType,
gpuCount: spec.request.gpuCount,
requiresHighSpeedInterconnect: spec.request.fastFabric,
minInterconnectType: spec.request.fastFabric ? 'Infiniband' : undefined,
minSecurityTier: spec.request.minSecurityTier ?? 'secure_cloud',
maxPricePerGpuHourCents: spec.request.maxPriceCents,
allowedRegions: [...(spec.request.allowedRegions ?? [])],
requiredCertifications: [...(spec.request.certifications ?? [])],
// Where capacity is already reserved, the requirement is dated to the
// window it is being served in. The forward-dated window this used to
// carry ran past the end of the block behind it, so every covered
// deal still read as uncovered.
startsAt: reservation?.startsAt ?? at(15),
endsAt: reservation?.endsAt ?? at(15 + spec.termMonths * 30),
totalGpuHours: hours(spec.request.gpuCount, spec.termMonths * 30, 1),
});
}
if (reservation && spec.allocation) {
if (!isAllocationStatus(spec.allocation.status)) {
throw new Error(`Invalid demo allocation status: ${spec.allocation.status}`);
}
const allocationRow = {
capacityCommitmentId: reservation.commitmentId,
demandDealId: deal.id,
gpuHours: String(reservation.gpuHours),
pricePerGpuHourCents: spec.allocation.priceCents,
startsAt: reservation.startsAt,
endsAt: reservation.endsAt,
status: spec.allocation.status,
guaranteeType: spec.allocation.status === 'planned' ? 'committed' : 'guaranteed',
priority: spec.allocation.status === 'planned' ? 100 : 10,
holdExpiresAt: spec.allocation.holdDays ? at(spec.allocation.holdDays) : null,
createdByUserId: accountOwnerId,
notes: spec.name,
} satisfies NewAllocation;
await db.insert(allocations).values(allocationRow);
}
if (isClosed && closedAt) {
/*
* A closed deal's last entry is its closure, written here rather than
* through `seedDealActivities` because that helper narrates a deal in
* flight — "next step agreed" is the wrong thing to say about a deal
* that has none.
*/
await db.insert(activities).values({
type: 'note',
subject: `${prefix}${spec.stage === 'closed_won' ? 'Closed won' : 'Closed lost'}${spec.name.slice(prefix.length)}`,
body: spec.closedReason,
accountId: account.id,
demandDealId: deal.id,
occurredAt: closedAt,
});
} else {
await seedDealActivities(context, {
accountId: account.id,
demandDealId: deal.id,
contactName: spec.primaryContact,
stage: spec.stage,
});
}
}
}
await seedInternalResearchBurn(context, commitmentIds);
}
/**
* The sellers themselves, keyed by the handle the book refers to them by.
*
* Guarded on the address rather than the name: `users.email` is unique, so a
* second run must find the row rather than collide with it. Team memberships
* are upserted for the same reason.
*/
async function seedDemoUsers(context: DemoContext): Promise<Map<string, string>> {
const { db, at } = context;
const ids = new Map<string, string>();
for (const person of demoUsers(context.prefix)) {
const [existing] = await db
.select({ id: users.id })
.from(users)
.where(eq(users.email, person.email))
.limit(1);
const id =
existing?.id ??
(
await db
.insert(users)
.values({
email: person.email,
name: person.name,
handle: person.handle,
title: person.title,
isPlatformAdmin: false,
lastSeenAt: at(-person.lastSeenDaysAgo),
})
.returning({ id: users.id })
)[0]?.id;
if (!id) continue;
ids.set(person.key, id);
for (const membership of person.teams) {
await db
.insert(teamMemberships)
.values({
userId: id,
team: membership.team,
role: membership.role,
isPrimary: membership.primary ?? false,
})
.onConflictDoNothing();
}
}
return ids;
}
/**
* Internal research burn against the largest block — real cost, no revenue.
*
* An allocation with no demand deal behind it, which is the case the margin
* view has to get right: the hours are gone and nothing was sold for them.
*/
async function seedInternalResearchBurn(
context: DemoContext,
commitmentIds: Map<string, string>,
): Promise<void> {
const { db, prefix } = context;
const coreweave = commitmentIds.get('coreweave.com');
if (!coreweave) return;
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);
}
}
+209
View File
@@ -0,0 +1,209 @@
/**
* 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 28% markup needs
* ~78% 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.
*
* ---
*
* This file is the orchestrator and the home of everything the slices share.
* The book itself is one module per slice supply, demand, contracts,
* activities, compliance, agent facts, learn, calendar, teardown because it
* was a single 1,400-line file that several people needed to edit at once, and
* every edit collided. The order of the inserts below is the order it has
* always run in; sections depend on ids the earlier ones return.
*/
import { quarterBoundsFor } from '@pig/core';
import { createDatabase, type Database } from '../../client';
import { users } from '../../schema/index';
import { seedSupplyActivities } from './activities';
import { seedFacts } from './agent';
import { seedCalendar } from './calendar';
import { seedCompliance } from './compliance';
import { seedDemandPaper } from './contracts';
import { seedDemand } from './demand';
import { seedHostedLearn, seedLearn } from './learn';
import { seedSupply } from './supply';
const db = createDatabase();
const PREFIX = 'DEMO — ';
const day = 86_400_000;
const now = Date.now();
const at = (days: number) => new Date(now + days * day);
/**
* Dates are placed by QUARTER, and deterministically.
*
* This file used to scatter close dates with `at(20 + Math.random() * 60)`,
* which put the whole book in one arbitrary bucket, differently on every run
* so the quarterly view could not be demonstrated and the CI seed-idempotency
* gate was one unlucky reseed away from a false failure. Placement is now
* deliberate: something in the quarter just gone, several in the one we are
* in, and a couple in the next, so the calendar has all three states to show.
*/
const thisQuarter = quarterBoundsFor(new Date(now));
function quarterAt(offset: -1 | 0 | 1, fraction: number): Date {
const bounds =
offset === 0
? thisQuarter
: quarterBoundsFor(
new Date(
offset < 0 ? thisQuarter.from.getTime() - 1 : thisQuarter.to.getTime(),
),
);
const span = bounds.to.getTime() - bounds.from.getTime();
return new Date(bounds.from.getTime() + Math.round(span * fraction));
}
/** 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));
/**
* What every module of the demo seed is handed, and why it is a parameter
* rather than an import.
*
* The modules under `demo/` deliberately import no *value* from this file. If
* they did, ES module evaluation would run their bodies before this one, so a
* constant declared at module scope with `${prefix}` in it would read PREFIX
* before it was initialised and the whole seed would die in the temporal dead
* zone a failure that would appear only when someone added an innocent
* top-level constant to one of the slices. Passing the shared pieces down makes
* that impossible to reintroduce, whichever module a later change lands in.
*/
export interface DemoContext {
readonly db: Database;
/** `DEMO — `. Every invented record carries it; `clear()` matches on it. */
readonly prefix: string;
/** A date relative to the instant the seed started, fixed for the whole run. */
readonly at: (days: number) => Date;
/** GPU-hours for a block, allowing for a maintenance/ramp haircut. */
readonly hours: (gpus: number, days: number, efficiency?: number) => string;
/** A point inside the previous, current or next quarter. See `quarterAt`. */
readonly quarterAt: (offset: -1 | 0 | 1, fraction: number) => Date;
}
/**
* The one context the commands run against, and therefore the one connection
* pool. Built here rather than per module so that importing two slices cannot
* open two pools against the same database.
*/
export const demoContext: DemoContext = { db, prefix: PREFIX, at, hours, quarterAt };
export async function seedDemo(context: DemoContext): Promise<void> {
console.log('Seeding the demo book…\n');
// The id map every later section joins against: one capacity commitment per
// supplier domain, which is how the demand book names the block it draws on.
const commitmentIds = await seedSupply(context);
await seedDemand(context, commitmentIds);
// Customer paper is written after the demand book, because it reads the
// accounts, deals and allocations that pass creates. Without it the renewal
// signals the Growth page is built around have nothing to fire on.
await seedDemandPaper(context);
const compliance = await seedCompliance(context);
// The supply-side timeline, the closed deals' histories, and the sweep that
// restamps lastActivityAt from the activities themselves. It must run after
// every section that creates an account or a deal, because it both rescues
// records that would otherwise have an empty timeline and restamps
// lastActivityAt from what it can see. Compliance creates three demand
// accounts of its own, so running before it left those three with no history
// at all on a first run — and a second run of the demo seed then added the
// missing 21 activities, which is why the book only settled after two runs.
// Compliance neither reads nor writes activities, so nothing moves the other
// way.
await seedSupplyActivities(context);
// Resolved once, here, because the calendar and the learn library must agree
// on who owns their rows; two lookups would be two chances to disagree.
// Ordered by creation, not arbitrary: the demand book now seeds its own
// sellers, and an unordered limit(1) would hand the calendar and the learn
// library to whichever of them Postgres returned first.
const [owner] = await context.db
.select({ id: users.id })
.from(users)
.orderBy(users.createdAt)
.limit(1);
const ownerUserId = owner?.id ?? null;
const calendar = await seedCalendar(context, ownerUserId);
const learn = await seedLearn(context, ownerUserId);
// The self-hosted set, which is real rather than invented — see the long
// note on `seedHostedLearn`. Folded into the demo seed so one command gives
// a complete Learn page, but kept in its own function with its own flags
// because it is not demo data and must not be removed with `--clear`.
const hosted = await seedHostedLearn(context);
const facts = await seedFacts(context);
console.log(' 5 capacity commitments (4 live, 1 lapsed), with sites, MSAs and negotiated SLAs');
console.log(` ${facts.total} agent-derived facts (${facts.added} new) — 2 applied, 4 awaiting review`);
console.log(
` ${facts.tasks} agent tasks and ${facts.runs} Piggy runs, ${facts.actions} idempotency-keyed actions, ` +
`${(facts.costMicroCents / 1_000_000).toFixed(4)} cents of model spend`,
);
console.log(
' 12 demand deals across all ten stages — 2 won, 1 lost, 1 expansion off a closed parent — and 8 supply deals',
);
console.log(' Allocations including one unconverted hold and internal research burn');
console.log(
' Close dates placed deliberately in the previous, current and next quarter',
);
console.log(
` ${compliance.authorizations.total} export authorisations (${compliance.authorizations.added} new) — ` +
`one lapsed, one expiring this quarter, ${compliance.artifacts.total} compliance artefacts, ` +
`${compliance.decisions.total} export-control decisions (allow, needs_review, block), ` +
`${calendar.total} calendar entries (${calendar.added} new)`,
);
console.log(
` ${learn.total} illustrative concept videos (${learn.added} new), members-only`,
);
console.log(
` ${hosted.present} PIG-hosted learn videos (${hosted.added} new)` +
`${hosted.missing > 0 ? `, ${hosted.missing} manifest entries with no file yet` : ''}`,
);
console.log('\nEverything is prefixed "DEMO — ". Remove it with: pnpm db:demo -- --clear');
console.log('The PIG-hosted rows are NOT prefixed and survive that. Remove them with: pnpm db:demo -- --clear-hosted');
}
export { clear } from './clear';
export { HOSTED_LEARN_MANIFEST, clearHostedLearn, seedHostedLearn } from './learn';
+392
View File
@@ -0,0 +1,392 @@
/**
* The Learn library: the illustrative demo rows, and the PIG-hosted real ones.
*
* They sit in one module because they write to one table and share the
* idempotency key, but they are not the same kind of data: the first set is
* invented and prefixed, the second is genuine product footage and survives
* `--clear`.
*/
import { LEARN_MEDIA_PATH_PREFIX, isLearnMediaFilename, learnMediaContentType } from '@pig/core';
import { eq } from 'drizzle-orm';
import { readdir } from 'node:fs/promises';
import { resolve } from 'node:path';
import { learnResources, users } from '../../schema/index';
import type { DemoContext } from './index';
/**
* Every id below is a REAL public recording on the Cap instance at
* video.karti.ai, and every duration is the MEASURED length of the file that
* embed plays. Both were re-checked against the instance `/s/<id>` and
* `/embed/<id>` answer 200, and the recordings are 60.4s and 6.2s because
* this list previously stated neither truthfully.
*
* It used to carry four rows, two of them sharing the id `0n6n9p83efnxbs2`
* under different titles and different stated lengths. That id is not a
* recording at all it 404s, and the only other place it appears in this
* repository is as the fixture string in `apps/api/test/learn.test.ts`, which
* is almost certainly where it was copied from. So two cards each promised a
* quarter of an hour of teaching and played nothing, on the one page that is
* deliberately shown to outsiders. A card that lies about its own content is
* worse than a track with one card in it, and there are exactly two public
* recordings on that instance so there are exactly two rows here, one per
* concept track.
*
* The titles remain illustrative and prefixed, which is the standing bargain
* for demo rows: the concepts they name are the ones this business actually
* teaches, and the footage behind them is whatever genuinely exists. The
* bargain only holds while the stated LENGTH is true, since that is the one
* claim a viewer can check before pressing play.
*
* PLATFORM rows are not seeded here. The five real recordings in
* HOSTED_LEARN_MANIFEST cover that track, and illustrative Cap rows beneath
* genuine ones made the page read as half-placeholder to the exact audience it
* is meant to convince.
*
* The concept rows stay: `supply` and `demand` have no purpose-shot recordings
* yet, and an empty track hides the shape of the page. They are
* `members`-visible, which the CHECK constraint enforces anyway only
* `platform` may be `code`.
*/
export async function seedLearn(
context: DemoContext,
ownerUserId: string | null,
): Promise<{ total: number; added: number }> {
const { db, prefix } = context;
const LEARN_RESOURCES = [
{
track: 'supply' as const,
title: `${prefix}How neocloud capacity is actually priced`,
summary: 'Reserved versus on-demand, commitment length, and where the spread comes from.',
externalId: '1rqq9rk4dpp71fd',
visibility: 'members' as const,
// 60.4s on the wire, rounded down: a duration that overstates by a
// second is the same class of claim as one that overstates by minutes.
durationSeconds: 60,
sortOrder: 10,
},
{
track: 'demand' as const,
title: `${prefix}What a hold takes off the board`,
summary:
'A hold reserves hours nobody else can be quoted, and it is not revenue until it converts.',
externalId: 'sjqqvthbfma27bm',
visibility: 'members' as const,
durationSeconds: 6,
sortOrder: 10,
},
];
/*
* The unique key is (track, provider, external_id), so the SAME recording on
* TWO tracks inserts perfectly happily which is how one id came to sit
* behind two different titles and two different stated durations for as long
* as it did. The database cannot catch that; this can. Thrown before any
* insert, and loudly, because it is a typo in a literal rather than a
* condition of the environment: there is nothing for an operator to fix at
* run time and nothing worth continuing past.
*/
const ids = LEARN_RESOURCES.map((resource) => resource.externalId);
if (new Set(ids).size !== ids.length) {
throw new Error(
'Two demo learn resources share an external id — one of them would be a lie about its own content.',
);
}
let learnAdded = 0;
for (const resource of LEARN_RESOURCES) {
// Idempotent on the unique key rather than an existence check, which is
// the whole reason that constraint exists: onConflictDoNothing without one
// is a silent no-op and has duplicated seed data here twice before.
const inserted = await db
.insert(learnResources)
.values({
track: resource.track,
title: resource.title,
summary: resource.summary,
url: `https://video.karti.ai/s/${resource.externalId}`,
provider: 'cap',
externalId: resource.externalId,
visibility: resource.visibility,
durationSeconds: resource.durationSeconds,
sortOrder: resource.sortOrder,
addedByUserId: ownerUserId,
})
.onConflictDoNothing({
target: [learnResources.track, learnResources.provider, learnResources.externalId],
})
.returning({ id: learnResources.id });
if (inserted.length) learnAdded += 1;
}
return { total: LEARN_RESOURCES.length, added: learnAdded };
}
// ------------------------------------------------------- PIG-hosted learn
//
// Real videos, served by PIG itself from PIG_MEDIA_DIR — not demo data. They
// carry no `DEMO — ` prefix precisely because they are genuine product
// walkthroughs, which also means `--clear` leaves them alone; `--clear-hosted`
// is their own switch.
//
// **A row is written only when its file is actually on disk.** A learn row
// whose media 404s is worse than a missing row: the card renders, the play
// button does nothing, and the feature reads as broken. So the manifest below
// declares the curriculum, and the seed inserts the entries it can find.
// Running it before the videos are generated is a no-op with a printed list,
// and running it again afterwards fills them in.
//
// That choice was re-examined, because the audience for the absence is not an
// operator: the anonymous share-code view of /learn shows this track and
// nothing else, so a missing file is a stranger's first impression of the
// product. A "coming soon" ROW was rejected. It would need a filename to point
// at, the card would carry a play button, and pressing it would fail — which
// is the one outcome worse than an empty section, and the same reason the
// access hero draws redacted bars rather than invented thumbnails. The absence
// is handled where it belongs instead: `apps/web/src/pages/Learn.tsx` gives a
// code-holder with nothing published a finished panel that says so and offers
// a way on, rather than the admin empty state.
//
// `media/` is gitignored — hundreds of megabytes of rendered MP4 are a release
// artefact, not source — so a fresh clone and every git worktree start without
// it, and that is the ordinary case rather than a fault. Point PIG_MEDIA_DIR
// at a directory holding the renders (the API route reads the same variable)
// and the five rows appear.
//
// **The filename is discovered, not written down.** Files are
// content-addressed — `<slug>.<hash>.mp4` — so the hash changes every time a
// video is re-rendered, and a manifest carrying the hash would be a file that
// has to be edited in lockstep with a render. Instead the slug is the stable
// identity and the directory supplies the rest. Idempotency then rests on the
// unique key (track, provider, external_id) exactly as the DEMO rows do.
//
// A re-render produces a NEW hash and therefore a new row; the old row keeps
// pointing at a file that is no longer there. That is reported rather than
// resolved automatically, because deleting rows on the strength of a missing
// file would empty the curriculum the first time someone ran this with the
// media directory unmounted.
interface HostedLearnEntry {
/** Stable identity. Also the filename stem: `<slug>.<hash>.<ext>`. */
slug: string;
title: string;
summary: string;
track: 'supply' | 'demand' | 'platform';
visibility: 'members' | 'code';
/**
* Measured from the render, to the nearest second not estimated from the
* script. Every one below was re-checked against the file it names, because
* a duration is the only claim a card makes that a viewer can verify before
* pressing play.
*/
durationSeconds: number;
sortOrder: number;
}
export const HOSTED_LEARN_MANIFEST: readonly HostedLearnEntry[] = [
{
slug: 'overview-and-margin',
title: 'Overview and the margin question',
summary:
'Which contracted capacity is sold, at what margin, and what is idle right now — and why cost is charged against the full commitment.',
track: 'platform',
visibility: 'code',
durationSeconds: 29,
sortOrder: 1,
},
{
slug: 'quarterly-calendar',
title: 'The quarterly calendar',
summary:
'What closes, what renews, what expires and when capacity lands — with export authorisations and compliance artefacts at the top.',
track: 'platform',
visibility: 'code',
durationSeconds: 30,
sortOrder: 2,
},
{
slug: 'capacity-to-allocations',
title: 'Capacity to allocations',
summary:
'Joining a commitment you bought to a deal you sold — the availability book, the matcher, and the allocation the ledger is built on.',
track: 'platform',
visibility: 'code',
durationSeconds: 26,
sortOrder: 3,
},
{
slug: 'importing-your-book',
title: 'Importing your book',
summary:
'Getting off the spreadsheet — CSV, Excel, Notion or a bounded Google Sheets range, with a dry run you review before anything is written.',
track: 'platform',
visibility: 'code',
durationSeconds: 28,
sortOrder: 4,
},
{
slug: 'piggy-and-its-boundary',
title: 'Piggy, and what it will not do',
summary:
'The docked agent reads through scoped, page-specific PIG tools — and has no shell, no filesystem, and no ability to write CRM records.',
track: 'platform',
visibility: 'code',
durationSeconds: 28,
sortOrder: 5,
},
];
/**
* Where the served files live. The same variable the API route reads.
*
* The default is resolved from this file's location, not from `process.cwd()`,
* because pnpm runs the seed with the working directory at `packages/db` while
* the server runs at the repository root so a relative default would mean
* two different directories, and the seed would write rows for files the API
* cannot find.
*
* Five levels up, because this file sits one deeper than the seed it was split
* out of: `packages/db/src/seed/demo` repository root.
*/
function mediaDirectory(): string {
const configured = process.env.PIG_MEDIA_DIR?.trim();
if (configured && configured.length > 0) return resolve(configured);
return resolve(import.meta.dirname, '../../../../../media');
}
/**
* Find the one VIDEO belonging to a slug.
*
* Two videos for one slug is an error rather than a choice: picking the newest
* would silently publish whichever render happened to finish last, and the
* operator has an old file to delete.
*
* Video extensions only, and that is the whole point of the second predicate.
* A poster is `<slug>.<hash>.jpg` deliberately the video's own stem, so it
* cannot go stale against the clip it shows (`learnPosterFilename`) and it
* sits in this same directory. Matching on the slug alone therefore found two
* files for every complete entry and declared each of them an ambiguous stale
* render, so a directory containing five finished walkthroughs AND their
* posters seeded exactly nothing, and the share-code page it feeds rendered
* empty on the one box that had the media.
*/
function mediaFileFor(
slug: string,
filenames: readonly string[],
): { filename: string | null; ambiguous: readonly string[] } {
const matches = filenames.filter(
(name) =>
isLearnMediaFilename(name) &&
name.startsWith(`${slug}.`) &&
learnMediaContentType(name)?.startsWith('video/'),
);
/*
* Reported and skipped, not thrown.
*
* This runs from the middle of seedDemo(), so throwing on a duplicate took
* out every later section facts, activities, the lot and left the
* operator working out why `pnpm db:demo` died on two MP4s sharing a slug.
* A stale render is a condition of one directory entry; its blast radius
* should be that entry. Missing files are already handled this way.
*/
if (matches.length > 1) return { filename: null, ambiguous: matches };
return { filename: matches[0] ?? null, ambiguous: [] };
}
export async function seedHostedLearn(context: DemoContext): Promise<{
present: number;
added: number;
missing: number;
}> {
const { db } = context;
const directory = mediaDirectory();
let filenames: string[] = [];
try {
filenames = await readdir(directory);
} catch {
// No directory is the normal state of a fresh checkout, not a failure.
console.log(
` (no media directory at ${directory} — skipping PIG-hosted learn videos; ` +
'set PIG_MEDIA_DIR if the renders live elsewhere)',
);
return { present: 0, added: 0, missing: HOSTED_LEARN_MANIFEST.length };
}
const [owner] = await db.select({ id: users.id }).from(users).limit(1);
let present = 0;
let added = 0;
const absent: string[] = [];
for (const entry of HOSTED_LEARN_MANIFEST) {
const { filename, ambiguous } = mediaFileFor(entry.slug, filenames);
if (ambiguous.length > 0) {
console.warn(
` ! ${entry.slug}: ${ambiguous.length} files match (${ambiguous.join(', ')}) — ` +
'content-addressed names mean one is a stale render. Delete it and re-run. Skipped.',
);
absent.push(entry.slug);
continue;
}
if (!filename) {
absent.push(entry.slug);
continue;
}
present += 1;
const inserted = await db
.insert(learnResources)
.values({
track: entry.track,
title: entry.title,
summary: entry.summary,
// The same path the resolver builds, from the same constant — so a
// seeded row and a row created through the API are indistinguishable.
url: `${LEARN_MEDIA_PATH_PREFIX}${filename}`,
provider: 'pig',
externalId: filename,
visibility: entry.visibility,
durationSeconds: entry.durationSeconds,
sortOrder: entry.sortOrder,
addedByUserId: owner?.id ?? null,
})
.onConflictDoNothing({
target: [learnResources.track, learnResources.provider, learnResources.externalId],
})
.returning({ id: learnResources.id });
if (inserted.length) added += 1;
}
if (absent.length) {
console.log(
` (no file yet in ${directory} for: ${absent.join(', ')}` +
'drop <slug>.<hash>.mp4 there, or point PIG_MEDIA_DIR at the renders, and run this again)',
);
}
// Rows whose file has gone: reported, never deleted. See the note above.
const orphans = (
await db
.select({ externalId: learnResources.externalId, title: learnResources.title })
.from(learnResources)
.where(eq(learnResources.provider, 'pig'))
).filter((row) => !filenames.includes(row.externalId));
for (const orphan of orphans) {
console.log(` ! "${orphan.title}" points at ${orphan.externalId}, which is not on disk`);
}
return { present, added, missing: absent.length };
}
/**
* `--clear-hosted`. Kept beside the seed it undoes rather than in `clear.ts`,
* because it is the opposite of a different command: `--clear` removes the
* invented book and must leave these genuine rows exactly where they are.
*/
export async function clearHostedLearn(context: DemoContext): Promise<void> {
const removed = await context.db
.delete(learnResources)
.where(eq(learnResources.provider, 'pig'))
.returning({ id: learnResources.id });
console.log(`Removed ${removed.length} PIG-hosted learn resource(s). Files on disk are untouched.`);
}
File diff suppressed because it is too large Load Diff
+99 -12
View File
@@ -15,9 +15,12 @@
* commitment, two allocations against it, and therefore a real margin
* number and a real idle-capacity alert on the dashboard.
*
* The example is clearly labelled. Nobody should mistake it for real business.
* The example is clearly labelled, and the company buying is invented. Real
* named companies appear here only with a source; commercial terms attached to
* one would be a fabricated record about someone else's business. The same rule
* `demo.ts` states, obeyed here too.
*/
import { eq } from 'drizzle-orm';
import { and, eq, ne } from 'drizzle-orm';
import { createDatabase } from '../client';
import {
accounts,
@@ -214,6 +217,12 @@ async function seed() {
// Illustrative only, and labelled as such. It exists so the dashboard has a
// real margin figure and a real idle-capacity alert on first run, rather
// than empty states that make the product look like it does nothing.
//
// The supplier is real and its block is illustrative; the buyer is invented
// outright. Naming a real company as the counterparty to an invented ACV with
// MSA and DPA flagged executed is a fabricated commercial record about that
// company, which no amount of an `EXAMPLE — ` prefix on the neighbouring rows
// makes acceptable.
const [supplier] = await db
.select({ id: accounts.id })
.from(accounts)
@@ -227,6 +236,10 @@ async function seed() {
.where(eq(capacityCommitments.name, EXAMPLE_COMMITMENT))
.limit(1);
// Before anything is created: repair the databases that already carry the
// example booked against a real company.
await rehomeExampleDeal();
if (supplier && !existingExample) {
const start = new Date();
const end = new Date(start.getTime() + 180 * 86_400_000);
@@ -259,18 +272,14 @@ async function seed() {
.returning();
if (commitment) {
const [customer] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, 'Ramp'))
.limit(1);
const customerId = await ensureExampleCustomer();
if (customer) {
if (customerId) {
const [deal] = await db
.insert(demandDeals)
.values({
accountId: customer.id,
name: 'EXAMPLE — post-training cluster',
accountId: customerId,
name: EXAMPLE_DEAL,
productLine: 'compute_reserved',
stage: 'deployment',
acvCents: 340_000_00,
@@ -323,8 +332,9 @@ async function seed() {
});
console.log(
' Worked example seeded: 1 commitment, 2 allocations (one of them internal ' +
'research burn), ~+10% margin with 20% still idle.',
` Worked example seeded against ${EXAMPLE_CUSTOMER} (fictional): 1 commitment, ` +
'2 allocations (one of them internal research burn), ~+10% margin with 20% ' +
'still idle.',
);
}
}
@@ -379,6 +389,83 @@ async function seed() {
console.log('\nDone. No email addresses were seeded or inferred.');
}
// -------------------------------------------------- the example's counterparty
const EXAMPLE_CUSTOMER = 'EXAMPLE — Fenwick Labs';
const EXAMPLE_DEAL = 'EXAMPLE — post-training cluster';
/**
* The invented company the worked example is sold to.
*
* An existence check rather than `onConflictDoNothing()`, for the same reason
* as the customer references above: this account deliberately has no domain
* it is not a real company and must never be mistaken for one and `domain`
* is the only unique index on `accounts`, so a conflict clause would have
* nothing to fire on and every run would add another Fenwick Labs.
*/
async function ensureExampleCustomer(): Promise<string | undefined> {
const [existing] = await db
.select({ id: accounts.id })
.from(accounts)
.where(eq(accounts.name, EXAMPLE_CUSTOMER))
.limit(1);
if (existing) return existing.id;
const [created] = await db
.insert(accounts)
.values({
name: EXAMPLE_CUSTOMER,
side: 'demand',
customerSegment: 'applied_ai_startup',
country: 'United States',
description:
'Fictional company, invented so the worked example has a buyer. Not a ' +
'customer, not a real business, and safe to delete along with the example.',
source: 'seed',
confidence: 'confirmed',
})
.returning();
return created?.id;
}
/**
* Move the example deal off whatever account an older seed attached it to.
*
* This example used to be booked against Ramp a real company, seeded from a
* public reference on primeintellect.ai complete with an invented ACV and
* both MSA and DPA flagged executed. Fixing the insert is not enough on its
* own: the worked-example section is skipped entirely whenever the commitment
* already exists, so a database seeded before the fix would keep it, and
* `pnpm db:demo -- --clear` never touched it because that only matches the
* `DEMO — ` prefix.
*
* Moved rather than deleted. The allocations hang off the deal, and they are
* what give the dashboard its margin figure and its idle-capacity alert; the
* problem was only ever which account the row pointed at.
*/
async function rehomeExampleDeal(): Promise<void> {
const [present] = await db
.select({ id: demandDeals.id })
.from(demandDeals)
.where(eq(demandDeals.name, EXAMPLE_DEAL))
.limit(1);
if (!present) return;
const customerId = await ensureExampleCustomer();
if (!customerId) return;
const moved = await db
.update(demandDeals)
.set({ accountId: customerId })
.where(and(eq(demandDeals.name, EXAMPLE_DEAL), ne(demandDeals.accountId, customerId)))
.returning({ id: demandDeals.id });
if (moved.length > 0) {
console.log(` Worked example moved off a real company and onto ${EXAMPLE_CUSTOMER}.`);
}
}
seed()
.then(() => process.exit(0))
.catch((error) => {
+6
View File
@@ -356,6 +356,12 @@ export const UNRESOLVED_NAMES = [
* Useful as accounts, but note these are named as references and integrations,
* which is not the same as a paying compute customer a distinction worth
* keeping in a CRM.
*
* These are REAL companies, so nothing may be attached to them that is not in
* the cited source. A deal, an ACV, an executed MSA or an allocation invented
* against one of these accounts is a fabricated commercial record about a real
* business the seed's worked example was booked against Ramp for exactly
* this reason, and it is now booked against an invented company instead.
*/
export const PUBLIC_CUSTOMER_REFERENCES = [
{