thumbgate 0.9.9 → 0.9.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/.claude-plugin/README.md +4 -4
  2. package/.claude-plugin/marketplace.json +4 -2
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +115 -312
  6. package/adapters/README.md +2 -2
  7. package/adapters/amp/skills/{rlhf-feedback → thumbgate-feedback}/SKILL.md +1 -1
  8. package/adapters/chatgpt/openapi.yaml +2 -2
  9. package/adapters/claude/.mcp.json +3 -3
  10. package/adapters/codex/config.toml +4 -4
  11. package/adapters/gemini/function-declarations.json +1 -1
  12. package/adapters/mcp/server-stdio.js +66 -6
  13. package/adapters/opencode/opencode.json +4 -2
  14. package/bin/cli.js +188 -39
  15. package/config/e2e-critical-flows.json +4 -0
  16. package/config/gates/default.json +74 -2
  17. package/config/github-about.json +1 -1
  18. package/config/mcp-allowlists.json +33 -6
  19. package/config/skill-packs/react-testing.json +1 -1
  20. package/config/tessl-tiles.json +3 -3
  21. package/openapi/openapi.yaml +2 -2
  22. package/package.json +23 -9
  23. package/plugins/amp-skill/INSTALL.md +3 -2
  24. package/plugins/amp-skill/SKILL.md +1 -0
  25. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  26. package/plugins/claude-codex-bridge/.mcp.json +5 -3
  27. package/plugins/claude-codex-bridge/README.md +1 -1
  28. package/plugins/claude-codex-bridge/skills/setup/SKILL.md +1 -1
  29. package/plugins/claude-skill/INSTALL.md +4 -3
  30. package/plugins/claude-skill/SKILL.md +1 -1
  31. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  32. package/plugins/codex-profile/.mcp.json +5 -3
  33. package/plugins/codex-profile/INSTALL.md +2 -2
  34. package/plugins/codex-profile/README.md +1 -1
  35. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  36. package/plugins/cursor-marketplace/README.md +5 -5
  37. package/plugins/cursor-marketplace/mcp.json +4 -2
  38. package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +1 -1
  39. package/plugins/cursor-marketplace/scripts/gate-check.sh +15 -5
  40. package/plugins/gemini-extension/INSTALL.md +4 -4
  41. package/plugins/opencode-profile/INSTALL.md +5 -5
  42. package/public/dashboard.html +15 -8
  43. package/public/index.html +134 -375
  44. package/public/js/buyer-intent.js +252 -0
  45. package/public/pro.html +1085 -0
  46. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  47. package/scripts/adk-consolidator.js +17 -5
  48. package/scripts/agent-readiness.js +3 -1
  49. package/scripts/agent-security-hardening.js +4 -4
  50. package/scripts/auto-promote-gates.js +8 -0
  51. package/scripts/auto-wire-hooks.js +105 -21
  52. package/scripts/billing.js +111 -7
  53. package/scripts/build-metadata.js +14 -0
  54. package/scripts/check-congruence.js +1 -1
  55. package/scripts/context-engine.js +2 -1
  56. package/scripts/daemon-manager.js +2 -2
  57. package/scripts/dashboard.js +2 -2
  58. package/scripts/data-governance.js +1 -1
  59. package/scripts/deploy-gcp.sh +1 -1
  60. package/scripts/deploy-policy.js +22 -4
  61. package/scripts/dispatch-brief.js +1 -1
  62. package/scripts/ensure-repo-bootstrap.js +1 -1
  63. package/scripts/feedback-attribution.js +22 -10
  64. package/scripts/feedback-fallback.js +3 -2
  65. package/scripts/feedback-inbox-read.js +1 -1
  66. package/scripts/feedback-loop.js +41 -3
  67. package/scripts/feedback-paths.js +8 -8
  68. package/scripts/feedback-schema.js +1 -1
  69. package/scripts/feedback-to-memory.js +2 -2
  70. package/scripts/filesystem-search.js +2 -2
  71. package/scripts/gates-engine.js +765 -34
  72. package/scripts/generate-paperbanana-diagrams.sh +3 -3
  73. package/scripts/github-about.js +1 -1
  74. package/scripts/gtm-revenue-loop.js +20 -1
  75. package/scripts/hook-runtime.js +89 -0
  76. package/scripts/hook-stop-self-score.sh +3 -3
  77. package/scripts/hook-thumbgate-cache-updater.js +98 -37
  78. package/scripts/hosted-config.js +12 -10
  79. package/scripts/hybrid-feedback-context.js +54 -13
  80. package/scripts/install-mcp.js +14 -1
  81. package/scripts/intent-router.js +1 -1
  82. package/scripts/internal-agent-bootstrap.js +1 -1
  83. package/scripts/lesson-inference.js +6 -1
  84. package/scripts/license.js +54 -16
  85. package/scripts/mcp-config.js +69 -7
  86. package/scripts/memory-migration.js +1 -1
  87. package/scripts/money-watcher.js +166 -16
  88. package/scripts/operational-integrity.js +480 -0
  89. package/scripts/optimize-context.js +1 -1
  90. package/scripts/perplexity-marketing.js +1 -1
  91. package/scripts/post-everywhere.js +7 -12
  92. package/scripts/post-to-x.js +1 -1
  93. package/scripts/pr-manager.js +14 -11
  94. package/scripts/problem-detail.js +10 -10
  95. package/scripts/profile-router.js +2 -0
  96. package/scripts/prompt-dlp.js +1 -0
  97. package/scripts/prove-adapters.js +6 -6
  98. package/scripts/prove-automation.js +1 -1
  99. package/scripts/prove-autoresearch.js +1 -1
  100. package/scripts/prove-claim-verification.js +3 -3
  101. package/scripts/prove-data-pipeline.js +5 -5
  102. package/scripts/prove-data-quality.js +1 -1
  103. package/scripts/prove-evolution.js +7 -7
  104. package/scripts/prove-harnesses.js +2 -2
  105. package/scripts/prove-lancedb.js +2 -2
  106. package/scripts/prove-local-intelligence.js +1 -1
  107. package/scripts/prove-loop-closure.js +1 -1
  108. package/scripts/prove-predictive-insights.js +2 -2
  109. package/scripts/prove-runtime.js +6 -6
  110. package/scripts/prove-seo-gsd.js +1 -1
  111. package/scripts/prove-settings.js +4 -4
  112. package/scripts/prove-subway-upgrades.js +1 -1
  113. package/scripts/prove-tessl.js +2 -2
  114. package/scripts/prove-xmemory.js +2 -2
  115. package/scripts/publish-decision.js +10 -0
  116. package/scripts/published-cli.js +34 -0
  117. package/scripts/rate-limiter.js +2 -2
  118. package/scripts/reddit-monitor-cron.sh +2 -2
  119. package/scripts/reminder-engine.js +1 -1
  120. package/scripts/schedule-manager.js +3 -3
  121. package/scripts/self-healing-check.js +1 -1
  122. package/scripts/shieldcortex-memory-firewall-runner.mjs +1 -1
  123. package/scripts/skill-quality-tracker.js +1 -1
  124. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  125. package/scripts/social-analytics/db/social-analytics.db-wal +0 -0
  126. package/scripts/social-analytics/engagement-audit.js +202 -0
  127. package/scripts/social-analytics/generate-instagram-card.js +1 -1
  128. package/scripts/social-analytics/instagram-thumbgate-post.js +5 -1
  129. package/scripts/social-analytics/install-growth-automation.js +114 -0
  130. package/scripts/social-analytics/publish-instagram-thumbgate.js +8 -2
  131. package/scripts/social-analytics/publish-thumbgate-launch.js +1 -1
  132. package/scripts/social-analytics/publishers/reddit.js +7 -12
  133. package/scripts/social-analytics/publishers/zernio.js +19 -0
  134. package/scripts/social-analytics/reconcile-thumbgate-campaign.js +165 -0
  135. package/scripts/social-analytics/schedule-thumbgate-campaign.js +275 -0
  136. package/scripts/social-analytics/sync-launch-assets.js +185 -0
  137. package/scripts/social-pipeline.js +2 -2
  138. package/scripts/social-post-hourly.js +185 -0
  139. package/scripts/social-quality-gate.js +119 -3
  140. package/scripts/social-reply-monitor.js +150 -34
  141. package/scripts/statusline-cache-path.js +27 -0
  142. package/scripts/statusline-meta.js +22 -0
  143. package/scripts/statusline.sh +24 -32
  144. package/scripts/sync-version.js +24 -12
  145. package/scripts/telemetry-analytics.js +4 -4
  146. package/scripts/tessl-export.js +1 -1
  147. package/scripts/test-coverage.js +20 -13
  148. package/scripts/thumbgate-search.js +2 -2
  149. package/scripts/tool-registry.js +98 -1
  150. package/scripts/train_from_feedback.py +1 -1
  151. package/scripts/user-profile.js +4 -4
  152. package/scripts/validate-feedback.js +1 -1
  153. package/scripts/vector-store.js +1 -1
  154. package/scripts/verification-loop.js +1 -1
  155. package/scripts/verify-run.js +1 -1
  156. package/scripts/weekly-auto-post.js +1 -1
  157. package/skills/{rlhf-feedback → thumbgate-feedback}/SKILL.md +1 -1
  158. package/src/api/server.js +291 -41
  159. package/scripts/__pycache__/train_from_feedback.cpython-314.pyc +0 -0
  160. package/scripts/social-analytics/db/social-analytics.db +0 -0
