@agentsean/measure 1.0.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.
Files changed (54) hide show
  1. package/LICENSE +661 -0
  2. package/dist/analyze.d.ts +19 -0
  3. package/dist/analyze.d.ts.map +1 -0
  4. package/dist/analyze.js +151 -0
  5. package/dist/analyze.js.map +1 -0
  6. package/dist/claims.d.ts +24 -0
  7. package/dist/claims.d.ts.map +1 -0
  8. package/dist/claims.js +59 -0
  9. package/dist/claims.js.map +1 -0
  10. package/dist/engine.d.ts +20 -0
  11. package/dist/engine.d.ts.map +1 -0
  12. package/dist/engine.js +108 -0
  13. package/dist/engine.js.map +1 -0
  14. package/dist/estimator.d.ts +17 -0
  15. package/dist/estimator.d.ts.map +1 -0
  16. package/dist/estimator.js +91 -0
  17. package/dist/estimator.js.map +1 -0
  18. package/dist/index.d.ts +14 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +13 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/ladder.d.ts +41 -0
  23. package/dist/ladder.d.ts.map +1 -0
  24. package/dist/ladder.js +99 -0
  25. package/dist/ladder.js.map +1 -0
  26. package/dist/peek.d.ts +19 -0
  27. package/dist/peek.d.ts.map +1 -0
  28. package/dist/peek.js +31 -0
  29. package/dist/peek.js.map +1 -0
  30. package/dist/persist.d.ts +66 -0
  31. package/dist/persist.d.ts.map +1 -0
  32. package/dist/persist.js +265 -0
  33. package/dist/persist.js.map +1 -0
  34. package/dist/power.d.ts +36 -0
  35. package/dist/power.d.ts.map +1 -0
  36. package/dist/power.js +130 -0
  37. package/dist/power.js.map +1 -0
  38. package/dist/register.d.ts +17 -0
  39. package/dist/register.d.ts.map +1 -0
  40. package/dist/register.js +86 -0
  41. package/dist/register.js.map +1 -0
  42. package/dist/suppress.d.ts +24 -0
  43. package/dist/suppress.d.ts.map +1 -0
  44. package/dist/suppress.js +60 -0
  45. package/dist/suppress.js.map +1 -0
  46. package/dist/track.d.ts +10 -0
  47. package/dist/track.d.ts.map +1 -0
  48. package/dist/track.js +30 -0
  49. package/dist/track.js.map +1 -0
  50. package/dist/types.d.ts +89 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +38 -0
  53. package/dist/types.js.map +1 -0
  54. package/package.json +52 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAmBpD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAoB,MAAM,YAAY,CAAC;AAEhF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,aAAa,GACnB,cAAc,CAmIhB"}
