thumbgate 1.25.0 โ†’ 1.25.2

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.25.0",
3
+ "version": "1.25.2",
4
4
  "owner": {
5
5
  "name": "Igor Ganapolsky",
6
6
  "email": "ig5973700@gmail.com"
@@ -14,7 +14,7 @@
14
14
  "source": "npm",
15
15
  "package": "thumbgate"
16
16
  },
17
- "version": "1.25.0",
17
+ "version": "1.25.2",
18
18
  "author": {
19
19
  "name": "Igor Ganapolsky",
20
20
  "email": "ig5973700@gmail.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thumbgate",
3
3
  "description": "One ๐Ÿ‘Ž becomes a hard rule the agent cannot bypass. Captures thumbs-down feedback, distills it into PreToolUse Pre-Action Checks, enforced across every future Claude Code session.",
4
- "version": "1.25.0",
4
+ "version": "1.25.2",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky",
7
7
  "email": "ig5973700@gmail.com",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.25.0",
3
+ "version": "1.25.2",
4
4
  "description": "ThumbGate โ€” ๐Ÿ‘๐Ÿ‘Ž feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
5
5
  "homepage": "https://thumbgate.ai",
6
6
  "transport": "stdio",
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.25.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.25.2", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.25.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.25.2", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -133,6 +133,7 @@
133
133
  "context": { "type": "string" },
134
134
  "mcpProfile": { "type": "string" },
135
135
  "bundleId": { "type": "string" },
136
+ "enforcePlanQuality": { "type": "boolean" },
136
137
  "approved": { "type": "boolean" }
137
138
  },
138
139
  "required": ["intentId"]
@@ -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.25.0' };
219
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.25.2' };
220
220
  const COMMERCE_CATEGORIES = [
221
221
  'product_recommendation',
222
222
  'brand_compliance',
@@ -779,6 +779,7 @@ async function callToolInner(name, args) {
779
779
  bundleId: args.bundleId,
780
780
  partnerProfile: args.partnerProfile,
781
781
  delegationMode: args.delegationMode,
782
+ enforcePlanQuality: args.enforcePlanQuality === true,
782
783
  approved: args.approved === true,
783
784
  repoPath: args.repoPath,
784
785
  }));
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.25.0",
10
+ "thumbgate@1.25.2",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
@@ -94,6 +94,8 @@ components:
94
94
  delegationMode:
95
95
  type: string
96
96
  enum: [off, auto, sequential]
97
+ enforcePlanQuality:
98
+ type: boolean
97
99
  approved:
98
100
  type: boolean
99
101
  repoPath:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.25.0",
3
+ "version": "1.25.2",
4
4
  "description": "ThumbGate self-improving agent governance: thumbs-up/down turns every mistake into a prevention rule and blocks repeat patterns. 36 pre-action checks, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
5
5
  "homepage": "https://thumbgate.ai",