@@ -4,7 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  PROJECT_ID=$(gcloud config get-value project)
7
- SERVICE_NAME="rlhf-control-plane"
7
+ SERVICE_NAME="thumbgate-control-plane"
8
8
  REGION="us-central1"
9
9
 
10
10
  : "${THUMBGATE_API_KEY:?THUMBGATE_API_KEY is required}"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const { normalizeOrigin } = require('./hosted-config');
4
+ const { DEFAULT_PUBLIC_APP_ORIGIN, normalizeOrigin } = require('./hosted-config');
5
5
 
6
6
  const SECRET_POLICY = {
7
7
  THUMBGATE_API_KEY: { rotatedAtEnv: 'THUMBGATE_API_KEY_ROTATED_AT', maxAgeDays: 30 },
@@ -39,6 +39,23 @@ const PROFILE_DEFS = {
39
39
  },
40
40
  };
41
41
 
42
+ function resolveEnvValue(name, env = process.env) {
43
+ const value = String(env[name] || '').trim();
44
+ if (value) {
45
+ return value;
46
+ }
47
+
48
+ if (name === 'THUMBGATE_PUBLIC_APP_ORIGIN') {
49
+ return DEFAULT_PUBLIC_APP_ORIGIN;
50
+ }
51
+
52
+ if (name === 'THUMBGATE_BILLING_API_BASE_URL') {
53
+ return resolveEnvValue('THUMBGATE_PUBLIC_APP_ORIGIN', env);
54
+ }
55
+
56
+ return '';
57
+ }
58
+
42
59
  function parseTimestamp(value) {
43
60
  if (!value || typeof value !== 'string') {
44
61
  return null;
@@ -98,7 +115,7 @@ function evaluateDeployPolicy(env = process.env, { profiles = ['runtime'], now =
98
115
  const errors = [];
99
116
 
100
117
  for (const name of requiredVars) {
101
- const value = String(env[name] || '').trim();
118
+ const value = resolveEnvValue(name, env);
102
119
  if (!value) {
103
120
  errors.push({ type: 'missing_variable', name, message: `${name} is required` });
104
121
  continue;
@@ -114,7 +131,7 @@ function evaluateDeployPolicy(env = process.env, { profiles = ['runtime'], now =
114
131
  }
115
132
 
116
133
  for (const name of requiredSecrets) {
117
- const secretValue = String(env[name] || '');
134
+ const secretValue = resolveEnvValue(name, env);
118
135
  if (!secretValue.trim()) {
119
136
  errors.push({ type: 'missing_secret', name, message: `${name} is required` });
120
137
  continue;
@@ -125,7 +142,7 @@ function evaluateDeployPolicy(env = process.env, { profiles = ['runtime'], now =
125
142
  continue;
126
143
  }
127
144
 
128
- const rotatedAtRaw = String(env[policy.rotatedAtEnv] || '').trim();
145
+ const rotatedAtRaw = resolveEnvValue(policy.rotatedAtEnv, env);
129
146
  if (!rotatedAtRaw) {
130
147
  errors.push({
131
148
  type: 'missing_rotation_timestamp',
@@ -222,6 +239,7 @@ module.exports = {
222
239
  PROFILE_DEFS,
223
240
  parseTimestamp,
224
241
  getAgeDays,
242
+ resolveEnvValue,
225
243
  evaluateDeployPolicy,
226
244
  formatReport,
227
245
  };
@@ -9,7 +9,7 @@ const DISPATCH_TASK_DESCRIPTIONS = {
9
9
  feedback_summary: 'Summarize recent wins, failures, and operator notes.',
10
10
  search_lessons: 'Search promoted lessons and inspect what corrective action the system linked to each one.',
11
11
  retrieve_lessons: 'Retrieve top-K relevant lessons for a given tool/action context (per-action guidance).',
12
- search_rlhf: 'Search raw ThumbGate feedback, ContextFS memory, and prevention rules.',
12
+ search_thumbgate: 'Search raw ThumbGate feedback, ContextFS memory, and prevention rules.',
13
13
  feedback_stats: 'Inspect approval trends and failure domains.',
14
14
  diagnose_failure: 'Explain why a run failed or was blocked.',
15
15
  list_intents: 'List available workflow plans without executing them.',
@@ -7,7 +7,7 @@ const path = require('path');
7
7
  const REPO_ROOT = path.resolve(process.argv[2] || process.cwd());
8
8
  const RLHF_ENTRY = {
9
9
  command: 'npx',
10
- args: ['-y', 'mcp-memory-gateway@latest', 'serve'],
10
+ args: ['-y', 'thumbgate@latest', 'serve'],
11
11
  };
12
12
  const LEGACY_SERVER_NAMES = ['thumbgate', 'rlhf_feedback_loop'];
13
13
  const INFO_EXCLUDE_ENTRIES = ['.rlhf/', '.thumbgate/', '.mcp.json'];
@@ -5,12 +5,22 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
  const { resolveFeedbackDir } = require('./feedback-paths');
7
7
 
8
- const FEEDBACK_DIR = resolveFeedbackDir();
9
- const PATHS = {
10
- actionLog: path.join(FEEDBACK_DIR, 'action-log.jsonl'),
11
- attributions: path.join(FEEDBACK_DIR, 'feedback-attributions.jsonl'),
12
- attributedFeedback: path.join(FEEDBACK_DIR, 'attributed-feedback.jsonl'),
13
- };
8
+ function getAttributionPaths(options = {}) {
9
+ const feedbackDir = resolveFeedbackDir({
10
+ cwd: options.cwd,
11
+ env: options.env,
12
+ feedbackDir: options.feedbackDir,
13
+ home: options.home,
14
+ });
15
+ return {
16
+ feedbackDir,
17
+ actionLog: path.join(feedbackDir, 'action-log.jsonl'),
18
+ attributions: path.join(feedbackDir, 'feedback-attributions.jsonl'),
19
+ attributedFeedback: path.join(feedbackDir, 'attributed-feedback.jsonl'),
20
+ };
21
+ }
22
+
23
+ const PATHS = getAttributionPaths();
14
24
 
15
25
  const STOPWORDS = new Set([
16
26
  'about', 'after', 'again', 'allow', 'already', 'always', 'because', 'before', 'being', 'between',
@@ -155,7 +165,7 @@ function scoreCandidate(action, feedbackNormalized, feedbackTokens, nowMs) {
155
165
  }
156
166
 
157
167
  function recordAction(toolName, toolInput, opts = {}) {
158
- const actionLogPath = opts.actionLogPath || process.env.THUMBGATE_ACTION_LOG || PATHS.actionLog;
168
+ const actionLogPath = opts.actionLogPath || process.env.THUMBGATE_ACTION_LOG || getAttributionPaths(opts).actionLog;
159
169
  const tool = String(toolName || 'unknown');
160
170
  const inputSummary = summarizeToolInput(tool, toolInput);
161
171
  const normalized = normalize(inputSummary);
@@ -175,9 +185,10 @@ function recordAction(toolName, toolInput, opts = {}) {
175
185
 
176
186
  function attributeFeedback(signal, feedbackContext, opts = {}) {
177
187
  const sig = String(signal || '').toLowerCase().trim();
178
- const actionLogPath = opts.actionLogPath || process.env.THUMBGATE_ACTION_LOG || PATHS.actionLog;
179
- const attributionsPath = opts.attributionsPath || process.env.THUMBGATE_FEEDBACK_ATTRIBUTIONS || PATHS.attributions;
180
- const attributedFeedbackPath = opts.attributedFeedbackPath || process.env.THUMBGATE_ATTRIBUTED_FEEDBACK || PATHS.attributedFeedback;
188
+ const paths = getAttributionPaths(opts);
189
+ const actionLogPath = opts.actionLogPath || process.env.THUMBGATE_ACTION_LOG || paths.actionLog;
190
+ const attributionsPath = opts.attributionsPath || process.env.THUMBGATE_FEEDBACK_ATTRIBUTIONS || paths.attributions;
191
+ const attributedFeedbackPath = opts.attributedFeedbackPath || process.env.THUMBGATE_ATTRIBUTED_FEEDBACK || paths.attributedFeedback;
181
192
 
182
193
  if (sig !== 'negative' && sig !== 'positive') {
183
194
  return { ok: true, skipped: true, reason: 'signal_not_supported' };
@@ -298,6 +309,7 @@ if (require.main === module) {
298
309
 
299
310
  module.exports = {
300
311
  PATHS,
312
+ getAttributionPaths,
301
313
  readJsonl,
302
314
  appendJsonl,
303
315
  normalize,
@@ -13,10 +13,11 @@
13
13
 
14
14
  const http = require('http');
15
15
  const https = require('https');
16
+ const { DEFAULT_PUBLIC_APP_ORIGIN } = require('./hosted-config');
16
17
 
17
18
  const ENDPOINTS = [
18
- { url: 'http://localhost:9876/v1/feedback/capture', key: 'tg_creator_dev_enterprise', label: 'local' },
19
- { url: 'http://localhost:3456/v1/feedback/capture', key: 'tg_creator_dev_enterprise', label: 'local-alt' },
19
+ { url: 'http://localhost:3456/v1/feedback/capture', key: process.env.THUMBGATE_API_KEY || 'tg_creator_dev_enterprise', label: 'local' },
20
+ { url: `${DEFAULT_PUBLIC_APP_ORIGIN}/v1/feedback/capture`, key: process.env.THUMBGATE_API_KEY || 'tg_creator_dev_enterprise', label: 'hosted' },
20
21
  ];
21
22
 
22
23
  function parseArgs() {
@@ -94,7 +94,7 @@ function runTests() {
94
94
  const entries = [
95
95
  { signal: 'negative', context: 'Bad thing happened', tags: ['testing'] },
96
96
  { signal: 'positive', context: 'Good thing happened', tags: ['testing'] },
97
- { signal: 'negative', context: 'Another bad thing', tags: ['rlhf'] },
97
+ { signal: 'negative', context: 'Another bad thing', tags: ['thumbgate'] },
98
98
  ];
99
99
  fs.writeFileSync(tmpInbox, entries.map((e) => JSON.stringify(e)).join('\n') + '\n');
100
100
 
@@ -105,8 +105,7 @@ const pendingBackgroundSideEffects = new Set();
105
105
  */
106
106
  function updateStatuslineWithLesson({ accepted, signal, memoryId, feedbackId, lesson, turnCount }) {
107
107
  try {
108
- const cacheDir = process.env.THUMBGATE_FEEDBACK_DIR || HOME || '.';
109
- const cachePath = path.join(cacheDir, '.thumbgate', 'statusline_cache.json');
108
+ const cachePath = path.join(getFeedbackPaths().FEEDBACK_DIR, 'statusline_cache.json');
110
109
  let cache = {};
111
110
  try {
112
111
  cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
@@ -138,6 +137,12 @@ function updateStatuslineWithLesson({ accepted, signal, memoryId, feedbackId, le
138
137
  cache.updated_at = String(Math.floor(Date.now() / 1000));
139
138
  fs.mkdirSync(path.dirname(cachePath), { recursive: true });
140
139
  fs.writeFileSync(cachePath, JSON.stringify(cache));
140
+ try {
141
+ const { refreshStatuslineCache } = require('./hook-thumbgate-cache-updater');
142
+ refreshStatuslineCache(analyzeFeedback(), cachePath);
143
+ } catch {
144
+ /* keep lesson refresh best-effort */
145
+ }
141
146
  } catch { /* statusline update is best-effort */ }
142
147
  }
143
148
 
@@ -615,6 +620,35 @@ function enrichFeedbackContext(feedbackEvent, params) {
615
620
  ? params.filePaths.split(',').map((f) => f.trim()).filter(Boolean)
616
621
  : [];
617
622
  const errorType = params.errorType || null;
623
+ const protectedFiles = filePaths.filter((filePath) => /(^|\/)(agents\.md|claude(\.local)?\.md|gemini\.md|readme\.md|\.gitignore|skill\.md)$|^\.husky\/|^config\/gates\//i.test(filePath));
624
+ const combinedText = [
625
+ feedbackEvent.context || '',
626
+ feedbackEvent.whatWentWrong || '',
627
+ feedbackEvent.whatToChange || '',
628
+ ...(Array.isArray(feedbackEvent.tags) ? feedbackEvent.tags : []),
629
+ ].join(' ').toLowerCase();
630
+ const includesPhrase = (phrase) => combinedText.includes(phrase);
631
+ const includesOrderedTerms = (firstTerm, secondTerm) => {
632
+ const firstIndex = combinedText.indexOf(firstTerm);
633
+ if (firstIndex === -1) return false;
634
+ return combinedText.indexOf(secondTerm, firstIndex + firstTerm.length) !== -1;
635
+ };
636
+ const enforcement = {
637
+ scopeViolation: includesPhrase('scope creep')
638
+ || includesPhrase('out of scope')
639
+ || includesOrderedTerms('outside', 'scope')
640
+ || includesPhrase('wrong files')
641
+ || includesPhrase('unrelated files'),
642
+ approvalFailure: includesPhrase('without approval')
643
+ || includesPhrase('missing approval')
644
+ || includesPhrase('approval required')
645
+ || includesPhrase('permission required'),
646
+ protectedFileViolation: protectedFiles.length > 0
647
+ || includesPhrase('protected file')
648
+ || includesPhrase('policy file')
649
+ || includesPhrase('hook file'),
650
+ protectedFiles,
651
+ };
618
652
 
619
653
  return {
620
654
  ...feedbackEvent,
@@ -623,6 +657,7 @@ function enrichFeedbackContext(feedbackEvent, params) {
623
657
  filePaths,
624
658
  errorType,
625
659
  outcomeCategory,
660
+ enforcement,
626
661
  },
627
662
  };
628
663
  } catch (_err) {
@@ -812,6 +847,9 @@ function inferLessonFromConversation(conversationWindow, signal) {
812
847
  const tags = [];
813
848
  if (filePaths.length > 0) tags.push('has-file-context');
814
849
  if (errorPatterns.length > 0) tags.push('has-error-context');
850
+ if (filePaths.some((filePath) => /(^|\/)(agents\.md|claude(\.local)?\.md|gemini\.md|readme\.md|\.gitignore|skill\.md)$|^\.husky\/|^config\/gates\//i.test(filePath))) {
851
+ tags.push('protected-file-context');
852
+ }
815
853
 
816
854
  return {
817
855
  lesson,
@@ -1753,7 +1791,7 @@ function runTests() {
1753
1791
  }
1754
1792
  }
1755
1793
 
1756
- const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'rlhf-loop-test-'));
1794
+ const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'thumbgate-loop-test-'));
1757
1795
  const localFeedbackLog = path.join(tmpDir, 'feedback-log.jsonl');
1758
1796
  process.env.THUMBGATE_FEEDBACK_DIR = tmpDir;
1759
1797
 
@@ -62,12 +62,12 @@ function getThumbgateFeedbackDir(options = {}) {
62
62
  return path.join(cwd, '.thumbgate');
63
63
  }
64
64
 
65
- function getRlhfFeedbackDir(options = {}) {
65
+ function getFallbackFeedbackDir(options = {}) {
66
66
  const env = options.env || process.env;
67
- if (env._TEST_RLHF_FEEDBACK_DIR) return env._TEST_RLHF_FEEDBACK_DIR;
68
- if (env.THUMBGATE_RLHF_FEEDBACK_DIR) return env.THUMBGATE_RLHF_FEEDBACK_DIR;
67
+ if (env._TEST_THUMBGATE_FALLBACK_FEEDBACK_DIR) return env._TEST_THUMBGATE_FALLBACK_FEEDBACK_DIR;
68
+ if (env.THUMBGATE_FALLBACK_FEEDBACK_DIR) return env.THUMBGATE_FALLBACK_FEEDBACK_DIR;
69
69
  const cwd = options.cwd || process.cwd();
70
- return path.join(cwd, '.rlhf');
70
+ return path.join(cwd, '.thumbgate-compat');
71
71
  }
72
72
 
73
73
  function getLegacyFeedbackDir(options = {}) {
@@ -91,8 +91,8 @@ function resolveFeedbackDir(options = {}) {
91
91
  const localThumbgate = getThumbgateFeedbackDir(options);
92
92
  if (dirExists(localThumbgate)) return localThumbgate;
93
93
 
94
- const localRlhf = getRlhfFeedbackDir(options);
95
- if (dirExists(localRlhf)) return localRlhf;
94
+ const localFallback = getFallbackFeedbackDir(options);
95
+ if (dirExists(localFallback)) return localFallback;
96
96
 
97
97
  const localLegacy = getLegacyFeedbackDir(options);
98
98
  if (dirExists(localLegacy)) return localLegacy;
@@ -107,7 +107,7 @@ function getFeedbackPaths(options = {}) {
107
107
  function listFallbackFeedbackDirs(options = {}) {
108
108
  const activeDir = path.resolve(resolveFeedbackDir(options));
109
109
  return uniquePaths([
110
- getRlhfFeedbackDir(options),
110
+ getFallbackFeedbackDir(options),
111
111
  getLegacyFeedbackDir(options),
112
112
  ]).filter((dirPath) => path.resolve(dirPath) !== activeDir);
113
113
  }
@@ -136,7 +136,7 @@ module.exports = {
136
136
  getFeedbackPaths,
137
137
  getGlobalFeedbackDir,
138
138
  getLegacyFeedbackDir,
139
- getRlhfFeedbackDir,
139
+ getFallbackFeedbackDir,
140
140
  getThumbgateFeedbackDir,
141
141
  listFallbackFeedbackDirs,
142
142
  listFeedbackArtifactPaths,
@@ -31,7 +31,7 @@ const {
31
31
  } = require('./feedback-quality');
32
32
 
33
33
  const INFERRED_TAG_RULES = [
34
- { tag: 'thumbgate', keywords: ['thumbgate', 'rlhf', 'statusline', 'dashboard', 'mcp'] },
34
+ { tag: 'thumbgate', keywords: ['thumbgate', 'feedback-loop', 'statusline', 'dashboard', 'mcp'] },
35
35
  { tag: 'testing', keywords: ['test', 'testing', 'jest', 'coverage', 'verify', 'verification'] },
36
36
  { tag: 'security', keywords: ['security', 'secret', 'credential', 'token', 'auth'] },
37
37
  { tag: 'performance', keywords: ['perf', 'performance', 'latency', 'slow'] },
@@ -119,7 +119,7 @@ function runTests() {
119
119
  const pos = convertFeedbackToMemory({
120
120
  signal: 'positive',
121
121
  whatWorked: 'Built schema-validated feedback system with prevention rules',
122
- tags: ['architecture', 'rlhf'],
122
+ tags: ['architecture', 'thumbgate'],
123
123
  });
124
124
  assert(pos.ok === true, 'valid positive → ok');
125
125
  assert(pos.actionType === 'store-learning', 'positive → store-learning');
@@ -151,7 +151,7 @@ function runTests() {
151
151
  const ctxNeg = convertFeedbackToMemory({
152
152
  signal: 'negative',
153
153
  context: 'Showed fake ThumbGate statistics panel to user',
154
- tags: ['rlhf'],
154
+ tags: ['thumbgate'],
155
155
  });
156
156
  assert(ctxNeg.ok === true, 'context-only negative → ok');
157
157
 
@@ -328,7 +328,7 @@ function getLastEmbeddingProfile() {
328
328
 
329
329
  function getVersionSnapshot() {
330
330
  return Promise.resolve({
331
- rlhf_memories: null,
331
+ thumbgate_memories: null,
332
332
  prevention_rules: null,
333
333
  context_packs: null,
334
334
  engine: 'filesystem-search',
@@ -394,7 +394,7 @@ module.exports = {
394
394
  getEmbeddingConfig,
395
395
  getLastEmbeddingProfile,
396
396
  getVersionSnapshot,
397
- TABLE_NAME: 'rlhf_memories',
397
+ TABLE_NAME: 'thumbgate_memories',
398
398
  TABLE_PREVENTION_RULES: 'prevention_rules',
399
399
  TABLE_CONTEXT_PACKS: 'context_packs',
400
400