@absmartly/cli 1.2.0 → 1.4.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/README.md +275 -0
- package/dist/commands/experiments/analyze.d.ts +3 -0
- package/dist/commands/experiments/analyze.d.ts.map +1 -0
- package/dist/commands/experiments/analyze.js +33 -0
- package/dist/commands/experiments/analyze.js.map +1 -0
- package/dist/commands/experiments/export.d.ts.map +1 -1
- package/dist/commands/experiments/export.js +11 -4
- package/dist/commands/experiments/export.js.map +1 -1
- package/dist/commands/experiments/index.d.ts.map +1 -1
- package/dist/commands/experiments/index.js +2 -0
- package/dist/commands/experiments/index.js.map +1 -1
- package/dist/core/experiments/analyze/extract-signals.d.ts +42 -0
- package/dist/core/experiments/analyze/extract-signals.d.ts.map +1 -0
- package/dist/core/experiments/analyze/extract-signals.js +154 -0
- package/dist/core/experiments/analyze/extract-signals.js.map +1 -0
- package/dist/core/experiments/analyze/heuristics.d.ts +43 -0
- package/dist/core/experiments/analyze/heuristics.d.ts.map +1 -0
- package/dist/core/experiments/analyze/heuristics.js +186 -0
- package/dist/core/experiments/analyze/heuristics.js.map +1 -0
- package/dist/core/experiments/analyze/index.d.ts +9 -0
- package/dist/core/experiments/analyze/index.d.ts.map +1 -0
- package/dist/core/experiments/analyze/index.js +114 -0
- package/dist/core/experiments/analyze/index.js.map +1 -0
- package/dist/core/experiments/analyze/related-benchmarks.d.ts +28 -0
- package/dist/core/experiments/analyze/related-benchmarks.d.ts.map +1 -0
- package/dist/core/experiments/analyze/related-benchmarks.js +54 -0
- package/dist/core/experiments/analyze/related-benchmarks.js.map +1 -0
- package/dist/core/experiments/analyze/source-signals.d.ts +8 -0
- package/dist/core/experiments/analyze/source-signals.d.ts.map +1 -0
- package/dist/core/experiments/analyze/source-signals.js +15 -0
- package/dist/core/experiments/analyze/source-signals.js.map +1 -0
- package/dist/core/experiments/analyze/summary.d.ts +3 -0
- package/dist/core/experiments/analyze/summary.d.ts.map +1 -0
- package/dist/core/experiments/analyze/summary.js +35 -0
- package/dist/core/experiments/analyze/summary.js.map +1 -0
- package/dist/core/experiments/analyze/types.d.ts +108 -0
- package/dist/core/experiments/analyze/types.d.ts.map +1 -0
- package/dist/core/experiments/analyze/types.js +2 -0
- package/dist/core/experiments/analyze/types.js.map +1 -0
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/api/axios-adapter.d.ts +30 -11
- package/dist/lib/api/axios-adapter.d.ts.map +1 -1
- package/dist/lib/api/axios-adapter.js +110 -0
- package/dist/lib/api/axios-adapter.js.map +1 -1
- package/dist/lib/api/client.d.ts +2 -6
- package/dist/lib/api/client.d.ts.map +1 -1
- package/dist/lib/api/client.js +1 -1
- package/dist/lib/api/client.js.map +1 -1
- package/dist/lib/api/request-logger.d.ts +18 -0
- package/dist/lib/api/request-logger.d.ts.map +1 -0
- package/dist/lib/api/request-logger.js +353 -0
- package/dist/lib/api/request-logger.js.map +1 -0
- package/dist/lib/utils/api-helper.d.ts +7 -0
- package/dist/lib/utils/api-helper.d.ts.map +1 -1
- package/dist/lib/utils/api-helper.js +22 -1
- package/dist/lib/utils/api-helper.js.map +1 -1
- package/dist/lib/utils/download.d.ts +10 -1
- package/dist/lib/utils/download.d.ts.map +1 -1
- package/dist/lib/utils/download.js +69 -8
- package/dist/lib/utils/download.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const FLAT_PCT = 1; // |percent_change| under 1% counts as flat
|
|
2
|
+
const FLAT_PVALUE = 0.5;
|
|
3
|
+
export function extractSignals(experiment) {
|
|
4
|
+
const snap = experiment.metrics_snapshot;
|
|
5
|
+
if (!snap || !Array.isArray(snap.rows) || snap.rows.length === 0) {
|
|
6
|
+
return { metricSignals: [], leadingVariant: null, participantCount: null };
|
|
7
|
+
}
|
|
8
|
+
const cols = snap.columnNames ?? [];
|
|
9
|
+
const idx = (name) => cols.indexOf(name);
|
|
10
|
+
const cMetric = idx('metric_id');
|
|
11
|
+
const cVariant = idx('variant');
|
|
12
|
+
const cPct = idx('percent_change');
|
|
13
|
+
const cP = idx('p_value');
|
|
14
|
+
const cLow = idx('confidence_interval_low');
|
|
15
|
+
const cHigh = idx('confidence_interval_high');
|
|
16
|
+
const cUnits = idx('cum_unit_count');
|
|
17
|
+
const alpha = parseAlpha(experiment.required_alpha) ?? 0.1;
|
|
18
|
+
const variantNames = new Map();
|
|
19
|
+
for (const v of experiment.variants ?? []) {
|
|
20
|
+
if (typeof v.variant === 'number')
|
|
21
|
+
variantNames.set(v.variant, v.name ?? `Variant ${v.variant}`);
|
|
22
|
+
}
|
|
23
|
+
const primaryMetricId = experiment.primary_metric_id ?? experiment.primary_metric?.id ?? null;
|
|
24
|
+
const metricKindById = new Map();
|
|
25
|
+
const metricNameById = new Map();
|
|
26
|
+
const lowerIsBetter = new Map();
|
|
27
|
+
if (primaryMetricId !== null) {
|
|
28
|
+
metricKindById.set(primaryMetricId, 'primary');
|
|
29
|
+
metricNameById.set(primaryMetricId, experiment.primary_metric?.name ?? `metric_${primaryMetricId}`);
|
|
30
|
+
if (experiment.primary_metric?.lower_is_better)
|
|
31
|
+
lowerIsBetter.set(primaryMetricId, true);
|
|
32
|
+
}
|
|
33
|
+
for (const sm of experiment.secondary_metrics ?? []) {
|
|
34
|
+
const mid = sm.metric_id ?? sm.metric?.id;
|
|
35
|
+
if (typeof mid !== 'number')
|
|
36
|
+
continue;
|
|
37
|
+
const kind = sm.type === 'guardrail'
|
|
38
|
+
? 'guardrail'
|
|
39
|
+
: sm.type === 'exploratory'
|
|
40
|
+
? 'exploratory'
|
|
41
|
+
: 'secondary';
|
|
42
|
+
if (!metricKindById.has(mid))
|
|
43
|
+
metricKindById.set(mid, kind);
|
|
44
|
+
if (!metricNameById.has(mid))
|
|
45
|
+
metricNameById.set(mid, sm.metric?.name ?? `metric_${mid}`);
|
|
46
|
+
if (sm.metric?.lower_is_better)
|
|
47
|
+
lowerIsBetter.set(mid, true);
|
|
48
|
+
}
|
|
49
|
+
const signals = [];
|
|
50
|
+
let bestPrimary = null;
|
|
51
|
+
let participantCount = null;
|
|
52
|
+
for (const row of snap.rows) {
|
|
53
|
+
if (!Array.isArray(row))
|
|
54
|
+
continue;
|
|
55
|
+
const metricId = numAt(row, cMetric);
|
|
56
|
+
const variantId = numAt(row, cVariant);
|
|
57
|
+
if (metricId === null || variantId === null)
|
|
58
|
+
continue;
|
|
59
|
+
if (variantId === 0) {
|
|
60
|
+
// baseline / control row — skip signal emission, but still use for participant count
|
|
61
|
+
const u = numAt(row, cUnits);
|
|
62
|
+
if (primaryMetricId !== null && metricId === primaryMetricId && u !== null) {
|
|
63
|
+
participantCount = participantCount === null ? u : Math.max(participantCount, u);
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const percent = numAt(row, cPct);
|
|
68
|
+
const pValue = numAt(row, cP);
|
|
69
|
+
const ciLow = numAt(row, cLow);
|
|
70
|
+
const ciHigh = numAt(row, cHigh);
|
|
71
|
+
const units = numAt(row, cUnits);
|
|
72
|
+
if (primaryMetricId !== null && metricId === primaryMetricId && units !== null) {
|
|
73
|
+
participantCount = participantCount === null ? units : Math.max(participantCount, units);
|
|
74
|
+
}
|
|
75
|
+
const kind = metricKindById.get(metricId) ?? 'secondary';
|
|
76
|
+
const status = classifyStatus(percent, pValue, alpha, lowerIsBetter.get(metricId) ?? false);
|
|
77
|
+
signals.push({
|
|
78
|
+
metric_id: metricId,
|
|
79
|
+
metric_name: metricNameById.get(metricId) ?? `metric_${metricId}`,
|
|
80
|
+
metric_type: kind,
|
|
81
|
+
variant_id: variantId,
|
|
82
|
+
variant_name: variantNames.get(variantId) ?? `Variant ${variantId}`,
|
|
83
|
+
percent_change: percent,
|
|
84
|
+
p_value: pValue,
|
|
85
|
+
ci_low: ciLow,
|
|
86
|
+
ci_high: ciHigh,
|
|
87
|
+
status,
|
|
88
|
+
});
|
|
89
|
+
if (primaryMetricId !== null &&
|
|
90
|
+
metricId === primaryMetricId &&
|
|
91
|
+
typeof percent === 'number' &&
|
|
92
|
+
Number.isFinite(percent)) {
|
|
93
|
+
if (bestPrimary === null || percent > bestPrimary.impact) {
|
|
94
|
+
bestPrimary = { variantId, impact: percent, pValue };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const leadingVariant = bestPrimary
|
|
99
|
+
? {
|
|
100
|
+
variant_id: bestPrimary.variantId,
|
|
101
|
+
variant_name: variantNames.get(bestPrimary.variantId) ?? `Variant ${bestPrimary.variantId}`,
|
|
102
|
+
impact_percent: bestPrimary.impact,
|
|
103
|
+
p_value: bestPrimary.pValue,
|
|
104
|
+
}
|
|
105
|
+
: null;
|
|
106
|
+
return { metricSignals: signals, leadingVariant, participantCount };
|
|
107
|
+
}
|
|
108
|
+
function numAt(row, i) {
|
|
109
|
+
if (i < 0 || i >= row.length)
|
|
110
|
+
return null;
|
|
111
|
+
const v = row[i];
|
|
112
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : null;
|
|
113
|
+
}
|
|
114
|
+
function parseAlpha(value) {
|
|
115
|
+
if (value === null || value === undefined)
|
|
116
|
+
return null;
|
|
117
|
+
const n = typeof value === 'string' ? parseFloat(value) : value;
|
|
118
|
+
return Number.isFinite(n) ? n : null;
|
|
119
|
+
}
|
|
120
|
+
function classifyStatus(percent, pValue, alpha, lowerIsBetter) {
|
|
121
|
+
if (percent === null || pValue === null)
|
|
122
|
+
return 'inconclusive';
|
|
123
|
+
const significant = pValue < alpha;
|
|
124
|
+
const directionGood = lowerIsBetter ? percent < 0 : percent > 0;
|
|
125
|
+
if (significant && directionGood)
|
|
126
|
+
return 'improves';
|
|
127
|
+
if (significant && !directionGood)
|
|
128
|
+
return 'contradicts';
|
|
129
|
+
if (Math.abs(percent) < FLAT_PCT && pValue > FLAT_PVALUE)
|
|
130
|
+
return 'flat';
|
|
131
|
+
return 'inconclusive';
|
|
132
|
+
}
|
|
133
|
+
export function leadingPrimaryImpactFromSnapshot(snapshot, primaryMetricId) {
|
|
134
|
+
if (!snapshot || !Array.isArray(snapshot.rows))
|
|
135
|
+
return null;
|
|
136
|
+
const cols = snapshot.columnNames ?? [];
|
|
137
|
+
const cMetric = cols.indexOf('metric_id');
|
|
138
|
+
const cVariant = cols.indexOf('variant');
|
|
139
|
+
const cPct = cols.indexOf('percent_change');
|
|
140
|
+
let best = null;
|
|
141
|
+
for (const row of snapshot.rows) {
|
|
142
|
+
if (!Array.isArray(row))
|
|
143
|
+
continue;
|
|
144
|
+
const m = numAt(row, cMetric);
|
|
145
|
+
const v = numAt(row, cVariant);
|
|
146
|
+
const p = numAt(row, cPct);
|
|
147
|
+
if (m !== primaryMetricId || v === null || v === 0 || p === null)
|
|
148
|
+
continue;
|
|
149
|
+
if (best === null || p > best)
|
|
150
|
+
best = p;
|
|
151
|
+
}
|
|
152
|
+
return best;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=extract-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-signals.js","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/extract-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AnalysisConfidence, DesignReadout, HeuristicEntry, LeadingVariant, MetricSignal, Recommendation } from './types.js';
|
|
2
|
+
interface AlertLite {
|
|
3
|
+
id: number;
|
|
4
|
+
type: string;
|
|
5
|
+
dismissed: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface ExpLite {
|
|
8
|
+
state?: string;
|
|
9
|
+
hypothesis?: string | null;
|
|
10
|
+
primary_metric_id?: number | null;
|
|
11
|
+
required_alpha?: string | number | null;
|
|
12
|
+
required_power?: string | number | null;
|
|
13
|
+
analysis_type?: string | null;
|
|
14
|
+
minimum_detectable_effect?: number | null;
|
|
15
|
+
baseline_primary_metric_mean?: number | null;
|
|
16
|
+
baseline_participants_per_day?: number | null;
|
|
17
|
+
percentage_of_traffic?: number | null;
|
|
18
|
+
secondary_metrics?: Array<{
|
|
19
|
+
type?: string;
|
|
20
|
+
}>;
|
|
21
|
+
recommended_action?: unknown;
|
|
22
|
+
started_at?: string | null;
|
|
23
|
+
stopped_at?: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface HeuristicsInput {
|
|
26
|
+
experiment: ExpLite;
|
|
27
|
+
alerts: AlertLite[];
|
|
28
|
+
metricSignals: MetricSignal[];
|
|
29
|
+
leadingVariant: LeadingVariant | null;
|
|
30
|
+
participantCount: number | null;
|
|
31
|
+
benchmark: {
|
|
32
|
+
observed_impacts: number[];
|
|
33
|
+
median_abs_impact: number | null;
|
|
34
|
+
} | null;
|
|
35
|
+
}
|
|
36
|
+
export declare function runHeuristics(input: HeuristicsInput): {
|
|
37
|
+
heuristicOutput: HeuristicEntry[];
|
|
38
|
+
recommendation: Recommendation | null;
|
|
39
|
+
};
|
|
40
|
+
export declare function computeAnalysisConfidence(input: HeuristicsInput): AnalysisConfidence;
|
|
41
|
+
export declare function computeDesignReadout(input: HeuristicsInput): DesignReadout;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=heuristics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heuristics.d.ts","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/heuristics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACZ,cAAc,EAEf,MAAM,YAAY,CAAC;AAYpB,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,OAAO;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,4BAA4B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,iBAAiB,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE;QAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACpF;AAsID,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG;IACrD,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC,CAOA;AAUD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,eAAe,GAAG,kBAAkB,CAoCpF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CA+C1E"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const BLOCKING_ALERT_TYPES = new Set([
|
|
2
|
+
'srm',
|
|
3
|
+
'audience_mismatch',
|
|
4
|
+
'assignment_conflict',
|
|
5
|
+
'experiments_interact',
|
|
6
|
+
]);
|
|
7
|
+
const RECOMMENDATION_OVERDUE_DAYS = 21;
|
|
8
|
+
const DEFAULT_ALPHA = 0.1;
|
|
9
|
+
const RULE_ORDER = [
|
|
10
|
+
'blocking_alert',
|
|
11
|
+
'cleanup_needed',
|
|
12
|
+
'guardrail_contradicts',
|
|
13
|
+
'primary_metric_significant_loss',
|
|
14
|
+
'primary_metric_significant_win',
|
|
15
|
+
'sample_size_not_reached',
|
|
16
|
+
'hypothesis_missing',
|
|
17
|
+
'no_recommendation_overdue',
|
|
18
|
+
'snapshot_unavailable',
|
|
19
|
+
];
|
|
20
|
+
const rules = {
|
|
21
|
+
blocking_alert: (input) => {
|
|
22
|
+
const hits = input.alerts.filter((a) => !a.dismissed && BLOCKING_ALERT_TYPES.has(a.type));
|
|
23
|
+
return entry('blocking_alert', hits.length > 0, 'warning', 'Investigate the experiment before making a rollout decision.', 'Active health checks indicate that the current results may be misleading. Resolve the data-quality or assignment issue before acting on the outcome.', { alert_types: hits.map((h) => h.type) });
|
|
24
|
+
},
|
|
25
|
+
cleanup_needed: (input) => {
|
|
26
|
+
const hits = input.alerts.filter((a) => !a.dismissed && a.type === 'cleanup_needed');
|
|
27
|
+
return entry('cleanup_needed', hits.length > 0, 'warning', 'Clean up stale assignments before proceeding.', 'The experiment has cleanup_needed signals; old data may skew the analysis.', { alert_ids: hits.map((h) => h.id) });
|
|
28
|
+
},
|
|
29
|
+
guardrail_contradicts: (input) => {
|
|
30
|
+
const hits = input.metricSignals.filter((s) => s.metric_type === 'guardrail' && s.status === 'contradicts');
|
|
31
|
+
const variant = input.leadingVariant?.variant_name ?? 'the leading variant';
|
|
32
|
+
return entry('guardrail_contradicts', hits.length > 0, 'warning', `Review guardrail regressions before rolling out ${variant}.`, 'At least one guardrail metric is moving in the wrong direction, so the apparent win on the primary metric should not be treated as rollout-ready yet.', { metrics: hits.map((h) => h.metric_name) });
|
|
33
|
+
},
|
|
34
|
+
primary_metric_significant_loss: (input) => {
|
|
35
|
+
const lv = input.leadingVariant;
|
|
36
|
+
const alpha = parseAlpha(input.experiment.required_alpha) ?? DEFAULT_ALPHA;
|
|
37
|
+
const fired = !!lv && lv.p_value !== null && lv.p_value < alpha && lv.impact_percent < 0;
|
|
38
|
+
return entry('primary_metric_significant_loss', fired, 'warning', 'Primary metric regressed at significance.', 'The leading variant moves the primary metric in the wrong direction with p-value below alpha. Do not roll out.', lv ? { variant: lv.variant_name, impact_percent: lv.impact_percent, p_value: lv.p_value } : {});
|
|
39
|
+
},
|
|
40
|
+
primary_metric_significant_win: (input) => {
|
|
41
|
+
const lv = input.leadingVariant;
|
|
42
|
+
const alpha = parseAlpha(input.experiment.required_alpha) ?? DEFAULT_ALPHA;
|
|
43
|
+
const fired = !!lv && lv.p_value !== null && lv.p_value < alpha && lv.impact_percent > 0;
|
|
44
|
+
return entry('primary_metric_significant_win', fired, 'success', `Primary metric improved with ${lv?.variant_name ?? 'the leading variant'}.`, 'The leading variant beat baseline on the primary metric with p-value below alpha.', lv ? { variant: lv.variant_name, impact_percent: lv.impact_percent, p_value: lv.p_value } : {});
|
|
45
|
+
},
|
|
46
|
+
sample_size_not_reached: (input) => {
|
|
47
|
+
const isRunningGS = input.experiment.state === 'running' && input.experiment.analysis_type === 'group_sequential';
|
|
48
|
+
const hasReachedAlert = input.alerts.some((a) => !a.dismissed && a.type === 'sample_size_reached');
|
|
49
|
+
const fired = isRunningGS && !hasReachedAlert;
|
|
50
|
+
return entry('sample_size_not_reached', fired, 'info', 'Sample size not reached.', 'Group-sequential analysis has not yet hit its planned sample size; treat results as interim.', {});
|
|
51
|
+
},
|
|
52
|
+
hypothesis_missing: (input) => {
|
|
53
|
+
const fired = !input.experiment.hypothesis || input.experiment.hypothesis.trim() === '';
|
|
54
|
+
return entry('hypothesis_missing', fired, 'info', 'No hypothesis recorded for this experiment.', 'Without a written hypothesis it is hard to judge whether the result answers the original question.', {});
|
|
55
|
+
},
|
|
56
|
+
no_recommendation_overdue: (input) => {
|
|
57
|
+
const startedAt = input.experiment.started_at ? Date.parse(input.experiment.started_at) : NaN;
|
|
58
|
+
const days = Number.isFinite(startedAt) ? (Date.now() - startedAt) / 86400000 : 0;
|
|
59
|
+
const fired = days >= RECOMMENDATION_OVERDUE_DAYS && !input.experiment.recommended_action;
|
|
60
|
+
return entry('no_recommendation_overdue', fired, 'info', 'Experiment has been running long without a recommended action.', 'Consider whether to stop, full-on, or iterate; running indefinitely is rarely the best option.', { days_running: Math.floor(days) });
|
|
61
|
+
},
|
|
62
|
+
snapshot_unavailable: (input) => {
|
|
63
|
+
const fired = input.participantCount === null && input.metricSignals.length === 0;
|
|
64
|
+
return entry('snapshot_unavailable', fired, 'info', 'No metric snapshot is available yet.', 'The previewer may not have processed this experiment; analysis is limited to design parameters.', {});
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export function runHeuristics(input) {
|
|
68
|
+
const heuristicOutput = RULE_ORDER.map((id) => rules[id](input));
|
|
69
|
+
const picked = pickRecommendation(heuristicOutput);
|
|
70
|
+
const recommendation = picked
|
|
71
|
+
? { theme: picked.theme, title: picked.title, details: picked.details }
|
|
72
|
+
: null;
|
|
73
|
+
return { heuristicOutput, recommendation };
|
|
74
|
+
}
|
|
75
|
+
function pickRecommendation(entries) {
|
|
76
|
+
const firstWarning = entries.find((h) => h.fired && h.theme === 'warning');
|
|
77
|
+
if (firstWarning)
|
|
78
|
+
return firstWarning;
|
|
79
|
+
const firstSuccess = entries.find((h) => h.fired && h.theme === 'success');
|
|
80
|
+
if (firstSuccess)
|
|
81
|
+
return firstSuccess;
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
export function computeAnalysisConfidence(input) {
|
|
85
|
+
const hasBlockingAlert = input.alerts.some((a) => !a.dismissed && BLOCKING_ALERT_TYPES.has(a.type));
|
|
86
|
+
const sampleReached = input.alerts.some((a) => !a.dismissed && a.type === 'sample_size_reached');
|
|
87
|
+
const hypothesisPresent = !!input.experiment.hypothesis && input.experiment.hypothesis.trim() !== '';
|
|
88
|
+
const primaryPresent = input.experiment.primary_metric_id !== null && input.experiment.primary_metric_id !== undefined;
|
|
89
|
+
const guardrailsPresent = (input.experiment.secondary_metrics ?? []).some((m) => m.type === 'guardrail');
|
|
90
|
+
const noBlockingAlerts = !hasBlockingAlert;
|
|
91
|
+
const factors = {
|
|
92
|
+
sample_size_reached: sampleReached,
|
|
93
|
+
hypothesis_present: hypothesisPresent,
|
|
94
|
+
primary_metric_present: primaryPresent,
|
|
95
|
+
guardrails_present: guardrailsPresent,
|
|
96
|
+
no_blocking_alerts: noBlockingAlerts,
|
|
97
|
+
};
|
|
98
|
+
const reasons = [];
|
|
99
|
+
if (!sampleReached)
|
|
100
|
+
reasons.push('Planned sample size has not been reached.');
|
|
101
|
+
if (!hypothesisPresent)
|
|
102
|
+
reasons.push('No written hypothesis.');
|
|
103
|
+
if (!primaryPresent)
|
|
104
|
+
reasons.push('No primary metric selected.');
|
|
105
|
+
if (!guardrailsPresent)
|
|
106
|
+
reasons.push('No guardrail metric configured.');
|
|
107
|
+
if (!noBlockingAlerts)
|
|
108
|
+
reasons.push('A blocking health alert is active.');
|
|
109
|
+
const missing = Object.values(factors).filter((v) => !v).length;
|
|
110
|
+
let level;
|
|
111
|
+
if (!noBlockingAlerts || missing >= 2)
|
|
112
|
+
level = 'low';
|
|
113
|
+
else if (missing === 1)
|
|
114
|
+
level = 'medium';
|
|
115
|
+
else
|
|
116
|
+
level = 'high';
|
|
117
|
+
return { level, reasons, factors };
|
|
118
|
+
}
|
|
119
|
+
export function computeDesignReadout(input) {
|
|
120
|
+
const exp = input.experiment;
|
|
121
|
+
const params = {
|
|
122
|
+
analysis_type: exp.analysis_type ?? null,
|
|
123
|
+
required_alpha: parseAlpha(exp.required_alpha),
|
|
124
|
+
required_power: numOrNull(exp.required_power),
|
|
125
|
+
minimum_detectable_effect: numOrNull(exp.minimum_detectable_effect),
|
|
126
|
+
baseline_primary_metric_mean: numOrNull(exp.baseline_primary_metric_mean),
|
|
127
|
+
baseline_participants_per_day: numOrNull(exp.baseline_participants_per_day),
|
|
128
|
+
percentage_of_traffic: numOrNull(exp.percentage_of_traffic),
|
|
129
|
+
};
|
|
130
|
+
const benchmark = input.benchmark;
|
|
131
|
+
const mde = params.minimum_detectable_effect;
|
|
132
|
+
let summary;
|
|
133
|
+
if (benchmark && benchmark.median_abs_impact !== null && mde !== null) {
|
|
134
|
+
if (benchmark.median_abs_impact >= mde * 1.5) {
|
|
135
|
+
summary = `Designed to detect effects in the expected range; comparable experiments moved this metric by ~${benchmark.median_abs_impact}%.`;
|
|
136
|
+
}
|
|
137
|
+
else if (benchmark.median_abs_impact <= mde * 0.5) {
|
|
138
|
+
summary = `MDE is larger than what comparable experiments have moved (~${benchmark.median_abs_impact}%); the next run should plan for a smaller expected effect or longer runtime.`;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
summary = `Design appears usable; comparable experiments moved this metric by ~${benchmark.median_abs_impact}%.`;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (benchmark && benchmark.median_abs_impact !== null) {
|
|
145
|
+
summary = `Comparable experiments moved this metric by ~${benchmark.median_abs_impact}%; review against the planned MDE.`;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
summary =
|
|
149
|
+
'Insufficient comparable history to benchmark the design — review MDE against domain knowledge.';
|
|
150
|
+
}
|
|
151
|
+
const notes = [];
|
|
152
|
+
if (params.percentage_of_traffic !== null && params.percentage_of_traffic < 20) {
|
|
153
|
+
notes.push(`Traffic share is only ${params.percentage_of_traffic}%; expect long runtimes.`);
|
|
154
|
+
}
|
|
155
|
+
if (params.baseline_primary_metric_mean === null) {
|
|
156
|
+
notes.push('No baseline mean recorded for the primary metric.');
|
|
157
|
+
}
|
|
158
|
+
if (input.experiment.started_at) {
|
|
159
|
+
const days = (Date.now() - Date.parse(input.experiment.started_at)) / 86400000;
|
|
160
|
+
if (days < 7 && input.experiment.state === 'running') {
|
|
161
|
+
notes.push('Less than a week of runtime so far.');
|
|
162
|
+
}
|
|
163
|
+
if (days > 90)
|
|
164
|
+
notes.push('Experiment has been running over 90 days; consider closing it out.');
|
|
165
|
+
}
|
|
166
|
+
return { summary, notes, parameters: params, benchmark };
|
|
167
|
+
}
|
|
168
|
+
function entry(rule, fired, theme, title, details, evidence) {
|
|
169
|
+
return { rule, fired, theme, title, details, evidence };
|
|
170
|
+
}
|
|
171
|
+
function parseAlpha(value) {
|
|
172
|
+
if (value === null || value === undefined)
|
|
173
|
+
return null;
|
|
174
|
+
const n = typeof value === 'string' ? parseFloat(value) : value;
|
|
175
|
+
return Number.isFinite(n) ? n : null;
|
|
176
|
+
}
|
|
177
|
+
function numOrNull(value) {
|
|
178
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
179
|
+
return value;
|
|
180
|
+
if (typeof value === 'string') {
|
|
181
|
+
const n = parseFloat(value);
|
|
182
|
+
return Number.isFinite(n) ? n : null;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=heuristics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heuristics.js","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/heuristics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { APIClient } from '../../../api-client/api-client.js';
|
|
2
|
+
import type { ExperimentId } from '../../../lib/api/branded-types.js';
|
|
3
|
+
import type { CommandResult } from '../../types.js';
|
|
4
|
+
import type { AnalyzeResult } from './types.js';
|
|
5
|
+
export interface AnalyzeExperimentParams {
|
|
6
|
+
experimentId: ExperimentId;
|
|
7
|
+
}
|
|
8
|
+
export declare function analyzeExperiment(client: APIClient, params: AnalyzeExperimentParams): Promise<CommandResult<AnalyzeResult>>;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAMpD,OAAO,KAAK,EAA0C,aAAa,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CA8GvC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { extractSignals } from './extract-signals.js';
|
|
2
|
+
import { computeAnalysisConfidence, computeDesignReadout, runHeuristics } from './heuristics.js';
|
|
3
|
+
import { summarizeRelatedExperiments } from './related-benchmarks.js';
|
|
4
|
+
import { SourceSignalRegistry } from './source-signals.js';
|
|
5
|
+
import { summarizeAnalyzeResult } from './summary.js';
|
|
6
|
+
export async function analyzeExperiment(client, params) {
|
|
7
|
+
const registry = new SourceSignalRegistry();
|
|
8
|
+
const experimentPromise = client.getExperiment(params.experimentId);
|
|
9
|
+
const experiment = (await experimentPromise);
|
|
10
|
+
const expType = experiment.type ?? '';
|
|
11
|
+
const relatedPromise = client
|
|
12
|
+
.listExperiments({
|
|
13
|
+
type: expType,
|
|
14
|
+
items: 25,
|
|
15
|
+
sort: 'updated_at',
|
|
16
|
+
ascending: false,
|
|
17
|
+
})
|
|
18
|
+
.catch((err) => {
|
|
19
|
+
registry.record('related_experiments', `error: ${err instanceof Error ? err.message : String(err)}`);
|
|
20
|
+
return [];
|
|
21
|
+
});
|
|
22
|
+
const alerts = await resolveAlerts(client, params.experimentId, experiment, registry);
|
|
23
|
+
const related = (await relatedPromise);
|
|
24
|
+
const { metricSignals, leadingVariant, participantCount } = extractSignals(experiment);
|
|
25
|
+
if (participantCount !== null) {
|
|
26
|
+
registry.record('experiment.participant_count', 'experiment.metrics_snapshot.rows[*].cum_unit_count');
|
|
27
|
+
}
|
|
28
|
+
if (leadingVariant) {
|
|
29
|
+
registry.record('experiment.leading_variant_impact_percent', 'experiment.metrics_snapshot.rows[*].percent_change');
|
|
30
|
+
}
|
|
31
|
+
const benchmarks = await summarizeRelatedExperiments(client, { id: Number(params.experimentId), primary_metric_id: numOrNull(experiment.primary_metric_id) }, related, registry);
|
|
32
|
+
const heuristicsInput = {
|
|
33
|
+
experiment: experiment,
|
|
34
|
+
alerts,
|
|
35
|
+
metricSignals,
|
|
36
|
+
leadingVariant,
|
|
37
|
+
participantCount,
|
|
38
|
+
benchmark: benchmarks.benchmark,
|
|
39
|
+
};
|
|
40
|
+
const { heuristicOutput, recommendation } = runHeuristics(heuristicsInput);
|
|
41
|
+
const analysisConfidence = computeAnalysisConfidence(heuristicsInput);
|
|
42
|
+
const designReadout = computeDesignReadout(heuristicsInput);
|
|
43
|
+
if (alerts.length > 0) {
|
|
44
|
+
registry.record('alerts', `experiment.alerts[*].type`);
|
|
45
|
+
}
|
|
46
|
+
if (experiment.recommended_action?.recommendation) {
|
|
47
|
+
registry.record('experiment.current_recommended_action', 'experiment.recommended_action.recommendation');
|
|
48
|
+
}
|
|
49
|
+
if (experiment.experiment_report
|
|
50
|
+
?.experiment_note?.note) {
|
|
51
|
+
registry.record('experiment.report_note', 'experiment.experiment_report.experiment_note.note');
|
|
52
|
+
}
|
|
53
|
+
const experimentSection = {
|
|
54
|
+
id: numOrNull(experiment.id) ?? Number(params.experimentId),
|
|
55
|
+
name: stringOr(experiment.name, ''),
|
|
56
|
+
type: stringOr(experiment.type, ''),
|
|
57
|
+
state: stringOr(experiment.state, ''),
|
|
58
|
+
hypothesis: stringOrNull(experiment.hypothesis),
|
|
59
|
+
primary_metric_name: experiment.primary_metric?.name ?? null,
|
|
60
|
+
unit_type_name: experiment.unit_type?.name ?? null,
|
|
61
|
+
participant_count: participantCount,
|
|
62
|
+
leading_variant_name: leadingVariant?.variant_name ?? null,
|
|
63
|
+
leading_variant_impact_percent: leadingVariant?.impact_percent ?? null,
|
|
64
|
+
// 1 - p_value (frequentist "confidence level"); interpret alongside p_value rather than as a calibrated probability
|
|
65
|
+
leading_variant_confidence: leadingVariant && leadingVariant.p_value !== null ? 1 - leadingVariant.p_value : null,
|
|
66
|
+
current_recommended_action: experiment.recommended_action?.recommendation ??
|
|
67
|
+
null,
|
|
68
|
+
report_note: experiment.experiment_report
|
|
69
|
+
?.experiment_note?.note ?? null,
|
|
70
|
+
};
|
|
71
|
+
const data = {
|
|
72
|
+
experiment: experimentSection,
|
|
73
|
+
alerts,
|
|
74
|
+
recommendation,
|
|
75
|
+
metric_signals: metricSignals,
|
|
76
|
+
related_experiments: benchmarks.items,
|
|
77
|
+
analysis_confidence: analysisConfidence,
|
|
78
|
+
design_readout: designReadout,
|
|
79
|
+
source_signals: registry.toArray(),
|
|
80
|
+
heuristic_output: heuristicOutput,
|
|
81
|
+
};
|
|
82
|
+
return { data, detail: summarizeAnalyzeResult(data) };
|
|
83
|
+
}
|
|
84
|
+
async function resolveAlerts(client, experimentId, experiment, registry) {
|
|
85
|
+
const embedded = experiment.alerts;
|
|
86
|
+
if (Array.isArray(embedded))
|
|
87
|
+
return embedded.map(toAlert);
|
|
88
|
+
try {
|
|
89
|
+
const list = await client.listExperimentAlerts(experimentId);
|
|
90
|
+
return list.map(toAlert);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
registry.record('alerts', `error: ${err instanceof Error ? err.message : String(err)}`);
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function toAlert(raw) {
|
|
98
|
+
const r = (raw ?? {});
|
|
99
|
+
return {
|
|
100
|
+
id: typeof r.id === 'number' ? r.id : 0,
|
|
101
|
+
type: typeof r.type === 'string' ? r.type : '',
|
|
102
|
+
dismissed: r.dismissed === true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function numOrNull(value) {
|
|
106
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
107
|
+
}
|
|
108
|
+
function stringOr(value, fallback) {
|
|
109
|
+
return typeof value === 'string' ? value : fallback;
|
|
110
|
+
}
|
|
111
|
+
function stringOrNull(value) {
|
|
112
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { APIClient } from '../../../api-client/api-client.js';
|
|
2
|
+
import { SourceSignalRegistry } from './source-signals.js';
|
|
3
|
+
import type { RelatedExperimentSummary } from './types.js';
|
|
4
|
+
interface RelatedRaw {
|
|
5
|
+
id: number;
|
|
6
|
+
name?: string;
|
|
7
|
+
state?: string;
|
|
8
|
+
started_at?: string | null;
|
|
9
|
+
stopped_at?: string | null;
|
|
10
|
+
primary_metric_id?: number | null;
|
|
11
|
+
primary_metric?: {
|
|
12
|
+
id?: number;
|
|
13
|
+
name?: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
interface FocalRaw {
|
|
17
|
+
id: number;
|
|
18
|
+
primary_metric_id?: number | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function summarizeRelatedExperiments(client: Pick<APIClient, 'getExperimentMetricsCached'>, focal: FocalRaw, related: RelatedRaw[], registry: SourceSignalRegistry): Promise<{
|
|
21
|
+
items: RelatedExperimentSummary[];
|
|
22
|
+
benchmark: {
|
|
23
|
+
observed_impacts: number[];
|
|
24
|
+
median_abs_impact: number | null;
|
|
25
|
+
} | null;
|
|
26
|
+
}>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=related-benchmarks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related-benchmarks.d.ts","sourceRoot":"","sources":["../../../../src/core/experiments/analyze/related-benchmarks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAGnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,4BAA4B,CAAC,EACrD,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC;IACT,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,SAAS,EAAE;QAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACpF,CAAC,CAsDD"}
|