konpeki 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/authoring-visuals/SKILL.md +82 -0
- package/AGENTS.md +33 -0
- package/AUTHORING.md +233 -0
- package/LICENSE +201 -0
- package/README.md +70 -0
- package/SETUP.md +86 -0
- package/composition/README.md +166 -0
- package/composition/compile.ts +227 -0
- package/composition/document.ts +709 -0
- package/composition/schema.json +2992 -0
- package/composition/schema.ts +435 -0
- package/composition/theme-tokens.ts +16 -0
- package/composition/types.ts +286 -0
- package/composition/validate.ts +684 -0
- package/composition/vector.ts +143 -0
- package/composition/visualizations.ts +335 -0
- package/design/README.md +17 -0
- package/design/palettes/README.md +14 -0
- package/design/palettes/base.ts +14 -0
- package/design/palettes/candidates.ts +19 -0
- package/design/palettes/index.ts +78 -0
- package/design/review/color-theme.md +44 -0
- package/design/review/layout.md +16 -0
- package/design/review/text.md +18 -0
- package/design/review/typography.md +15 -0
- package/design/review/visuals.md +31 -0
- package/design/semantic-patterns.md +43 -0
- package/design/themes/README.md +22 -0
- package/design/themes/index.ts +13 -0
- package/design/visual-languages/technical-product.md +17 -0
- package/design/visual-review.md +88 -0
- package/docs/development.md +140 -0
- package/docs/workflow.md +61 -0
- package/index.html +17 -0
- package/lib/assets.d.ts +8 -0
- package/lib/charts.ts +18 -0
- package/lib/contrast.ts +16 -0
- package/lib/layouts.ts +50 -0
- package/lib/slide.tsx +42 -0
- package/lib/taste.ts +17 -0
- package/lib/text.tsx +89 -0
- package/lib/typeface.ts +44 -0
- package/package.json +85 -0
- package/runtime/konpeki.mjs +1685 -0
- package/scripts/migrate-react-page.ts +120 -0
- package/slides/README.md +153 -0
- package/slides/architecture/PROMPT.md +31 -0
- package/slides/architecture/index.tsx +102 -0
- package/slides/article-brief/PROMPT.md +35 -0
- package/slides/article-brief/index.tsx +71 -0
- package/slides/bar-chart/PROMPT.md +39 -0
- package/slides/bar-chart/index.tsx +97 -0
- package/slides/comparison/PROMPT.md +29 -0
- package/slides/comparison/index.tsx +95 -0
- package/slides/decision-memo/PROMPT.md +34 -0
- package/slides/decision-memo/index.tsx +85 -0
- package/slides/delivery-plan/PROMPT.md +45 -0
- package/slides/delivery-plan/index.tsx +105 -0
- package/slides/experiment/PROMPT.md +44 -0
- package/slides/experiment/index.tsx +127 -0
- package/slides/incident-workflow/PROMPT.md +57 -0
- package/slides/incident-workflow/index.tsx +78 -0
- package/slides/introducing-konpeki/PROMPT.md +19 -0
- package/slides/introducing-konpeki/README.md +54 -0
- package/slides/introducing-konpeki/SOURCE.md +20 -0
- package/slides/introducing-konpeki/author.ts +163 -0
- package/slides/introducing-konpeki/composition.json +3265 -0
- package/slides/line-chart/PROMPT.md +40 -0
- package/slides/line-chart/index.tsx +72 -0
- package/slides/migration/PROMPT.md +38 -0
- package/slides/migration/index.tsx +89 -0
- package/slides/og-images/PROMPT.md +21 -0
- package/slides/og-images/index.tsx +76 -0
- package/slides/product-introduction/PROMPT.md +24 -0
- package/slides/product-introduction/index.tsx +105 -0
- package/slides/research-brief/PROMPT.md +40 -0
- package/slides/research-brief/index.tsx +104 -0
- package/slides/results-explanation/PROMPT.md +32 -0
- package/slides/results-explanation/index.tsx +96 -0
- package/slides/retrospective/PROMPT.md +43 -0
- package/slides/retrospective/index.tsx +105 -0
- package/slides/sankey/PROMPT.md +11 -0
- package/slides/sankey/index.tsx +93 -0
- package/slides/teaching/PROMPT.md +45 -0
- package/slides/teaching/index.tsx +124 -0
- package/slides/vertical-bar-charts/PROMPT.md +13 -0
- package/slides/vertical-bar-charts/index.tsx +97 -0
- package/src/app/App.tsx +694 -0
- package/src/assets/konpeki-mark.png +0 -0
- package/src/components/Canvas.tsx +1168 -0
- package/src/components/DiagramTypeIcon.tsx +78 -0
- package/src/components/InspectorPanel.tsx +687 -0
- package/src/components/LeftPanel.tsx +107 -0
- package/src/components/PageSizePicker.tsx +30 -0
- package/src/components/Presentation.tsx +105 -0
- package/src/components/RightPanel.tsx +201 -0
- package/src/components/VectorOverflowWarning.tsx +46 -0
- package/src/components/WorkspaceChrome.tsx +199 -0
- package/src/components/ui.tsx +53 -0
- package/src/lib/examples/react-page-migration.json +1295 -0
- package/src/lib/examples.ts +42 -0
- package/src/lib/export-png.ts +101 -0
- package/src/lib/file-session.ts +74 -0
- package/src/lib/history.ts +53 -0
- package/src/lib/model.ts +188 -0
- package/src/lib/page-size.ts +24 -0
- package/src/lib/presentation.ts +17 -0
- package/src/lib/storage.ts +43 -0
- package/src/lib/theme.ts +25 -0
- package/src/lib/use-file-session.ts +162 -0
- package/src/main.tsx +26 -0
- package/src/styles/base.css +105 -0
- package/src/styles/canvas.css +268 -0
- package/src/styles/chrome.css +214 -0
- package/src/styles/component-previews.css +386 -0
- package/src/styles/feedback.css +71 -0
- package/src/styles/left-panel.css +125 -0
- package/src/styles/presentation.css +72 -0
- package/src/styles/right-panel.css +1172 -0
- package/src/styles/shell.css +247 -0
- package/vite.config.ts +6 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Bar } from '@nivo/bar';
|
|
3
|
+
import '../../lib/typeface.ts';
|
|
4
|
+
import { chartDefaults } from '../../lib/charts.ts';
|
|
5
|
+
import { palettes } from '../../lib/taste.ts';
|
|
6
|
+
|
|
7
|
+
const ink = '#182B36';
|
|
8
|
+
const muted = '#445663';
|
|
9
|
+
const before = '#536879';
|
|
10
|
+
const after = '#146B60';
|
|
11
|
+
export const workflows = [
|
|
12
|
+
{ workflow: 'Account setup', Before: 18, After: 12 },
|
|
13
|
+
{ workflow: 'Address correction', Before: 11, After: 10 },
|
|
14
|
+
{ workflow: 'Refund review', Before: 25, After: 19 },
|
|
15
|
+
{ workflow: 'Access removal', Before: 7, After: 8 },
|
|
16
|
+
{ workflow: 'Supplier onboarding', Before: 32, After: 24 },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function Copy({ x = 112, y, size = 32, weight = 400, fill = ink, children }: {
|
|
20
|
+
x?: number; y: number; size?: number; weight?: number; fill?: string; children: ReactNode;
|
|
21
|
+
}) {
|
|
22
|
+
return <text x={x} y={y} fontSize={size} fontWeight={weight} fill={fill}>{children}</text>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function Canvas({ title, description, page, children }: {
|
|
26
|
+
title: string; description: string; page: number; children: ReactNode;
|
|
27
|
+
}) {
|
|
28
|
+
return <svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080"
|
|
29
|
+
role="img" aria-label={`${title}. ${description}`} fontFamily="IBM Plex Sans, sans-serif" data-birch-page={page}>
|
|
30
|
+
<rect width="1920" height="1080" fill="#FFFFFF" />
|
|
31
|
+
<Copy y={136} size={62} weight={600}>{title}</Copy>
|
|
32
|
+
{children}
|
|
33
|
+
<Copy x={1770} y={1020} size={24} fill={muted}>{page} / 2</Copy>
|
|
34
|
+
</svg>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const Evidence = () => <Canvas page={1} title="Four medians fell; access removal rose"
|
|
38
|
+
description="Synthetic Birch data, median active processing minutes per completed case; lower is better. Account setup: before 18, after 12. Address correction: before 11, after 10. Refund review: before 25, after 19. Access removal: before 7, after 8. Supplier onboarding: before 32, after 24. Each workflow has 80 independent cases per period. Waiting time excluded. These observations do not establish causation.">
|
|
39
|
+
<Copy y={202} size={30} fill={muted}>Birch · Synthetic median active processing time per completed case · Lower is better</Copy>
|
|
40
|
+
<g transform="translate(112 262)">
|
|
41
|
+
<Bar {...chartDefaults(palettes.paper)} width={1696} height={640}
|
|
42
|
+
data={[...workflows].reverse()} keys={['Before', 'After']} indexBy="workflow"
|
|
43
|
+
layout="horizontal" groupMode="grouped" valueScale={{ type: 'linear', min: 0, max: 35 }}
|
|
44
|
+
margin={{ top: 0, right: 90, bottom: 60, left: 345 }} padding={0.26} innerPadding={7}
|
|
45
|
+
colors={({ id }) => id === 'Before' ? before : after}
|
|
46
|
+
label={d => `${d.id} ${d.value}`} labelTextColor="#FFFFFF" labelSkipWidth={0} labelSkipHeight={0}
|
|
47
|
+
axisLeft={{ tickSize: 0, tickPadding: 24 }}
|
|
48
|
+
axisBottom={{ tickSize: 0, tickPadding: 16, tickValues: [0, 5, 10, 15, 20, 25, 30, 35] }}
|
|
49
|
+
enableGridX enableGridY={false} gridXValues={[0, 5, 10, 15, 20, 25, 30, 35]}
|
|
50
|
+
theme={{ text: { fontFamily: 'IBM Plex Sans', fontSize: 28, fill: ink },
|
|
51
|
+
axis: { ticks: { text: { fontSize: 28, fill: ink } }, domain: { line: { stroke: '#8A969F' } } },
|
|
52
|
+
grid: { line: { stroke: '#DCE2E5', strokeWidth: 1 } },
|
|
53
|
+
labels: { text: { fontSize: 26, fontWeight: 500 } } }}
|
|
54
|
+
/>
|
|
55
|
+
</g>
|
|
56
|
+
<Copy x={1340} y={935} size={27} fill={muted}>Minutes · common zero baseline</Copy>
|
|
57
|
+
<Copy y={934} size={30} weight={600} fill={after}>Access removal: +1 minute</Copy>
|
|
58
|
+
<Copy y={984} size={27} fill={muted}>80 different cases per workflow per period · Two weeks each · Waiting time excluded</Copy>
|
|
59
|
+
</Canvas>;
|
|
60
|
+
|
|
61
|
+
const Decision = () => <Canvas page={2} title="Investigate before extending the revised queue"
|
|
62
|
+
description="Recommendation: investigate the access-removal increase and check case mix and quality before extending the revised queue. Supplier onboarding has the largest absolute median reduction, 8 minutes, but still the highest after median, 24 minutes. Independent groups were not randomized or matched; complexity and staffing could differ. No raw times, variability or quality measurements were supplied. Median differences cannot establish total savings or imply every case became faster.">
|
|
63
|
+
<Copy y={207} size={32} fill={muted}>Observed changes are a reason to investigate, not evidence that the queue caused them.</Copy>
|
|
64
|
+
<Copy y={322} size={38} weight={600}>Check before rollout</Copy>
|
|
65
|
+
<Copy x={1050} y={322} size={38} weight={600}>What the comparison cannot tell us</Copy>
|
|
66
|
+
|
|
67
|
+
<Copy y={400} size={32} weight={600} fill={after}>Investigate access removal</Copy>
|
|
68
|
+
<Copy y={451}>Its median rose from 7 to 8 minutes.</Copy>
|
|
69
|
+
<Copy y={497}>Review the workflow and the cases behind it.</Copy>
|
|
70
|
+
|
|
71
|
+
<Copy y={594} size={32} weight={600} fill={after}>Check case mix, staffing and quality</Copy>
|
|
72
|
+
<Copy y={645}>Before extending the queue, compare complexity</Copy>
|
|
73
|
+
<Copy y={691}>and staffing, and collect quality measurements.</Copy>
|
|
74
|
+
|
|
75
|
+
<Copy y={788} size={32} weight={600} fill={after}>Keep supplier onboarding in view</Copy>
|
|
76
|
+
<Copy y={839}>32 → 24 minutes: the largest drop, 8 minutes.</Copy>
|
|
77
|
+
<Copy y={885}>It still has the highest after-period median.</Copy>
|
|
78
|
+
|
|
79
|
+
<Copy x={1050} y={400} size={32} weight={600}>No causal attribution</Copy>
|
|
80
|
+
<Copy x={1050} y={451}>The queue changed between two two-week periods.</Copy>
|
|
81
|
+
<Copy x={1050} y={497}>Groups were independent, not randomized or matched;</Copy>
|
|
82
|
+
<Copy x={1050} y={543}>case complexity and staffing could differ.</Copy>
|
|
83
|
+
|
|
84
|
+
<Copy x={1050} y={640} size={32} weight={600}>No estimate of uncertainty or total savings</Copy>
|
|
85
|
+
<Copy x={1050} y={691}>No raw times, variability or quality data were supplied.</Copy>
|
|
86
|
+
<Copy x={1050} y={737}>Do not multiply median changes by case counts</Copy>
|
|
87
|
+
<Copy x={1050} y={783}>to claim total time or money saved.</Copy>
|
|
88
|
+
<Copy x={1050} y={861}>A lower median does not mean every case was faster.</Copy>
|
|
89
|
+
<Copy y={1000} size={27} fill={muted}>Birch is fictional. All measurements are synthetic, hand-authored data.</Copy>
|
|
90
|
+
</Canvas>;
|
|
91
|
+
|
|
92
|
+
export const meta = { title: 'Birch — Processing time' };
|
|
93
|
+
export const notes = [
|
|
94
|
+
'Source: exact supplied PROMPT.md. The chart compares independent medians, not paired cases. All bars share a 0–35 minute scale.',
|
|
95
|
+
'Recommendation follows the supplied brief. No causal, total-savings, statistical-significance or universal-improvement claim is justified.',
|
|
96
|
+
];
|
|
97
|
+
export default [Evidence, Decision];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Make a three-page presentation helping the operations lead at Moss choose a
|
|
2
|
+
support inbox for a six-person team. Compare the options against the team's
|
|
3
|
+
actual needs and recommend what to trial.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Moss and all three products are fictional. The team needs email intake, shared
|
|
8
|
+
assignment and a complete CSV export of ticket history. Its monthly subscription
|
|
9
|
+
budget is $150. Chat support would be useful later, but is not required now.
|
|
10
|
+
The team does not have capacity to operate its own server.
|
|
11
|
+
|
|
12
|
+
- Postbox: hosted, $18 per agent per month. Email intake, shared assignment and
|
|
13
|
+
complete CSV history export are included. No chat channel. No setup fee.
|
|
14
|
+
- Threadline: hosted, $24 per agent per month. Includes email, chat, shared
|
|
15
|
+
assignment and complete CSV history export. No setup fee.
|
|
16
|
+
- OwnDesk: self-hosted, no software subscription fee. Includes email, chat,
|
|
17
|
+
shared assignment and complete CSV history export. The team must supply
|
|
18
|
+
hosting, backups, upgrades and incident response; their costs are unknown.
|
|
19
|
+
|
|
20
|
+
These are hand-authored scenario specifications, not vendor research. Hosted
|
|
21
|
+
prices exclude tax and assume six paid agents. There are no measured usability,
|
|
22
|
+
reliability or migration results. A feature being listed does not establish
|
|
23
|
+
how well it works.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Recommend a first trial, explain what would make the other hosted option worth
|
|
28
|
+
its extra cost, and identify what to verify before purchase. Treat self-hosting
|
|
29
|
+
as an operational commitment rather than a zero-cost option.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import '../../lib/typeface.ts';
|
|
3
|
+
|
|
4
|
+
const ink = '#172B26';
|
|
5
|
+
const muted = '#4F605A';
|
|
6
|
+
const accent = '#236B50';
|
|
7
|
+
const rule = '#C4CEC9';
|
|
8
|
+
|
|
9
|
+
function Copy({ x = 112, y, lines, size = 36, weight = 400, color = ink }: {
|
|
10
|
+
x?: number; y: number; lines: string[]; size?: number; weight?: number; color?: string;
|
|
11
|
+
}) {
|
|
12
|
+
return <text x={x} y={y} fill={color} fontSize={size} fontWeight={weight}>
|
|
13
|
+
{lines.map((line, i) => <tspan key={i} x={x} dy={i ? size * 1.35 : 0}>{line}</tspan>)}
|
|
14
|
+
</text>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function Canvas({ title, description, number, children }: {
|
|
18
|
+
title: string; description: string; number: number; children: ReactNode;
|
|
19
|
+
}) {
|
|
20
|
+
return <svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080"
|
|
21
|
+
fontFamily="IBM Plex Sans" role="img" aria-label={`${title}. ${description}`} data-moss-page={number}>
|
|
22
|
+
<rect width="1920" height="1080" fill="#FFFFFF" />
|
|
23
|
+
<Copy y={154} lines={[title]} size={72} weight={600} />
|
|
24
|
+
{children}
|
|
25
|
+
<Copy x={1752} y={1022} lines={[`${number} / 3`]} size={28} color={muted} />
|
|
26
|
+
</svg>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const Shortlist = () => <Canvas number={1} title="Moss should trial Postbox first"
|
|
30
|
+
description="Fictional scenario. Six agents need email, shared assignment and complete CSV history export. Postbox includes all three for $108 per month before tax, leaving $42 of the $150 subscription budget. Threadline costs $144 and adds chat. OwnDesk requires server operations Moss cannot supply.">
|
|
31
|
+
<Copy y={234} lines={['Six people. Email intake, shared assignment and complete CSV history export.']} color={muted} />
|
|
32
|
+
<Copy y={332} lines={['All three list the required features. Cost and operating capacity decide the shortlist.']} size={38} weight={500} />
|
|
33
|
+
<Copy x={112} y={423} lines={['Option']} size={30} color={muted} />
|
|
34
|
+
<Copy x={510} y={423} lines={['Monthly cost · six agents']} size={30} color={muted} />
|
|
35
|
+
<Copy x={1038} y={423} lines={['Fit for Moss now']} size={30} color={muted} />
|
|
36
|
+
<line x1={112} x2={1808} y1={452} y2={452} stroke={rule} strokeWidth={2} />
|
|
37
|
+
<Copy y={512} lines={['Postbox']} size={44} weight={600} color={accent} />
|
|
38
|
+
<Copy x={510} y={512} lines={['$108 subscription', '$18 × 6 agents']} size={36} />
|
|
39
|
+
<Copy x={1038} y={512} lines={['Hosted · trial first', 'Meets today’s needs; no chat channel.']} size={36} />
|
|
40
|
+
<line x1={112} x2={1808} y1={594} y2={594} stroke={rule} strokeWidth={2} />
|
|
41
|
+
<Copy y={653} lines={['Threadline']} size={44} weight={600} />
|
|
42
|
+
<Copy x={510} y={653} lines={['$144 subscription', '$24 × 6 agents']} size={36} />
|
|
43
|
+
<Copy x={1038} y={653} lines={['Hosted · conditional alternative', 'Adds chat, useful later rather than now.']} size={36} />
|
|
44
|
+
<line x1={112} x2={1808} y1={735} y2={735} stroke={rule} strokeWidth={2} />
|
|
45
|
+
<Copy y={794} lines={['OwnDesk']} size={44} weight={600} />
|
|
46
|
+
<Copy x={510} y={794} lines={['$0 software subscription', 'Operating costs unknown']} size={36} />
|
|
47
|
+
<Copy x={1038} y={794} lines={['Self-hosted · exclude for now', 'Moss cannot operate its own server.']} size={36} />
|
|
48
|
+
<line x1={112} x2={1808} y1={876} y2={876} stroke={rule} strokeWidth={2} />
|
|
49
|
+
<Copy y={936} lines={['Fictional, hand-authored specifications—not vendor research. Hosted prices exclude tax;', 'both hosted options have no setup fee. Listed features do not establish quality.']} size={30} color={muted} />
|
|
50
|
+
</Canvas>;
|
|
51
|
+
|
|
52
|
+
const Tradeoff = () => <Canvas number={2} title="Chat must earn its $36 monthly premium"
|
|
53
|
+
description="Postbox is $108 per month with $42 subscription headroom; Threadline is $144 with $6 headroom against a $150 budget, before tax. Trial Threadline if a concrete near-term chat workflow is valuable enough to justify the premium. OwnDesk includes chat but requires hosting, backups, upgrades and incident response with unknown costs.">
|
|
54
|
+
<Copy y={239} lines={['Both hosted options fit the $150 subscription budget before tax.']} size={38} color={muted} />
|
|
55
|
+
<Copy y={358} lines={['Postbox']} size={42} weight={600} color={accent} />
|
|
56
|
+
<Copy y={442} lines={['$108 / month']} size={64} weight={600} />
|
|
57
|
+
<Copy y={505} lines={['$42 budget headroom']} size={34} color={muted} />
|
|
58
|
+
<Copy x={982} y={358} lines={['Threadline']} size={42} weight={600} />
|
|
59
|
+
<Copy x={982} y={442} lines={['$144 / month']} size={64} weight={600} />
|
|
60
|
+
<Copy x={982} y={505} lines={['$6 budget headroom']} size={34} color={muted} />
|
|
61
|
+
<Copy y={624} lines={['Start with the current workflow']} size={40} weight={600} />
|
|
62
|
+
<Copy y={682} lines={['Postbox covers the three required capabilities.', 'Do not pay for chat on a feature list alone.']} size={36} />
|
|
63
|
+
<Copy x={982} y={624} lines={['Trial Threadline when chat has a job']} size={40} weight={600} />
|
|
64
|
+
<Copy x={982} y={682} lines={['Name a near-term chat workflow and test it.', 'Choose Threadline only if the added value', 'justifies $36/month and the final bill fits.']} size={36} />
|
|
65
|
+
<line x1={112} x2={1808} y1={847} y2={847} stroke={rule} strokeWidth={2} />
|
|
66
|
+
<Copy y={911} lines={['OwnDesk also lists chat, but Moss would own hosting, backups, upgrades and incident', 'response. With no operating capacity and unknown costs, it is not a zero-cost alternative.']} size={34} />
|
|
67
|
+
<Copy y={1014} lines={['Fictional scenario · subscription calculations for six paid agents, before tax.']} size={28} color={muted} />
|
|
68
|
+
</Canvas>;
|
|
69
|
+
|
|
70
|
+
const Trial = () => <Canvas number={3} title="Use the trial to test the purchase decision"
|
|
71
|
+
description="Start Postbox with a representative sample. Verify email intake and shared assignment with all six agents; reconcile a CSV export to ticket history; confirm six-agent pricing and tax. No usability, reliability or migration results are measured. Purchase only after required workflow and export checks pass; compare Threadline if chat becomes a justified need.">
|
|
72
|
+
<Copy y={239} lines={['Begin with Postbox and representative tickets, then make a go/no-go decision.']} size={38} color={muted} />
|
|
73
|
+
<Copy y={369} lines={['Verify in the trial']} size={32} color={muted} />
|
|
74
|
+
<Copy x={788} y={369} lines={['Evidence to collect before purchase']} size={32} color={muted} />
|
|
75
|
+
<line x1={112} x2={1808} y1={397} y2={397} stroke={rule} strokeWidth={2} />
|
|
76
|
+
<Copy y={463} lines={['Email + assignment']} size={40} weight={600} />
|
|
77
|
+
<Copy x={788} y={463} lines={['Send incoming email; assign and reassign tickets.', 'Have all six agents confirm ownership is clear.']} size={36} />
|
|
78
|
+
<line x1={112} x2={1808} y1={549} y2={549} stroke={rule} strokeWidth={2} />
|
|
79
|
+
<Copy y={613} lines={['Complete CSV history']} size={40} weight={600} />
|
|
80
|
+
<Copy x={788} y={613} lines={['Export the sample and reconcile it to ticket history.', 'Check records, fields and chronological completeness.']} size={36} />
|
|
81
|
+
<line x1={112} x2={1808} y1={699} y2={699} stroke={rule} strokeWidth={2} />
|
|
82
|
+
<Copy y={763} lines={['Final cost + transition']} size={40} weight={600} />
|
|
83
|
+
<Copy x={788} y={763} lines={['Confirm the six-agent quote and tax against budget.', 'Test a small migration before committing the inbox.']} size={36} />
|
|
84
|
+
<line x1={112} x2={1808} y1={849} y2={849} stroke={rule} strokeWidth={2} />
|
|
85
|
+
<Copy y={915} lines={['Buy only after required workflow and export checks pass.']} size={40} weight={600} color={accent} />
|
|
86
|
+
<Copy y={974} lines={['No measured usability, reliability or migration results exist in this fictional scenario.', 'Review reliability evidence separately; a short trial cannot establish long-term reliability.']} size={30} color={muted} />
|
|
87
|
+
</Canvas>;
|
|
88
|
+
|
|
89
|
+
export const meta = { title: 'Moss — choosing a support inbox', createdAt: '2026-09-12T14:20:00Z' };
|
|
90
|
+
export const notes = [
|
|
91
|
+
'Recommendation based only on supplied fictional specifications, not observed product performance.',
|
|
92
|
+
'Derived arithmetic: 18 × 6 = 108; 24 × 6 = 144; 144 − 108 = 36; 150 − 108 = 42; 150 − 144 = 6.',
|
|
93
|
+
'Trial checks are proposed decision criteria, not measured results or claims about product behavior.',
|
|
94
|
+
];
|
|
95
|
+
export default [Shortlist, Tradeoff, Trial];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Make a three-page presentation for the operations lead at Cedar Support to help
|
|
2
|
+
decide whether to extend a trial of suggested replies. Explain the trade-off
|
|
3
|
+
between handling time and quality, what the evidence supports, and what the
|
|
4
|
+
team should learn next.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Cedar Support is a fictional customer-support team. These figures are synthetic,
|
|
9
|
+
hand-authored examples rather than results of an actual trial.
|
|
10
|
+
|
|
11
|
+
Two groups each handled 120 tickets during one week. Assignment was not
|
|
12
|
+
randomized, and ticket difficulty and agent experience were not controlled.
|
|
13
|
+
|
|
14
|
+
- Standard workflow: median handling time of 12 minutes; 108 tickets passed
|
|
15
|
+
quality review; 9 reopened within seven days of closure.
|
|
16
|
+
- Suggested replies: median handling time of 9 minutes; 102 tickets passed
|
|
17
|
+
quality review; 15 reopened within seven days of closure.
|
|
18
|
+
|
|
19
|
+
Quality review and reopening are separate measures: a ticket can pass review
|
|
20
|
+
and later reopen. Each rate uses all 120 tickets in its group. The quality rates
|
|
21
|
+
are 90% and 85%; the reopen rates are 7.5% and 12.5%.
|
|
22
|
+
|
|
23
|
+
We have no raw timing observations, variance estimates, confidence intervals,
|
|
24
|
+
labor costs or customer-satisfaction results. The groups cannot establish
|
|
25
|
+
causality, and their median times cannot tell us total hours saved.
|
|
26
|
+
|
|
27
|
+
The proposed next step is a longer randomized trial with comparable ticket
|
|
28
|
+
categories and human review retained. Quality and reopen-rate acceptance
|
|
29
|
+
criteria would be agreed before starting; no numerical thresholds have been set.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
Give it a light editorial feel, with a white background, a deep forest-green
|
|
34
|
+
accent, serif headlines and clean sans-serif body text.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import '@fontsource/newsreader/latin-400.css';
|
|
3
|
+
import '@fontsource/ibm-plex-sans/latin-400.css';
|
|
4
|
+
import '@fontsource/ibm-plex-sans/latin-600.css';
|
|
5
|
+
|
|
6
|
+
const green = '#164D3A';
|
|
7
|
+
const ink = '#202B26';
|
|
8
|
+
const muted = '#526159';
|
|
9
|
+
function Copy({ x = 112, y, lines, size = 36, color = ink, bold = false }: {
|
|
10
|
+
x?: number; y: number; lines: string[]; size?: number; color?: string; bold?: boolean;
|
|
11
|
+
}) {
|
|
12
|
+
return <text x={x} y={y} fill={color} fontSize={size} fontWeight={bold ? 600 : 400}>
|
|
13
|
+
{lines.map((line, i) => <tspan key={i} x={x} dy={i ? size * 1.35 : 0}>{line}</tspan>)}
|
|
14
|
+
</text>;
|
|
15
|
+
}
|
|
16
|
+
function Frame({ number, title, summary, children }: {
|
|
17
|
+
number: number; title: string[]; summary: string; children: ReactNode;
|
|
18
|
+
}) {
|
|
19
|
+
return <svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080"
|
|
20
|
+
role="img" aria-label={`${title.join(' ')}. ${summary}`} fontFamily="IBM Plex Sans" data-cedar-page={number}>
|
|
21
|
+
<rect width="1920" height="1080" fill="#FFFFFF" />
|
|
22
|
+
<text x="112" y="160" fontFamily="Newsreader" fontSize="82" fill={green}>
|
|
23
|
+
{title.map((line, i) => <tspan key={i} x="112" dy={i ? 90 : 0}>{line}</tspan>)}
|
|
24
|
+
</text>
|
|
25
|
+
{children}
|
|
26
|
+
<text x="1808" y="1024" textAnchor="end" fontSize="28" fill={muted}>{number} / 3</text>
|
|
27
|
+
</svg>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const Tradeoff = () => <Frame number={1} title={['Suggested replies were faster;', 'quality signals were weaker.']}
|
|
31
|
+
summary="Cedar Support fictional trial, synthetic data. One week, 120 tickets per group. Standard versus suggested replies: median handling time 12 versus 9 minutes; quality passed 108 of 120 (90%) versus 102 of 120 (85%); reopened within seven days of closure 9 of 120 (7.5%) versus 15 of 120 (12.5%). Quality and reopening are separate measures; a passing ticket can reopen. Each rate uses all 120 tickets in its group.">
|
|
32
|
+
<Copy y={335} lines={['Cedar Support · One week · 120 tickets per group']} color={muted} />
|
|
33
|
+
<Copy x={900} y={443} lines={['Standard workflow']} size={32} bold />
|
|
34
|
+
<Copy x={1335} y={443} lines={['Suggested replies']} size={32} color={green} bold />
|
|
35
|
+
<line x1="112" x2="1808" y1="478" y2="478" stroke="#A4B2AA" />
|
|
36
|
+
<Copy y={553} lines={['Median handling time']} />
|
|
37
|
+
<Copy x={900} y={553} lines={['12 min']} size={46} />
|
|
38
|
+
<Copy x={1335} y={553} lines={['9 min']} size={46} color={green} />
|
|
39
|
+
<line x1="112" x2="1808" y1="601" y2="601" stroke="#D7DED9" />
|
|
40
|
+
<Copy y={676} lines={['Passed quality review']} />
|
|
41
|
+
<Copy x={900} y={676} lines={['108 / 120 · 90%']} size={40} />
|
|
42
|
+
<Copy x={1335} y={676} lines={['102 / 120 · 85%']} size={40} color={green} />
|
|
43
|
+
<line x1="112" x2="1808" y1="724" y2="724" stroke="#D7DED9" />
|
|
44
|
+
<Copy y={791} lines={['Reopened within 7 days', 'of closure']} size={34} />
|
|
45
|
+
<Copy x={900} y={791} lines={['9 / 120 · 7.5%']} size={40} />
|
|
46
|
+
<Copy x={1335} y={791} lines={['15 / 120 · 12.5%']} size={40} color={green} />
|
|
47
|
+
<line x1="112" x2="1808" y1="861" y2="861" stroke="#A4B2AA" />
|
|
48
|
+
<Copy y={922} lines={['Quality and reopening are separate measures: a passing ticket can reopen.',
|
|
49
|
+
'Fictional team; synthetic, hand-authored figures—not an actual trial.']} size={30} color={muted} />
|
|
50
|
+
</Frame>;
|
|
51
|
+
|
|
52
|
+
const Evidence = () => <Frame number={2} title={['The pattern warrants a better test,', 'not a causal claim.']}
|
|
53
|
+
summary="The observed median is 3 minutes lower, while quality pass rate is 5 percentage points lower and reopen rate 5 points higher. These are descriptive differences in synthetic data, not causal effects. Assignment was not randomized; ticket difficulty and agent experience were not controlled. There are no raw timing observations, variance estimates or confidence intervals. Medians cannot establish total hours saved. Labor costs and customer satisfaction were not measured.">
|
|
54
|
+
<Copy y={360} lines={['What the comparison shows']} size={38} color={green} bold />
|
|
55
|
+
<Copy y={433} lines={['3 minutes lower median handling time', '5 percentage points lower quality pass rate', '5 percentage points higher reopen rate']} size={37} />
|
|
56
|
+
<Copy x={1035} y={360} lines={['What could explain it']} size={38} color={green} bold />
|
|
57
|
+
<Copy x={1035} y={433} lines={['Assignment was not randomized.', 'Ticket difficulty and agent experience', 'were not controlled.']} size={37} />
|
|
58
|
+
<Copy y={677} lines={['Precision is unknown']} size={38} color={green} bold />
|
|
59
|
+
<Copy y={750} lines={['No raw timing observations, variance', 'estimates or confidence intervals.']} size={37} />
|
|
60
|
+
<Copy x={1035} y={677} lines={['Business impact is unknown']} size={38} color={green} bold />
|
|
61
|
+
<Copy x={1035} y={750} lines={['Medians cannot yield total hours saved.', 'No labor-cost or customer-satisfaction', 'results are available.']} size={37} />
|
|
62
|
+
<Copy y={948} lines={['These are descriptive differences in synthetic data, not estimates of treatment effects.']} size={30} color={muted} />
|
|
63
|
+
</Frame>;
|
|
64
|
+
|
|
65
|
+
const Decision = () => <Frame number={3} title={['Extend with a longer randomized trial', 'and retain human review.']}
|
|
66
|
+
summary="Recommendation to Cedar Support’s operations lead: authorize a longer randomized trial with comparable ticket categories and human review retained, rather than broad rollout. Agree quality and reopen-rate acceptance criteria before starting; no numerical thresholds have been set. Collect raw handling-time observations and both quality measures, retaining seven-day reopening follow-up. Decide whether speed improves while both quality guardrails are met; revise or stop expansion if either fails. These collection and decision details are recommendations, not observed results.">
|
|
67
|
+
<Copy y={347} lines={['Recommendation to Cedar Support’s operations lead']} size={34} color={muted} />
|
|
68
|
+
<Copy y={475} lines={['Before launch']} size={40} color={green} bold />
|
|
69
|
+
<Copy x={650} y={475} lines={['Agree quality and reopen-rate acceptance criteria.', 'No numerical thresholds have been set.']} size={38} />
|
|
70
|
+
<line x1="112" x2="1808" y1="578" y2="578" stroke="#D7DED9" />
|
|
71
|
+
<Copy y={651} lines={['During the trial']} size={40} color={green} bold />
|
|
72
|
+
<Copy x={650} y={651} lines={['Randomize across comparable ticket categories; retain human review.', 'Collect raw handling times and both quality measures.', 'Allow seven-day reopening follow-up after closure.']} size={35} />
|
|
73
|
+
<line x1="112" x2="1808" y1="798" y2="798" stroke="#D7DED9" />
|
|
74
|
+
<Copy y={871} lines={['At the decision']} size={40} color={green} bold />
|
|
75
|
+
<Copy x={650} y={871} lines={['Does speed improve while both quality guardrails are met?', 'Use the results to judge rollout; revise or stop expansion if either fails.']} size={35} />
|
|
76
|
+
<line x1="112" x2="1808" y1="968" y2="968" stroke="#A4B2AA" />
|
|
77
|
+
</Frame>;
|
|
78
|
+
|
|
79
|
+
export const meta = { title: 'Cedar Support — suggested replies decision', createdAt: '2026-09-12T14:00:00Z' };
|
|
80
|
+
export const notes = [
|
|
81
|
+
'All figures are synthetic and supplied in PROMPT.md. Rates use 120 tickets in each group; quality review and reopening are not mutually exclusive.',
|
|
82
|
+
'Differences are arithmetic descriptions only. Non-random assignment and uncontrolled difficulty/experience prevent causal attribution.',
|
|
83
|
+
'The longer randomized trial, comparable categories, human review, and pre-agreed criteria are supplied proposals. Raw-time collection, complete follow-up and the decision sequence are author recommendations. Trial duration, sample size and thresholds require planning; none is invented here.',
|
|
84
|
+
];
|
|
85
|
+
export default [Tradeoff, Evidence, Decision];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Make a three-page delivery-plan briefing for the sponsor and delivery team
|
|
2
|
+
at Harbor. Show the original schedule, the current forecast and the decision
|
|
3
|
+
needed now. Make dependencies and release gates clear.
|
|
4
|
+
|
|
5
|
+
Include a baseline-versus-forecast timeline on a shared date axis, distinguishing
|
|
6
|
+
completed work from forecast work. Show dependency arrows and release gates.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Harbor is a fictional membership service moving its member directory to a new
|
|
11
|
+
system. This is a hand-authored status packet as of the end of 14 October 2026.
|
|
12
|
+
The schedule uses Monday–Friday working days, with no holidays in this scenario.
|
|
13
|
+
|
|
14
|
+
Original baseline, agreed 2 October:
|
|
15
|
+
- Import: 5–9 October, owned by data lead Ana.
|
|
16
|
+
- Validation: 12–14 October, owned by QA lead Ben.
|
|
17
|
+
- Staff training: 15–16 October, owned by operations lead Cora.
|
|
18
|
+
- Launch: 19 October, subject to sponsor approval.
|
|
19
|
+
|
|
20
|
+
Actual progress: import started on 5 October and finished on 14 October.
|
|
21
|
+
The input file contained duplicate member identifiers; resolving them delayed
|
|
22
|
+
completion. Import completion does not mean validation has passed. Validation
|
|
23
|
+
and training have not started. Training materials are ready.
|
|
24
|
+
|
|
25
|
+
Dependencies: validation starts after import completion and requires three
|
|
26
|
+
working days. Training starts after validation passes and requires two working
|
|
27
|
+
days. Launch is no earlier than the next working day after training completes.
|
|
28
|
+
No work overlaps these stages in the current plan.
|
|
29
|
+
|
|
30
|
+
Current forecast, assuming no new defects: validation on 15, 16 and 19 October;
|
|
31
|
+
training on 20–21 October; launch on 22 October. These are forecast dates, not
|
|
32
|
+
completed work or a launch commitment.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
Validation must reconcile member counts and required fields against the approved
|
|
37
|
+
input and resolve every duplicate identifier. An unresolved discrepancy blocks
|
|
38
|
+
training and launch. The operations lead must confirm staff readiness after
|
|
39
|
+
training; the sponsor then decides whether to release. No validation result is
|
|
40
|
+
available yet.
|
|
41
|
+
|
|
42
|
+
Ask the sponsor to accept the revised forecast and reserve staff for 20–21
|
|
43
|
+
October. If the original date is immovable, the team needs a separate scope
|
|
44
|
+
decision and revised plan; no safe shortcut has been established. Do not present
|
|
45
|
+
skipping validation as a way to recover the schedule.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { fontsReady } from '../../lib/typeface.ts';
|
|
3
|
+
|
|
4
|
+
await fontsReady;
|
|
5
|
+
const ink = '#172B36', muted = '#50616B', accent = '#006B74', line = '#CAD3D7';
|
|
6
|
+
function Label({ x, y, children, size = 32, color = ink, weight = 400 }: { x: number; y: number; children: ReactNode; size?: number; color?: string; weight?: number }) {
|
|
7
|
+
return <text x={x} y={y} fontSize={size} fill={color} fontWeight={weight}>{children}</text>;
|
|
8
|
+
}
|
|
9
|
+
function Frame({ title, subtitle, page, description, children }: { title: string; subtitle: string; page: number; description: string; children: ReactNode }) {
|
|
10
|
+
return <svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080" fontFamily="IBM Plex Sans" role="img" aria-label={`${title}. ${description}`} data-page={page}>
|
|
11
|
+
<rect width="1920" height="1080" fill="#FFFFFF" />
|
|
12
|
+
<Label x={100} y={140} size={64} weight={600}>{title}</Label>
|
|
13
|
+
<Label x={100} y={207} size={32} color={muted}>{subtitle}</Label>
|
|
14
|
+
{children}
|
|
15
|
+
<Label x={1705} y={1020} size={26} color={muted}>{page} / 3</Label>
|
|
16
|
+
</svg>;
|
|
17
|
+
}
|
|
18
|
+
const x = (day: number) => 440 + (day - 5) * 70;
|
|
19
|
+
function Gate({ day, y }: { day: number; y: number }) {
|
|
20
|
+
return <path d={`M${x(day)} ${y - 12} l12 12 -12 12 -12 -12 Z`} fill="white" stroke={accent} strokeWidth={3} />;
|
|
21
|
+
}
|
|
22
|
+
function Arrow({ from, to, y }: { from: number; to: number; y: number }) {
|
|
23
|
+
return <path d={`M${x(from)} ${y} V${y + 29} H${x(to)} V${y + 82} m-7 -10 7 10 7 -10`} stroke={accent} strokeWidth={3} fill="none" />;
|
|
24
|
+
}
|
|
25
|
+
const Schedule = () => <Frame page={1} title="Launch moves from 19 to 22 October" subtitle="Import is complete. The remaining dates are a forecast, assuming no new defects." description="Shared calendar axis, October 5–22. Baseline agreed October 2: import October 5–9, validation 12–14, training 15–16, launch 19 subject to sponsor approval. Actual import October 5–14. Forecast validation October 15, 16 and 19; training 20–21; launch 22. Arrows connect non-overlapping forecast stages; diamonds mark validation pass, readiness confirmation and sponsor release gates.">
|
|
26
|
+
<rect x={100} y={263} width={38} height={16} fill="none" stroke={muted} strokeWidth={2} />
|
|
27
|
+
<Label x={153} y={282} size={27}>Baseline · agreed 2 Oct</Label>
|
|
28
|
+
<rect x={500} y={263} width={38} height={16} fill={accent} />
|
|
29
|
+
<Label x={553} y={282} size={27}>Completed</Label>
|
|
30
|
+
<rect x={755} y={263} width={38} height={16} fill="none" stroke={accent} strokeDasharray="6 4" strokeWidth={3} />
|
|
31
|
+
<Label x={808} y={282} size={27}>Forecast</Label>
|
|
32
|
+
<path d="M1050 259 l12 12 -12 12 -12 -12 Z" stroke={accent} strokeWidth={3} fill="white" />
|
|
33
|
+
<Label x={1076} y={282} size={27}>Release gate</Label>
|
|
34
|
+
<Label x={1440} y={282} size={27} color={muted}>Shaded = weekend</Label>
|
|
35
|
+
{[10, 11, 17, 18].map(day => <rect key={day} x={x(day)} y={326} width={70} height={499} fill="#F0F3F4" />)}
|
|
36
|
+
{Array.from({ length: 18 }, (_, i) => i + 5).map(day => <g key={day}>
|
|
37
|
+
<Label x={x(day) + 18} y={352} size={26} color={muted}>{day}</Label>
|
|
38
|
+
<line x1={x(day)} x2={x(day)} y1={367} y2={825} stroke="#E6EBED" />
|
|
39
|
+
</g>)}
|
|
40
|
+
<Label x={100} y={320} size={25} color={muted}>October 2026</Label>
|
|
41
|
+
<Label x={100} y={355} size={25} color={muted}>As of end of 14 Oct</Label>
|
|
42
|
+
{[['Import', 'Ana · data lead'], ['Validation', 'Ben · QA lead'], ['Training', 'Cora · operations'], ['Launch', 'Sponsor approval']].map(([stage, owner], i) => <g key={stage}>
|
|
43
|
+
<Label x={100} y={409 + i * 108} size={34} weight={600}>{stage}</Label>
|
|
44
|
+
<Label x={100} y={447 + i * 108} size={26} color={muted}>{owner}</Label>
|
|
45
|
+
<line x1={100} x2={1770} y1={474 + i * 108} y2={474 + i * 108} stroke={line} />
|
|
46
|
+
</g>)}
|
|
47
|
+
{[[5, 10, 389], [12, 15, 497], [15, 17, 605]].map(([a, b, y]) => <rect key={y} x={x(a)} y={y} width={x(b) - x(a)} height={17} fill="white" stroke={muted} strokeWidth={2} />)}
|
|
48
|
+
<path d={`M${x(19) + 35} 711 l10 10 -10 10 -10 -10 Z`} fill="white" stroke={muted} strokeWidth={2} />
|
|
49
|
+
<rect x={x(5)} y={424} width={x(15) - x(5)} height={26} fill={accent} />
|
|
50
|
+
<Label x={x(5) + 18} y={445} size={23} color="white" weight={500}>5–14 Oct · complete</Label>
|
|
51
|
+
{[[15, 17, 532], [19, 20, 532], [20, 22, 640]].map(([a, b, y]) => <rect key={`${a}-${y}`} x={x(a)} y={y} width={x(b) - x(a)} height={26} fill="white" stroke={accent} strokeWidth={3} strokeDasharray="7 4" />)}
|
|
52
|
+
<Arrow from={15} to={15} y={450} />
|
|
53
|
+
<Arrow from={20} to={20} y={558} />
|
|
54
|
+
<Arrow from={22} to={22.5} y={666} />
|
|
55
|
+
<Gate day={20} y={545} /><Gate day={22} y={653} /><Gate day={22.5} y={761} />
|
|
56
|
+
<Label x={100} y={885} size={32} weight={500}>Duplicate member identifiers delayed import completion.</Label>
|
|
57
|
+
<Label x={100} y={931} size={29} color={muted}>Mon–Fri working days; no holidays. No stage overlap. Import complete does not mean validation passed.</Label>
|
|
58
|
+
<Label x={100} y={972} size={25} color={muted}>Diamonds at bar ends mark completion gates; launch diamonds mark release dates.</Label>
|
|
59
|
+
</Frame>;
|
|
60
|
+
|
|
61
|
+
const Gates = () => <Frame page={2} title="Every release gate still needs evidence" subtitle="Validation and training have not started. No validation result is available yet." description="Validation must reconcile member counts and required fields against approved input and resolve every duplicate identifier. An unresolved discrepancy blocks training and launch. Training follows validation pass and lasts two working days. Cora confirms staff readiness after training; sponsor then decides whether to release. Launch no earlier than next working day after training completes.">
|
|
62
|
+
<Label x={100} y={331} size={28} color={muted}>FORECAST STAGE</Label>
|
|
63
|
+
<Label x={670} y={331} size={28} color={muted}>EVIDENCE REQUIRED TO PROCEED</Label>
|
|
64
|
+
<line x1={100} x2={1800} y1={357} y2={357} stroke={line} />
|
|
65
|
+
<Label x={100} y={413} size={38} weight={600}>Validation · Ben</Label>
|
|
66
|
+
<Label x={100} y={461} size={30} color={accent}>15, 16 & 19 Oct · 3 working days</Label>
|
|
67
|
+
<Label x={670} y={413} size={34}>Reconcile member counts and required fields</Label>
|
|
68
|
+
<Label x={670} y={459} size={34}>against approved input; resolve every duplicate ID.</Label>
|
|
69
|
+
<Label x={670} y={511} size={29} color={accent} weight={500}>Any unresolved discrepancy blocks training and launch.</Label>
|
|
70
|
+
<line x1={100} x2={1800} y1={553} y2={553} stroke={line} />
|
|
71
|
+
<Label x={100} y={611} size={38} weight={600}>Staff training · Cora</Label>
|
|
72
|
+
<Label x={100} y={659} size={30} color={accent}>20–21 Oct · 2 working days</Label>
|
|
73
|
+
<Label x={670} y={611} size={34}>Start only after validation passes.</Label>
|
|
74
|
+
<Label x={670} y={657} size={34}>Operations lead confirms staff readiness afterward.</Label>
|
|
75
|
+
<Label x={670} y={709} size={29} color={muted}>Training materials are ready; staff readiness is not yet confirmed.</Label>
|
|
76
|
+
<line x1={100} x2={1800} y1={751} y2={751} stroke={line} />
|
|
77
|
+
<Label x={100} y={809} size={38} weight={600}>Release · Sponsor</Label>
|
|
78
|
+
<Label x={100} y={857} size={30} color={accent}>22 Oct · conditional forecast</Label>
|
|
79
|
+
<Label x={670} y={809} size={34}>Sponsor decides after staff readiness is confirmed.</Label>
|
|
80
|
+
<Label x={670} y={855} size={34}>No earlier than the next working day after training.</Label>
|
|
81
|
+
<line x1={100} x2={1800} y1={901} y2={901} stroke={line} />
|
|
82
|
+
</Frame>;
|
|
83
|
+
|
|
84
|
+
const Decision = () => <Frame page={3} title="Accept the forecast and reserve staff now" subtitle="Sponsor decision requested · Keep the release gates intact." description="Ask sponsor to accept the revised conditional launch forecast for October 22 and reserve staff for training October 20–21. Forecast assumes no new defects and is not a launch commitment. If October 19 is immovable, a separate scope decision and revised plan are needed. No safe shortcut has been established; do not skip validation.">
|
|
85
|
+
<Label x={100} y={367} size={48} weight={600}>Accept 22 October</Label>
|
|
86
|
+
<Label x={100} y={424} size={34}>as the revised launch forecast,</Label>
|
|
87
|
+
<Label x={100} y={470} size={34}>assuming no new defects.</Label>
|
|
88
|
+
<Label x={100} y={540} size={30} color={accent} weight={500}>A forecast, not a launch commitment.</Label>
|
|
89
|
+
<Label x={1010} y={367} size={48} weight={600}>Reserve 20–21 October</Label>
|
|
90
|
+
<Label x={1010} y={424} size={34}>for staff training with Cora.</Label>
|
|
91
|
+
<Label x={1010} y={470} size={34}>Materials are ready.</Label>
|
|
92
|
+
<Label x={1010} y={540} size={30} color={accent} weight={500}>Training starts only after validation passes.</Label>
|
|
93
|
+
<line x1={100} x2={1800} y1={641} y2={641} stroke={line} />
|
|
94
|
+
<Label x={100} y={723} size={42} weight={600}>If 19 October is immovable</Label>
|
|
95
|
+
<Label x={100} y={785} size={36}>The team needs a separate scope decision and a revised plan.</Label>
|
|
96
|
+
<Label x={100} y={846} size={36}>No safe shortcut has been established. Do not skip validation.</Label>
|
|
97
|
+
</Frame>;
|
|
98
|
+
|
|
99
|
+
export default [Schedule, Gates, Decision];
|
|
100
|
+
export const meta = { title: 'Harbor — Delivery plan', createdAt: '2026-09-12T00:00:00Z' };
|
|
101
|
+
export const notes = [
|
|
102
|
+
'Fictional, hand-authored packet as of end of 14 October 2026. Baseline agreed 2 October. Calendar axis is continuous, weekends shaded; forecast validation has no work on 17–18 October. Diamonds occur at stage completion boundaries or the launch date. All future stages and gates are conditional.',
|
|
103
|
+
'Import started 5 October and finished 14 October after duplicate member identifiers were resolved. Import completion is not evidence of validation passing. The validation gate still requires all stated checks.',
|
|
104
|
+
'Request acceptance of the revised forecast and reserve staff, not unconditional release authorization. No safe shortcut has been established for retaining the original launch date.',
|
|
105
|
+
];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Make a three-page presentation for the engineering team at Fieldnote explaining
|
|
2
|
+
an experiment with batching search-index updates. Help them weigh indexing
|
|
3
|
+
throughput against how long users wait for a document to become searchable,
|
|
4
|
+
and decide what to test next.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Fieldnote is a fictional document workspace. Its current indexer processes
|
|
9
|
+
document updates individually. The team tested batches of 20 and 100 updates
|
|
10
|
+
against that baseline.
|
|
11
|
+
|
|
12
|
+
Each configuration processed the same fixed set of 60,000 document updates
|
|
13
|
+
on the same machine, starting with an empty queue and an identical index.
|
|
14
|
+
An update's visibility delay runs from submission until the updated document
|
|
15
|
+
appears in search. Each configuration was run once.
|
|
16
|
+
|
|
17
|
+
Individual updates:
|
|
18
|
+
- Total processing time: 300 seconds.
|
|
19
|
+
- Median visibility delay: 1.2 seconds.
|
|
20
|
+
- 95th-percentile visibility delay: 2.4 seconds.
|
|
21
|
+
|
|
22
|
+
Batches of 20:
|
|
23
|
+
- Total processing time: 200 seconds.
|
|
24
|
+
- Median visibility delay: 1.8 seconds.
|
|
25
|
+
- 95th-percentile visibility delay: 4.1 seconds.
|
|
26
|
+
|
|
27
|
+
Batches of 100:
|
|
28
|
+
- Total processing time: 150 seconds.
|
|
29
|
+
- Median visibility delay: 4.9 seconds.
|
|
30
|
+
- 95th-percentile visibility delay: 11.8 seconds.
|
|
31
|
+
|
|
32
|
+
All configurations produced the expected final document versions, with no
|
|
33
|
+
missing updates in the final check. These are synthetic, hand-authored results.
|
|
34
|
+
There are no repeated runs, uncertainty estimates or production measurements.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
The team's proposed acceptance criteria are at least 250 updates per second
|
|
39
|
+
and a 95th-percentile visibility delay no greater than 5 seconds.
|
|
40
|
+
|
|
41
|
+
Recommend which configuration deserves a follow-up test. Explain why the
|
|
42
|
+
fastest configuration is not necessarily the best fit. The next experiment
|
|
43
|
+
should repeat the runs and include both sparse arrivals and bursts, since
|
|
44
|
+
a fixed workload does not establish behavior under live traffic.
|