thumbgate 1.16.21 → 1.16.22

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.21",
3
+ "version": "1.16.22",
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.21",
16
+ "version": "1.16.22",
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.21",
4
+ "version": "1.16.22",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.16.21",
3
+ "version": "1.16.22",
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.21", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.16.22", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.16.21", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.16.22", "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.21' };
219
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.16.22' };
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.21",
10
+ "thumbgate@1.16.22",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
package/bin/cli.js CHANGED
@@ -1112,7 +1112,6 @@ function pro() {
1112
1112
  }
1113
1113
 
1114
1114
  if (args.upgrade) {
1115
- const proDir = path.join(PKG_ROOT, 'pro');
1116
1115
  const thumbgateDir = path.join(CWD, '.thumbgate');
1117
1116
  if (!fs.existsSync(thumbgateDir)) fs.mkdirSync(thumbgateDir, { recursive: true });
1118
1117
 
@@ -1123,6 +1122,21 @@ function pro() {
1123
1122
  ['reminders-pro.json', '8 reminder templates'],
1124
1123
  ];
1125
1124
 
1125
+ const candidateDirs = [
1126
+ path.join(PKG_ROOT, 'config', 'pro'),
1127
+ path.join(PKG_ROOT, 'pro'),
1128
+ ];
1129
+ const proDir = candidateDirs.find((dir) =>
1130
+ files.every(([file]) => fs.existsSync(path.join(dir, file)))
1131
+ );
1132
+
1133
+ if (!proDir) {
1134
+ console.error('Pro upgrade bundle is missing from this ThumbGate install.');
1135
+ console.error(`Expected files under: ${path.join(PKG_ROOT, 'config', 'pro')}`);
1136
+ console.error('Please upgrade to the latest thumbgate package and retry: npm install -g thumbgate@latest');
1137
+ process.exit(1);
1138
+ }
1139
+
1126
1140
  for (const [file] of files) {
1127
1141
  fs.copyFileSync(path.join(proDir, file), path.join(thumbgateDir, file));
1128
1142
  }
@@ -0,0 +1,57 @@
1
+ {
2
+ "version": 1,
3
+ "name": "ThumbGate Pro Constraints",
4
+ "description": "Public Pro upgrade bundle installed by `thumbgate pro --upgrade` for local workflow hardening.",
5
+ "constraints": [
6
+ {
7
+ "id": "evidence-before-completion",
8
+ "severity": "critical",
9
+ "rule": "Do not claim done, fixed, shipped, published, or paid until the relevant command, URL, PR, workflow, or billing record has been checked."
10
+ },
11
+ {
12
+ "id": "read-before-write",
13
+ "severity": "high",
14
+ "rule": "Before editing existing code, read the surrounding implementation and tests so the patch follows local contracts."
15
+ },
16
+ {
17
+ "id": "no-destructive-git-without-intent",
18
+ "severity": "critical",
19
+ "rule": "Block destructive git operations such as reset --hard, checkout --, clean -fd, and force-push unless the operator explicitly requested that exact operation."
20
+ },
21
+ {
22
+ "id": "production-data-write-gate",
23
+ "severity": "critical",
24
+ "rule": "Block production database writes, deletes, migrations, and irreversible data operations unless a backup, target environment, and rollback plan are present."
25
+ },
26
+ {
27
+ "id": "secrets-redaction",
28
+ "severity": "critical",
29
+ "rule": "Never print, commit, paste, or persist secrets. Use only sanitized status output when verifying credentials."
30
+ },
31
+ {
32
+ "id": "test-before-merge",
33
+ "severity": "high",
34
+ "rule": "Before saying a code change is ready, run the narrow relevant tests or explain exactly why verification could not run."
35
+ },
36
+ {
37
+ "id": "no-synthetic-traction",
38
+ "severity": "critical",
39
+ "rule": "Do not describe views, clicks, stars, configured gates, or generated artifacts as revenue, customers, or proven interventions."
40
+ },
41
+ {
42
+ "id": "paid-path-health",
43
+ "severity": "high",
44
+ "rule": "Before promoting a paid offer, verify the landing page and checkout route return HTTP 200 and point to the intended Stripe path."
45
+ },
46
+ {
47
+ "id": "single-source-commercial-truth",
48
+ "severity": "high",
49
+ "rule": "Commercial claims must match docs/COMMERCIAL_TRUTH.md for pricing, traction, tier limits, and proof language."
50
+ },
51
+ {
52
+ "id": "bounded-agent-run",
53
+ "severity": "high",
54
+ "rule": "Long-running agent work must have a bounded objective, progress evidence, and a stop condition instead of open-ended activity."
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,27 @@
1
+ # ThumbGate Pro Prevention Rules
2
+
3
+ These public Pro rules are installed by `thumbgate pro --upgrade` into `.thumbgate/`.
4
+ They are starting points for local operator hardening, not proof that any gate has fired.
5
+
6
+ ## Evidence Claims
7
+
8
+ - Require a fresh command, API response, workflow status, URL check, or billing record before completion claims.
9
+ - Treat configured checks as inventory and recorded blocks or warnings as usage evidence.
10
+ - Treat Stripe-reconciled charges as revenue proof; treat traffic and clicks as funnel evidence only.
11
+
12
+ ## Code Changes
13
+
14
+ - Read the existing file and nearby tests before editing.
15
+ - Keep edits scoped to the requested behavior.
16
+ - Run narrow tests for the touched behavior before reporting success.
17
+
18
+ ## Risky Actions
19
+
20
+ - Block destructive git commands unless the operator explicitly asked for the exact action.
21
+ - Block production data changes unless the target, backup, and rollback plan are explicit.
22
+ - Block checkout, publish, deploy, or customer-write claims until the live path is verified.
23
+
24
+ ## Agent Workflow
25
+
26
+ - If an agent repeats a known failure, capture the failed action, expected behavior, and enforcement rule in one concise lesson.
27
+ - Prefer one workflow owner, one repeated failure, and one proof review before expanding a Team rollout.
@@ -0,0 +1,38 @@
1
+ {
2
+ "version": 1,
3
+ "name": "ThumbGate Pro Reminder Templates",
4
+ "reminders": [
5
+ {
6
+ "id": "verify-before-claim",
7
+ "text": "Verify with a tool before claiming this is done."
8
+ },
9
+ {
10
+ "id": "read-local-contract",
11
+ "text": "Read the local implementation and tests before editing."
12
+ },
13
+ {
14
+ "id": "protect-user-work",
15
+ "text": "Do not revert user changes or unrelated dirty worktree state."
16
+ },
17
+ {
18
+ "id": "billing-truth",
19
+ "text": "Do not claim revenue unless Stripe or billing evidence proves it."
20
+ },
21
+ {
22
+ "id": "configured-is-not-fired",
23
+ "text": "Configured checks are inventory; recorded blocks and warnings are usage evidence."
24
+ },
25
+ {
26
+ "id": "checkout-health",
27
+ "text": "Verify the paid landing page and checkout route before sending traffic."
28
+ },
29
+ {
30
+ "id": "narrow-tests",
31
+ "text": "Run the smallest relevant test set for this change."
32
+ },
33
+ {
34
+ "id": "bounded-workflow",
35
+ "text": "Name the workflow owner, repeated failure, proof artifact, and stop condition."
36
+ }
37
+ ]
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "version": 1,
3
+ "name": "ThumbGate Pro Thompson Sampling Presets",
4
+ "presets": [
5
+ {
6
+ "id": "conservative",
7
+ "description": "Prefer warn before block until repeated harmful evidence accumulates.",
8
+ "alpha": 1,
9
+ "beta": 3,
10
+ "blockThreshold": 0.82,
11
+ "warnThreshold": 0.55
12
+ },
13
+ {
14
+ "id": "balanced",
15
+ "description": "Default local hardening profile for repeated workflow failures.",
16
+ "alpha": 2,
17
+ "beta": 2,
18
+ "blockThreshold": 0.72,
19
+ "warnThreshold": 0.48
20
+ },
21
+ {
22
+ "id": "strict",
23
+ "description": "Use for high-blast-radius workflows such as production data, deploys, billing, and destructive git.",
24
+ "alpha": 3,
25
+ "beta": 1,
26
+ "blockThreshold": 0.62,
27
+ "warnThreshold": 0.38
28
+ },
29
+ {
30
+ "id": "evidence-first",
31
+ "description": "Bias toward interventions when the agent lacks proof for claims or risky writes.",
32
+ "alpha": 4,
33
+ "beta": 2,
34
+ "blockThreshold": 0.66,
35
+ "warnThreshold": 0.42
36
+ }
37
+ ]
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.16.21",
3
+ "version": "1.16.22",
4
4
  "description": "ThumbGate self-improving agent governance: thumbs-up/down turns every mistake into a prevention rule and blocks repeat patterns. 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
@@ -1298,7 +1298,7 @@ __GA_BOOTSTRAP__
1298
1298
  <!-- HOW IT WORKS -->
1299
1299
  <section class="how-it-works" id="how-it-works">
1300
1300
  <div class="container">
1301
- <div class="section-label">New in v1.16.21</div>
1301
+ <div class="section-label">New in v1.16.22</div>
1302
1302
  <h2 class="section-title">Three steps to stop repeated AI failures</h2>
1303
1303
  <div class="steps">
1304
1304
  <div class="step">
@@ -1717,7 +1717,7 @@ __GA_BOOTSTRAP__
1717
1717
  <a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
1718
1718
  <a href="/blog">Blog</a>
1719
1719
  </div>
1720
- <span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.16.21</span>
1720
+ <span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.16.22</span>
1721
1721
  </div>
1722
1722
  </footer>
1723
1723
 
@@ -6,9 +6,9 @@
6
6
  <meta name="generator" content="ThumbGate">
7
7
  <meta name="author" content="Igor Ganapolsky">
8
8
  <title>ThumbGate — The Numbers | First-Party Data Snapshot</title>
9
- <meta name="description" content="ThumbGate's generated first-party operational snapshot: active pre-action checks, AI agent actions blocked, estimated LLM tokens and dollars saved, and the Bayes error rate of the intervention scorer.">
9
+ <meta name="description" content="ThumbGate's generated first-party operational snapshot: configured pre-action checks, recorded block/warn events, estimated LLM token savings when events exist, and scorer calibration when the sample supports it.">
10
10
  <meta property="og:title" content="ThumbGate — The Numbers">
11
- <meta property="og:description" content="Generated first-party operational metrics: gates, blocks, token savings, and scorer calibration.">
11
+ <meta property="og:description" content="Generated first-party operational snapshot: configured gates, recorded interventions, and explicit zero-evidence caveats.">
12
12
  <meta property="og:type" content="website">
13
13
  <meta property="og:url" content="https://thumbgate-production.up.railway.app/numbers">
14
14
  <meta name="twitter:card" content="summary_large_image">
@@ -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.21",
28
+ "softwareVersion": "1.16.22",
29
29
  "url": "https://thumbgate-production.up.railway.app/numbers",
30
- "dateModified": "2026-05-06",
30
+ "dateModified": "2026-05-07",
31
31
  "creator": {
32
32
  "@type": "Person",
33
33
  "name": "Igor Ganapolsky",
@@ -44,8 +44,8 @@
44
44
  {
45
45
  "@context": "https://schema.org",
46
46
  "@type": "Dataset",
47
- "name": "ThumbGate Live Operational Metrics",
48
- "description": "First-party operational metrics from the ThumbGate pre-action check runtime: active checks, blocked AI agent actions, estimated token savings, and Bayes error rate of the intervention scorer.",
47
+ "name": "ThumbGate Operational Snapshot",
48
+ "description": "First-party operational snapshot from the ThumbGate pre-action check runtime: configured checks, recorded block/warn events, estimated token savings from recorded blocks, and Bayes error rate when the sample supports it.",
49
49
  "url": "https://thumbgate-production.up.railway.app/numbers",
50
50
  "license": "https://opensource.org/licenses/MIT",
51
51
  "creator": {
@@ -57,8 +57,8 @@
57
57
  "https://www.linkedin.com/in/igorganapolsky"
58
58
  ]
59
59
  },
60
- "dateModified": "2026-05-06",
61
- "datePublished": "2026-05-06",
60
+ "dateModified": "2026-05-07",
61
+ "datePublished": "2026-05-07",
62
62
  "keywords": [
63
63
  "AI agent gates",
64
64
  "LLM token savings",
@@ -69,7 +69,7 @@
69
69
  "variableMeasured": [
70
70
  {
71
71
  "@type": "PropertyValue",
72
- "name": "active_gates",
72
+ "name": "configured_gates",
73
73
  "value": 36
74
74
  },
75
75
  {
@@ -119,6 +119,8 @@
119
119
  --cyan: #22d3ee;
120
120
  --green: #34d399;
121
121
  --amber: #fbbf24;
122
+ --amber-soft: rgba(251, 191, 36, 0.1);
123
+ --amber-line: rgba(251, 191, 36, 0.34);
122
124
  }
123
125
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; }
124
126
  nav { padding: 1rem 2rem; border-bottom: 1px solid var(--border); display: flex; gap: 1.5rem; align-items: center; }
@@ -140,6 +142,16 @@
140
142
  font-weight: 600;
141
143
  margin-bottom: 2.5rem;
142
144
  }
145
+ .truth-note {
146
+ background: var(--amber-soft);
147
+ border: 1px solid var(--amber-line);
148
+ border-radius: 12px;
149
+ color: #fde68a;
150
+ padding: 16px 18px;
151
+ margin: 0 0 2.5rem;
152
+ font-size: 0.95rem;
153
+ }
154
+ .truth-note strong { color: #fff3bd; }
143
155
  .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 18px; margin: 1.5rem 0; }
144
156
  .stat-card {
145
157
  background: var(--bg-card);
@@ -189,33 +201,34 @@
189
201
 
190
202
  <main class="container">
191
203
  <h1>The Numbers</h1>
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-06 · Version 1.16.21</div>
204
+ <p class="subtitle">Generated first-party operational snapshot from the ThumbGate runtime. This is not customer traction, install volume, revenue, or proof that a configured gate has fired.</p>
205
+ <div class="freshness">Updated: 2026-05-07 · Version 1.16.22</div>
206
+ <div class="truth-note"><strong>Read this first:</strong> configured checks are inventory. Recorded blocks and warnings are usage evidence. This snapshot currently reports 0 recorded hard-block event(s) and 0 recorded warning event(s).</div>
194
207
 
195
208
  <h2>Gate enforcement</h2>
196
209
  <div class="stats-grid">
197
210
  <div class="stat-card">
198
- <div class="stat-label">Active gates</div>
211
+ <div class="stat-label">Configured checks</div>
199
212
  <div class="stat-value">36</div>
200
- <div class="stat-sub">36 manual · 0 auto-promoted</div>
213
+ <div class="stat-sub">36 shipped defaults · 0 auto-promoted; inventory, not usage</div>
201
214
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
202
215
  </div>
203
216
  <div class="stat-card">
204
217
  <div class="stat-label">Actions blocked</div>
205
218
  <div class="stat-value">0</div>
206
- <div class="stat-sub">repeat AI mistakes prevented at the gate</div>
219
+ <div class="stat-sub">no recorded hard-block events in this snapshot</div>
207
220
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
208
221
  </div>
209
222
  <div class="stat-card">
210
223
  <div class="stat-label">Actions warned</div>
211
224
  <div class="stat-value">0</div>
212
- <div class="stat-sub">soft interventions; not blocks</div>
225
+ <div class="stat-sub">no recorded soft-warning events in this snapshot</div>
213
226
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
214
227
  </div>
215
228
  <div class="stat-card">
216
- <div class="stat-label">Top blocked gate</div>
217
- <div class="stat-value" style="font-size:1.1rem;">local-only-git-writes (0 blocks)</div>
218
- <div class="stat-sub">highest-occurrence prevention rule</div>
229
+ <div class="stat-label">Top recorded blocker</div>
230
+ <div class="stat-value" style="font-size:1.1rem;">No recorded blocker yet</div>
231
+ <div class="stat-sub">top blocker appears only after at least one recorded block</div>
219
232
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
220
233
  </div>
221
234
  </div>
@@ -225,25 +238,25 @@
225
238
  <div class="stat-card">
226
239
  <div class="stat-label">Estimated hours saved</div>
227
240
  <div class="stat-value">0.0</div>
228
- <div class="stat-sub">~15 min per blocked mistake × blocks+warns</div>
241
+ <div class="stat-sub">0 because no block/warn events are recorded</div>
229
242
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/gate-stats.js">source: gate-stats.js</a>
230
243
  </div>
231
244
  <div class="stat-card">
232
245
  <div class="stat-label">Estimated LLM dollars saved</div>
233
246
  <div class="stat-value">$0.00</div>
234
- <div class="stat-sub">blended Sonnet/Opus/Haiku 80/15/5 mix</div>
247
+ <div class="stat-sub">0 because no recorded block events feed this estimate</div>
235
248
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/token-savings.js">source: token-savings.js</a>
236
249
  </div>
237
250
  <div class="stat-card">
238
251
  <div class="stat-label">Tokens not spent</div>
239
252
  <div class="stat-value">0</div>
240
- <div class="stat-sub">2,000 input + 600 output per block, conservative</div>
253
+ <div class="stat-sub">0 because no recorded block events feed this estimate</div>
241
254
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/token-savings.js">source: token-savings.js</a>
242
255
  </div>
243
256
  <div class="stat-card">
244
257
  <div class="stat-label">Scorer Bayes error</div>
245
- <div class="stat-value">n/a (no feedback sequences recorded yet)</div>
246
- <div class="stat-sub">irreducible error given current feature set</div>
258
+ <div class="stat-value">n/a</div>
259
+ <div class="stat-sub">needs both safe and harmful feedback sequences</div>
247
260
  <a class="stat-source" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/scripts/bayes-optimal-gate.js">source: bayes-optimal-gate.js</a>
248
261
  </div>
249
262
  </div>
@@ -252,11 +265,11 @@
252
265
  <div class="method">
253
266
  <p><strong>Where the numbers come from.</strong> This page is regenerated from local scripts — no survey data, no hand-edited figures, no third-party attribution. Every number on this page is produced by code in the public <a href="https://github.com/IgorGanapolsky/ThumbGate">ThumbGate repo</a>.</p>
254
267
  <ul>
255
- <li><strong>Active checks</strong> — union of shipped default rules and the auto-promotion ledger (auto).</li>
256
- <li><strong>Actions blocked/warned</strong> — sum of <code>occurrences</code> across gates with the corresponding action.</li>
257
- <li><strong>Hours saved</strong> — conservative 15-minute/incident estimate for debugging a repeated AI mistake × (blocks + warns).</li>
258
- <li><strong>Dollars saved</strong> — blended per-call token estimate (2k input + 600 output) × blocks × 2026-04-15 Anthropic + OpenAI list prices. See <code>scripts/token-savings.js</code> for the full price snapshot.</li>
259
- <li><strong>Bayes error rate</strong> — irreducible classifier error of the current risk scorer given its feature set. High values mean "add features, don't tune thresholds."</li>
268
+ <li><strong>Configured checks</strong> — union of shipped default rules and the auto-promotion ledger. This is inventory, not proof that the check fired.</li>
269
+ <li><strong>Actions blocked/warned</strong> — recorded intervention counts from gate occurrence data. These are the evidence counters.</li>
270
+ <li><strong>Hours saved</strong> — conservative 15-minute/incident estimate, shown only as a function of recorded block/warn counts.</li>
271
+ <li><strong>Dollars saved</strong> — blended per-call token estimate (2k input + 600 output) × recorded blocks × 2026-04-15 Anthropic + OpenAI list prices. See <code>scripts/token-savings.js</code> for the full price snapshot.</li>
272
+ <li><strong>Bayes error rate</strong> — shown only when the feedback sample contains both safe and harmful outcomes. One-class samples are reported as n/a.</li>
260
273
  </ul>
261
274
  <p style="margin-top:12px;">Last auto-promotion: none. Regenerated on every release via <code>npm run numbers:generate</code> and on a weekly cadence.</p>
262
275
  </div>
@@ -264,7 +277,7 @@
264
277
  <div class="cta">
265
278
  <a href="https://www.npmjs.com/package/thumbgate">Install ThumbGate — npx thumbgate init</a>
266
279
  <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-06T21:53:14.685Z UTC.</div>
280
+ <div class="footer-note">Generated at 2026-05-07T14:59:51.816Z UTC.</div>
268
281
  </div>
269
282
  </main>
270
283
  </body>
@@ -43,10 +43,12 @@ function calculateStats() {
43
43
  .filter((g) => g.action === 'warn')
44
44
  .reduce((sum, g) => sum + (g.occurrences || 0), 0);
45
45
 
46
- // Top blocked gate
46
+ // Top blocked gate. A configured block rule with zero occurrences is not a
47
+ // "top blocker"; only recorded block events should appear here.
47
48
  const topBlocked = [...allGates]
49
+ .filter((g) => g.action === 'block' && Number(g.occurrences || 0) > 0)
48
50
  .sort((a, b) => (b.occurrences || 0) - (a.occurrences || 0))
49
- .find((g) => g.action === 'block') || null;
51
+ .at(0) || null;
50
52
 
51
53
  // Last promotion event
52
54
  const lastPromotion = promotionLog.length > 0
@@ -58,11 +60,9 @@ function calculateStats() {
58
60
  const estimatedHoursSaved = (estimatedMinutesSaved / 60).toFixed(1);
59
61
 
60
62
  // Bayes error rate: irreducible error floor of the current scorer given its
61
- // feature set (tag signatures). If this is near zero, the scorer is already
62
- // close to optimal threshold tuning won't help, and new features are the
63
- // only lever. If this is high, the feature set can't discriminate the signal
64
- // and we should add features (file path, recency, commit context) rather
65
- // than tune thresholds. Null when no feedback sequences have been recorded.
63
+ // feature set (tag signatures). It is only meaningful when the local sample
64
+ // contains both harmful and safe outcomes; an all-negative or all-positive
65
+ // sample can produce a misleading 0.0% floor.
66
66
  const bayesErrorRate = tryComputeBayesErrorRate();
67
67
 
68
68
  return {
@@ -90,12 +90,33 @@ function tryComputeBayesErrorRate() {
90
90
  .filter(Boolean)
91
91
  .map((line) => { try { return JSON.parse(line); } catch { return null; } })
92
92
  .filter(Boolean);
93
+ if (!hasMixedOutcomeClasses(rows)) return null;
93
94
  return computeBayesErrorRate(rows);
94
95
  } catch {
95
96
  return null;
96
97
  }
97
98
  }
98
99
 
100
+ function hasMixedOutcomeClasses(rows) {
101
+ if (!Array.isArray(rows) || rows.length < 2) return false;
102
+ let harmful = 0;
103
+ let safe = 0;
104
+ for (const row of rows) {
105
+ if (sequenceIsHarmful(row)) harmful += 1;
106
+ else safe += 1;
107
+ if (harmful > 0 && safe > 0) return true;
108
+ }
109
+ return false;
110
+ }
111
+
112
+ function sequenceIsHarmful(row) {
113
+ if (!row || typeof row !== 'object') return false;
114
+ if (typeof row.targetRisk === 'number') return row.targetRisk > 0;
115
+ if (typeof row.accepted === 'boolean' && row.accepted === false) return true;
116
+ const label = String(row.label || row.signal || '').toLowerCase();
117
+ return label === 'negative';
118
+ }
119
+
99
120
  function formatLastPromotion(promo) {
100
121
  if (!promo) return 'none';
101
122
  const ts = promo.timestamp ? new Date(promo.timestamp) : null;
@@ -125,7 +146,7 @@ function formatStats(stats) {
125
146
  }
126
147
 
127
148
  function formatBayesErrorRate(rate) {
128
- if (rate === null || rate === undefined) return 'n/a (no feedback sequences yet)';
149
+ if (rate === null || rate === undefined) return 'n/a (need both safe and harmful feedback sequences)';
129
150
  const pct = (rate * 100).toFixed(1);
130
151
  if (rate < 0.02) return `${pct}% — scorer is near-optimal; add features, don't tune thresholds`;
131
152
  if (rate < 0.10) return `${pct}% — scorer has modest headroom`;