6
6
  "repository": {
@@ -340,7 +340,7 @@
340
340
  "social:prospect:bluesky:dry": "node scripts/social-bluesky-prospecting.js --dry-run",
341
341
  "social:reply-publish:bluesky:dry": "node scripts/social-reply-monitor-bluesky.js --publish-approved --dry-run",
342
342
  "test:python": "python3 -m pytest tests/*.py",
343
- "test": "npm run test:python && npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:platform-limits && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:post-everywhere-channels && npm run test:post-everywhere-zernio-default && npm run test:zernio-canonical-pollers && npm run test:zernio-status && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:memory-scope-readiness && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operational-dashboard && npm run test:operator-artifacts && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:mcp-tool-annotations && npm run test:mcp-oauth && npm run test:mcp-oauth-flow && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:audit-pr-bot-contamination && npm run test:stripe-bootstrap-saas-catalog && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:lesson-semantic-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:predictive-credible-range && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:lesson-canonical && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:community-course-platform-launch-kit && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:social-dedupe-cleanup && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-archived-product-guard && npm run test:postgres-guard && npm run test:checkout-bot-guard && npm run test:checkout-pro-confirmation-gate && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:telemetry-tracked-link-slug && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:numbers-page && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:competitive-positioning-marketing && npm run test:medium-weekly && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring && npm run test:pretooluse-injection && npm run test:recent-corrective-context && npm run test:durability-step && npm run test:mailer && npm run test:brand-assets && npm run test:enforcement-teeth && npm run test:bayes-optimal-gate && npm run test:swarm-coordinator && npm run test:session-report && npm run test:agent-reasoning-traces && npm run test:judge-reward && npm run test:llm-behavior-monitor && npm run test:prompting-os && npm run test:single-use-credential-gate && npm run test:structured-prompt-driven && npm run test:require-evidence-gate && npm run test:rule-validator && npm run test:bluesky-atproto && npm run test:social-reply-monitor-bluesky && npm run test:bluesky-delete-replies && npm run test:architect-kit-memory-bridge && npm run test:sonar-review-hotspots && npm run test:actionable-remediations && npm run test:gemini-embedding-policy && npm run test:agent-design-governance && npm run test:public-core-boundary && npm run test:hook-stop-verify-deploy && npm run test:hook-stop-anti-claim && npm run test:plausible-server-events && npm run test:activation-tracker && npm run test:unified-revenue-rollup && npm run test:conversion-rate-stats && npm run test:external-customer-audit && npm run test:telemetry-export && npm run test:stripe-checkout-diagnostic && npm run test:stripe-business-identity-probe && npm run test:revenue-observability-doctor && npm run test:public-bundle-ratchet && npm run test:stripe-payment-link-update && npm run test:ci-cd-hygiene-audit && npm run test:verify-marketing-pages-deployed && npm run test:install-email-capture && npm run test:install-shim && npm run test:hook-runtime-subcommands && npm run test:implementation-notes && npm run test:daily-block-cap && npm run test:free-to-paid-conversion-units && npm run test:metrics-real-endpoint && npm run test:cli-trial-and-help && npm run test:cost-cli && npm run test:silent-failure-cluster && npm run test:proof:truth",
343
+ "test": "npm run test:python && npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:platform-limits && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:post-everywhere-channels && npm run test:post-everywhere-zernio-default && npm run test:zernio-canonical-pollers && npm run test:zernio-status && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:memory-scope-readiness && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operational-dashboard && npm run test:operator-artifacts && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:mcp-tool-annotations && npm run test:mcp-oauth && npm run test:mcp-oauth-flow && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:audit-pr-bot-contamination && npm run test:stripe-bootstrap-saas-catalog && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:lesson-semantic-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:predictive-credible-range && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:lesson-canonical && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:community-course-platform-launch-kit && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:social-dedupe-cleanup && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-archived-product-guard && npm run test:postgres-guard && npm run test:checkout-bot-guard && npm run test:checkout-pro-confirmation-gate && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:telemetry-tracked-link-slug && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:numbers-page && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:competitive-positioning-marketing && npm run test:medium-weekly && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring && npm run test:pretooluse-injection && npm run test:recent-corrective-context && npm run test:durability-step && npm run test:mailer && npm run test:brand-assets && npm run test:enforcement-teeth && npm run test:bayes-optimal-gate && npm run test:swarm-coordinator && npm run test:session-report && npm run test:agent-reasoning-traces && npm run test:judge-reward && npm run test:llm-behavior-monitor && npm run test:prompting-os && npm run test:single-use-credential-gate && npm run test:structured-prompt-driven && npm run test:require-evidence-gate && npm run test:rule-validator && npm run test:bluesky-atproto && npm run test:social-reply-monitor-bluesky && npm run test:bluesky-delete-replies && npm run test:architect-kit-memory-bridge && npm run test:sonar-review-hotspots && npm run test:actionable-remediations && npm run test:gemini-embedding-policy && npm run test:agent-design-governance && npm run test:public-core-boundary && npm run test:hook-stop-verify-deploy && npm run test:hook-stop-anti-claim && npm run test:plausible-server-events && npm run test:activation-tracker && npm run test:unified-revenue-rollup && npm run test:conversion-rate-stats && npm run test:external-customer-audit && npm run test:telemetry-export && npm run test:stripe-checkout-diagnostic && npm run test:stripe-business-identity-probe && npm run test:revenue-observability-doctor && npm run test:public-bundle-ratchet && npm run test:stripe-payment-link-update && npm run test:ci-cd-hygiene-audit && npm run test:verify-marketing-pages-deployed && npm run test:install-email-capture && npm run test:install-shim && npm run test:hook-runtime-subcommands && npm run test:implementation-notes && npm run test:daily-block-cap && npm run test:free-to-paid-conversion-units && npm run test:metrics-real-endpoint && npm run test:cli-trial-and-help && npm run test:cost-cli && npm run test:silent-failure-cluster && npm run test:proof:truth && node --test tests/adaptive-reliability.test.js && npm run test:mcp-oauth-reviewer",
344
344
  "test:hook-stop-verify-deploy": "node --test tests/hook-stop-verify-deploy.test.js",
345
345
  "test:hook-stop-anti-claim": "node --test tests/hook-stop-anti-claim.test.js",
346
346
  "test:plausible-server-events": "node --test tests/plausible-server-events.test.js tests/plausible-poller.test.js",
@@ -687,11 +687,12 @@
687
687
  "test:dashboard-page-clickability": "playwright test tests/e2e/dashboard-page-clickability.spec.js",
688
688
  "test:agent-manager-page-clickability": "playwright test tests/e2e/agent-manager-page-clickability.spec.js",
689
689
  "test:pricing-page-clickability": "playwright test tests/e2e/pricing-page-clickability.spec.js",
690
- "test:proof:truth": "node --test tests/knowledge-entropy.test.js tests/mcp-wiring-doctor.test.js tests/sequence-guard.test.js tests/slopsquat-guard.test.js tests/slopsquat-stress.test.js tests/truth-and-proof.test.js tests/wire-proof-gate.test.js",
690
+ "test:proof:truth": "node --test tests/knowledge-entropy.test.js tests/mcp-wiring-doctor.test.js tests/sequence-guard.test.js tests/slopsquat-guard.test.js tests/slopsquat-stress.test.js tests/truth-and-proof.test.js tests/wire-proof-gate.test.js tests/adaptive-reliability.test.js",
691
691
  "build:grok-plugin": "node scripts/build-grok-plugin.js",
692
692
  "promote:launch": "node scripts/x-autonomous-marketing.js",
693
693
  "feedback:ingest": "node scripts/ingest-manual-feedback.js",
694
- "verify-proof": "node scripts/require-proof.js"
694
+ "verify-proof": "node scripts/require-proof.js",
695
+ "test:mcp-oauth-reviewer": "node --test tests/mcp-oauth-reviewer.test.js"
695
696
  },
