thumbgate 1.16.19 โ†’ 1.16.20

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate-marketplace",
3
- "version": "1.16.19",
3
+ "version": "1.16.20",
4
4
  "owner": {
5
5
  "name": "Igor Ganapolsky",
6
6
  "email": "ig5973700@gmail.com"
@@ -13,7 +13,7 @@
13
13
  "source": "npm",
14
14
  "package": "thumbgate"
15
15
  },
16
- "version": "1.16.19",
16
+ "version": "1.16.20",
17
17
  "author": {
18
18
  "name": "Igor Ganapolsky"
19
19
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thumbgate",
3
3
  "description": "Type ๐Ÿ‘ or ๐Ÿ‘Ž on any agent action. ThumbGate captures it, distills a lesson, and blocks the pattern from repeating. One thumbs-down = the agent physically cannot make that mistake again. 33 pre-action checks, budget enforcement, self-protection, and NIST/SOC2 compliance tags.",
4
- "version": "1.16.19",
4
+ "version": "1.16.20",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.16.19",
3
+ "version": "1.16.20",
4
4
  "description": "ThumbGate โ€” ๐Ÿ‘๐Ÿ‘Ž feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
5
5
  "homepage": "https://thumbgate-production.up.railway.app",
6
6
  "transport": "stdio",
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.16.19", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.16.20", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.16.19", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.16.20", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -216,7 +216,7 @@ const {
216
216
  finalizeSession: finalizeFeedbackSession,
217
217
  } = require('../../scripts/feedback-session');
218
218
 
219
- const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.16.19' };
219
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.16.20' };
220
220
  const COMMERCE_CATEGORIES = [
221
221
  'product_recommendation',
222
222
  'brand_compliance',
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.16.19",
10
+ "thumbgate@1.16.20",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
@@ -20,8 +20,8 @@ const {
20
20
 
21
21
  // Tracked click-through path: /go/pro โ†’ /checkout/pro โ†’ Stripe.
22
22
  // This captures UTM attribution in our funnel before handing off to Stripe.
23
- const PRO_CTA_URL = 'https://thumbgate-production.up.railway.app/go/pro?utm_source=npm&utm_medium=postinstall&utm_campaign=first_dollar';
24
- const WORKFLOW_SPRINT_URL = 'https://thumbgate-production.up.railway.app/#workflow-sprint-intake';
23
+ const PRO_CTA_URL = 'https://thumbgate.ai/go/pro?utm_source=npm&utm_medium=postinstall&utm_campaign=first_dollar';
24
+ const WORKFLOW_SPRINT_URL = 'https://thumbgate.ai/#workflow-sprint-intake';
25
25
 
26
26
  process.stderr.write(`
27
27
  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.16.19",
3
+ "version": "1.16.20",
4
4
  "description": "Self-improving agent governance: type thumbs-up or thumbs-down on any AI agent action. ThumbGate turns every mistake into a prevention rule and blocks the pattern from repeating. One thumbs-down, never again. 33 pre-action checks, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
5
5
  "homepage": "https://thumbgate-production.up.railway.app",
6
6
  "repository": {
package/public/index.html CHANGED
@@ -696,7 +696,7 @@ __GA_BOOTSTRAP__
696
696
  <div id="pro-pitch" style="max-width:820px;margin:0 auto 32px;padding:24px 28px;background:linear-gradient(180deg,rgba(17,17,19,0.94) 0%,rgba(22,22,24,0.94) 100%);border:1px solid rgba(34,211,238,0.32);border-radius:20px;box-shadow:0 0 0 1px rgba(34,211,238,0.18),0 24px 64px rgba(0,0,0,0.35);text-align:left;">
697
697
  <div style="display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:16px;">
698
698
  <div>
699
- <div style="display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:999px;border:1px solid rgba(34,211,238,0.25);background:var(--cyan-dim);color:var(--cyan);font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;">Start 7-day free trial</div>
699
+ <div style="display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:999px;border:1px solid rgba(34,211,238,0.25);background:var(--cyan-dim);color:var(--cyan);font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;">Pay-now Pro</div>
700
700
  <h2 style="margin:10px 0 4px;font-size:22px;letter-spacing:-0.025em;line-height:1.2;">Go Pro โ€” one correction, every agent, every session.</h2>
701
701
  <p style="margin:0;font-size:13px;color:var(--text-muted);">Personal local dashboard ยท DPO export from real corrections ยท founder support on risky flows.</p>
702
702
  </div>
@@ -717,7 +717,7 @@ __GA_BOOTSTRAP__
717
717
  <a href="/checkout/pro?utm_source=website&utm_medium=hero_pricing_card&utm_campaign=pro_pack&cta_id=hero_pro_annual&cta_placement=hero_pricing&plan_id=pro&billing_cycle=annual&landing_path=%2F" onclick="posthog.capture('hero_pricing_annual_click',{cta:'choose_annual'})" style="display:inline-flex;align-items:center;gap:6px;padding:11px 20px;background:rgba(17,17,19,0.75);color:var(--text);border:1px solid var(--border);border-radius:999px;text-decoration:none;font-weight:700;font-size:14px;white-space:nowrap;">Choose annual โ†’</a>
718
718
  </div>
719
719
  </div>
720
- <p style="margin:14px 0 0;font-size:11px;color:var(--text-muted);text-align:center;">No credit card for 7-day trial ยท cancel anytime ยท your rules and captures stay local. <a href="/go/install" style="color:var(--cyan);text-decoration:none;">Prefer free? Install CLI โ†’</a></p>
720
+ <p style="margin:14px 0 0;font-size:11px;color:var(--text-muted);text-align:center;">Card required ยท billed today ยท cancel anytime ยท your rules and captures stay local. <a href="/go/install" style="color:var(--cyan);text-decoration:none;">Prefer free? Install CLI โ†’</a></p>
721
721
  </div>
722
722
 
723
723
  <div class="hero-paid-path" aria-label="Paid AI agent governance sprint checkout options">
@@ -773,7 +773,7 @@ __GA_BOOTSTRAP__
773
773
  <span class="copy-hint">click to copy</span>
774
774
  </div>
775
775
  <a href="/go/install?utm_source=website&utm_medium=hero_cta&utm_campaign=install_free&cta_id=hero_install_cli&cta_placement=hero" onclick="posthog.capture('hero_install_click',{cta:'install_cli'})" class="btn-gpt-page btn-install-hero" style="font-size:18px;padding:16px 36px;">Install Free CLI</a>
776
- <a href="/go/pro?utm_source=website&utm_medium=hero_cta&utm_campaign=pro_upgrade&cta_id=hero_go_pro&cta_placement=hero&plan_id=pro&landing_path=%2F" onclick="posthog.capture('hero_pro_click',{cta:'go_pro'})" class="btn-pro-page" style="font-size:18px;padding:16px 32px;background:linear-gradient(135deg,#f59e0b 0%,#ef4444 100%);color:#fff;font-weight:700;border-radius:10px;box-shadow:0 0 32px rgba(239,68,68,0.35);display:inline-flex;align-items:center;gap:8px;">Start 7-day Pro trial โ€” $19/mo <span style="font-size:12px;opacity:0.85;font-weight:500;">โ†’</span></a>
776
+ <a href="/go/pro?utm_source=website&utm_medium=hero_cta&utm_campaign=pro_upgrade&cta_id=hero_go_pro&cta_placement=hero&plan_id=pro&landing_path=%2F" onclick="posthog.capture('hero_pro_click',{cta:'go_pro'})" class="btn-pro-page" style="font-size:18px;padding:16px 32px;background:linear-gradient(135deg,#f59e0b 0%,#ef4444 100%);color:#fff;font-weight:700;border-radius:10px;box-shadow:0 0 32px rgba(239,68,68,0.35);display:inline-flex;align-items:center;gap:8px;">Start Pro โ€” $19/mo <span style="font-size:12px;opacity:0.85;font-weight:500;">โ†’</span></a>
777
777
  <div class="hero-secondary-ctas" style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-top:8px;opacity:0.7;">
778
778
  <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" class="btn-gpt-page" target="_blank" rel="noopener" onclick="posthog.capture('hero_claude_extension_click',{cta:'install_claude_extension'})" style="font-size:12px;padding:8px 16px;background:#d97706;color:#fff;box-shadow:none;">Install Claude Extension</a>
779
779
  <a href="/go/github?utm_source=website&utm_medium=hero_cta&utm_campaign=github_repo&cta_id=hero_star_github&cta_placement=hero" target="_blank" rel="noopener" class="btn-free" style="display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border-radius:999px;font-size:12px;">โญ Star on GitHub</a>
@@ -792,7 +792,7 @@ __GA_BOOTSTRAP__
792
792
  <div id="demo" style="margin:28px auto 0;max-width:560px;text-align:center;" onclick="posthog.capture('hero_demo_view')">
793
793
  <div style="font-size:13px;color:var(--text-muted);margin-bottom:8px;letter-spacing:0.04em;text-transform:uppercase;">โ–ถ 90-second demo ยท force-push โ†’ ๐Ÿ‘Ž โ†’ blocked</div>
794
794
  <video src="/assets/tiktok-agent-memory.mp4" controls playsinline preload="metadata" poster="/assets/instagram-card.png" style="width:100%;max-width:560px;border-radius:12px;border:1px solid var(--border);background:#000;box-shadow:0 10px 40px rgba(0,0,0,0.4);"></video>
795
- <a href="/checkout/pro?utm_source=website&utm_medium=hero_demo&utm_campaign=pro_trial&cta_id=hero_post_demo" onclick="posthog.capture('hero_cta_click',{cta:'start_trial_post_demo'})" style="display:inline-block;margin-top:14px;color:var(--cyan);font-size:14px;font-weight:700;text-decoration:none;">โ†’ Start 7-day Pro trial</a>
795
+ <a href="/checkout/pro?utm_source=website&utm_medium=hero_demo&utm_campaign=pro_trial&cta_id=hero_post_demo" onclick="posthog.capture('hero_cta_click',{cta:'start_trial_post_demo'})" style="display:inline-block;margin-top:14px;color:var(--cyan);font-size:14px;font-weight:700;text-decoration:none;">โ†’ Start Pro</a>
796
796
  </div>
797
797
  <p style="font-size:13px;color:var(--text-muted);margin:8px auto 28px;max-width:560px;">Your agent has no memory. Every session, the same wrong pattern runs. ThumbGate turns a single correction into a permanent block โ€” before the next tool call fires. <a href="#pricing" style="color:var(--cyan);text-decoration:none;">See all plans โ†’</a></p>
798
798
  <div class="first-check-card" id="first-check">
@@ -1300,7 +1300,7 @@ __GA_BOOTSTRAP__
1300
1300
  </div>
1301
1301
  <div class="autoresearch-cta">
1302
1302
  <a class="primary" href="/guides/autoresearch-agent-safety?utm_source=website&utm_medium=autoresearch_pack&utm_campaign=autoresearch_safety&cta_id=autoresearch_guide&cta_placement=autoresearch_pack">Read the Autoresearch guide</a>
1303
- <a class="secondary" href="/checkout/pro?utm_source=website&utm_medium=autoresearch_pack&utm_campaign=autoresearch_safety&cta_id=autoresearch_pro_trial&cta_placement=autoresearch_pack&plan_id=pro&landing_path=%2F">Start Pro trial</a>
1303
+ <a class="secondary" href="/checkout/pro?utm_source=website&utm_medium=autoresearch_pack&utm_campaign=autoresearch_safety&cta_id=autoresearch_pro_trial&cta_placement=autoresearch_pack&plan_id=pro&landing_path=%2F">Start Pro</a>
1304
1304
  </div>
1305
1305
  </div>
1306
1306
  </div>
@@ -1309,7 +1309,7 @@ __GA_BOOTSTRAP__
1309
1309
  <!-- HOW IT WORKS -->
1310
1310
  <section class="how-it-works" id="how-it-works">
1311
1311
  <div class="container">
1312
- <div class="section-label">New in v1.16.19</div>
1312
+ <div class="section-label">New in v1.16.20</div>
1313
1313
  <h2 class="section-title">Three steps to stop repeated AI failures</h2>
1314
1314
  <div class="steps">
1315
1315
  <div class="step">
@@ -1481,7 +1481,7 @@ __GA_BOOTSTRAP__
1481
1481
  <div class="price-sub">or $149/yr (save 35%) ยท Personal dashboard + enforcement proof</div>
1482
1482
  <p style="font-size:13px;color:var(--cyan);margin-bottom:16px;font-weight:500;">Unlimited captures, unlimited rules, full recall. $19/mo costs less than 20 minutes of re-fixing a mistake your agent already learned to avoid.</p>
1483
1483
  <div class="pro-upgrade-triggers" style="font-size:12px;color:#aaa;margin-bottom:12px;">
1484
- <strong style="color:#fff;">No credit card required.</strong> 7-day free trial. Cancel anytime. Your rules and captures stay local.
1484
+ <strong style="color:#fff;">Card required.</strong> Billed today. Cancel anytime. Your rules and captures stay local.
1485
1485
  </div>
1486
1486
  <div class="dashboard-preview" style="margin-bottom:16px;border:1px solid #333;border-radius:8px;overflow:hidden;">
1487
1487
  <div style="background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);padding:16px;text-align:center;">
@@ -1504,13 +1504,13 @@ __GA_BOOTSTRAP__
1504
1504
  <li>Personal local dashboard โ€” every Pro user gets a localhost dashboard without extra cloud setup</li>
1505
1505
  <li>Review-ready workflow support โ€” we help you wire the riskiest flows first: migrations, force-pushes, deploys, and CI</li>
1506
1506
  </ul>
1507
- <div class="trial-badge" style="background:var(--cyan);color:#000;display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:700;margin-bottom:12px;">7-DAY FREE TRIAL</div>
1507
+ <div class="trial-badge" style="background:var(--cyan);color:#000;display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:700;margin-bottom:12px;">PAY-NOW PRO</div>
1508
1508
  <div style="display:flex;gap:8px;margin-bottom:12px;">
1509
1509
  <input type="email" id="pro-email" data-buyer-email placeholder="you@company.com" style="flex:1;padding:10px 12px;border:1px solid var(--border);border-radius:8px;background:var(--bg-raised);color:var(--text);font-size:14px;">
1510
- <a href="/go/pro?utm_source=website&utm_medium=pricing_card&utm_campaign=pro_upgrade&cta_id=pricing_pro_upgrade&cta_placement=pricing&plan_id=pro&landing_path=%2F" id="pro-checkout-link" class="btn-pro" onclick="handleProTrial();return false;" style="display:flex;align-items:center;padding:10px 20px;font-size:14px;white-space:nowrap;">Start Free Trial</a>
1510
+ <a href="/go/pro?utm_source=website&utm_medium=pricing_card&utm_campaign=pro_upgrade&cta_id=pricing_pro_upgrade&cta_placement=pricing&plan_id=pro&landing_path=%2F" id="pro-checkout-link" class="btn-pro" onclick="handleProTrial();return false;" style="display:flex;align-items:center;padding:10px 20px;font-size:14px;white-space:nowrap;">Upgrade now</a>
1511
1511
  </div>
1512
1512
  <a href="/go/pro?utm_source=website&utm_medium=pricing_card&utm_campaign=pro_upgrade&cta_id=pricing_pro_upgrade&cta_placement=pricing&plan_id=pro&landing_path=%2F" class="btn-pro" onclick="posthog.capture('pricing_cta_click',{cta:'pro_upgrade',plan:'pro'})" style="display:block;width:100%;text-align:center;padding:12px;font-size:15px;">Upgrade to Pro โ€” $19/mo</a>
1513
- <p style="font-size:11px;color:#666;margin-top:8px;">No credit card required. Cancel anytime. Your rules and captures stay local.</p>
1513
+ <p style="font-size:11px;color:#666;margin-top:8px;">Card required. Billed today. Cancel anytime. Your rules and captures stay local.</p>
1514
1514
  </div>
1515
1515
  <div class="price-card team">
1516
1516
  <div class="tier">Team</div>
@@ -1656,7 +1656,7 @@ __GA_BOOTSTRAP__
1656
1656
  </div>
1657
1657
  <div class="faq-item">
1658
1658
  <div class="faq-q" role="button" tabindex="0" aria-expanded="false" onclick="toggleFaq(this)" onkeydown="handleFaqKeydown(event)">What does Pro cost?</div>
1659
- <div class="faq-a">Pro is $19/mo or $149/yr for individual operators and starts with a 7-day free trial, no credit card required. Team is $49/seat/mo with a 3-seat minimum and starts with the Workflow Hardening Sprint intake, not a self-serve trial.</div>
1659
+ <div class="faq-a">Pro is $19/mo or $149/yr for individual operators and bills immediately through Stripe so the self-serve path can create revenue today. Team is $49/seat/mo with a 3-seat minimum and starts with the Workflow Hardening Sprint intake, not a self-serve trial.</div>
1660
1660
  </div>
1661
1661
  </div>
1662
1662
  </div>
@@ -1708,7 +1708,7 @@ __GA_BOOTSTRAP__
1708
1708
  <a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
1709
1709
  <a href="/blog">Blog</a>
1710
1710
  </div>
1711
- <span class="footer-copy">ยฉ 2026 Max Smith KDP LLC ยท MIT License ยท v1.16.19</span>
1711
+ <span class="footer-copy">ยฉ 2026 Max Smith KDP LLC ยท MIT License ยท v1.16.20</span>
1712
1712
  </div>
1713
1713
  </footer>
1714
1714
 
@@ -25,9 +25,9 @@
25
25
  "alternateName": "thumbgate",
26
26
  "applicationCategory": "DeveloperApplication",
27
27
  "operatingSystem": "Cross-platform, Node.js >=18.18.0",
28
- "softwareVersion": "1.16.19",
28
+ "softwareVersion": "1.16.20",
29
29
  "url": "https://thumbgate-production.up.railway.app/numbers",
30
- "dateModified": "2026-05-04",
30
+ "dateModified": "2026-05-05",
31
31
  "creator": {
32
32
  "@type": "Person",
33
33
  "name": "Igor Ganapolsky",
@@ -57,8 +57,8 @@
57
57
  "https://www.linkedin.com/in/igorganapolsky"
58
58
  ]
59
59
  },
60
- "dateModified": "2026-05-04",
61
- "datePublished": "2026-05-04",
60
+ "dateModified": "2026-05-05",
61
+ "datePublished": "2026-05-05",
62
62
  "keywords": [
63
63
  "AI agent gates",
64
64
  "LLM token savings",
@@ -70,7 +70,7 @@
70
70
  {
71
71
  "@type": "PropertyValue",
72
72
  "name": "active_gates",
73
- "value": 36
73
+ "value": 37
74
74
  },
75
75
  {
76
76
  "@type": "PropertyValue",
@@ -101,7 +101,7 @@
101
101
  {
102
102
  "@type": "PropertyValue",
103
103
  "name": "bayes_error_rate",
104
- "value": null
104
+ "value": 0
105
105
  }
106
106
  ]
107
107
  }
@@ -190,14 +190,14 @@
190
190
  <main class="container">
191
191
  <h1>The Numbers</h1>
192
192
  <p class="subtitle">Generated first-party operational data from the ThumbGate runtime. No surveys or projections โ€” this page is a release-time snapshot produced by the same local scripts that power the CLI and dashboard.</p>
193
- <div class="freshness">Updated: 2026-05-04 ยท Version 1.16.19</div>
193
+ <div class="freshness">Updated: 2026-05-05 ยท Version 1.16.20</div>
194
194
 
195
195
  <h2>Gate enforcement</h2>
196
196
  <div class="stats-grid">
197
197
  <div class="stat-card">
198
198
  <div class="stat-label">Active gates</div>
199
- <div class="stat-value">36</div>
200
- <div class="stat-sub">36 manual ยท 0 auto-promoted</div>
199
+ <div class="stat-value">37</div>
200
+ <div class="stat-sub">36 manual ยท 1 auto-promoted</div>
201
201
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
202
202
  </div>
203
203
  <div class="stat-card">
@@ -242,7 +242,7 @@
242
242
  </div>
243
243
  <div class="stat-card">
244
244
  <div class="stat-label">Scorer Bayes error</div>
245
- <div class="stat-value">n/a (no feedback sequences recorded yet)</div>
245
+ <div class="stat-value">0.0%</div>
246
246
  <div class="stat-sub">irreducible error given current feature set</div>
247
247
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/bayes-optimal-gate.js">source: bayes-optimal-gate.js</a>
248
248
  </div>
@@ -264,7 +264,7 @@
264
264
  <div class="cta">
265
265
  <a href="https://www.npmjs.com/package/thumbgate">Install ThumbGate โ€” npx thumbgate init</a>
266
266
  <div class="footer-note">Prefer the raw feed? See <a href="https://github.com/IgorGanapolsky/ThumbGate">GitHub</a> or run <code>npm run gate:stats</code> locally.</div>
267
- <div class="footer-note">Generated at 2026-05-04T21:47:27.878Z UTC.</div>
267
+ <div class="footer-note">Generated at 2026-05-05T14:49:47.056Z UTC.</div>
268
268
  </div>
269
269
  </main>
270
270
  </body>
package/public/pro.html CHANGED
@@ -796,7 +796,7 @@ __GA_BOOTSTRAP__
796
796
  <a href="#pricing">Pricing</a>
797
797
  <a href="#faq">FAQ</a>
798
798
  <a href="/dashboard">Demo</a>
799
- <a class="nav-cta btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_nav&utm_campaign=pro_pack&cta_id=pro_page_nav&cta_placement=nav&plan_id=pro&landing_path=%2Fpro">Start 7-Day Free Trial</a>
799
+ <a class="nav-cta btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_nav&utm_campaign=pro_pack&cta_id=pro_page_nav&cta_placement=nav&plan_id=pro&landing_path=%2Fpro">Start Pro Now</a>
800
800
  </div>
801
801
  </div>
802
802
  </nav>
@@ -816,7 +816,7 @@ __GA_BOOTSTRAP__
816
816
  <div class="proof-pill">Founder support on risky flows</div>
817
817
  </div>
818
818
  <div class="hero-actions">
819
- <a class="btn-primary btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_hero&utm_campaign=pro_pack&cta_id=pro_page_primary&cta_placement=hero&plan_id=pro&landing_path=%2Fpro">Start 7-Day Free Trial</a>
819
+ <a class="btn-primary btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_hero&utm_campaign=pro_pack&cta_id=pro_page_primary&cta_placement=hero&plan_id=pro&landing_path=%2Fpro">Start Pro Now</a>
820
820
  <a class="btn-secondary btn-demo" href="/dashboard?utm_source=website&utm_medium=pro_page&utm_campaign=pro_pack">Open dashboard demo</a>
821
821
  <a class="btn-ghost btn-free-path" href="/guide?utm_source=website&utm_medium=pro_page&utm_campaign=free_install">Stay on Free and install locally</a>
822
822
  </div>
@@ -860,7 +860,7 @@ __GA_BOOTSTRAP__
860
860
  <input type="email" name="email" data-buyer-email placeholder="you@company.com" required>
861
861
  <div class="buyer-form-actions">
862
862
  <button type="submit" class="btn-secondary">Email me the demo</button>
863
- <button type="button" class="btn-primary btn-email-checkout">Start trial with this email</button>
863
+ <button type="button" class="btn-primary btn-email-checkout">Start Pro with this email</button>
864
864
  </div>
865
865
  <p class="buyer-form-note">No sales deck. Just the Pro demo path, launch updates, and a prefilled checkout when you are ready.</p>
866
866
  <p class="buyer-form-status" data-newsletter-status aria-live="polite"></p>
@@ -962,7 +962,7 @@ __GA_BOOTSTRAP__
962
962
  <div class="section-label" style="text-align:left;margin-bottom:8px;">Pricing</div>
963
963
  <h3>ThumbGate Pro</h3>
964
964
  <div class="price">$19<span>/mo</span></div>
965
- <div class="annual">$149/year available ยท 7-day trial ยท Card required, no charge today</div>
965
+ <div class="annual">$149/year available ยท Card required ยท billed today</div>
966
966
  <p class="pricing-note">For the individual operator who wants a personal local dashboard, DPO export, review-ready evidence, and founder help on the first risky workflow.</p>
967
967
  <ul>
968
968
  <li><strong>Personal local dashboard</strong> โ€” inspect blocked actions, active checks, and lesson evidence without a cloud account.</li>
@@ -971,7 +971,7 @@ __GA_BOOTSTRAP__
971
971
  <li><strong>Founder support</strong> โ€” get help hardening the first force-push, deploy, migration, or CI failure that keeps repeating.</li>
972
972
  </ul>
973
973
  <div class="pricing-actions">
974
- <a class="btn-primary btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_pricing&utm_campaign=pro_pack&cta_id=pricing_pro&cta_placement=pricing&plan_id=pro&landing_path=%2Fpro">Start 7-Day Free Trial</a>
974
+ <a class="btn-primary btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_pricing&utm_campaign=pro_pack&cta_id=pricing_pro&cta_placement=pricing&plan_id=pro&landing_path=%2Fpro">Start Pro Now</a>
975
975
  <a class="btn-secondary btn-pro-checkout" href="/checkout/pro?utm_source=website&utm_medium=pro_page_pricing&utm_campaign=pro_pack&cta_id=pricing_pro_annual&cta_placement=pricing&plan_id=pro&billing_cycle=annual&landing_path=%2Fpro">Choose annual</a>
976
976
  </div>
977
977
  <div class="pricing-meta">Best for one operator with one repeated failure to prove. Stay on Free if you only need the local install; buy Pro when the dashboard, export, and proof trail save you time.</div>
@@ -2523,6 +2523,23 @@ function buildCheckoutSessionPayload({ successUrl, cancelUrl, customerEmail, che
2523
2523
  quantity: checkoutSelection.quantity,
2524
2524
  }];
2525
2525
 
2526
+ const explicitTrialDays = normalizeInteger(
2527
+ checkoutMetadata?.trialPeriodDays
2528
+ ?? checkoutMetadata?.trial_period_days
2529
+ ?? checkoutMetadata?.trialDays
2530
+ ?? checkoutMetadata?.trial_days
2531
+ );
2532
+ const trialFlag = (normalizeText(checkoutMetadata?.trial) || '').toLowerCase();
2533
+ const shouldStartTrial = !pack && (
2534
+ explicitTrialDays > 0
2535
+ || trialFlag === '1'
2536
+ || trialFlag === 'true'
2537
+ || trialFlag === 'yes'
2538
+ );
2539
+ const trialPeriodDays = explicitTrialDays > 0
2540
+ ? Math.min(explicitTrialDays, 30)
2541
+ : 7;
2542
+
2526
2543
  const sessionPayload = {
2527
2544
  success_url: successUrl,
2528
2545
  cancel_url: cancelUrl,
@@ -2539,10 +2556,9 @@ function buildCheckoutSessionPayload({ successUrl, cancelUrl, customerEmail, che
2539
2556
  packId: pack ? pack.id : null,
2540
2557
  credits: pack ? pack.credits : null,
2541
2558
  }),
2542
- // Keep the trial, but require a payment method so trials can convert without dunning.
2543
2559
  ...(pack ? {} : {
2544
- subscription_data: { trial_period_days: 7 },
2545
2560
  payment_method_collection: 'always',
2561
+ ...(shouldStartTrial ? { subscription_data: { trial_period_days: trialPeriodDays } } : {}),
2546
2562
  }),
2547
2563
  };
2548
2564
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const PRO_MONTHLY_PAYMENT_LINK = 'https://thumbgate-production.up.railway.app/go/pro?utm_source=offer';
3
+ const PRO_MONTHLY_PAYMENT_LINK = 'https://thumbgate.ai/go/pro?utm_source=offer';
4
4
  const PRO_ANNUAL_PAYMENT_LINK = 'https://buy.stripe.com/3cI8wPfCYaPs2dzdKz3sI07';
5
5
 
6
6
  const PRO_MONTHLY_PRICE_ID = 'price_1THQY7GGBpd520QYHoS7RG0J';
@@ -19,6 +19,7 @@ const MARKETING_CLICK_EVENT_TYPES = new Set([
19
19
  'cta_click',
20
20
  'checkout_start',
21
21
  'checkout_bootstrap',
22
+ 'checkout_interstitial_cta_clicked',
22
23
  'chatgpt_gpt_open',
23
24
  'chatgpt_gpt_click',
24
25
  'install_guide_click',
@@ -324,6 +325,7 @@ function sanitizeTelemetryPayload(payload = {}, headers = {}) {
324
325
  maxScrollPercent: normalizeInteger(raw.maxScrollPercent ?? raw.scrollPercent),
325
326
  buyerEmailFocused: Boolean(raw.buyerEmailFocused),
326
327
  buyerEmailCaptured: Boolean(raw.buyerEmailCaptured),
328
+ checkoutIntentClassification: pickFirstText(raw.checkoutIntentClassification),
327
329
  trafficChannel: inferTrafficChannel(raw, referrerHost),
328
330
  failureCode: pickFirstText(raw.failureCode),
329
331
  httpStatus: normalizeInteger(raw.httpStatus),
@@ -490,6 +492,14 @@ function getTelemetrySummary(feedbackDir, options = {}) {
490
492
  let ctaClicks = 0;
491
493
  let ctaImpressions = 0;
492
494
  let checkoutStarts = 0;
495
+ let checkoutInterstitialViews = 0;
496
+ let checkoutBotDeflections = 0;
497
+ let checkoutInterstitialClicks = 0;
498
+ let checkoutInterstitialProConfirms = 0;
499
+ let checkoutInterstitialWorkflowIntakeClicks = 0;
500
+ let checkoutInterstitialTeamPathClicks = 0;
501
+ let checkoutInterstitialDiagnosticCheckoutClicks = 0;
502
+ let checkoutInterstitialWorkflowSprintCheckoutClicks = 0;
493
503
  let checkoutFailures = 0;
494
504
  let checkoutCancelled = 0;
495
505
  let checkoutAbandoned = 0;
@@ -561,6 +571,29 @@ function getTelemetrySummary(feedbackDir, options = {}) {
561
571
  }
562
572
  }
563
573
 
574
+ if ((entry.eventType || entry.event) === 'checkout_interstitial_view') {
575
+ checkoutInterstitialViews += 1;
576
+ }
577
+
578
+ if ((entry.eventType || entry.event) === 'checkout_bot_deflected') {
579
+ checkoutBotDeflections += 1;
580
+ }
581
+
582
+ if ((entry.eventType || entry.event) === 'checkout_interstitial_cta_clicked') {
583
+ checkoutInterstitialClicks += 1;
584
+ if (entry.ctaId === 'pro_checkout_confirmed') {
585
+ checkoutInterstitialProConfirms += 1;
586
+ } else if (entry.ctaId === 'workflow_sprint_intake') {
587
+ checkoutInterstitialWorkflowIntakeClicks += 1;
588
+ } else if (entry.ctaId === 'team_paid_path') {
589
+ checkoutInterstitialTeamPathClicks += 1;
590
+ } else if (entry.ctaId === 'sprint_diagnostic_checkout') {
591
+ checkoutInterstitialDiagnosticCheckoutClicks += 1;
592
+ } else if (entry.ctaId === 'workflow_sprint_checkout') {
593
+ checkoutInterstitialWorkflowSprintCheckoutClicks += 1;
594
+ }
595
+ }
596
+
564
597
  if ((entry.eventType || entry.event) === 'checkout_start' || (entry.eventType || entry.event) === 'checkout_bootstrap') {
565
598
  checkoutStarts += 1;
566
599
  incrementCounter(checkoutStartsBySource, entry.source);
@@ -737,11 +770,15 @@ function getTelemetrySummary(feedbackDir, options = {}) {
737
770
  installCopies,
738
771
  gptOpens,
739
772
  checkoutStarts,
773
+ checkoutInterstitialViews,
774
+ checkoutInterstitialClicks,
740
775
  trialEmails,
741
776
  proConversions,
742
777
  landingToInstallCopyRate: safeRate(installCopies, pageViews),
743
778
  landingToGptOpenRate: safeRate(gptOpens, pageViews),
744
779
  landingToCheckoutRate: safeRate(checkoutStarts, pageViews),
780
+ checkoutInterstitialClickRate: safeRate(checkoutInterstitialClicks, checkoutInterstitialViews),
781
+ checkoutInterstitialProConfirmRate: safeRate(checkoutInterstitialProConfirms, checkoutInterstitialViews),
745
782
  checkoutToTrialEmailRate: safeRate(trialEmails, checkoutStarts),
746
783
  checkoutToProConversionRate: safeRate(proConversions, checkoutStarts),
747
784
  },
@@ -753,6 +790,14 @@ function getTelemetrySummary(feedbackDir, options = {}) {
753
790
  pageViews,
754
791
  ctaClicks,
755
792
  checkoutStarts,
793
+ checkoutInterstitialViews,
794
+ checkoutBotDeflections,
795
+ checkoutInterstitialClicks,
796
+ checkoutInterstitialProConfirms,
797
+ checkoutInterstitialWorkflowIntakeClicks,
798
+ checkoutInterstitialTeamPathClicks,
799
+ checkoutInterstitialDiagnosticCheckoutClicks,
800
+ checkoutInterstitialWorkflowSprintCheckoutClicks,
756
801
  checkoutFailures,
757
802
  checkoutCancelled,
758
803
  checkoutAbandoned,
@@ -915,6 +960,14 @@ function getTelemetryAnalytics(feedbackDir, options = {}) {
915
960
  ctas: {
916
961
  totalClicks: summary.web.ctaClicks,
917
962
  checkoutStarts: summary.web.checkoutStarts,
963
+ checkoutInterstitialViews: summary.web.checkoutInterstitialViews,
964
+ checkoutBotDeflections: summary.web.checkoutBotDeflections,
965
+ checkoutInterstitialClicks: summary.web.checkoutInterstitialClicks,
966
+ checkoutInterstitialProConfirms: summary.web.checkoutInterstitialProConfirms,
967
+ checkoutInterstitialWorkflowIntakeClicks: summary.web.checkoutInterstitialWorkflowIntakeClicks,
968
+ checkoutInterstitialTeamPathClicks: summary.web.checkoutInterstitialTeamPathClicks,
969
+ checkoutInterstitialDiagnosticCheckoutClicks: summary.web.checkoutInterstitialDiagnosticCheckoutClicks,
970
+ checkoutInterstitialWorkflowSprintCheckoutClicks: summary.web.checkoutInterstitialWorkflowSprintCheckoutClicks,
918
971
  uniqueCheckoutStarters: summary.web.uniqueCheckoutStarters,
919
972
  checkoutFailures: summary.web.checkoutFailures,
920
973
  checkoutCancelled: summary.web.checkoutCancelled,
@@ -950,6 +1003,30 @@ function getTelemetryAnalytics(feedbackDir, options = {}) {
950
1003
  pageViewToCheckoutRate: summary.web.pageViewToCheckoutRate,
951
1004
  visitorToCheckoutRate: summary.web.visitorToCheckoutRate,
952
1005
  clickToCheckoutRate: safeRate(summary.web.checkoutStarts, summary.web.ctaClicks),
1006
+ checkoutInterstitialClickRate: safeRate(
1007
+ summary.web.checkoutInterstitialClicks,
1008
+ summary.web.checkoutInterstitialViews
1009
+ ),
1010
+ checkoutInterstitialProConfirmRate: safeRate(
1011
+ summary.web.checkoutInterstitialProConfirms,
1012
+ summary.web.checkoutInterstitialViews
1013
+ ),
1014
+ checkoutInterstitialWorkflowIntakeRate: safeRate(
1015
+ summary.web.checkoutInterstitialWorkflowIntakeClicks,
1016
+ summary.web.checkoutInterstitialViews
1017
+ ),
1018
+ checkoutInterstitialTeamPathRate: safeRate(
1019
+ summary.web.checkoutInterstitialTeamPathClicks,
1020
+ summary.web.checkoutInterstitialViews
1021
+ ),
1022
+ checkoutInterstitialDiagnosticCheckoutRate: safeRate(
1023
+ summary.web.checkoutInterstitialDiagnosticCheckoutClicks,
1024
+ summary.web.checkoutInterstitialViews
1025
+ ),
1026
+ checkoutInterstitialWorkflowSprintCheckoutRate: safeRate(
1027
+ summary.web.checkoutInterstitialWorkflowSprintCheckoutClicks,
1028
+ summary.web.checkoutInterstitialViews
1029
+ ),
953
1030
  cancellationRate: safeRate(summary.web.checkoutCancelled, summary.web.checkoutStarts),
954
1031
  abandonmentRate: safeRate(summary.web.checkoutAbandoned, summary.web.checkoutStarts),
955
1032
  paidConfirmationRate: safeRate(summary.web.checkoutPaidConfirmations, summary.web.checkoutStarts),
package/src/api/server.js CHANGED
@@ -1453,6 +1453,40 @@ function buildCheckoutFallbackUrl(baseUrl, metadata = {}) {
1453
1453
  return restoreStripeCheckoutPlaceholder(url.toString());
1454
1454
  }
1455
1455
 
1456
+ function buildCheckoutIntentHref(baseUrl, metadata = {}, overrides = {}) {
1457
+ return buildCheckoutFallbackUrl(baseUrl, {
1458
+ ...metadata,
1459
+ ...overrides,
1460
+ });
1461
+ }
1462
+
1463
+ function renderCheckoutIntentPage({
1464
+ confirmHref,
1465
+ workflowIntakeHref,
1466
+ teamOptionsHref,
1467
+ diagnosticCheckoutHref,
1468
+ sprintCheckoutHref,
1469
+ sprintDiagnosticPriceDollars = 499,
1470
+ workflowSprintPriceDollars = 1500,
1471
+ }) {
1472
+ const safeConfirmHref = escapeHtmlAttribute(confirmHref);
1473
+ const safeWorkflowIntakeHref = escapeHtmlAttribute(workflowIntakeHref);
1474
+ const safeTeamOptionsHref = escapeHtmlAttribute(teamOptionsHref);
1475
+ const safeDiagnosticCheckoutHref = diagnosticCheckoutHref
1476
+ ? escapeHtmlAttribute(diagnosticCheckoutHref)
1477
+ : '';
1478
+ const safeSprintCheckoutHref = sprintCheckoutHref
1479
+ ? escapeHtmlAttribute(sprintCheckoutHref)
1480
+ : '';
1481
+ const diagnosticAction = safeDiagnosticCheckoutHref
1482
+ ? `<a data-i="sprint_diagnostic_checkout" href="${safeDiagnosticCheckoutHref}">Book $${sprintDiagnosticPriceDollars} diagnostic</a>`
1483
+ : '';
1484
+ const sprintAction = safeSprintCheckoutHref
1485
+ ? `<a data-i="workflow_sprint_checkout" href="${safeSprintCheckoutHref}">Start $${workflowSprintPriceDollars} sprint</a>`
1486
+ : '';
1487
+ return `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>body{background:#0a0a0a;color:#eee;font-family:system-ui,sans-serif}div{max-width:560px;margin:12vh auto}a{display:block;margin:10px 0;padding:12px;border:1px solid #374151;color:inherit;text-align:center}.primary{background:#22d3ee;color:#000}</style><div><h1>Choose the right paid path.</h1><p>Pick Pro, diagnostic, sprint, or intake.</p><a class="primary" data-i="pro_checkout_confirmed" href="${safeConfirmHref}">Continue to Stripe</a>${diagnosticAction}${sprintAction}<a data-i="workflow_sprint_intake" href="${safeWorkflowIntakeHref}">Send workflow first</a><a data-i="team_paid_path" href="${safeTeamOptionsHref}">See diagnostic and sprint options</a><p>Stripe checkout.</p><a href="/">Back</a></div><script>addEventListener('click',e=>{let a=e.target.closest('[data-i]');if(a&&navigator.sendBeacon)navigator.sendBeacon('/v1/telemetry/ping',new Blob([JSON.stringify({eventType:'checkout_interstitial_cta_clicked',clientType:'web',page:'/checkout/pro',ctaId:a.dataset.i,ctaPlacement:'checkout_interstitial'})],{type:'application/json'}))})</script>`;
1488
+ }
1489
+
1456
1490
  function buildCheckoutBootstrapBody(parsed, req, journeyState = resolveJourneyState(req, parsed)) {
1457
1491
  const params = parsed.searchParams;
1458
1492
  const traceId = pickFirstText(params.get('trace_id')) || createJourneyId('checkout');
@@ -1505,6 +1539,26 @@ function buildCheckoutConfirmHref(parsed) {
1505
1539
  return `${confirmUrl.pathname}${confirmUrl.search}`;
1506
1540
  }
1507
1541
 
1542
+ function normalizeCheckoutCustomerEmail(value) {
1543
+ const email = (normalizeNullableText(value) || '').toLowerCase();
1544
+ const atIndex = email.indexOf('@');
1545
+ const domain = email.slice(atIndex + 1);
1546
+ if (!email || email.length > 254 || atIndex <= 0 || atIndex !== email.lastIndexOf('@') || !domain || !domain.includes('.') || domain.startsWith('.') || domain.endsWith('.') || domain.includes('..')) return null;
1547
+ for (const ch of email) if (ch <= ' ' || ch === '<' || ch === '>' || ch === '"') return null;
1548
+ return email;
1549
+ }
1550
+
1551
+ function renderCheckoutIntentGate(parsed, responseHeaders = {}) {
1552
+ let hiddenInputs = '';
1553
+ for (const [key, value] of parsed.searchParams.entries()) {
1554
+ if (key !== 'confirm' && key !== 'customer_email') hiddenInputs += `<input type=hidden name=${escapeHtmlAttribute(key)} value=${escapeHtmlAttribute(value)}>`;
1555
+ }
1556
+ return {
1557
+ html: `<!doctype html><h1>Email for Stripe receipt</h1><form action=/checkout/pro>${hiddenInputs}<input type=hidden name=confirm value=1><input name=customer_email type=email required><button>Continue</button></form>`,
1558
+ headers: responseHeaders,
1559
+ };
1560
+ }
1561
+
1508
1562
  function normalizeTrackedLinkSlug(value) {
1509
1563
  return String(value || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '');
1510
1564
  }
@@ -1746,9 +1800,7 @@ function appendBestEffortTelemetry(feedbackDir, payload, headers, context) {
1746
1800
  evidence: [err && err.message ? err.message : 'unknown_error'],
1747
1801
  },
1748
1802
  });
1749
- } catch (_) {
1750
- // Public telemetry remains best-effort even when diagnostics fail.
1751
- }
1803
+ } catch (_) {}
1752
1804
  return false;
1753
1805
  }
