marketing-mindset 1.7.0 → 1.8.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 (3) hide show
  1. package/README.md +20 -0
  2. package/bin/cli.js +59 -0
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -94,3 +94,23 @@ the dated read, a week-by-week table with the percentage of the floor covered, t
94
94
  kill rule. `--json` returns the same object for an agent or a script.
95
95
 
96
96
  Method, packages and the paid version of this work: https://axelfreeman.com/marketing-engineer.html
97
+
98
+ ## `mde` — what a volume you can afford can actually read
99
+
100
+ The other direction of the same arithmetic: instead of the volume a lift requires, the lift a volume can
101
+ read. Useful when the channel caps the volume (a small list, a niche audience, one store's traffic) and the
102
+ honest question is not "how much do we need" but "what is the smallest win this test could ever show".
103
+
104
+ ```bash
105
+ npx marketing-mindset mde --base 0.03 --per-arm 5000
106
+ # base rate 3.00% · per arm 5,000 · power 0.8 · alpha 0.05
107
+ # smallest readable relative lift: 33.4% (1pp absolute)
108
+ # verdict: at this volume only a difference of 33.4% or more is readable ...
109
+
110
+ npx marketing-mindset mde --base 0.03 --per-arm 5000 --json
111
+ ```
112
+
113
+ `--per-arm` takes the volume you can actually buy per variant; `--power` (0.8 or 0.9) and `--alpha`
114
+ (0.05, 0.01, 0.1) are the same knobs as `sample`. When no lift is readable at that volume the command
115
+ says so instead of printing a number, and names the three ways out: more volume, a higher base rate, or a
116
+ cheaper measurable unit (for cold email the reply rate, floor ~1,500–2,000 sends per variant).
package/bin/cli.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * marketing-mindset help + the test-size floors
4
4
  * marketing-mindset sample required per-arm sample size for a two-proportion test
5
5
  * marketing-mindset kill the kill rule for a running test
6
+ * marketing-mindset mde smallest relative lift a fixed per-arm volume can read
6
7
  * marketing-mindset sections list every section of SKILL.md
7
8
  * marketing-mindset read <text> print one section by fuzzy title match
8
9
  * marketing-mindset install copy the skill into your agent's skills directory
@@ -383,6 +384,60 @@ function runPlan(opts) {
383
384
 
384
385
  /* brief — the whole plan as one markdown page a client can keep: the floor, what reaching it costs,
385
386
  * the dates, the gate for each week and the kill rule. --json returns the same object for an agent. */
387
+ function mdeLift(rate, perArm, power, alpha) {
388
+ if (sampleSize(rate, 5, power, alpha) > perArm) { return null; }
389
+ let lo = 1e-6, hi = 5;
390
+ for (let i = 0; i < 100; i++) {
391
+ const mid = (lo + hi) / 2;
392
+ if (sampleSize(rate, mid, power, alpha) <= perArm) { hi = mid; } else { lo = mid; }
393
+ }
394
+ return hi;
395
+ }
396
+
397
+ function runMde(opts) {
398
+ const rate = Number(opts.base !== undefined ? opts.base : 0.03);
399
+ const perArm = Number(opts["per-arm"] !== undefined ? opts["per-arm"] : (opts.n !== undefined ? opts.n : 5000));
400
+ const power = Number(opts.power !== undefined ? opts.power : 0.8);
401
+ const alpha = Number(opts.alpha !== undefined ? opts.alpha : 0.05);
402
+ const problems = [];
403
+ if (!(rate > 0 && rate < 1)) { problems.push("base must be between 0 and 1 (0.03 = 3%)"); }
404
+ if (!(perArm > 0)) { problems.push("per-arm must be a positive volume (contacts, sends or visitors)"); }
405
+ if (!ZB[String(power)]) { problems.push("power must be 0.8 or 0.9 - this CLI carries exact quantiles for those two"); }
406
+ if (!ZA[String(alpha)]) { problems.push("alpha must be 0.05, 0.01 or 0.1"); }
407
+ if (problems.length) { console.error("mde: " + problems.join("; ")); return 1; }
408
+ const lift = mdeLift(rate, perArm, power, alpha);
409
+ if (lift === null) {
410
+ const out = {
411
+ base_rate: rate, per_arm: perArm, power, alpha,
412
+ min_relative_lift: null, min_absolute_pp: null, readable: false,
413
+ verdict: "no lift is readable at this volume: even a five-fold difference needs more than " + fmtNum(perArm) + " per arm at a " + (rate * 100).toFixed(2) + "% base rate. Raise the volume, raise the base rate (tighter list or sharper promise), or measure a cheaper unit (for cold email the readable unit is the reply rate, floor ~1,500-2,000 sends per variant)."
414
+ };
415
+ if (opts.json) { console.log(JSON.stringify(out, null, 2)); } else {
416
+ console.log("base rate " + (rate * 100).toFixed(2) + "% · per arm " + fmtNum(perArm) + " · power " + power + " · alpha " + alpha);
417
+ console.log("smallest readable relative lift: none");
418
+ console.log("verdict: " + out.verdict);
419
+ }
420
+ return 0;
421
+ }
422
+ const pct = Math.round(lift * 1000) / 10;
423
+ const pp = Math.round(rate * lift * 100 * 100) / 100;
424
+ const verdict = pct >= 20
425
+ ? "at this volume only a difference of " + pct + "% or more is readable - a smaller win will not separate from noise, so the honest plan is a bigger volume before the first read"
426
+ : "at this volume a difference of " + pct + "% or more is readable - a plan that promises less than that is promising a number this test cannot produce";
427
+ const out = {
428
+ base_rate: rate, per_arm: perArm, power, alpha,
429
+ min_relative_lift: Math.round(lift * 1e9) / 1e9,
430
+ min_absolute_pp: pp, readable: true, verdict
431
+ };
432
+ if (opts.json) { console.log(JSON.stringify(out, null, 2)); } else {
433
+ console.log("base rate " + (rate * 100).toFixed(2) + "% · per arm " + fmtNum(perArm) + " · power " + power + " · alpha " + alpha);
434
+ console.log("smallest readable relative lift: " + pct + "% (" + pp + "pp absolute)");
435
+ console.log("contacts needed at that lift: " + fmtNum(sampleSize(rate, lift, power, alpha)) + " per arm");
436
+ console.log("verdict: " + verdict);
437
+ }
438
+ return 0;
439
+ }
440
+
386
441
  function fmtNum(n) {
387
442
  return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
388
443
  }
@@ -519,6 +574,8 @@ if (cmd === "sample") {
519
574
  process.exit(runBrief(flags(rest)));
520
575
  } else if (cmd === "plan") {
521
576
  process.exit(runPlan(flags(rest)));
577
+ } else if (cmd === "mde") {
578
+ process.exit(runMde(flags(rest)));
522
579
  } else if (cmd === "budget") {
523
580
  process.exit(runBudget(flags(rest)));
524
581
  } else if (cmd === "warmup") {
@@ -553,6 +610,8 @@ Usage:
553
610
  --base 0.03 --lift 0.2 --cpl 4 [--daily 500]
554
611
  npx marketing-mindset plan dated plan: weekly volume, gates, first honest read
555
612
  --base 0.03 --lift 0.2 --daily 500 [--weeks 4] [--start 2026-09-21]
613
+ npx marketing-mindset mde what a volume you can afford can actually read
614
+ --base 0.03 --per-arm 5000 [--power 0.8] [--alpha 0.05] [--json]
556
615
  npx marketing-mindset warmup day-by-day sending ramp with stop rules
557
616
  --start 2026-09-21 --target 200 --days 21 --mailboxes 4
558
617
  npx marketing-mindset jd marketing engineer job description
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "marketing-mindset",
3
- "version": "1.7.0",
4
- "description": "A marketer's operating mindset as an installable agent skill and CLI: test-size floors, kill rules, agent-readiness checklist, marketing-engineer job description. npx marketing-mindset sample|kill|budget|brief|plan|warmup|aeo|jd|sections|read|install.",
3
+ "version": "1.8.0",
4
+ "description": "A marketer's operating mindset as an installable agent skill and CLI: test-size floors, kill rules, the lift a volume can actually read, agent-readiness checklist, marketing-engineer job description. npx marketing-mindset sample|kill|mde|budget|brief|plan|warmup|aeo|jd|sections|read|install.",
5
5
  "keywords": [
6
6
  "agent-skill",
7
7
  "skill",
@@ -13,6 +13,7 @@
13
13
  "llm",
14
14
  "prompt",
15
15
  "sample-size",
16
+ "minimum-detectable-effect",
16
17
  "job-description",
17
18
  "cold-email",
18
19
  "deliverability",