696
697
  "keywords": [
697
698
  "mcp",
package/public/index.html CHANGED
@@ -20,7 +20,7 @@ __GOOGLE_SITE_VERIFICATION_META__
20
20
  <meta property="og:image" content="https://thumbgate.ai/og.png">
21
21
  <meta name="twitter:card" content="summary_large_image">
22
22
  <meta name="twitter:image" content="https://thumbgate.ai/og.png">
23
- <meta name="thumbgate-version" content="1.25.0">
23
+ <meta name="thumbgate-version" content="1.25.2">
24
24
  <meta name="keywords" content="ThumbGate, thumbgate, AI agent orchestration, AI experience orchestration, agentic development cycle, AC/DC framework, Guide Generate Verify Solve, agent enforcement layer, save LLM tokens, reduce Claude API cost, reduce OpenAI cost, AI agent token savings, prevent LLM retries, prevent hallucination retries, stop AI token waste, pre-action checks, agent governance, Claude Code, Cursor, Codex, Gemini, Amp, Cline, OpenCode, workflow hardening, context engineering, AI authenticity, brand authenticity AI">
25
25
  <link rel="canonical" href="__APP_ORIGIN__/">
26
26
  <link rel="alternate" type="text/markdown" title="ThumbGate LLM context" href="__APP_ORIGIN__/llm-context.md">
@@ -1586,7 +1586,7 @@ __GA_BOOTSTRAP__
1586
1586
  <a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
1587
1587
  <a href="/blog">Blog</a>
1588
1588
  </div>
1589
- <span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.25.0</span>
1589
+ <span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.25.2</span>
1590
1590
  </div>
1591
1591
  </footer>
1592
1592
 
@@ -25,7 +25,7 @@
25
25
  "alternateName": "thumbgate",
26
26
  "applicationCategory": "DeveloperApplication",
27
27
  "operatingSystem": "Cross-platform, Node.js >=18.18.0",
28
- "softwareVersion": "1.25.0",
28
+ "softwareVersion": "1.25.2",
29
29
  "url": "https://thumbgate.ai/numbers",
30
30
  "dateModified": "2026-05-07",
31
31
  "creator": {
@@ -202,7 +202,7 @@
202
202
  <main class="container">
203
203
  <h1>The Numbers</h1>
204
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.25.0</div>
205
+ <div class="freshness">Updated: 2026-05-07 ยท Version 1.25.2</div>
206
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>
207
207
 
208
208
  <h2>Gate enforcement</h2>
@@ -27,8 +27,9 @@ const {
27
27
  recordProvenance,
28
28
  } = require('./contextfs');
29
29
  const { loadOptionalModule } = require('./private-core-boundary');
30
- const { retrieveRelevantLessons } = loadOptionalModule('./lesson-retrieval', () => ({
30
+ const { retrieveRelevantLessons, calculateRetrievalEntropy } = loadOptionalModule('./lesson-retrieval', () => ({
31
31
  retrieveRelevantLessons: () => [],
32
+ calculateRetrievalEntropy: () => 0,
32
33
  }));
33
34
  const { evaluatePretool } = require('./hybrid-feedback-context');
34
35
  const { loadProfile } = require('./user-profile');
@@ -93,13 +94,21 @@ function assembleSession() {
93
94
 
94
95
  function assembleLessons(query, agentProfile, options = {}) {
95
96
  try {
96
- return retrieveRelevantLessons(
97
+ const lessons = retrieveRelevantLessons(
97
98
  options.toolName || '',
98
99
  query,
99
100
  { maxResults: agentProfile.maxLessons, feedbackDir: options.feedbackDir },
100
101
  );
102
+
103
+ const entropy = calculateRetrievalEntropy(lessons);
104
+
105
+ return {
106
+ items: lessons,
107
+ entropy,
108
+ highConflict: entropy > 0.7
109
+ };
101
110
  } catch {
102
- return [];
111
+ return { items: [], entropy: 0, highConflict: false };
103
112
  }
104
113
  }
105
114
 
@@ -224,7 +233,8 @@ function assembleUnifiedContext(params = {}) {
224
233
  // Assemble all components โ€” each is fault-tolerant
225
234
  const session = assembleSession();
226
235
  const userProfile = assembleUserProfile();
227
- const lessons = assembleLessons(query, agentProfile, { toolName, feedbackDir });
236
+ const lessonData = assembleLessons(query, agentProfile, { toolName, feedbackDir });
237
+ const lessons = lessonData.items;
228
238
  const guards = assembleGuards(toolName, toolInput);
229
239
  const contextPack = assembleContextPack(query, agentProfile);
230
240
  const codeGraph = assembleCodeGraph(query, repoPath, agentProfile);
@@ -232,9 +242,17 @@ function assembleUnifiedContext(params = {}) {
232
242
  const components = { session, userProfile, lessons, guards, contextPack, codeGraph };
233
243
  const tier = classifyTier(components);
234
244
 
245
+ // v4.2: Entropy-Aware Reliability Directive
246
+ let reliabilityDirective = null;
247
+ if (lessonData.highConflict) {
248
+ reliabilityDirective = 'CAUTION: Conflicting past patterns detected for this action. Prioritize absolute ground truth verification over rapid completion.';
249
+ }
250
+
235
251
  const result = {
236
252
  tier,
237
253
  agentType: agentType || 'default',
254
+ reliabilityDirective,
255
+ entropy: lessonData.entropy,
238
256
  agentProfile: {
239
257
  maxLessons: agentProfile.maxLessons,
240
258
  contextBudget: agentProfile.contextBudget,
@@ -2135,10 +2135,7 @@ function buildRecentCorrectiveActionsContext(options = {}) {
2135
2135
  function buildRelevantLessonContext(toolName, toolInput) {
2136
2136
  if (!toolName) return null;
2137
2137
 
2138
- const { retrieveRelevantLessons, calculateRetrievalEntropy } = loadOptionalModule('./lesson-retrieval', () => ({
2139
- retrieveRelevantLessons: () => [],
2140
- calculateRetrievalEntropy: () => 0,
2141
- }));
2138
+ const { retrieveRelevantLessons, calculateRetrievalEntropy, filterTopP } = loadOptionalModule("./lesson-retrieval", () => ({ retrieveRelevantLessons: () => [], calculateRetrievalEntropy: () => 0, filterTopP: (l) => l }));
2142
2139
 
2143
2140
  // Extract a searchable action context from the tool input
2144
2141
  const actionContext = extractActionContext(toolName, toolInput);
@@ -302,24 +302,30 @@ function getCalibration(model) {
302
302
  // ---------------------------------------------------------------------------
303
303
 
304
304
  /**
305
- * Draw one sample from the Beta posterior for each category via the
306
- * Marsaglia-Tsang (2000) gamma ratio method. No external library needed.
305
+ * Draw one sample from the Beta posterior for each category.
306
+ * Supports temperature scaling to adjust exploitation vs exploration.
307
307
  *
308
- * betaSample(alpha, beta) = gammaSample(alpha) / (gammaSample(alpha) + gammaSample(beta))
308
+ * Temperature (T):
309
+ * T = 1.0 (default) โ€” Standard Thompson Sampling.
310
+ * T < 1.0 โ€” Sharper distribution, favors high-reliability categories (exploit).
311
+ * T > 1.0 โ€” Flatter distribution, increases uncertainty and exploration.
309
312
  *
310
- * This is the JS equivalent of Python's random.betavariate(alpha, beta).
311
- * Used for Thompson Sampling action selection (explore via uncertainty).
313
+ * Implementation: Scales alpha and beta by 1/T.
312
314
  *
313
315
  * @param {Object} model - Model object containing categories
316
+ * @param {number} temperature - Scaling factor (default 1.0)
314
317
  * @returns {Object} Map of category โ†’ float sample in [0, 1]
315
318
  */
316
- function samplePosteriors(model) {
319
+ function samplePosteriors(model, temperature = 1.0) {
317
320
  const samples = {};
321
+ const T = Math.max(0.01, Number(temperature) || 1.0);
322
+ const invT = 1.0 / T;
323
+
318
324
  for (const [cat, params] of Object.entries(model.categories || {})) {
319
- samples[cat] = betaSample(
320
- Math.max(params.alpha, 0.01),
321
- Math.max(params.beta, 0.01),
322
- );
325
+ // Scale precision by inverse temperature
326
+ const alpha = Math.max(params.alpha * invT, 0.01);
327
+ const beta = Math.max(params.beta * invT, 0.01);
328
+ samples[cat] = betaSample(alpha, beta);
323
329
  }
324
330
  return samples;
325
331
  }
@@ -476,6 +476,7 @@ const TOOLS = [
476
476
  bundleId: { type: 'string' },
477
477
  partnerProfile: { type: 'string' },
478
478
  delegationMode: { type: 'string', enum: ['off', 'auto', 'sequential'] },
479
+ enforcePlanQuality: { type: 'boolean' },
479
480
  approved: { type: 'boolean' },
480
481
  repoPath: { type: 'string' },
481
482
  },
package/src/api/server.js CHANGED
@@ -3662,6 +3662,49 @@ function extractApiKey(req) {
3662
3662
  return '';
3663
3663
  }
3664
3664
 
3665
+ /**
3666
+ * Map a ThumbGate key presented at the OAuth consent screen to a role.
3667
+ *
3668
+ * - When any key is configured (production), the presented key MUST match a
3669
+ * configured admin/operator/reviewer key; otherwise returns null (reject) so
3670
+ * the OAuth flow actually authenticates the holder.
3671
+ * - When NO keys are configured (insecure/dev mode, e.g. local tests), any
3672
+ * non-empty key is accepted as role 'dev' to preserve local development.
3673
+ *
3674
+ * 'reviewer' (THUMBGATE_REVIEWER_KEY) is a read-only, independently-revocable
3675
+ * credential safe to share with a directory reviewer โ€” tool execution enforces
3676
+ * read-only for it (see the tools/call handler).
3677
+ */
3678
+ // Constant-time comparison of two API/OAuth bearer keys. We compare the raw
3679
+ // bytes with crypto.timingSafeEqual after an explicit equal-length guard
3680
+ // (timingSafeEqual throws on a length mismatch). No digest is taken: these are
3681
+ // high-entropy random credentials compared transiently at request time, not
3682
+ // user passwords stored at rest, so neither a KDF (bcrypt/scrypt/argon2) nor a
3683
+ // length-normalizing hash is appropriate โ€” and hashing the credential here is
3684
+ // exactly what static analysis (correctly, for *stored* passwords) flags. The
3685
+ // only side-channel is whether the two keys share a length, which reveals
3686
+ // nothing useful about a random secret. Once lengths match, the byte compare
3687
+ // is constant-time and leaks no information about where they differ.
3688
+ function safeKeyEqual(a, b) {
3689
+ const x = Buffer.from(String(a || ''), 'utf8');
3690
+ const y = Buffer.from(String(b || ''), 'utf8');
3691
+ if (x.length === 0 || y.length === 0 || x.length !== y.length) return false;
3692
+ return require('crypto').timingSafeEqual(x, y);
3693
+ }
3694
+
3695
+ function resolveKeyRole(key) {
3696
+ const k = String(key || '').trim();
3697
+ const adminKey = String(process.env.THUMBGATE_API_KEY || '').trim();
3698
+ const operatorKey = String(process.env.THUMBGATE_OPERATOR_KEY || '').trim();
3699
+ const reviewerKey = String(process.env.THUMBGATE_REVIEWER_KEY || '').trim();
3700
+ const configured = [adminKey, operatorKey, reviewerKey].filter(Boolean);
3701
+ if (configured.length === 0) return k ? 'dev' : null;
3702
+ if (safeKeyEqual(k, adminKey)) return 'admin';
3703
+ if (safeKeyEqual(k, operatorKey)) return 'operator';
3704
+ if (safeKeyEqual(k, reviewerKey)) return 'reviewer';
3705
+ return null;
3706
+ }
3707
+
3665
3708
  /**
3666
3709
  * Admin-only guard for static THUMBGATE_API_KEY.
3667
3710
  * Billing keys are intentionally excluded from admin actions.
@@ -3883,7 +3926,8 @@ function createApiServer() {
3883
3926
  // operator/admin key โ€” never "any non-empty bearer".
3884
3927
  const adminKey = String(process.env.THUMBGATE_API_KEY || '').trim();
3885
3928
  const operatorKey = String(process.env.THUMBGATE_OPERATOR_KEY || '').trim();
3886
- const rawKeyValid = Boolean(bearer) && ((adminKey && bearer === adminKey) || (operatorKey && bearer === operatorKey));
3929
+ const reviewerKey = String(process.env.THUMBGATE_REVIEWER_KEY || '').trim();
3930
+ const rawKeyValid = Boolean(bearer) && (safeKeyEqual(bearer, adminKey) || safeKeyEqual(bearer, operatorKey) || safeKeyEqual(bearer, reviewerKey));
3887
3931
  const authed = oauthSession
3888
3932
  ? mcpOauth.tokenAudienceValid(oauthSession, resourceUrl)
3889
3933
  : rawKeyValid;
@@ -3899,6 +3943,24 @@ function createApiServer() {
3899
3943
  }));
3900
3944
  return;
3901
3945
  }
3946
+ // The reviewer credential (THUMBGATE_REVIEWER_KEY) is read-only: it may
3947
+ // only invoke tools annotated readOnlyHint:true. This makes a credential
3948
+ // safe to share (e.g. with a directory reviewer) without granting the
3949
+ // ability to mutate shared server state.
3950
+ const effectiveKey = oauthSession ? String(oauthSession.boundKey || '') : bearer;
3951
+ const isReviewer = Boolean(reviewerKey) && safeKeyEqual(effectiveKey, reviewerKey);
3952
+ if (isReviewer) {
3953
+ const name = msg.params && msg.params.name;
3954
+ const tool = MCP_TOOLS.find((t) => t.name === name);
3955
+ const readOnly = Boolean(tool && tool.annotations && tool.annotations.readOnlyHint === true);
3956
+ if (!readOnly) {
3957
+ sendJson(res, 200, {
3958
+ jsonrpc: '2.0', id: msg.id,
3959
+ error: { code: -32002, message: `Tool "${name}" requires write access; the reviewer credential is read-only.` },
3960
+ });
3961
+ return;
3962
+ }
3963
+ }
3902
3964
  (async () => {
3903
3965
  try {
3904
3966
  const { callTool } = require('../../adapters/mcp/server-stdio');
@@ -5278,6 +5340,14 @@ ${hidden}
5278
5340
  const form = new URLSearchParams(body);
5279
5341
  const redirectUri = form.get('redirect_uri') || '';
5280
5342
  const state = form.get('state') || '';
5343
+ // Validate the presented ThumbGate key before issuing a code. When keys
5344
+ // are configured (production) the key MUST match a configured admin /
5345
+ // operator / reviewer key โ€” otherwise OAuth would authenticate nobody.
5346
+ // In insecure/dev mode (no keys configured) any non-empty key is accepted.
5347
+ if (!resolveKeyRole(form.get('api_key') || '')) {
5348
+ sendJson(res, 400, { error: 'access_denied', error_description: 'invalid ThumbGate API key' });
5349
+ return;
5350
+ }
5281
5351
  const issued = mcpOauth.createAuthorizationCode(oauthStore, {
5282
5352
  clientId: form.get('client_id') || '',
5283
5353
  redirectUri,
@@ -6397,6 +6467,49 @@ ${hidden}
6397
6467
  }
6398
6468
 
6399
6469
 
6470
+ // Remote MCP connector documentation โ€” the `resource_documentation` target
6471
+ // advertised by /.well-known/oauth-protected-resource. The Claude Connectors
6472
+ // Directory requires this URL to resolve (200) for submission review.
6473
+ if (isGetLikeRequest && (pathname === '/docs/connectors' || pathname === '/docs/connectors/')) {
6474
+ const mcpUrl = buildPublicUrl(hostedConfig, '/mcp');
6475
+ const cardUrl = buildPublicUrl(hostedConfig, '/.well-known/mcp/server-card.json');
6476
+ const prmUrl = buildPublicUrl(hostedConfig, '/.well-known/oauth-protected-resource');
6477
+ sendHtml(res, 200, `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Remote MCP Connector โ€” ThumbGate</title><meta name="description" content="Connect ThumbGate to Claude as a remote MCP server: OAuth 2.1 (PKCE) authorization, available tools, and the read-only reviewer credential."><style>body{font-family:system-ui,-apple-system,sans-serif;max-width:780px;margin:0 auto;padding:32px 20px;line-height:1.55;color:#1f2937}h1{font-size:30px;margin:0 0 8px}.lede{color:#6b7280;font-size:18px;margin:0 0 28px}h2{font-size:20px;margin:28px 0 8px}code{background:#f3f4f6;padding:1px 6px;border-radius:4px;font-size:13.5px}pre{background:#0f172a;color:#e2e8f0;padding:14px 16px;border-radius:8px;overflow:auto;font-size:13px}a{color:#0066cc}ol,ul{padding-left:22px}li{margin:6px 0}.note{border-left:3px solid #22d3ee;background:#ecfeff;padding:10px 14px;border-radius:0 8px 8px 0;margin:16px 0}footer{margin-top:40px;padding-top:20px;border-top:1px solid #e5e7eb;color:#6b7280;font-size:14px}</style></head><body>
6478
+ <h1>ThumbGate โ€” Remote MCP Connector</h1>
6479
+ <p class="lede">ThumbGate is a remote Model Context Protocol (MCP) server. Add it as a connector in Claude to give an agent governed access to ThumbGate's feedback capture, lesson retrieval, context assembly, and pre-action gate tools โ€” over HTTP, authenticated with OAuth 2.1.</p>
6480
+
6481
+ <h2>Connect URL</h2>
6482
+ <pre>${esc(mcpUrl)}</pre>
6483
+ <p>In Claude, add a custom connector and paste the URL above. Claude discovers the authorization server automatically via the protected-resource metadata at <a href="${esc(prmUrl)}">${esc(prmUrl)}</a>.</p>
6484
+
6485
+ <h2>Authorization (OAuth 2.1 + PKCE)</h2>
6486
+ <ol>
6487
+ <li>Claude reads the <code>resource</code> and <code>authorization_servers</code> from the protected-resource metadata.</li>
6488
+ <li>It runs the standard OAuth 2.1 authorization-code flow with PKCE (<code>S256</code> only โ€” <code>plain</code> is rejected).</li>
6489
+ <li>The issued access token is audience-bound to the <code>${esc(mcpUrl)}</code> resource (RFC 8707); a token for any other audience is rejected.</li>
6490
+ <li>The bearer token is then sent on the <code>Authorization</code> header for every <code>tools/call</code>.</li>
6491
+ </ol>
6492
+
6493
+ <h2>Available tools</h2>
6494
+ <p>The full, machine-readable tool registry โ€” names, input schemas, and the <code>readOnlyHint</code> / <code>destructiveHint</code> annotations โ€” is published at <a href="${esc(cardUrl)}">${esc(cardUrl)}</a>. Tools fall into these groups:</p>
6495
+ <ul>
6496
+ <li><strong>Feedback &amp; lessons</strong> โ€” <code>capture_feedback</code>, <code>feedback_summary</code>, <code>search_lessons</code>, <code>retrieve_lessons</code>, <code>prevention_rules</code>.</li>
6497
+ <li><strong>Context engineering</strong> โ€” <code>construct_context_pack</code>, <code>evaluate_context_pack</code>, <code>unified_context</code>, <code>recall</code>.</li>
6498
+ <li><strong>Pre-action gates &amp; governance</strong> โ€” <code>satisfy_gate</code>, <code>track_action</code>, <code>approve_protected_action</code>, <code>verify_claim</code>, <code>enforcement_matrix</code>.</li>
6499
+ <li><strong>Diagnostics &amp; planning</strong> โ€” <code>diagnose_failure</code>, <code>suggest_fix</code>, <code>security_scan</code>, and the <code>plan_*</code> advisory tools.</li>
6500
+ </ul>
6501
+
6502
+ <h2>Reviewer credential (read-only)</h2>
6503
+ <div class="note">For directory reviewers: ThumbGate issues a dedicated <strong>read-only</strong> reviewer credential. A token bound to that credential may invoke only tools annotated <code>readOnlyHint: true</code>; any write or mutating tool call is rejected. This makes the credential safe to share for review without granting the ability to mutate shared server state. Request it from the contact below.</div>
6504
+
6505
+ <h2>Source &amp; contact</h2>
6506
+ <p>Open-source CLI and server: <a href="https://github.com/IgorGanapolsky/ThumbGate">github.com/IgorGanapolsky/ThumbGate</a>. Questions or reviewer-credential requests: <a href="mailto:igor.ganapolsky@gmail.com">igor.ganapolsky@gmail.com</a>.</p>
6507
+
6508
+ <footer><a href="/">ThumbGate</a> ยท <a href="/support">Support</a> ยท <a href="/privacy">Privacy</a> ยท <a href="/terms">Terms</a></footer>
6509
+ </body></html>`, {}, { headOnly: isHeadRequest });
6510
+ return;
6511
+ }
6512
+
6400
6513
  // Public support / contact page โ€” required for Stripe Business โ†’ Public
6401
6514
  // details "Customer support URL" field. Single source of truth for how
6402
6515
  // customers reach us (email, GitHub issues, status page).
@@ -6753,6 +6866,7 @@ ${hidden}
6753
6866
  bundleId: body.bundleId,
6754
6867
  partnerProfile: body.partnerProfile,
6755
6868
  delegationMode: body.delegationMode,
6869
+ enforcePlanQuality: body.enforcePlanQuality === true,
6756
6870
  approved: body.approved === true,
6757
6871
  repoPath: body.repoPath,
6758
6872
  });