1754
1806
  }
@@ -2055,7 +2107,6 @@ a{color:#22d3ee;text-decoration:none}</style></head><body>
2055
2107
  const timestamp = merged.timestamp ? new Date(merged.timestamp).toLocaleString() : '';
2056
2108
  const isoTimestamp = merged.timestamp || '';
2057
2109
 
2058
- // Technical metadata
2059
2110
  const failureType = merged.failureType || null;
2060
2111
  const skill = merged.skill || null;
2061
2112
  const source = merged.source || fb.source || null;
@@ -2066,19 +2117,12 @@ a{color:#22d3ee;text-decoration:none}</style></head><body>
2066
2117
  const guardrails = merged.guardrails || null;
2067
2118
  const rubricScores = merged.rubricScores || null;
2068
2119
 
2069
- // Structured rule
2070
2120
  const rule = merged.structuredRule || merged.rule || null;
2071
- // Conversation window
2072
2121
  const convoWindow = merged.conversationWindow || merged.chatHistory || [];
2073
- // Reflector analysis
2074
2122
  const reflector = merged.reflectorAnalysis || merged.reflector || null;
2075
- // Diagnosis
2076
2123
  const diagnosis = merged.diagnosis || null;
2077
- // Rubric
2078
2124
  const rubric = merged.rubricEvaluation || merged.rubric || null;
2079
- // Synthesis
2080
2125
  const synthesis = merged.synthesis || null;
2081
- // Bayesian
2082
2126
  const bayesian = merged.bayesianBelief || merged.bayesian || null;
2083
2127
 
2084
2128
  function sectionCard(titleText, content, id) {
@@ -2501,14 +2545,6 @@ function servePublicMarketingPage({
2501
2545
  'landing_page_view'
2502
2546
  );
2503
2547
 
2504
- // Funnel-ledger write (2026-04-21): populate funnel-events.jsonl with a
2505
- // discovery-stage event on every landing-page view so UTM-tagged social
2506
- // traffic becomes visible in `npm run feedback:summary` and
2507
- // `bin/cli.js cfo --today`. Prior to this wire, landing views wrote only
2508
- // to telemetry-pings.jsonl (invisible to the CEO-facing revenue surface),
2509
- // leaving funnel-events.jsonl empty despite 404 published Zernio posts.
2510
- // Best-effort: wrapped in try/catch so a billing-ledger hiccup never
2511
- // breaks a page render.
2512
2548
  try {
2513
2549
  appendFunnelEvent({
2514
2550
  stage: 'discovery',
@@ -3361,10 +3397,8 @@ function isAuthorized(req, expected) {
3361
3397
  if (!expected) return true;
3362
3398
  const token = extractApiKey(req);
3363
3399
 
3364
- // Check static THUMBGATE_API_KEY first
3365
3400
  if (token === expected) return true;
3366
3401
 
3367
- // Also accept any valid provisioned billing key
3368
3402
  if (token) {
3369
3403
  const result = validateApiKey(token);
3370
3404
  return result.valid === true;
@@ -3373,9 +3407,6 @@ function isAuthorized(req, expected) {
3373
3407
  return false;
3374
3408
  }
3375
3409
 
3376
- /**
3377
- * Extract the Bearer token from a request (returns '' if absent).
3378
- */
3379
3410
  function extractBearerToken(req) {
3380
3411
  const auth = req.headers.authorization || '';
3381
3412
  return auth.startsWith('Bearer ') ? auth.slice(7) : '';
@@ -3537,15 +3568,6 @@ function createApiServer() {
3537
3568
  const expectedApiKey = getExpectedApiKey();
3538
3569
  const expectedOperatorKey = getExpectedOperatorKey();
3539
3570
 
3540
- // Live-event bus. Feedback captures, prevention-rule regenerations, and
3541
- // gate decisions push to this emitter; the /v1/events SSE endpoint streams
3542
- // those events to connected dashboard clients so they render in real time
3543
- // instead of waiting for the next manual refresh.
3544
- //
3545
- // See .changeset/dashboard-sse-live.md for the ROI rationale โ€” this is a
3546
- // direct application of the "persistent channel beats per-turn HTTP" pattern
3547
- // to ThumbGate's dashboard surface (the primary UI for watching team
3548
- // feedback flow).
3549
3571
  const eventBus = new EventEmitter();
3550
3572
  eventBus.setMaxListeners(200);
3551
3573
 
@@ -4386,37 +4408,94 @@ async function addContext(){
4386
4408
  ? { 'Set-Cookie': journeyState.setCookieHeaders }
4387
4409
  : {};
4388
4410
 
4389
- // โ”€โ”€ Bot guard โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
4390
- // Creating a Stripe Checkout session on every GET means crawlers,
4391
- // link-preview fetchers, and LLM scrapers inflate "sessions opened"
4392
- // while completions stay at zero. Serve bots an interstitial HTML
4393
- // page instead โ€” no Stripe session created, no funnel pollution.
4394
- // The `?confirm=1` query param or POST below is the real-user path.
4395
4411
  const botClassification = classifyRequester(req.headers);
4396
4412
  const confirmParam = parsed?.searchParams?.get('confirm') ?? null;
4397
4413
  const isConfirmedCheckout = confirmParam === '1'
4398
4414
  || confirmParam === 'true'
4399
4415
  || req.method === 'POST';
4400
- if (botClassification.isBot && !isConfirmedCheckout) {
4416
+ if (!isConfirmedCheckout) {
4417
+ const eventType = botClassification.isBot ? 'checkout_bot_deflected' : 'checkout_interstitial_view';
4401
4418
  appendBestEffortTelemetry(FEEDBACK_DIR, {
4402
- eventType: 'checkout_bot_deflected',
4419
+ eventType,
4403
4420
  clientType: 'web',
4404
4421
  traceId,
4422
+ acquisitionId: analyticsMetadata.acquisitionId,
4423
+ visitorId: analyticsMetadata.visitorId,
4424
+ sessionId: analyticsMetadata.sessionId,
4405
4425
  utmSource: analyticsMetadata.utmSource,
4406
4426
  utmMedium: analyticsMetadata.utmMedium,
4407
4427
  utmCampaign: analyticsMetadata.utmCampaign,
4428
+ utmContent: analyticsMetadata.utmContent,
4429
+ utmTerm: analyticsMetadata.utmTerm,
4408
4430
  referrer: analyticsMetadata.referrer,
4409
4431
  referrerHost: analyticsMetadata.referrerHost,
4410
4432
  page: '/checkout/pro',
4433
+ ctaId: analyticsMetadata.ctaId,
4434
+ ctaPlacement: analyticsMetadata.ctaPlacement,
4411
4435
  planId: analyticsMetadata.planId,
4412
4436
  reason: botClassification.reason,
4413
- }, req.headers, 'checkout_bot_deflected');
4414
- const confirmHref = escapeHtmlAttribute(buildCheckoutConfirmHref(parsed));
4415
- const html = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>ThumbGate Pro \u2014 Confirm checkout</title><style>*{box-sizing:border-box}body{background:#0a0a0a;color:#e5e5e5;font-family:system-ui,-apple-system,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:20px}.card{background:#141414;border:1px solid #222;border-radius:16px;padding:48px 40px;max-width:460px;width:100%;text-align:center;box-shadow:0 8px 32px rgba(0,0,0,.5)}h1{margin:0 0 12px;font-size:22px;color:#22d3ee}p{color:#9ca3af;font-size:14px;line-height:1.55;margin:0 0 24px}.btn{display:inline-block;background:#22d3ee;color:#000;text-decoration:none;font-weight:700;padding:14px 32px;border-radius:999px;font-size:16px;cursor:pointer;border:none}.btn:hover{opacity:.9}.sub{margin-top:16px;font-size:12px;color:#6b7280}a.back{color:#6b7280;font-size:13px;text-decoration:underline}</style></head><body><div class="card"><h1>Continue to secure checkout</h1><p>You're one click from ThumbGate Pro at $19/mo. We create the payment session only after you confirm \u2014 keeps your path clean and our funnel honest.</p><a class="btn" href="${confirmHref}" rel="noopener">Continue to Stripe \u2192</a><div class="sub">Payments handled by Stripe. 7-day trial. Card required; no charge today. Cancel anytime.</div><div class="sub"><a class="back" href="/">\u2190 Back to homepage</a></div></div></body></html>`;
4437
+ }, req.headers, eventType);
4438
+ const workflowIntakeHref = buildCheckoutIntentHref(`${hostedConfig.appOrigin}/#workflow-sprint-intake`, analyticsMetadata, {
4439
+ utmMedium: 'checkout_interstitial_recovery',
4440
+ utmCampaign: analyticsMetadata.utmCampaign || 'checkout_interstitial_workflow_sprint',
4441
+ ctaId: 'checkout_interstitial_workflow_sprint_intake',
4442
+ ctaPlacement: 'checkout_interstitial',
4443
+ planId: 'team',
4444
+ });
4445
+ const teamOptionsHref = buildCheckoutIntentHref(`${hostedConfig.appOrigin}/guides/ai-agent-governance-sprint`, analyticsMetadata, {
4446
+ utmMedium: 'checkout_interstitial_paid_path',
4447
+ utmCampaign: analyticsMetadata.utmCampaign || 'checkout_interstitial_team_paid_path',
4448
+ ctaId: 'checkout_interstitial_team_paid_path',
4449
+ ctaPlacement: 'checkout_interstitial',
4450
+ planId: 'team',
4451
+ });
4452
+ const diagnosticCheckoutHref = hostedConfig.sprintDiagnosticCheckoutUrl
4453
+ ? buildCheckoutIntentHref(hostedConfig.sprintDiagnosticCheckoutUrl, analyticsMetadata, {
4454
+ utmMedium: 'checkout_interstitial_paid_path',
4455
+ utmCampaign: analyticsMetadata.utmCampaign || 'checkout_interstitial_diagnostic',
4456
+ ctaId: 'checkout_interstitial_sprint_diagnostic_checkout',
4457
+ ctaPlacement: 'checkout_interstitial',
4458
+ planId: 'sprint_diagnostic',
4459
+ })
4460
+ : '';
4461
+ const sprintCheckoutHref = hostedConfig.workflowSprintCheckoutUrl
4462
+ ? buildCheckoutIntentHref(hostedConfig.workflowSprintCheckoutUrl, analyticsMetadata, {
4463
+ utmMedium: 'checkout_interstitial_paid_path',
4464
+ utmCampaign: analyticsMetadata.utmCampaign || 'checkout_interstitial_workflow_sprint',
4465
+ ctaId: 'checkout_interstitial_workflow_sprint_checkout',
4466
+ ctaPlacement: 'checkout_interstitial',
4467
+ planId: 'workflow_sprint',
4468
+ })
4469
+ : '';
4470
+ const html = renderCheckoutIntentPage({
4471
+ confirmHref: buildCheckoutConfirmHref(parsed),
4472
+ workflowIntakeHref,
4473
+ teamOptionsHref,
4474
+ diagnosticCheckoutHref,
4475
+ sprintCheckoutHref,
4476
+ sprintDiagnosticPriceDollars: hostedConfig.sprintDiagnosticPriceDollars || 499,
4477
+ workflowSprintPriceDollars: hostedConfig.workflowSprintPriceDollars || 1500,
4478
+ botClassification,
4479
+ });
4416
4480
  sendHtml(res, 200, html, responseHeaders);
4417
4481
  return;
4418
4482
  }
4419
4483
 
4484
+ const normalizedCheckoutEmail = normalizeCheckoutCustomerEmail(bootstrapBody.customerEmail);
4485
+ if (!normalizedCheckoutEmail) {
4486
+ appendBestEffortTelemetry(FEEDBACK_DIR, {
4487
+ eventType: 'checkout_email_gate_shown',
4488
+ clientType: 'web',
4489
+ traceId,
4490
+ page: '/checkout/pro',
4491
+ planId: analyticsMetadata.planId,
4492
+ }, req.headers, 'checkout_email_gate_shown');
4493
+ const { html, headers } = renderCheckoutIntentGate(parsed, responseHeaders);
4494
+ sendHtml(res, 200, html, headers);
4495
+ return;
4496
+ }
4497
+ bootstrapBody.customerEmail = normalizedCheckoutEmail;
4498
+
4420
4499
  appendBestEffortTelemetry(FEEDBACK_DIR, {
4421
4500
  eventType: 'checkout_bootstrap',
4422
4501
  clientType: 'web',
@@ -4792,7 +4871,7 @@ async function addContext(){
4792
4871
  .map(l => { try { return JSON.parse(l); } catch(_e) { return null; } })
4793
4872
  .filter(Boolean);
4794
4873
  }
4795
- } catch (_) {}
4874
+ } catch { entries = []; }
4796
4875
 
4797
4876
  const now = Date.now();
4798
4877
  const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000;