Add Motion: the go-to-market operating system on top of the ledger
The ledger answers which contracted capacity is sold, to whom, at what margin. It says nothing about the motion — the repeatable practice that turns a customer conversation into a scoped deployment, and turns that deployment into something the next one reuses. Motion is deliberately not a parallel entity tree. DEMAND_STAGES already is the motion, so Motion binds reusable artefacts to the stages of a demand deal that already exists: an engagement hangs off one deal, cascade deleted, one per deal by unique constraint. Nine closed kinds, each declaring which stages it serves, and a starter library of twelve templates covering all eight open stages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
/**
|
||||
* Two demo engagements, chosen so the loop is visible without a live customer.
|
||||
*
|
||||
* The loop is the only reason Motion exists:
|
||||
*
|
||||
* library template --instantiate--> engagement artifact --promote--> v2
|
||||
*
|
||||
* A screenshot of the library alone shows a folder of documents, which is not
|
||||
* the claim. So one engagement is **mid-POC with three qualification scores**,
|
||||
* because a single score is a number and three are a trajectory — the movement
|
||||
* is the evidence that qualification happened at all — and the other is
|
||||
* **closed-won with a promoted artifact**, which puts a version 2 into the
|
||||
* library carrying `supersedes_id` back to the shipped version 1 and
|
||||
* `origin_artifact_id` back to the engagement that proved it. Both halves of
|
||||
* the FK cycle are therefore populated on a first run.
|
||||
*
|
||||
* Both hang off demand deals the demand book already created, rather than deals
|
||||
* of their own: an engagement has no independent existence, and inventing a
|
||||
* deal here would put a thirteenth row on a pipeline whose counts are quoted in
|
||||
* `demo/index.ts`.
|
||||
*
|
||||
* The scores are computed with `motionScoreBasisPoints` rather than written as
|
||||
* literals. Hard-coding 6600 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 MotionDimensionScore } 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';
|
||||
|
||||
/**
|
||||
* The scorecard's dimensions and their authored weights, copied from
|
||||
* `seed/motion/trainability-qualification.json`.
|
||||
*
|
||||
* Copied rather than read out of the seeded row, deliberately: a stored score
|
||||
* is a snapshot of the framework *as it was scored*, which is the whole reason
|
||||
* `qualification_scores.dimensions` holds the weights rather than a reference.
|
||||
* Reading them live would make the demo history silently re-weight itself the
|
||||
* day someone edits the template, which is precisely the behaviour the column
|
||||
* exists to prevent.
|
||||
*/
|
||||
const SCORECARD_WEIGHTS: readonly { readonly id: string; readonly weight: number }[] = [
|
||||
{ id: 'task_definability', weight: 10 },
|
||||
{ id: 'verifier_quality', weight: 13 },
|
||||
{ id: 'trace_data_rights', weight: 8 },
|
||||
{ id: 'baseline_measured', weight: 8 },
|
||||
{ id: 'headroom', weight: 10 },
|
||||
{ id: 'env_constructibility', weight: 8 },
|
||||
{ id: 'metric_owner', weight: 9 },
|
||||
{ id: 'budget_source', weight: 9 },
|
||||
{ id: 'exec_sponsor', weight: 4 },
|
||||
{ id: 'security_legal_path', weight: 8 },
|
||||
{ id: 'forcing_function', weight: 8 },
|
||||
{ id: 'expansion_surface', weight: 5 },
|
||||
];
|
||||
|
||||
/**
|
||||
* Three passes over the same scorecard, in the order they were run.
|
||||
*
|
||||
* The trajectory is the teaching: the deal opens borderline on an unmeasured
|
||||
* verifier and no named budget, the POC scoping call fixes the verifier, and
|
||||
* the third pass lands once finance names a source. Two dimensions deliberately
|
||||
* do NOT move — `trace_data_rights` and `expansion_surface` — because a
|
||||
* scorecard where every number rises on every pass is a scorecard nobody is
|
||||
* really filling in.
|
||||
*/
|
||||
const SCORE_PASSES: readonly {
|
||||
readonly daysAgo: number;
|
||||
readonly note: string;
|
||||
readonly scores: Readonly<Record<string, number>>;
|
||||
}[] = [
|
||||
{
|
||||
daysAgo: 52,
|
||||
note:
|
||||
'First pass, straight out of technical discovery. The task is well specified and there ' +
|
||||
'is real headroom, but the verifier is a rubric nobody has run against human labels and ' +
|
||||
'no budget line has been named. Not yet — and the two things to fix are explicit.',
|
||||
scores: {
|
||||
task_definability: 3,
|
||||
verifier_quality: 1,
|
||||
trace_data_rights: 2,
|
||||
baseline_measured: 2,
|
||||
headroom: 3,
|
||||
env_constructibility: 2,
|
||||
metric_owner: 2,
|
||||
budget_source: 1,
|
||||
exec_sponsor: 2,
|
||||
security_legal_path: 2,
|
||||
forcing_function: 2,
|
||||
expansion_surface: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
daysAgo: 27,
|
||||
note:
|
||||
'Re-scored after the POC scoping call. They ran the judge against 300 human-labelled ' +
|
||||
'items and the baseline is now measured rather than remembered. Budget is still a ' +
|
||||
'reallocation nobody has signed.',
|
||||
scores: {
|
||||
task_definability: 3,
|
||||
verifier_quality: 3,
|
||||
trace_data_rights: 2,
|
||||
baseline_measured: 3,
|
||||
headroom: 3,
|
||||
env_constructibility: 3,
|
||||
metric_owner: 3,
|
||||
budget_source: 1,
|
||||
exec_sponsor: 2,
|
||||
security_legal_path: 3,
|
||||
forcing_function: 2,
|
||||
expansion_surface: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
daysAgo: 6,
|
||||
note:
|
||||
'Third pass, in POC week two. Finance named the source and the VP Engineering owns the ' +
|
||||
'metric in their own planning doc. Data rights are unchanged: the customer still cannot ' +
|
||||
'export traces beyond the pilot without a DPA amendment, and that is the live risk.',
|
||||
scores: {
|
||||
task_definability: 4,
|
||||
verifier_quality: 3,
|
||||
trace_data_rights: 2,
|
||||
baseline_measured: 3,
|
||||
headroom: 4,
|
||||
env_constructibility: 3,
|
||||
metric_owner: 4,
|
||||
budget_source: 3,
|
||||
exec_sponsor: 3,
|
||||
security_legal_path: 3,
|
||||
forcing_function: 3,
|
||||
expansion_surface: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function dimensionsFor(scores: Readonly<Record<string, number>>): MotionDimensionScore[] {
|
||||
return SCORECARD_WEIGHTS.map((dimension) => ({
|
||||
id: dimension.id,
|
||||
weight: dimension.weight,
|
||||
score: scores[dimension.id] ?? 0,
|
||||
}));
|
||||
}
|
||||
|
||||
async function findDeal(context: DemoContext, name: string): Promise<string | undefined> {
|
||||
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<string | null> {
|
||||
const [seller] = await context.db
|
||||
.select({ id: users.id })
|
||||
.from(users)
|
||||
.where(eq(users.name, `${context.prefix}${name}`))
|
||||
.limit(1);
|
||||
return seller?.id ?? null;
|
||||
}
|
||||
|
||||
async function findTemplate(
|
||||
context: DemoContext,
|
||||
slug: string,
|
||||
): Promise<{ id: string; version: number } | undefined> {
|
||||
const [template] = await context.db
|
||||
.select({ id: motionTemplates.id, version: motionTemplates.version })
|
||||
.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 }> {
|
||||
const { db, prefix, at } = context;
|
||||
|
||||
/*
|
||||
* The whole section is skipped if either engagement already exists.
|
||||
*
|
||||
* `engagements_demand_deal_key` would refuse a duplicate engagement, but
|
||||
* nothing would refuse a second set of artifacts 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; three more rows on
|
||||
* every run would turn the 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 };
|
||||
}
|
||||
|
||||
const playbook = await findTemplate(context, 'strategic-deployment-playbook');
|
||||
const scorecard = await findTemplate(context, 'trainability-qualification');
|
||||
const pocTemplate = await findTemplate(context, 'post-training-poc');
|
||||
const caseStudy = await findTemplate(context, 'case-study-frame');
|
||||
|
||||
let engagementCount = 0;
|
||||
let artifactCount = 0;
|
||||
let scoreCount = 0;
|
||||
let promotedCount = 0;
|
||||
|
||||
// ------------------------------------------------- mid-POC, still scoring
|
||||
const halcyonDealId = await findDeal(context, `${prefix}Managed post-training run`);
|
||||
const ines = await findSeller(context, 'Ines Fabre');
|
||||
|
||||
/*
|
||||
* A missing deal is reported, not skipped in silence.
|
||||
*
|
||||
* Both engagements hang off deals 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.
|
||||
*/
|
||||
if (!halcyonDealId) {
|
||||
console.warn(
|
||||
` No "${prefix}Managed post-training run" deal — skipping the mid-POC engagement. ` +
|
||||
'Run `pnpm db:demo -- --clear` and reseed to rebuild the demand book.',
|
||||
);
|
||||
}
|
||||
|
||||
if (halcyonDealId) {
|
||||
const [engagement] = await db
|
||||
.insert(engagements)
|
||||
.values({
|
||||
demandDealId: halcyonDealId,
|
||||
playbookTemplateId: playbook?.id ?? null,
|
||||
ownerUserId: ines,
|
||||
status: 'open',
|
||||
summary: `${prefix}Post-training motion on the Halcyon summarisation workflow — POC week two.`,
|
||||
openedAt: at(-58),
|
||||
})
|
||||
.returning({ id: engagements.id });
|
||||
if (engagement) {
|
||||
engagementCount += 1;
|
||||
|
||||
await db.insert(engagementArtifacts).values({
|
||||
engagementId: engagement.id,
|
||||
templateId: scorecard?.id ?? null,
|
||||
kind: 'discovery',
|
||||
stage: 'qualification',
|
||||
title: `${prefix}Discovery notes — Halcyon summarisation`,
|
||||
body:
|
||||
'## What they are trying to do\n\n' +
|
||||
'Reduce reviewer time on internal research summaries. Today a senior analyst reads a ' +
|
||||
'40-page source and writes a one-page brief; the bar is "would the head of research ' +
|
||||
'send this out unedited".\n\n' +
|
||||
'## Unit of work\n\n' +
|
||||
'One source document in, one brief out. They have 4,100 historical pairs and the ' +
|
||||
'reviewer decision on each.\n\n' +
|
||||
'## Verifier\n\n' +
|
||||
'A model judge calibrated against 300 of those human decisions. Agreement is 0.81 ' +
|
||||
'Cohen’s kappa, measured on a held-out slice rather than the calibration set.\n\n' +
|
||||
'## The live risk\n\n' +
|
||||
'Trace export beyond the pilot needs a DPA amendment their counsel has not seen yet.',
|
||||
status: 'final',
|
||||
authoredByUserId: ines,
|
||||
fields: { source: 'Technical discovery call, plus the follow-up with the data owner.' },
|
||||
});
|
||||
|
||||
await db.insert(engagementArtifacts).values({
|
||||
engagementId: engagement.id,
|
||||
templateId: pocTemplate?.id ?? null,
|
||||
kind: 'poc',
|
||||
stage: 'poc',
|
||||
title: `${prefix}POC plan — summarisation reward model`,
|
||||
body:
|
||||
'## Success criterion, agreed in writing\n\n' +
|
||||
'Judge-scored acceptance rate on a held-out set of 400 briefs rises from the measured ' +
|
||||
'baseline of 61% to at least 78%, at no more than 1.4× the current inference cost ' +
|
||||
'per brief.\n\n' +
|
||||
'## What we run\n\n' +
|
||||
'Two weeks on 32× H100. Week one builds the environment and reproduces the ' +
|
||||
'baseline; week two is the training run and the evaluation.\n\n' +
|
||||
'## What we hand back\n\n' +
|
||||
'The environment, the eval harness, and the number — whichever way it comes out. ' +
|
||||
'A POC that reports a failure honestly is what makes the next number believable.\n\n' +
|
||||
'## Open\n\n' +
|
||||
'Trace rights beyond the pilot. Blocked on the DPA amendment.',
|
||||
status: 'review',
|
||||
authoredByUserId: ines,
|
||||
fields: { baselineAcceptancePct: 61, targetAcceptancePct: 78, gpuCount: 32, weeks: 2 },
|
||||
});
|
||||
artifactCount += 2;
|
||||
|
||||
for (const pass of SCORE_PASSES) {
|
||||
const dimensions = dimensionsFor(pass.scores);
|
||||
const basisPoints = motionScoreBasisPoints(dimensions);
|
||||
await db.insert(qualificationScores).values({
|
||||
engagementId: engagement.id,
|
||||
frameworkTemplateId: scorecard?.id ?? null,
|
||||
// The column is `Record<string, unknown>[]`; Drizzle's jsonb `$type`
|
||||
// will not take an interface with readonly properties, and widening
|
||||
// the column to suit the seed would lose the shape everywhere else.
|
||||
dimensions: dimensions as unknown as Record<string, unknown>[],
|
||||
basisPoints,
|
||||
band: motionBand(basisPoints).label,
|
||||
note: `${prefix}${pass.note}`,
|
||||
scoredByUserId: ines,
|
||||
scoredAt: at(-pass.daysAgo),
|
||||
});
|
||||
scoreCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------- closed won, and promoted afterwards
|
||||
const northwindDealId = await findDeal(context, `${prefix}A100 inference pilot`);
|
||||
const marcus = await findSeller(context, 'Marcus Oyelaran');
|
||||
|
||||
if (!northwindDealId) {
|
||||
console.warn(
|
||||
` No "${prefix}A100 inference pilot" deal — skipping the closed-won engagement, and ` +
|
||||
'with it the promotion that demonstrates the loop.',
|
||||
);
|
||||
}
|
||||
|
||||
if (northwindDealId) {
|
||||
const [engagement] = await db
|
||||
.insert(engagements)
|
||||
.values({
|
||||
demandDealId: northwindDealId,
|
||||
playbookTemplateId: playbook?.id ?? null,
|
||||
ownerUserId: marcus,
|
||||
status: 'won',
|
||||
summary: `${prefix}Northwind inference pilot — won, and written up.`,
|
||||
openedAt: at(-190),
|
||||
closedAt: at(-96),
|
||||
})
|
||||
.returning({ id: engagements.id });
|
||||
|
||||
if (engagement) {
|
||||
engagementCount += 1;
|
||||
|
||||
const [artifact] = await db
|
||||
.insert(engagementArtifacts)
|
||||
.values({
|
||||
engagementId: engagement.id,
|
||||
templateId: caseStudy?.id ?? null,
|
||||
kind: 'case_study',
|
||||
stage: 'expansion',
|
||||
title: `${prefix}Northwind Robotics — A100 inference pilot`,
|
||||
body:
|
||||
'## The problem\n\n' +
|
||||
'Northwind ran perception inference on reserved A100s they had bought for training, ' +
|
||||
'and were paying training prices for a serving workload with a 40:1 peak-to-trough ' +
|
||||
'shape.\n\n' +
|
||||
'## What we did\n\n' +
|
||||
'Moved the trough onto committed capacity and the peak onto burst, with the split ' +
|
||||
'set by their own 90-day request trace rather than by a headline number.\n\n' +
|
||||
'## The number\n\n' +
|
||||
'Cost per million inferences fell 34%. Measured against their own billing, over a ' +
|
||||
'full quarter, not against a list price.\n\n' +
|
||||
'## What made it work, and what to reuse\n\n' +
|
||||
'They had the request trace. Every engagement since has asked for it in the first ' +
|
||||
'call, which is the change this write-up put into the frame itself.',
|
||||
status: 'final',
|
||||
authoredByUserId: marcus,
|
||||
fields: {
|
||||
metric: 'Cost per million inferences',
|
||||
improvementPct: 34,
|
||||
window: 'One quarter, customer billing',
|
||||
approvedForExternalUse: false,
|
||||
},
|
||||
})
|
||||
.returning({ id: engagementArtifacts.id, title: engagementArtifacts.title });
|
||||
|
||||
artifactCount += 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 the service does — version = previous + 1, `supersedesId` to the
|
||||
* shipped v1, `originArtifactId` to the artifact, `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 (artifact && caseStudy) {
|
||||
const [promoted] = await db
|
||||
.insert(motionTemplates)
|
||||
.values({
|
||||
kind: 'case_study',
|
||||
stage: 'expansion',
|
||||
slug: 'case-study-frame',
|
||||
version: caseStudy.version + 1,
|
||||
title: `${prefix}Case Study Frame — ask for the request trace first`,
|
||||
summary:
|
||||
'Version 2, promoted out of the Northwind pilot write-up. Adds the one question ' +
|
||||
'that made that engagement measurable: get the customer’s own usage trace ' +
|
||||
'before anyone quotes a saving.',
|
||||
body:
|
||||
'_Promoted from an engagement. The change from version 1 is the section below._\n\n' +
|
||||
'## Before you frame anything: get the trace\n\n' +
|
||||
'A case study is only as good as the baseline it is measured against, and the ' +
|
||||
'only baseline a customer cannot argue with afterwards is their own telemetry. ' +
|
||||
'Ask for it in the first call, not at write-up time.\n\n' +
|
||||
'## Everything else\n\n' +
|
||||
'As version 1: the problem, what we did, the number, what to reuse.',
|
||||
fields: {
|
||||
promotedFrom: artifact.title,
|
||||
addedSection: 'Before you frame anything: get the trace',
|
||||
},
|
||||
visibility: 'shared',
|
||||
ownerUserId: marcus,
|
||||
supersedesId: caseStudy.id,
|
||||
originArtifactId: artifact.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, artifact.id));
|
||||
promotedCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* `usage_count` is what the API reads to refuse a `PATCH` on a used
|
||||
* template, so the demo must move it or a library where three templates have
|
||||
* visibly been instantiated still reads as never used — and the rule the
|
||||
* whole feature turns on would be undemonstrable. Incremented in one sweep at
|
||||
* the end rather than per insert, so the count is derived from the artefacts
|
||||
* that actually landed and `clear()` can undo it by counting the same rows.
|
||||
*/
|
||||
const instantiated = await db
|
||||
.select({ templateId: engagementArtifacts.templateId })
|
||||
.from(engagementArtifacts)
|
||||
.where(like(engagementArtifacts.title, `${prefix}%`));
|
||||
const usageByTemplate = new Map<string, number>();
|
||||
for (const row of instantiated) {
|
||||
if (row.templateId) usageByTemplate.set(row.templateId, (usageByTemplate.get(row.templateId) ?? 0) + 1);
|
||||
}
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user