This release includes breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+14 more
Summary
AI summaryBroad release touches Patch Changes, Minor Changes, Release Links, and Verification Standard.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Feature | Low |
npm Email Companion provides full release-note companion for published email template. npm Email Companion provides full release-note companion for published email template. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
Moat decision (2026-05-18) confirms public/private split is not real; public code permissive. Moat decision (2026-05-18) confirms public/private split is not real; public code permissive. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
`scripts/ci-cd-hygiene-audit.js` daily audit surfaces stale PRs, unresolved reviews, conflicts, abandoned PRs, broken workflows. `scripts/ci-cd-hygiene-audit.js` daily audit surfaces stale PRs, unresolved reviews, conflicts, abandoned PRs, broken workflows. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
Two new public pages `/compare/rein` and `/learn/ai-agent-governance` added for competitive intel and SEO term capture. Two new public pages `/compare/rein` and `/learn/ai-agent-governance` added for competitive intel and SEO term capture. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
Pro buyer path collapsed to one Stripe CTA plus intake fallback; added revenue observability doctor. Pro buyer path collapsed to one Stripe CTA plus intake fallback; added revenue observability doctor. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
Gate pattern keys normalized to collapse trivial command variants (e.g., rm -rf node_modules variations). Gate pattern keys normalized to collapse trivial command variants (e.g., rm -rf node_modules variations). Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
New article `/learn/agent-swarms-shared-gates` explains shared gate layer benefits for multi-agent swarms. New article `/learn/agent-swarms-shared-gates` explains shared gate layer benefits for multi-agent swarms. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
`scripts/stripe-business-identity-probe.js` extracts Stripe merchant identity fields visible on checkout page. `scripts/stripe-business-identity-probe.js` extracts Stripe merchant identity fields visible on checkout page. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Feature | Low |
`scripts/stripe-checkout-diagnostic.js` diagnoses why 1000 lifetime checkout sessions produce 0 completed payments. `scripts/stripe-checkout-diagnostic.js` diagnoses why 1000 lifetime checkout sessions produce 0 completed payments. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Performance | Low |
Auto-promoted gates now expire after default 90 days, refreshing on fire and aging out dormant rules. Auto-promoted gates now expire after default 90 days, refreshing on fire and aging out dormant rules. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Bugfix | Medium |
`hook-auto-capture` no longer crashes with `MODULE_NOT_FOUND` in published [email protected]. `hook-auto-capture` no longer crashes with `MODULE_NOT_FOUND` in published [email protected]. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Bugfix | Medium |
Four install-flow bugs fixed: creator-dev fallback, hook pruning with shell vars, isProTier ignoring creator-dev, proNudge upsell nagging paid users. Four install-flow bugs fixed: creator-dev fallback, hook pruning with shell vars, isProTier ignoring creator-dev, proNudge upsell nagging paid users. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Bugfix | Low |
`thumbgate help` now shows curated 8-command short surface, full via `help all`. `thumbgate help` now shows curated 8-command short surface, full via `help all`. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
| Refactor | Low |
`/` workflow-sprint section now wrapped in `<details>` element, default collapsed. `/` workflow-sprint section now wrapped in `<details>` element, default collapsed. Source: granite4.1:8b-q6_K@2026-05-19 Confidence: high |
— |
Full changelog
[email protected]
Release Links
- npm: https://www.npmjs.com/package/thumbgate/v/1.20.0
- GitHub Release: https://github.com/IgorGanapolsky/ThumbGate/releases/tag/v1.20.0
- Compare: https://github.com/IgorGanapolsky/ThumbGate/compare/v1.19.0...v1.20.0
- Publish workflow: https://github.com/IgorGanapolsky/ThumbGate/actions/runs/26056454240
- npm published at: 2026-05-18T19:46:11.527Z
- npm shasum:
e4e125bc989c586a8882c66930908edce0644a2b - npm tarball: https://registry.npmjs.org/thumbgate/-/thumbgate-1.20.0.tgz
- Release ref: 439b57f1d03d6e83250e96d7732403f486954c22
npm Email Companion
npm controls the native "Successfully published" email template, so the email itself stays short. Treat this generated artifact as the full release-note companion for that email: it carries the Changeset summaries, CHANGELOG entry, publish workflow, npm tarball, and shasum when available.
Full Changeset Release Notes
Minor Changes
.changeset/fix-cli-feedback-private-core-require.md
Fix: hook-auto-capture crashed with MODULE_NOT_FOUND in published [email protected].
scripts/cli-feedback.js did an unconditional require('./history-distiller'). But history-distiller.js is a PRIVATE_CORE_MODULE — present in the source checkout and in ThumbGate-Core, but intentionally excluded from the public npm tarball (see tests/public-package-boundary.test.js). When a published install ran the Claude Code UserPromptSubmit hook (hook-auto-capture), the require chain reached cli-feedback.js, hit the missing history-distiller, and threw — meaning every thumbs up: / thumbs down: typed in a hooked agent was silently dropped.
Fix: switched the require to loadOptionalModule('./history-distiller', () => ({ distillFromHistory: () => null })), matching the pattern already in use by scripts/feedback-loop.js and src/api/server.js. The caller in processInlineFeedback already handles distillResult === null gracefully, so the public-shell state degrades cleanly: feedback is still captured, distillation is skipped.
Regression test in tests/public-package-boundary.test.js#cli-feedback loads and runs in public-tarball state forces the public-shell state via the existing withBoundaryFallbackModule helper and asserts processInlineFeedback returns a feedback record with distillResult either null or an object. This locks the bug class for cli-feedback.
.changeset/moat-decision-ratchet.md
Moat decision (2026-05-18, audit-based). Settles the "is the public/private split real?" question. Audit found 212 of 216 Core scripts also ship publicly via npm (98% overlap). The previous CLAUDE.md framing was aspirational; in practice the boundary did not exist.
This commit picks Option A from the strict assessment: hosted-services moat, not closed-source intelligence. Public code is permissive on purpose. The defensibility surfaces are (a) hosted infrastructure + reliability, (b) adapter compatibility matrix across Claude / Cursor / Codex / Gemini / Amp / Cline / OpenCode, (c) the dashboard + DPO export pipeline, (d) sprint / setup support revenue.
Surfaces:
MOAT.md— full reasoning, including the 412 / 216 / 212 / 4 file-count breakdownCLAUDE.md— "Product Architecture Split" section rewritten as "Moat — Hosted Services, Not Closed-Source Intelligence." Four active rules replace the previous five aspirational onestests/public-bundle-ratchet.test.js— pins the npm bundle file count at the 2026-05-18 baseline (254 files). Can decrease, cannot increase without a baseline bump + CHANGELOG note. Override env varTHUMBGATE_BUNDLE_RATCHET_BASELINEdocumented inlinepackage.json—test:public-bundle-ratchetwired into the maintestchain so the regression-guard runs
tests/public-core-boundary.test.js is unchanged and stays green — it tests that default public CI doesn't depend on Core, which is still a real correctness property.
.changeset/rule-ttl-expiry.md
Auto-promoted gates now expire. Default TTL is 90 days from promotion; tunable via THUMBGATE_RULE_TTL_DAYS. Gates that fire within the window have their TTL refreshed automatically (high-signal rules survive, dormant ones age out). Manually force-promoted gates (MANUAL=1) remain permanent (expiresAt=null).
Addresses the public critique from r/ClaudeCode (MomSausageandPeppers, 2026-05-17): "make single thumbs-down promotion reversible or expiry-bound; otherwise accidental dislikes become policy forever." Previously, one thumbs-down at BLOCK_THRESHOLD could pin a gate on disk indefinitely with no decay path.
New exports on scripts/auto-promote-gates.js:
expireGates(data, now?)— sweeps expired gates, refreshes recently-fired onesrecordGateFire(data, gateId, now?)— call when a gate actually blocks; updateslastFiredAtand extendsexpiresAtgetRuleTtlDays()/getRuleTtlMs()/DEFAULT_RULE_TTL_DAYS
promote() now calls expireGates() before the promotion loop, so every daily run garbage-collects stale rules. New gate records carry expiresAt (ISO date) and lastFiredAt (null until first block). Malformed input (missing gates, non-array gates) is tolerated without throwing.
10 new unit tests in tests/auto-promote-gates.test.js cover TTL defaults, env override (with negative/non-numeric fallback), expiry sweep, refresh-on-fire, permanent-gate semantics, and malformed-input tolerance. All 30 tests in the file pass.
Patch Changes
.changeset/ci-cd-hygiene-audit.md
Add scripts/ci-cd-hygiene-audit.js — daily audit that surfaces stale PRs, unresolved bot review threads, ignored CLEAN PRs, and repeatedly-failing workflows.
This is the missing fire-alarm for the kind of problem that just bit us: on 2026-05-17 the CEO asked "why isn't v1.19.0 published?" and the audit-by-hand turned up #1953 sitting CLEAN for 5 days, 4 unresolved Codex bot threads across 2 PRs, and the release PR (#2082) blocked on one failing test that nobody had looked at. None of it was visible until someone asked.
Surfaces 5 signal classes:
- Merge backlog — CLEAN PRs sitting open ≥ 2 days
- Unread review — PRs with unresolved bot review threads (Codex / SonarCloud / etc.)
- Stale conflicts — DIRTY PRs open ≥ 5 days
- Abandoned — PRs with zero comments + zero reviews after 7 days
- Broken workflows — workflows that failed ≥3 times in the last 100 runs
Wired into the Daily Revenue Loop alongside the existing rollups; outputs go to reports/revenue/cicd-hygiene.{md,json} and a GitHub Actions job-summary section. --strict exits 1 when the merge backlog reaches 3, so the workflow goes yellow when shipping hygiene is failing.
10 unit tests with an injected fake gh exec cover all 5 buckets, the age math, the workflow-failure-threshold logic, and the markdown render (both populated and empty paths).
.changeset/compare-rein-and-governance-pattern.md
Ship two new public pages from competitive-intel on the Rein governance project (LinkedIn post by @jnwhampton, 2026-05-15):
-
/compare/rein— honest side-by-side. Both projects intercept agent actions before they fire; that's the shared category. The differences: integration layer (decorator vs PreToolUse hook), target user (production app agents in regulated domains vs AI coding agents), license (AGPL vs MIT), and learning loop (Rein has policy authoring; ThumbGate has thumbs-down → auto-promoted prevention rule). Not framed as "we win" — Rein is well-designed software, picks differ by stack. -
/learn/ai-agent-governance— claim the SEO term Rein is targeting by defining the four-layer pattern (prompt rules / decorator wrappers / pre-action hooks / sandbox isolation) and positioning ThumbGate at layer 3. The page is layer-agnostic; it explicitly tells readers to pick Rein at layer 2 if Rein's profile matches their stack.
Also wires both pages into /compare index card layout and adds them to the tests/learn-hub.test.js valid-internal-paths allowlist alongside /learn/spec-driven-development (the previous PR that was missed in that allowlist).
.changeset/curate-help-output.md
thumbgate help (and bare thumbgate) now shows a curated 8-command short surface — init, capture, stats, lessons, explore, dashboard, doctor, pro — instead of dumping ~70 subcommands, internal hooks, "Also available" specialists, global flags, every explore sub-mode, and 18 example invocations the moment a first-time user types it.
The full surface is still discoverable via thumbgate help all (also --all / --full), unchanged from before.
Test coverage rewritten: tests/cli.test.js now asserts the short surface in the default path and the full surface behind help all, with a negative assertion that deep-niche commands (proactive-agent-eval-guardrails, repair-github-marketplace, etc.) stay out of the default view.
Surfaced by a real customer screenshot on 2026-05-18: the default output was getting truncated at the terminal's right margin and reading as noise.
.changeset/fix-creator-dev-and-init-bugs.md
Fix four install-flow bugs surfaced during a real customer walkthrough on 2026-05-18:
-
npx thumbgate pro(no args) silently falls back to the info banner for creator-dev users — the dashboard-launch predicateif (resolvedKey && resolvedKey.key)rejected the legitimate{key:'', source:'creator-dev', plan:'enterprise'}shape thatresolveProKey()returns whenTHUMBGATE_DEV_KEYis unset. Predicate now also acceptssource === 'creator-dev', matching whatstartLocalProDashboardalready supports. -
initsilently deletes user-authored hooks whose command contains a shell variable.pruneStaleFileHookswas treating"$CLAUDE_PROJECT_DIR"/.claude/hooks/x.shas a literal filesystem path, sofs.existsSyncreturned false and the hook was removed with a misleading "Removed stale hook referencing missing file" warning even when the script existed. Added a bounded$VAR/${VAR}expander with quote stripping, and a fail-safe: if any$remains after expansion, skip pruning rather than risk destroying a valid hook. -
isProTier()ignored creator-dev installs, so commands that DO consult it (upgradeNudge, rate gates) still nagged the maintainer on their own machine. Added anisCreatorDev()check. -
proNudgenever consultedisProTierat all — everystats/lessons/summarycall printed the Pro upsell even for paid users. Now short-circuits on Pro tier (and transitively on creator-dev).
README Quick Start showed the bare positional npx thumbgate capture "text" form which actually errors Missing or unrecognized --feedback=up|down — replaced with the working --feedback= --context= form. Same correction in the CLI Reference section.
6 new regression tests in tests/creator-dev-and-prune.test.js. All 150 existing cli / hook / rate-limiter tests still pass.
.changeset/focused-pro-checkout-observability.md
Collapse the Pro buyer path to one Stripe CTA plus intake fallback by removing unrelated service payment links from /pro and the checkout interstitial, and add a revenue observability doctor that fails closed when revenue or visitor proof access is missing.
.changeset/funnel-collapse-services.md
Funnel collapse on /. The workflow-sprint section (paid consulting: $97 kit, $499 diagnostic, $1500 sprint, $3997 setup, $297/mo retainer) is now wrapped in a <details> element collapsed by default. A cold visitor scrolling the landing page sees only the three coherent SaaS tiers (Free $0, Pro $19/mo, Team $49/seat/mo) instead of 11 competing price points.
Verified counts:
- Before: 11 distinct price points visible on default scroll
- After: 6 visible (
$0,$19,$19/mo,$49,$49/seat/mo,$147/mo) — all SaaS tier prices, no mixed signals - Consulting prices still present, one click away, no revenue surface lost
Addresses the 2026-05-18 strict assessment finding: "Eleven distinct price points on one page, with three separate purchase paths. A cold buyer cannot tell what to buy. This is the biggest single problem."
Zero changes to: server routes, Stripe links, telemetry hooks, anchor IDs (#workflow-sprint-intake still resolves), form submission flow. Pure HTML restructure.
.changeset/gate-command-normalization.md
Gate pattern keys now collapse trivial command variants. Previously, rm -rf node_modules, rm -rf ./node_modules, and rm -rf "node_modules" produced three separate gate IDs — accidental dislikes proliferated and one captured failure didn't catch its near-twins on the next run.
Addresses the r/ClaudeCode critique (MomSausageandPeppers, 2026-05-17): "commands are matched by string equality, so trivial variations create separate gates."
New helper normalizeCommandSignature(input) (exported from scripts/auto-promote-gates.js) applies a conservative set of transforms:
- lowercase
- strip
/Users/<name>/and/home/<name>/home-dir prefixes (→~) - drop
:LINEand:LINE:COLrefs - per-token: strip one layer of matching outer quotes/backticks
- per-token: drop leading
./ - collapse whitespace + trim
Explicitly does not reorder flags, collapse && chains, or canonicalize subcommands — each of those can change semantics. Regression tests pin both behaviors (does NOT reorder flags, does NOT collapse && chains).
extractPatternKey() now routes context through normalizeCommandSignature so five common rm-rf variants collapse to one gate ID. Tag-based keys still take precedence when tags are present.
12 new tests in tests/auto-promote-gates.test.js; 31/31 in file passing.
.changeset/learn-agent-swarms.md
New article: /learn/agent-swarms-shared-gates — explains why multi-agent swarms pay N× the token cost on every repeated mistake without shared safety memory, and how a single MCP gate layer makes Opus, GPT, and Gemini fail the same way only once.
Captures real search intent ("agent swarm token cost", "multi-agent shared memory", "agent swarm shared state") and grounds the claim in ThumbGate's actual architecture: one feedback dir, one PreToolUse hook, model-agnostic pattern matching, JSONL append-only feedback log that handles concurrent captures from multiple agents.
Honest framing: explicitly states what a shared gate layer does NOT solve (work routing, model selection, load balancing — that's the swarm framework's job). Linked from the learn index.
.changeset/stripe-business-identity-probe.md
Add scripts/stripe-business-identity-probe.js — what does the buyer actually see on the Stripe-hosted checkout page?
The stripe-checkout-diagnostic from PR #2097 revealed the failure mode is buyer-bail-at-Stripe-page (100 sessions, 100% open/expired, 100% no customer email, zero payment_intent errors). That means buyers are seeing something on the Stripe page in the first 3 seconds that makes them close the tab. The diagnostic doesn't pull the identity surface — what name/logo/description/statement_descriptor the merchant actually has configured. This probe does.
Pulls every Stripe-side field that contributes to brand recognition on the checkout page:
account.business_profile.{name, url, support_email, product_description, mcc}— buyer-facing merchant identityaccount.settings.payments.statement_descriptor— what shows on the card statement after purchaseaccount.settings.card_payments.statement_descriptor_prefixaccount.settings.branding.{logo, icon, primary_color, secondary_color}— visual continuity from thumbgate.ai → Stripe pagepaymentLinks.listper-link config:active,submit_type,billing_address_collection,phone_number_collection, custom_text presence, metadata keys- Diagnoses each missing field as
critical/warning/infowith a specific message about what the buyer will see (or not see) as a result.
Wired into the Daily Revenue Loop workflow as a new step between unified-rollup and external-customer-audit. Outputs markdown + JSON to reports/revenue/stripe-business-identity.* plus a GitHub Actions job-summary section.
12 unit tests cover identity field extraction (with and without business_profile / branding / payments / card_payments sections), gap diagnosis (critical on missing name, warning when name doesn't contain "ThumbGate", info on missing URL / support_email), Payment Link summary extraction, Payment Link gap diagnosis (critical on inactive Payment Link still on file, warning on phone-collection friction), the runProbe end-to-end happy path, and unconfigured-Stripe degradation.
.changeset/stripe-checkout-diagnostic.md
Add scripts/stripe-checkout-diagnostic.js — answers the question raised by the external-customer-audit (PR #2095): WHY are 1000 lifetime checkout sessions producing 0 completed payments? The unified rollup reports the count but not the cause. This script pulls real Stripe API data for the cause.
Diagnostic surface:
- Checkout session terminal-status breakdown (complete / expired / open / ...) plus payment_status distribution.
- PaymentIntent
last_payment_errorrollup by code, type, and decline_code — distinguishes "buyer abandoned at email step" from "card declined" from "fraud rule fired." - Stripe Account health:
details_submitted,charges_enabled,payouts_enabled,requirements.disabled_reason,currently_due,past_due,pending_verificationarrays — the explicit fields blocking the account from normal processing. - Webhook endpoint inventory — flags the perception-risk case where checkouts complete on Stripe but our local ledger never sees them because no webhook is wired.
- Recent-20-sessions table with cross-linked payment_intent error data so the operator can see the most recent failure modes in one view.
The markdown report includes a top-to-bottom diagnosis ranking: if charges_enabled = false it names that as the binding blocker before anything else; if zero payment intents have errors but many sessions exist, it names buyer abandonment as the diagnosis; if no webhooks are configured, it warns that "0 completions" may be undercounted.
Wired into the Daily Revenue Loop workflow alongside the unified rollup and the external-customer audit. Outputs both markdown and JSON to reports/revenue/stripe-checkout-diagnostic.* and a GitHub job-summary section.
9 unit tests with an injected fake Stripe client cover argument parsing, status / payment-status / error-code bucketing, the binding-blocker diagnosis path, the missing-webhook flag, recent-sessions table rendering with PI error codes, and the uniform-abandonment-without-errors diagnosis.
CHANGELOG.md Entry
No CHANGELOG.md section was found for 1.20.0; the release notes above were generated from the changed Changeset files.
Verification Standard
- Publish only runs from
mainafter version sync, tests, and runtime proof pass. - The npm package is smoke-tested after publish by installing
thumbgate@VERSIONin a clean runtime. - GitHub Release notes are generated from Changesets, not only GitHub auto-generated PR titles.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About IgorGanapolsky/mcp-memory-gateway
Pre-action gates that prevent AI coding agents from repeating known mistakes. Captures explicit feedback, auto-promotes failures into prevention rules, and enforces them via hooks.
Related context
Beta — feedback welcome: [email protected]