/** * The demo book's Motion half: eight engagements, one at every open stage. * * The loop is the only reason Motion exists: * * library template --instantiate--> engagement artefact --promote--> v2 * * A screenshot of the library alone shows a folder of documents, which is not * the claim being made. So the book is laid out to prove three things a folder * cannot. **Every stage is occupied**, because the page that matters asks * whether the motion is repeating and a rail of zeroes cannot answer it. * **Scores move, and sometimes move down** — a single score is a number and * four are a trajectory; a scorecard that only ever rises is a ratchet, so the * Verity fine-tuning record deliberately goes 62.5 → 60.5 → 84.0 → 80.8, and * nine dimensions regress somewhere in the book. And **one engagement closes * the loop**, putting a version 2 into the library carrying `supersedes_id` * back to the shipped version 1 and `origin_artifact_id` back to the artefact * that proved it, so both halves of the FK cycle are populated on a first run. * * The artefact bodies are the point. An artefact whose body is the template * with the blanks still in it is exactly what this data exists to disprove, so * every one of them is written as the customer's own facts — named people, real * volumes, the specific thing going wrong. That is also why they live in JSON * beside this file rather than in TypeScript literals: forty-four markdown * bodies as backtick strings would be a module nobody can review. * * Every engagement hangs off a demand deal the demand book already created, * rather than a deal of its own. An engagement has no independent existence, * and inventing deals here would put rows on a pipeline whose counts are quoted * in `demo/index.ts`. * * Scores are computed with `motionScoreBasisPoints` and banded with * `motionBand`, never written as literals. Hard-coding 8280 would let the seed * and the product disagree about what the same dimensions are worth, and the * first place anyone would notice is a demo. */ import { motionBand, motionScoreBasisPoints, type ArtifactStatus, type DemandStage, type EngagementStatus, type MotionDimensionScore, type MotionKind, } from '@pig/core'; import { and, eq, like, sql } from 'drizzle-orm'; import { demandDeals, engagementArtifacts, engagements, motionTemplates, qualificationScores, users, } from '../../schema/index'; import type { DemoContext } from './index'; import aurelianCommittedCapacity from './motion/aurelian-committed-capacity.json' with { type: 'json' }; import halcyonPostTraining from './motion/halcyon-post-training.json' with { type: 'json' }; import northwindBlackwell from './motion/northwind-blackwell.json' with { type: 'json' }; import northwindFleetExpansion from './motion/northwind-fleet-expansion.json' with { type: 'json' }; import quillonEvalHarness from './motion/quillon-eval-harness.json' with { type: 'json' }; import tessellateBurstInference from './motion/tessellate-burst-inference.json' with { type: 'json' }; import verityEuFineTuning from './motion/verity-eu-fine-tuning.json' with { type: 'json' }; import verityEuInference from './motion/verity-eu-inference.json' with { type: 'json' }; interface DemoArtefact { readonly templateSlug: string | null; /* * Carried on the artefact rather than looked up from its template, because * six of the forty-four have no template at all — the work a lead does that * no library entry covers, which is the honest shape of an engagement. A * `kind` derived from the template would have been null for exactly those * six, and `engagement_artifacts.kind` is NOT NULL. */ readonly kind: MotionKind; readonly stage: DemandStage; readonly title: string; readonly status: ArtifactStatus; readonly authoredDaysAgo: number; readonly body: string; } interface DemoScore { readonly daysAgo: number; readonly note: string; readonly dimensions: readonly MotionDimensionScore[]; } interface DemoEngagement { readonly key: string; readonly dealName: string; readonly accountName: string; readonly stage: DemandStage; readonly status: EngagementStatus; readonly summary: string; readonly openedDaysAgo: number; readonly artefacts: readonly DemoArtefact[]; readonly scores: readonly DemoScore[]; readonly promote: { readonly artefactTitle: string; readonly intoSlug: string } | null; } /** * Ordered oldest-opened first, so the engagement list reads as a book somebody * built up rather than eight things that appeared at once. */ const DEMO_ENGAGEMENTS = [ northwindFleetExpansion, northwindBlackwell, halcyonPostTraining, verityEuFineTuning, verityEuInference, aurelianCommittedCapacity, tessellateBurstInference, quillonEvalHarness, ] as unknown as readonly DemoEngagement[]; /** * Which demo seller owns which account. * * Assigned by account rather than by engagement, because the two accounts that * appear twice (Verity Health AI, Northwind Robotics) are one relationship each * — a second engagement handed to a different owner would contradict the * continuity the artefacts themselves describe. */ const OWNER_BY_ACCOUNT: Readonly> = { 'Quillon AI': 'Wren Abbot', 'Aurelian Systems': 'Marcus Oyelaran', 'Verity Health AI': 'Ines Fabre', 'Tessellate Labs': 'Rosalind Achebe', 'Halcyon Research': 'Ines Fabre', 'Northwind Robotics': 'Marcus Oyelaran', }; async function findDeal(context: DemoContext, name: string): Promise { const [deal] = await context.db .select({ id: demandDeals.id }) .from(demandDeals) .where(eq(demandDeals.name, name)) .limit(1); return deal?.id; } async function findSeller(context: DemoContext, name: string): Promise { const [seller] = await context.db .select({ id: users.id }) .from(users) .where(eq(users.name, `${context.prefix}${name}`)) .limit(1); return seller?.id ?? null; } /** The shipped version 1 of a lineage. Promotion needs its id and its version. */ async function findTemplate( context: DemoContext, slug: string, ): Promise<{ id: string; version: number; summary: string } | undefined> { const [template] = await context.db .select({ id: motionTemplates.id, version: motionTemplates.version, summary: motionTemplates.summary, }) .from(motionTemplates) .where(and(eq(motionTemplates.slug, slug), eq(motionTemplates.isSystem, true))) .limit(1); return template; } export async function seedMotionEngagements( context: DemoContext, ): Promise<{ engagements: number; artifacts: number; scores: number; promoted: number; missingDeals: readonly string[]; }> { const { db, prefix, at } = context; /* * The whole section is skipped if any demo engagement already exists. * * `engagements_demand_deal_key` would refuse a duplicate engagement, but * nothing would refuse a second set of artefacts or — worse — a second * promotion, and a second promotion writes case-study-frame v3 on top of the * v2 this seed already created. `qualification_scores` is append-only by * design and so has no constraint to conflict on at all; nineteen more rows * on every run would turn every trajectory into noise. An existence check on * the parent is the only thing that covers all three. */ const existing = await db .select({ id: engagements.id }) .from(engagements) .where(like(engagements.summary, `${prefix}%`)) .limit(1); if (existing.length > 0) { return { engagements: 0, artifacts: 0, scores: 0, promoted: 0, missingDeals: [] }; } const playbook = await findTemplate(context, 'strategic-deployment-playbook'); const templateCache = new Map(); const templateBySlug = async (slug: string) => { if (!templateCache.has(slug)) { const found = await findTemplate(context, slug); if (found) templateCache.set(slug, found); } return templateCache.get(slug); }; const usageByTemplate = new Map(); const missingDeals: string[] = []; let engagementCount = 0; let artifactCount = 0; let scoreCount = 0; let promotedCount = 0; for (const demo of DEMO_ENGAGEMENTS) { /* * A missing deal is reported, not skipped in silence. * * Every engagement hangs off a deal the demand book creates, and that book * skips an account it has already seen — so a database where the accounts * survive but the deals were removed leaves these lookups empty and this * whole section a no-op that reports zeroes and looks like a bug in the * loader. It was found exactly that way, on a shared development database. */ const dealId = await findDeal(context, demo.dealName); if (!dealId) { missingDeals.push(demo.dealName); continue; } const ownerName = OWNER_BY_ACCOUNT[demo.accountName.replace(prefix, '')]; const ownerId = ownerName ? await findSeller(context, ownerName) : null; const [engagement] = await db .insert(engagements) .values({ demandDealId: dealId, playbookTemplateId: playbook?.id ?? null, ownerUserId: ownerId, status: demo.status, summary: demo.summary, openedAt: at(-demo.openedDaysAgo), closedAt: demo.status === 'won' ? at(-Math.floor(demo.openedDaysAgo / 8)) : null, }) .returning({ id: engagements.id }); if (!engagement) continue; engagementCount += 1; const artefactIdByTitle = new Map(); for (const artefact of demo.artefacts) { const template = artefact.templateSlug ? await templateBySlug(artefact.templateSlug) : undefined; const [written] = await db .insert(engagementArtifacts) .values({ engagementId: engagement.id, templateId: template?.id ?? null, kind: artefact.kind, stage: artefact.stage, title: artefact.title, body: artefact.body, status: artefact.status, authoredByUserId: ownerId, createdAt: at(-artefact.authoredDaysAgo), updatedAt: at(-artefact.authoredDaysAgo), }) .returning({ id: engagementArtifacts.id }); if (!written) continue; artifactCount += 1; artefactIdByTitle.set(artefact.title, { id: written.id, body: artefact.body }); if (template) { usageByTemplate.set(template.id, (usageByTemplate.get(template.id) ?? 0) + 1); } } for (const score of demo.scores) { const basisPoints = motionScoreBasisPoints(score.dimensions); await db.insert(qualificationScores).values({ engagementId: engagement.id, frameworkTemplateId: (await templateBySlug('trainability-qualification'))?.id ?? null, /* * Copied, not referenced. `qualification_scores.dimensions` stores the * framework AS IT WAS SCORED — weights included — so that re-authoring * the scorecard later cannot retroactively change what a past score * meant. Handing the same array to every row would make that snapshot * a shared object. */ dimensions: score.dimensions.map((dimension) => ({ ...dimension })), basisPoints, band: motionBand(basisPoints).label, note: score.note, scoredByUserId: ownerId, scoredAt: at(-score.daysAgo), }); scoreCount += 1; } /* * The promotion, written by hand rather than by calling the API service: * the seed has no HTTP surface and no principal. It follows the same rules * `promoteArtifact` does — version = newest + 1, `supersedesId` to the * shipped v1, `originArtifactId` to the artefact, **`body` copied from the * artefact verbatim**, `visibility: 'shared'`, `isSystem: false` — because * a demo that produced a row the real path could not have produced would * teach the wrong shape of the table. * * `isSystem` is false and the title is prefixed, which is what lets * `clear()` find it. It is a version 2 of a shipped lineage, so removing * the demo book genuinely returns the library to what ships. */ if (demo.promote) { const artefact = artefactIdByTitle.get(demo.promote.artefactTitle); const supersedes = await templateBySlug(demo.promote.intoSlug); if (artefact && supersedes) { const [promoted] = await db .insert(motionTemplates) .values({ kind: 'case_study', stage: 'expansion', slug: demo.promote.intoSlug, version: supersedes.version + 1, title: demo.promote.artefactTitle, summary: `Version ${supersedes.version + 1}, promoted out of the ` + `${demo.accountName.replace(prefix, '')} expansion. The frame as it was actually ` + 'filled in, with the numbers the customer approved for named use.', body: artefact.body, fields: { promotedFrom: demo.promote.artefactTitle, engagement: demo.key }, visibility: 'shared', ownerUserId: ownerId, supersedesId: supersedes.id, originArtifactId: artefact.id, isSystem: false, }) .onConflictDoNothing({ target: [motionTemplates.slug, motionTemplates.version] }) .returning({ id: motionTemplates.id }); if (promoted) { await db .update(engagementArtifacts) .set({ promotedTemplateId: promoted.id }) .where(eq(engagementArtifacts.id, artefact.id)); promotedCount += 1; } } } } /* * `usage_count` is raised once per template at the end rather than once per * artefact inside the loop, because it is the counter that makes a template * permanently un-editable and `clear()` gives back exactly what was borrowed. * One statement per template keeps the two halves symmetrical. */ for (const [templateId, count] of usageByTemplate) { await db .update(motionTemplates) .set({ usageCount: sql`${motionTemplates.usageCount} + ${count}` }) .where(eq(motionTemplates.id, templateId)); } return { engagements: engagementCount, artifacts: artifactCount, scores: scoreCount, promoted: promotedCount, missingDeals, }; }