@@ -0,0 +1,151 @@
1
+ import { changepointsOverlapping } from "@agentsean/google";
2
+ import { assignEvidenceTier, claimCausation, statementFor, TIER_A_MDE_MAX, UNDERPOWERED_MDE, } from "./ladder.js";
3
+ import { estimateLift } from "./estimator.js";
4
+ import { suppress } from "./suppress.js";
5
+ import { guardPeeking } from "./peek.js";
6
+ import { getExperiment, overlappingAnomalies, saveClaim, saveResult, setExperimentStatus, } from "./persist.js";
7
+ import { splitMde, prePostMde } from "./power.js";
8
+ export function analyzeExperiment(db, input) {
9
+ const exp = getExperiment(db, input.experimentId);
10
+ if (!exp)
11
+ throw new Error(`unknown experiment ${input.experimentId}`);
12
+ const peek = guardPeeking(exp.plannedEnd, input.now, exp.peekingBlocked === 1);
13
+ const metric = input.metric ?? exp.primaryMetric;
14
+ const hasControl = input.control.length > 0 && exp.design !== "uncontrolled";
15
+ const incidents = changepointsOverlapping(db, exp.preStart, exp.plannedEnd);
16
+ const ranking = incidents.some((c) => /core|spam|ranking|update/i.test(c.title) || c.kind === "RANKING_UPDATE");
17
+ const anomalies = input.overlappingAnomalies ??
18
+ overlappingAnomalies(db, exp.preStart, exp.plannedEnd);
19
+ const realisedMde = hasControl
20
+ ? splitMde({
21
+ monthlyClicks: monthlyFromSeries(input.treatment, input.control),
22
+ pageCount: Math.max(input.treatment.length + input.control.length, 2),
23
+ pagesPerArm: Math.max(input.control.length, 1),
24
+ })
25
+ : prePostMde(56);
26
+ const rules = suppress({
27
+ metric,
28
+ preStart: exp.preStart,
29
+ plannedEnd: exp.plannedEnd,
30
+ hasControl,
31
+ plannedMde: exp.plannedMde,
32
+ now: input.now,
33
+ overlappingAnomalies: anomalies,
34
+ overlappingRankingUpdate: ranking,
35
+ treatment: input.treatment,
36
+ control: input.control,
37
+ reserve: input.reserve,
38
+ });
39
+ if (!peek.allowed) {
40
+ const statement = peek.reason;
41
+ return {
42
+ experimentId: exp.id,
43
+ peeking: true,
44
+ provisional: true,
45
+ reason: peek.reason,
46
+ evidenceTier: null,
47
+ causationClaimed: false,
48
+ statement,
49
+ lift: null,
50
+ ciLow: null,
51
+ ciHigh: null,
52
+ probPositive: null,
53
+ realisedMde,
54
+ suppressedBy: rules.includes("S9") ? rules : ["S9", ...rules],
55
+ };
56
+ }
57
+ const est = input.treatment.length > 0
58
+ ? estimateLift(input.treatment, hasControl ? input.control : zeroControl(input.treatment), {
59
+ seed: exp.randomisationSeed,
60
+ })
61
+ : null;
62
+ const lift = est?.lift ?? null;
63
+ const tier = assignEvidenceTier({
64
+ applied: true,
65
+ preRegistered: true,
66
+ design: exp.design,
67
+ hasControl,
68
+ powerOk: realisedMde <= TIER_A_MDE_MAX,
69
+ underpowered: exp.plannedMde > UNDERPOWERED_MDE || rules.includes("S8"),
70
+ peeking: false,
71
+ suppressed: rules,
72
+ lift,
73
+ realisedMde,
74
+ googleUpdateJoined: true,
75
+ });
76
+ const cause = claimCausation(tier);
77
+ const causationClaimed = cause.allowed && est !== null && est.ciLow > 0;
78
+ const statement = peekingOrStatement(tier, {
79
+ lift,
80
+ realisedMde,
81
+ incidentTitles: incidents.map((c) => c.title),
82
+ });
83
+ saveResult(db, exp.id, {
84
+ metric,
85
+ pointEstimate: lift,
86
+ ciLow: est?.ciLow ?? null,
87
+ ciHigh: est?.ciHigh ?? null,
88
+ ciLevel: est?.ciLevel ?? null,
89
+ probPositive: est?.probPositive ?? null,
90
+ realisedMde,
91
+ nBoot: est?.nBoot ?? null,
92
+ suppressedBy: rules,
93
+ evidenceTier: tier,
94
+ statement,
95
+ causationClaimed,
96
+ analysedAt: input.now.toISOString(),
97
+ });
98
+ setExperimentStatus(db, exp.id, "concluded", {
99
+ evidenceTier: tier,
100
+ concludedAt: input.now.toISOString(),
101
+ });
102
+ saveClaim(db, {
103
+ siteId: exp.siteId,
104
+ changeId: null,
105
+ experimentId: exp.id,
106
+ evidenceTier: tier,
107
+ statement,
108
+ metric,
109
+ causationClaimed,
110
+ refusedReason: causationClaimed ? null : cause.reason,
111
+ createdAt: input.now.toISOString(),
112
+ });
113
+ return {
114
+ experimentId: exp.id,
115
+ peeking: false,
116
+ provisional: false,
117
+ reason: null,
118
+ evidenceTier: tier,
119
+ causationClaimed,
120
+ statement,
121
+ lift,
122
+ ciLow: est?.ciLow ?? null,
123
+ ciHigh: est?.ciHigh ?? null,
124
+ probPositive: est?.probPositive ?? null,
125
+ realisedMde,
126
+ suppressedBy: rules,
127
+ };
128
+ }
129
+ function peekingOrStatement(tier, opts) {
130
+ return statementFor(tier, {
131
+ lift: opts.lift,
132
+ realisedMde: opts.realisedMde,
133
+ incidentTitles: opts.incidentTitles,
134
+ });
135
+ }
136
+ function monthlyFromSeries(treatment, control) {
137
+ let clicks = 0;
138
+ for (const r of treatment)
139
+ clicks += r.preClicks;
140
+ for (const r of control)
141
+ clicks += r.preClicks;
142
+ return clicks * (30 / 56);
143
+ }
144
+ function zeroControl(treatment) {
145
+ return treatment.map((r) => ({
146
+ url: `control:${r.url}`,
147
+ preClicks: r.preClicks,
148
+ postClicks: r.preClicks,
149
+ }));
150
+ }
151
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ import { claimForChange, listClaims } from "./persist.js";
3
+ import type { ClaimRecord } from "./types.js";
4
+ export type ClaimHeadline = {
5
+ applied: number;
6
+ byTier: Record<string, number>;
7
+ measured: number;
8
+ notMeasurable: number;
9
+ line: string;
10
+ };
11
+ export declare function headline(rows: ClaimRecord[]): ClaimHeadline;
12
+ export declare function labelAppliedChange(db: SqliteDatabase, opts: {
13
+ siteId: string;
14
+ changeId: string;
15
+ now?: Date | undefined;
16
+ monthlyClicks?: number | undefined;
17
+ pageCount?: number | undefined;
18
+ }): ClaimRecord;
19
+ export declare function backfillUnlabelledChanges(db: SqliteDatabase, siteId: string, now: Date, traffic?: {
20
+ monthlyClicks: number;
21
+ pageCount: number;
22
+ }): number;
23
+ export { listClaims, claimForChange };
24
+ //# sourceMappingURL=claims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAa,MAAM,cAAc,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,aAAa,CAU3D;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,GACA,WAAW,CAsBb;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,IAAI,EACT,OAAO,CAAC,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrD,MAAM,CAeR;AAED,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC"}
package/dist/claims.js ADDED
@@ -0,0 +1,59 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { changes } from "@agentsean/db";
3
+ import { DEFAULT_EVIDENCE_TIER, claimCausation, statementFor } from "./ladder.js";
4
+ import { sitePowerBrief } from "./power.js";
5
+ import { claimForChange, listClaims, saveClaim } from "./persist.js";
6
+ export function headline(rows) {
7
+ const byTier = { A: 0, B: 0, C: 0, D: 0, E: 0 };
8
+ for (const r of rows) {
9
+ byTier[r.evidenceTier] = (byTier[r.evidenceTier] ?? 0) + 1;
10
+ }
11
+ const applied = rows.length;
12
+ const measured = (byTier.A ?? 0) + (byTier.B ?? 0);
13
+ const notMeasurable = byTier.E ?? 0;
14
+ const line = `${applied} changes applied · ${measured} measured · ${byTier.C ?? 0} observed pre/post · ${byTier.D ?? 0} directional · ${notMeasurable} not measurable`;
15
+ return { applied, byTier, measured, notMeasurable, line };
16
+ }
17
+ export function labelAppliedChange(db, opts) {
18
+ const existing = claimForChange(db, opts.changeId);
19
+ if (existing)
20
+ return existing;
21
+ const brief = sitePowerBrief({
22
+ monthlyClicks: opts.monthlyClicks ?? 0,
23
+ pageCount: opts.pageCount ?? 0,
24
+ });
25
+ const cause = claimCausation(DEFAULT_EVIDENCE_TIER);
26
+ return saveClaim(db, {
27
+ siteId: opts.siteId,
28
+ changeId: opts.changeId,
29
+ experimentId: null,
30
+ evidenceTier: DEFAULT_EVIDENCE_TIER,
31
+ statement: statementFor(DEFAULT_EVIDENCE_TIER, {
32
+ monthlyClicks: brief.monthlyClicks,
33
+ neededClicksPerArm: 1900,
34
+ }),
35
+ metric: "clicks",
36
+ causationClaimed: false,
37
+ refusedReason: cause.reason,
38
+ createdAt: (opts.now ?? new Date()).toISOString(),
39
+ });
40
+ }
41
+ export function backfillUnlabelledChanges(db, siteId, now, traffic) {
42
+ const rows = db.select().from(changes).where(eq(changes.siteId, siteId)).all();
43
+ let n = 0;
44
+ for (const row of rows) {
45
+ if (claimForChange(db, row.id))
46
+ continue;
47
+ labelAppliedChange(db, {
48
+ siteId,
49
+ changeId: row.id,
50
+ now,
51
+ monthlyClicks: traffic?.monthlyClicks,
52
+ pageCount: traffic?.pageCount,
53
+ });
54
+ n++;
55
+ }
56
+ return n;
57
+ }
58
+ export { listClaims, claimForChange };
59
+ //# sourceMappingURL=claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.js","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ import { type AnalysisResult } from "./analyze.js";
3
+ import type { ClaimRecord, PageSeries, PowerBrief } from "./types.js";
4
+ import type { WaterfallResult } from "@agentsean/google";
5
+ export type MeasureJobResult = {
6
+ siteId: string;
7
+ power: PowerBrief;
8
+ waterfall: WaterfallResult | null;
9
+ analysed: AnalysisResult[];
10
+ claims: ClaimRecord[];
11
+ headline: string;
12
+ backfilled: number;
13
+ };
14
+ export declare function monthlyClicksForSite(db: SqliteDatabase, siteId: string): number;
15
+ export declare function seriesForUrls(db: SqliteDatabase, siteId: string, urls: string[], preStart: string, preEnd: string, postStart: string, postEnd: string): PageSeries[];
16
+ export declare function runMeasureJob(db: SqliteDatabase, opts: {
17
+ siteId: string;
18
+ now?: Date | undefined;
19
+ }): MeasureJobResult;
20
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAGnF,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAQtE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAOF,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAW/E;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,UAAU,EAAE,CAkBd;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CAAE,GAC/C,gBAAgB,CAqFlB"}
package/dist/engine.js ADDED
@@ -0,0 +1,108 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { gscDaily, gscPageDaily, pages } from "@agentsean/db";
3
+ import { persistWaterfall, waterfallFromSite } from "@agentsean/google";
4
+ import { sitePowerBrief } from "./power.js";
5
+ import { analyzeExperiment } from "./analyze.js";
6
+ import { backfillUnlabelledChanges, headline, listClaims } from "./claims.js";
7
+ import { getExperiment, listCohortUrls, listExperiments, seedDataAnomalies, } from "./persist.js";
8
+ function addDays(iso, days) {
9
+ const t = Date.parse(`${iso}T00:00:00Z`) + days * 86_400_000;
10
+ return new Date(t).toISOString().slice(0, 10);
11
+ }
12
+ export function monthlyClicksForSite(db, siteId) {
13
+ const rows = db.select().from(gscDaily).where(eq(gscDaily.siteId, siteId)).all();
14
+ const byDate = new Map();
15
+ for (const r of rows) {
16
+ if (r.searchType !== "web")
17
+ continue;
18
+ byDate.set(r.date, (byDate.get(r.date) ?? 0) + r.clicks);
19
+ }
20
+ if (byDate.size === 0)
21
+ return 0;
22
+ let sum = 0;
23
+ for (const v of byDate.values())
24
+ sum += v;
25
+ return sum * (30 / byDate.size);
26
+ }
27
+ export function seriesForUrls(db, siteId, urls, preStart, preEnd, postStart, postEnd) {
28
+ const rows = db
29
+ .select()
30
+ .from(gscPageDaily)
31
+ .where(eq(gscPageDaily.siteId, siteId))
32
+ .all();
33
+ const out = [];
34
+ for (const url of urls) {
35
+ let pre = 0;
36
+ let post = 0;
37
+ for (const r of rows) {
38
+ if (r.page !== url || r.searchType !== "web")
39
+ continue;
40
+ if (r.date >= preStart && r.date <= preEnd)
41
+ pre += r.clicks;
42
+ if (r.date >= postStart && r.date <= postEnd)
43
+ post += r.clicks;
44
+ }
45
+ out.push({ url, preClicks: pre, postClicks: post });
46
+ }
47
+ return out;
48
+ }
49
+ export function runMeasureJob(db, opts) {
50
+ const now = opts.now ?? new Date();
51
+ const today = now.toISOString().slice(0, 10);
52
+ seedDataAnomalies(db);
53
+ const monthly = monthlyClicksForSite(db, opts.siteId);
54
+ const pageCount = db
55
+ .select()
56
+ .from(pages)
57
+ .where(eq(pages.siteId, opts.siteId))
58
+ .all().length;
59
+ const power = sitePowerBrief({ monthlyClicks: monthly, pageCount });
60
+ const windowEnd = addDays(today, -3);
61
+ const windowStart = addDays(windowEnd, -27);
62
+ let waterfall = null;
63
+ try {
64
+ waterfall = waterfallFromSite(db, opts.siteId, windowStart, windowEnd);
65
+ persistWaterfall(db, opts.siteId, waterfall, now);
66
+ }
67
+ catch {
68
+ waterfall = null;
69
+ }
70
+ const analysed = [];
71
+ for (const exp of listExperiments(db, opts.siteId)) {
72
+ if (exp.status !== "running" &&
73
+ exp.status !== "planned" &&
74
+ exp.status !== "analysing")
75
+ continue;
76
+ if (exp.status === "planned")
77
+ continue;
78
+ const stored = getExperiment(db, exp.id);
79
+ if (!stored)
80
+ continue;
81
+ const urls = listCohortUrls(db, exp.id);
82
+ const treatment = seriesForUrls(db, opts.siteId, urls.treatment, stored.preStart, stored.preEnd, stored.postStart, stored.plannedEnd);
83
+ const control = seriesForUrls(db, opts.siteId, urls.control, stored.preStart, stored.preEnd, stored.postStart, stored.plannedEnd);
84
+ const reserve = seriesForUrls(db, opts.siteId, urls.reserve, stored.preStart, stored.preEnd, stored.postStart, stored.plannedEnd);
85
+ analysed.push(analyzeExperiment(db, {
86
+ experimentId: exp.id,
87
+ now,
88
+ treatment,
89
+ control,
90
+ reserve,
91
+ }));
92
+ }
93
+ const backfilled = backfillUnlabelledChanges(db, opts.siteId, now, {
94
+ monthlyClicks: monthly,
95
+ pageCount,
96
+ });
97
+ const claims = listClaims(db, opts.siteId);
98
+ return {
99
+ siteId: opts.siteId,
100
+ power,
101
+ waterfall,
102
+ analysed,
103
+ claims,
104
+ headline: headline(claims).line,
105
+ backfilled,
106
+ };
107
+ }
108
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Estimate, PageSeries } from "./types.js";
2
+ export declare const DEFAULT_BOOT = 2000;
3
+ export declare const DEFAULT_CI_LEVEL = 0.95;
4
+ /**
5
+ * Click-weighted log ratio-of-ratios:
6
+ * log(post_T / pre_T) − log(post_C / pre_C).
7
+ * Continuity correction of 0.5 so zeros do not explode.
8
+ */
9
+ export declare function logRatioOfRatios(treatment: PageSeries[], control: PageSeries[]): number;
10
+ export declare function relativeLift(logEstimate: number): number;
11
+ export declare function estimateLift(treatment: PageSeries[], control: PageSeries[], opts?: {
12
+ nBoot?: number | undefined;
13
+ seed?: number | undefined;
14
+ ciLevel?: number | undefined;
15
+ }): Estimate;
16
+ export declare function ciSpansZero(est: Estimate): boolean;
17
+ //# sourceMappingURL=estimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimator.d.ts","sourceRoot":"","sources":["../src/estimator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAmBrC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,UAAU,EAAE,EACvB,OAAO,EAAE,UAAU,EAAE,GACpB,MAAM,CAMR;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAqBD,wBAAgB,YAAY,CAC1B,SAAS,EAAE,UAAU,EAAE,EACvB,OAAO,EAAE,UAAU,EAAE,EACrB,IAAI,CAAC,EAAE;IACL,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,GACA,QAAQ,CAoCV;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAElD"}
@@ -0,0 +1,91 @@
1
+ export const DEFAULT_BOOT = 2000;
2
+ export const DEFAULT_CI_LEVEL = 0.95;
3
+ function mulberry32(seed) {
4
+ let a = seed >>> 0;
5
+ return () => {
6
+ a = (a + 0x6d2b79f5) >>> 0;
7
+ let t = a;
8
+ t = Math.imul(t ^ (t >>> 15), t | 1);
9
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
10
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
11
+ };
12
+ }
13
+ function sumClicks(rows, field) {
14
+ let s = 0;
15
+ for (const r of rows)
16
+ s += r[field];
17
+ return s;
18
+ }
19
+ /**
20
+ * Click-weighted log ratio-of-ratios:
21
+ * log(post_T / pre_T) − log(post_C / pre_C).
22
+ * Continuity correction of 0.5 so zeros do not explode.
23
+ */
24
+ export function logRatioOfRatios(treatment, control) {
25
+ const preT = sumClicks(treatment, "preClicks") + 0.5;
26
+ const postT = sumClicks(treatment, "postClicks") + 0.5;
27
+ const preC = sumClicks(control, "preClicks") + 0.5;
28
+ const postC = sumClicks(control, "postClicks") + 0.5;
29
+ return Math.log(postT / preT) - Math.log(postC / preC);
30
+ }
31
+ export function relativeLift(logEstimate) {
32
+ return Math.exp(logEstimate) - 1;
33
+ }
34
+ function resample(rows, rng) {
35
+ if (rows.length === 0)
36
+ return [];
37
+ const out = [];
38
+ for (let i = 0; i < rows.length; i++) {
39
+ const idx = Math.floor(rng() * rows.length);
40
+ out.push(rows[idx]);
41
+ }
42
+ return out;
43
+ }
44
+ function quantile(sorted, q) {
45
+ if (sorted.length === 0)
46
+ return 0;
47
+ const i = Math.min(sorted.length - 1, Math.max(0, Math.floor(q * (sorted.length - 1))));
48
+ return sorted[i];
49
+ }
50
+ export function estimateLift(treatment, control, opts) {
51
+ const nBoot = opts?.nBoot ?? DEFAULT_BOOT;
52
+ const ciLevel = opts?.ciLevel ?? DEFAULT_CI_LEVEL;
53
+ const seed = opts?.seed ?? 1;
54
+ const pointLog = logRatioOfRatios(treatment, control);
55
+ const lift = relativeLift(pointLog);
56
+ if (treatment.length === 0 || control.length === 0) {
57
+ return {
58
+ lift,
59
+ ciLow: lift,
60
+ ciHigh: lift,
61
+ ciLevel,
62
+ probPositive: lift > 0 ? 1 : 0,
63
+ nBoot: 0,
64
+ };
65
+ }
66
+ const rng = mulberry32(seed);
67
+ const samples = [];
68
+ let positive = 0;
69
+ for (let i = 0; i < nBoot; i++) {
70
+ const t = resample(treatment, rng);
71
+ const c = resample(control, rng);
72
+ const v = relativeLift(logRatioOfRatios(t, c));
73
+ samples.push(v);
74
+ if (v > 0)
75
+ positive++;
76
+ }
77
+ samples.sort((a, b) => a - b);
78
+ const alpha = (1 - ciLevel) / 2;
79
+ return {
80
+ lift,
81
+ ciLow: quantile(samples, alpha),
82
+ ciHigh: quantile(samples, 1 - alpha),
83
+ ciLevel,
84
+ probPositive: positive / nBoot,
85
+ nBoot,
86
+ };
87
+ }
88
+ export function ciSpansZero(est) {
89
+ return est.ciLow <= 0 && est.ciHigh >= 0;
90
+ }
91
+ //# sourceMappingURL=estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimator.js","sourceRoot":"","sources":["../src/estimator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type { EvidenceTier, ExperimentStatus, ExperimentDesign, ExperimentUnit, CohortArm, SuppressionRule, PageSeries, Estimate, PowerBrief, ClaimRecord, ExperimentSpec, AnalysisInput, } from "./types.js";
2
+ export { EVIDENCE_TIERS, EVIDENCE_MEANING, DEFAULT_EVIDENCE_TIER, EXPERIMENT_STATUSES, EXPERIMENT_DESIGNS, EXPERIMENT_UNITS, COHORT_ARMS, SUPPRESSION_RULES, } from "./types.js";
3
+ export { assignEvidenceTier, claimCausation, refuseUrlAttribution, statementFor, isEvidenceTier, TIER_A_MDE_MAX, UNDERPOWERED_MDE, } from "./ladder.js";
4
+ export { prePostMde, splitMde, sitePowerBrief, clicksPerArmInWindow, naiveFalseWinProbability, PRE_POST_MDE_28D, PRE_POST_MDE_56D, PRE_POST_MDE_91D, SPLIT_MDE_2K_56D, PEEKING_FP_FIXED, PEEKING_FP_DAILY, FABRICATED_WIN_20, SEARCHPILOT_MIN_SESSIONS, SEMRUSH_MIN_CLICKS_100D, DEFAULT_WINDOW_DAYS, } from "./power.js";
5
+ export { estimateLift, logRatioOfRatios, relativeLift, ciSpansZero, } from "./estimator.js";
6
+ export { suppress, SUPPRESSION_LABEL } from "./suppress.js";
7
+ export { guardPeeking, analysisDateReached, PlannedEndImmutableError } from "./peek.js";
8
+ export { registerExperiment, startExperiment, type RegisterResult, } from "./register.js";
9
+ export { seedDataAnomalies, getExperiment, listExperiments, listClaims, claimForChange, saveClaim, listCohortUrls, setExperimentStatus, assertPlannedEndImmutable, type StoredExperiment, } from "./persist.js";
10
+ export { analyzeExperiment, type AnalysisResult } from "./analyze.js";
11
+ export { labelAppliedChange, backfillUnlabelledChanges, headline } from "./claims.js";
12
+ export { trackForActionKind, TRACK_A_KINDS, TRACK_B_KINDS, type Track, } from "./track.js";
13
+ export { runMeasureJob, monthlyClicksForSite, seriesForUrls, type MeasureJobResult, } from "./engine.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACxF,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,UAAU,EACV,cAAc,EACd,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,KAAK,KAAK,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export { EVIDENCE_TIERS, EVIDENCE_MEANING, DEFAULT_EVIDENCE_TIER, EXPERIMENT_STATUSES, EXPERIMENT_DESIGNS, EXPERIMENT_UNITS, COHORT_ARMS, SUPPRESSION_RULES, } from "./types.js";
2
+ export { assignEvidenceTier, claimCausation, refuseUrlAttribution, statementFor, isEvidenceTier, TIER_A_MDE_MAX, UNDERPOWERED_MDE, } from "./ladder.js";
3
+ export { prePostMde, splitMde, sitePowerBrief, clicksPerArmInWindow, naiveFalseWinProbability, PRE_POST_MDE_28D, PRE_POST_MDE_56D, PRE_POST_MDE_91D, SPLIT_MDE_2K_56D, PEEKING_FP_FIXED, PEEKING_FP_DAILY, FABRICATED_WIN_20, SEARCHPILOT_MIN_SESSIONS, SEMRUSH_MIN_CLICKS_100D, DEFAULT_WINDOW_DAYS, } from "./power.js";
4
+ export { estimateLift, logRatioOfRatios, relativeLift, ciSpansZero, } from "./estimator.js";
5
+ export { suppress, SUPPRESSION_LABEL } from "./suppress.js";
6
+ export { guardPeeking, analysisDateReached, PlannedEndImmutableError } from "./peek.js";
7
+ export { registerExperiment, startExperiment, } from "./register.js";
8
+ export { seedDataAnomalies, getExperiment, listExperiments, listClaims, claimForChange, saveClaim, listCohortUrls, setExperimentStatus, assertPlannedEndImmutable, } from "./persist.js";
9
+ export { analyzeExperiment } from "./analyze.js";
10
+ export { labelAppliedChange, backfillUnlabelledChanges, headline } from "./claims.js";
11
+ export { trackForActionKind, TRACK_A_KINDS, TRACK_B_KINDS, } from "./track.js";
12
+ export { runMeasureJob, monthlyClicksForSite, seriesForUrls, } from "./engine.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACxF,OAAO,EACL,kBAAkB,EAClB,eAAe,GAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,UAAU,EACV,cAAc,EACd,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,yBAAyB,GAE1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAuB,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,aAAa,GAEd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,GAEd,MAAM,aAAa,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { DEFAULT_EVIDENCE_TIER, EVIDENCE_MEANING, EVIDENCE_TIERS, type EvidenceTier, type ExperimentDesign } from "./types.js";
2
+ export { EVIDENCE_MEANING, EVIDENCE_TIERS, DEFAULT_EVIDENCE_TIER };
3
+ export type { EvidenceTier };
4
+ /** Realised MDE at or below this is "sufficient power" for tier A. */
5
+ export declare const TIER_A_MDE_MAX = 0.25;
6
+ /** Rule S8: refuse to start a test whose MDE exceeds 40%. */
7
+ export declare const UNDERPOWERED_MDE = 0.4;
8
+ export type LadderInput = {
9
+ applied: boolean;
10
+ preRegistered: boolean;
11
+ design: ExperimentDesign | null;
12
+ hasControl: boolean;
13
+ powerOk: boolean;
14
+ underpowered: boolean;
15
+ peeking: boolean;
16
+ suppressed: string[];
17
+ lift: number | null;
18
+ realisedMde: number | null;
19
+ googleUpdateJoined: boolean;
20
+ };
21
+ export type CausationDecision = {
22
+ allowed: boolean;
23
+ reason: string;
24
+ };
25
+ export declare function isEvidenceTier(value: string): value is EvidenceTier;
26
+ /**
27
+ * PLAN Phase 7 ladder. Most rows on agency sites land in E.
28
+ * Causation is only allowed for A.
29
+ */
30
+ export declare function assignEvidenceTier(input: LadderInput): EvidenceTier;
31
+ export declare function claimCausation(tier: EvidenceTier): CausationDecision;
32
+ /** Per-URL "this change generated N clicks" must never exist. */
33
+ export declare function refuseUrlAttribution(url: string): never;
34
+ export declare function statementFor(tier: EvidenceTier, opts?: {
35
+ lift?: number | null | undefined;
36
+ realisedMde?: number | null | undefined;
37
+ incidentTitles?: string[] | undefined;
38
+ monthlyClicks?: number | undefined;
39
+ neededClicksPerArm?: number | undefined;
40
+ }): string;
41
+ //# sourceMappingURL=ladder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ladder.d.ts","sourceRoot":"","sources":["../src/ladder.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,sEAAsE;AACtE,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAEnE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAgCnE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,iBAAiB,CAWpE;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAIvD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,YAAY,EAClB,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,GACA,MAAM,CAkCR"}