thumbgate 1.27.16 → 1.27.18

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 (165) hide show
  1. package/.claude-plugin/marketplace.json +85 -0
  2. package/.claude-plugin/plugin.json +3 -4
  3. package/.well-known/llms.txt +12 -33
  4. package/.well-known/mcp/server-card.json +8 -8
  5. package/README.md +30 -215
  6. package/adapters/chatgpt/openapi.yaml +1695 -0
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/gemini/function-declarations.json +0 -1
  9. package/adapters/mcp/server-stdio.js +11 -263
  10. package/adapters/opencode/opencode.json +1 -1
  11. package/bench/thumbgate-bench.json +2 -2
  12. package/bin/cli.js +122 -1421
  13. package/bin/postinstall.js +27 -11
  14. package/config/gate-templates.json +0 -216
  15. package/config/gates/claim-verification.json +0 -12
  16. package/config/gates/default.json +2 -31
  17. package/config/github-about.json +2 -2
  18. package/config/mcp-allowlists.json +13 -23
  19. package/config/merge-quality-checks.json +1 -0
  20. package/config/model-candidates.json +6 -121
  21. package/openapi/openapi.yaml +0 -12
  22. package/package.json +98 -228
  23. package/public/blog.html +4 -4
  24. package/public/codex-plugin.html +20 -72
  25. package/public/compare.html +8 -31
  26. package/public/dashboard.html +166 -930
  27. package/public/federal.html +2 -2
  28. package/public/guide.html +9 -33
  29. package/public/index.html +116 -495
  30. package/public/learn.html +18 -191
  31. package/public/lessons.html +10 -168
  32. package/public/numbers.html +7 -7
  33. package/public/pro.html +11 -34
  34. package/scripts/agent-memory-lifecycle.js +0 -211
  35. package/scripts/agent-readiness.js +3 -167
  36. package/scripts/agent-reward-model.js +1 -53
  37. package/scripts/auto-promote-gates.js +10 -82
  38. package/scripts/auto-wire-hooks.js +0 -14
  39. package/scripts/billing.js +1 -93
  40. package/scripts/build-metadata.js +10 -50
  41. package/scripts/cli-feedback.js +6 -18
  42. package/scripts/cli-schema.js +0 -90
  43. package/scripts/cli-telemetry.js +1 -6
  44. package/scripts/commercial-offer.js +2 -82
  45. package/scripts/context-manager.js +6 -74
  46. package/scripts/dashboard.js +2 -68
  47. package/scripts/durability/step.js +3 -3
  48. package/scripts/export-databricks-bundle.js +1 -5
  49. package/scripts/export-dpo-pairs.js +2 -7
  50. package/scripts/feedback-loop.js +1 -123
  51. package/scripts/feedback-quality.js +0 -87
  52. package/scripts/filesystem-search.js +10 -35
  53. package/scripts/gate-stats.js +0 -89
  54. package/scripts/gates-engine.js +85 -1105
  55. package/scripts/gemini-embedding-policy.js +1 -2
  56. package/scripts/hook-runtime.js +14 -20
  57. package/scripts/hook-thumbgate-cache-updater.js +2 -18
  58. package/scripts/hybrid-feedback-context.js +7 -142
  59. package/scripts/lesson-inference.js +3 -8
  60. package/scripts/lesson-search.js +1 -17
  61. package/scripts/license.js +1 -0
  62. package/scripts/llm-client.js +9 -390
  63. package/scripts/local-model-profile.js +8 -15
  64. package/scripts/memory-scope-readiness.js +0 -159
  65. package/scripts/meta-agent-loop.js +0 -36
  66. package/scripts/operational-integrity.js +5 -39
  67. package/scripts/oss-pr-opportunity-scout.js +5 -35
  68. package/scripts/plausible-server-events.js +6 -9
  69. package/scripts/pro-local-dashboard.js +4 -4
  70. package/scripts/proxy-pointer-rag-guardrails.js +1 -42
  71. package/scripts/rate-limiter.js +13 -64
  72. package/scripts/secret-scanner.js +5 -44
  73. package/scripts/security-scanner.js +10 -260
  74. package/scripts/self-distill-agent.js +1 -3
  75. package/scripts/seo-gsd.js +2 -916
  76. package/scripts/statusline-cache-path.js +2 -17
  77. package/scripts/statusline-local-stats.js +1 -9
  78. package/scripts/statusline-meta.js +2 -28
  79. package/scripts/statusline.sh +4 -20
  80. package/scripts/telemetry-analytics.js +0 -357
  81. package/scripts/thompson-sampling.js +10 -31
  82. package/scripts/thumbgate-bench.js +1 -16
  83. package/scripts/thumbgate-search.js +19 -85
  84. package/scripts/tool-registry.js +1 -169
  85. package/scripts/vector-store.js +0 -45
  86. package/scripts/workflow-sentinel.js +53 -286
  87. package/scripts/workspace-evolver.js +2 -62
  88. package/src/api/server.js +290 -2578
  89. package/.claude/commands/dashboard.md +0 -15
  90. package/.claude/commands/thumbgate-blocked.md +0 -27
  91. package/.claude/commands/thumbgate-dashboard.md +0 -15
  92. package/.claude/commands/thumbgate-doctor.md +0 -30
  93. package/.claude/commands/thumbgate-guard.md +0 -36
  94. package/.claude/commands/thumbgate-protect.md +0 -30
  95. package/.claude/commands/thumbgate-rules.md +0 -30
  96. package/.well-known/agentic-verify.txt +0 -1
  97. package/adapters/gcp/dfcx-webhook-gate.js +0 -295
  98. package/adapters/letta/README.md +0 -41
  99. package/adapters/letta/thumbgate-letta-adapter.js +0 -133
  100. package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
  101. package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
  102. package/bench/observability-eval-suite.json +0 -26
  103. package/bin/dashboard-cli.js +0 -7
  104. package/commands/dashboard.md +0 -15
  105. package/commands/thumbgate-dashboard.md +0 -15
  106. package/config/builtin-lessons.json +0 -23
  107. package/config/gate-classifier-routing.json +0 -98
  108. package/config/post-deploy-marketing-pages.json +0 -61
  109. package/public/about.html +0 -162
  110. package/public/agent-manager.html +0 -179
  111. package/public/agents-cost-savings.html +0 -153
  112. package/public/ai-malpractice-prevention.html +0 -818
  113. package/public/assets/brand/github-social-preview.png +0 -0
  114. package/public/assets/brand/thumbgate-icon-512.png +0 -0
  115. package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
  116. package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
  117. package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
  118. package/public/assets/brand/thumbgate-logo-transparent.svg +0 -22
  119. package/public/assets/brand/thumbgate-mark-inline-v3.svg +0 -19
  120. package/public/assets/brand/thumbgate-mark-pro.svg +0 -23
  121. package/public/assets/brand/thumbgate-mark-team.svg +0 -26
  122. package/public/assets/brand/thumbgate-mark.svg +0 -21
  123. package/public/assets/brand/thumbgate-wordmark.svg +0 -20
  124. package/public/assets/claude-thumbgate-statusbar.svg +0 -8
  125. package/public/assets/codex-thumbgate-statusbar-test.svg +0 -9
  126. package/public/assets/legal-intake-control-flow.svg +0 -66
  127. package/public/brand/thumbgate-mark.svg +0 -19
  128. package/public/brand/thumbgate-og.svg +0 -16
  129. package/public/chatgpt-app.html +0 -330
  130. package/public/codex-enterprise.html +0 -123
  131. package/public/js/buyer-intent.js +0 -672
  132. package/public/pricing.html +0 -399
  133. package/scripts/action-receipts.js +0 -324
  134. package/scripts/activation-quickstart.js +0 -187
  135. package/scripts/agent-operations-planner.js +0 -621
  136. package/scripts/ai-component-inventory.js +0 -367
  137. package/scripts/async-eval-observability.js +0 -236
  138. package/scripts/audit.js +0 -65
  139. package/scripts/aws-blocks-guardrails.js +0 -228
  140. package/scripts/classifier-routing.js +0 -130
  141. package/scripts/dashboard-chat.js +0 -332
  142. package/scripts/feedback-aggregate.js +0 -281
  143. package/scripts/feedback-sanitizer.js +0 -105
  144. package/scripts/hob-pack.js +0 -591
  145. package/scripts/hook-stop-anti-claim.js +0 -301
  146. package/scripts/install-shim.js +0 -87
  147. package/scripts/mcp-oauth.js +0 -293
  148. package/scripts/noop-detect.js +0 -285
  149. package/scripts/omlx-smoke.js +0 -192
  150. package/scripts/parallel-workflow-orchestrator.js +0 -293
  151. package/scripts/plan-gate.js +0 -243
  152. package/scripts/plausible-domain-config.js +0 -99
  153. package/scripts/qa-scenario-planner.js +0 -136
  154. package/scripts/repeat-metric.js +0 -137
  155. package/scripts/secret-fixture-tokens.js +0 -61
  156. package/scripts/secret-redaction.js +0 -166
  157. package/scripts/self-harness-optimizer.js +0 -141
  158. package/scripts/self-healing-check.js +0 -193
  159. package/scripts/silent-failure-cluster.js +0 -531
  160. package/scripts/statusline-cache-read.js +0 -57
  161. package/scripts/sync-telemetry-from-prod.js +0 -374
  162. package/scripts/tool-contract-validator.js +0 -76
  163. package/scripts/trajectory-scorer.js +0 -63
  164. package/scripts/verify-marketing-pages-deployed.js +0 -195
  165. package/scripts/visitor-journey.js +0 -172
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const DEFAULT_ENDPOINT = 'https://api.oraclestechnologies.com/v1/guardian/analyze';
5
-
6
- function requireApiKey(env = process.env) {
7
- const key = env.ETHICORE_API_KEY || env.GUARDIAN_API_KEY || env.ORACLES_GUARDIAN_API_KEY;
8
- if (!key) {
9
- throw new Error('ETHICORE_API_KEY env var is required');
10
- }
11
- return key;
12
- }
13
-
14
- async function analyzeText(text, options = {}) {
15
- if (!String(text || '').trim()) {
16
- throw new Error('analyzeText requires text');
17
- }
18
-
19
- const env = options.env || process.env;
20
- const endpoint = options.endpoint || env.ETHICORE_GUARDIAN_ENDPOINT || DEFAULT_ENDPOINT;
21
- const apiKey = options.apiKey || requireApiKey(env);
22
- const fetchImpl = options.fetch || fetch;
23
-
24
- const response = await fetchImpl(endpoint, {
25
- method: 'POST',
26
- headers: {
27
- Authorization: `Bearer ${apiKey}`,
28
- 'Content-Type': 'application/json',
29
- },
30
- body: JSON.stringify({ text }),
31
- });
32
-
33
- const bodyText = await response.text();
34
- let body = bodyText;
35
- try {
36
- body = bodyText ? JSON.parse(bodyText) : {};
37
- } catch {
38
- // Keep non-JSON body for diagnostics.
39
- }
40
-
41
- if (!response.ok) {
42
- throw new Error(`Ethicore Guardian API ${response.status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
43
- }
44
-
45
- return body;
46
- }
47
-
48
- function createEthicorePolicyCheck(options = {}) {
49
- return async function ethicorePolicyCheck(action = {}) {
50
- const toolText = [
51
- action.toolName,
52
- action.actionType,
53
- action.command,
54
- action.path,
55
- action.url,
56
- action.input ? JSON.stringify(action.input) : '',
57
- ].filter(Boolean).join('\n');
58
-
59
- return analyzeText(toolText || JSON.stringify(action), options);
60
- };
61
- }
62
-
63
- module.exports = {
64
- DEFAULT_ENDPOINT,
65
- analyzeText,
66
- createEthicorePolicyCheck,
67
- requireApiKey,
68
- };
@@ -1,260 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const { normalizeProviderAction } = require('../../scripts/provider-action-normalizer');
5
-
6
- const BLOCK_DECISIONS = new Set([
7
- 'block',
8
- 'blocked',
9
- 'deny',
10
- 'denied',
11
- 'disallow',
12
- 'disallowed',
13
- 'fail',
14
- 'failed',
15
- 'forbid',
16
- 'forbidden',
17
- 'reject',
18
- 'rejected',
19
- 'unsafe',
20
- 'violation',
21
- ]);
22
-
23
- const REVIEW_DECISIONS = new Set([
24
- 'approval',
25
- 'approval-required',
26
- 'approval_required',
27
- 'approve',
28
- 'human-review',
29
- 'human_review',
30
- 'manual-review',
31
- 'manual_review',
32
- 'review',
33
- 'requires-approval',
34
- 'requires_approval',
35
- 'requires-review',
36
- 'requires_review',
37
- ]);
38
-
39
- const ALLOW_DECISIONS = new Set([
40
- 'accept',
41
- 'accepted',
42
- 'allow',
43
- 'allowed',
44
- 'ok',
45
- 'pass',
46
- 'passed',
47
- 'permit',
48
- 'permitted',
49
- 'safe',
50
- ]);
51
-
52
- function asObject(value) {
53
- return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
54
- }
55
-
56
- function asArray(value) {
57
- return Array.isArray(value) ? value : [];
58
- }
59
-
60
- function firstString(...values) {
61
- for (const value of values) {
62
- const text = String(value || '').trim();
63
- if (text) return text;
64
- }
65
- return '';
66
- }
67
-
68
- function normalizeDecisionToken(value) {
69
- return String(value || '')
70
- .trim()
71
- .toLowerCase()
72
- .replace(/\s+/g, '-');
73
- }
74
-
75
- function normalizeEvidence(value) {
76
- const direct = asArray(value.evidence);
77
- const citations = asArray(value.citations);
78
- const violations = asArray(value.violations);
79
- const reasons = asArray(value.reasons);
80
- const reasoning = asArray(value.reasoning);
81
- const threatTypes = asArray(value.threat_types || value.threatTypes)
82
- .map((threatType) => ({
83
- code: String(threatType || '').trim(),
84
- message: `Threat type: ${String(threatType || '').trim()}`,
85
- source: 'guardian',
86
- severity: firstString(value.threat_level, value.threatLevel),
87
- }));
88
- return [...direct, ...citations, ...violations, ...reasons, ...reasoning, ...threatTypes]
89
- .map((entry) => {
90
- if (typeof entry === 'string') return { text: entry };
91
- const object = asObject(entry);
92
- if (!Object.keys(object).length) return null;
93
- return {
94
- id: firstString(object.id, object.ruleId, object.rule_id, object.code),
95
- text: firstString(object.text, object.reason, object.message, object.description, object.title),
96
- source: firstString(object.source, object.provider, object.policy),
97
- severity: firstString(object.severity, object.level),
98
- raw: object,
99
- };
100
- })
101
- .filter(Boolean);
102
- }
103
-
104
- function extractPolicyDecision(input = {}) {
105
- const event = asObject(input);
106
- for (const candidate of [
107
- event.policyDecision,
108
- event.policy_decision,
109
- event.guardrailResult,
110
- event.guardrail_result,
111
- event.result,
112
- ]) {
113
- const object = asObject(candidate);
114
- if (Object.keys(object).length) return object;
115
- }
116
- return event;
117
- }
118
-
119
- function classifyPolicyDecision(input = {}) {
120
- const value = extractPolicyDecision(input);
121
- const token = normalizeDecisionToken(firstString(
122
- value.decision,
123
- value.action,
124
- value.status,
125
- value.result,
126
- value.verdict,
127
- value.outcome,
128
- value.effect,
129
- value.recommended_action,
130
- value.recommendedAction,
131
- ));
132
-
133
- if (
134
- value.allowed === false
135
- || value.is_safe === false
136
- || value.isSafe === false
137
- || value.accepted === false
138
- || value.blocked === true
139
- || value.denied === true
140
- || BLOCK_DECISIONS.has(token)
141
- ) {
142
- return 'block';
143
- }
144
- if (
145
- value.requiresApproval === true
146
- || value.requires_approval === true
147
- || value.reviewRequired === true
148
- || value.review_required === true
149
- || REVIEW_DECISIONS.has(token)
150
- ) {
151
- return 'approval_required';
152
- }
153
- if (
154
- value.allowed === true
155
- || value.is_safe === true
156
- || value.isSafe === true
157
- || value.accepted === true
158
- || ALLOW_DECISIONS.has(token)
159
- ) {
160
- return 'allow';
161
- }
162
- return 'unknown';
163
- }
164
-
165
- function normalizePolicyDecision(input = {}, options = {}) {
166
- const value = extractPolicyDecision(input);
167
- const decision = classifyPolicyDecision(value);
168
- const source = firstString(
169
- options.source,
170
- value.source,
171
- value.provider,
172
- value.engine,
173
- value.policyEngine,
174
- value.policy_engine,
175
- 'policy-engine'
176
- );
177
- const reason = firstString(
178
- value.reason,
179
- value.message,
180
- value.explanation,
181
- value.summary,
182
- asArray(value.reasoning).join('; '),
183
- asArray(value.reasons).join('; '),
184
- decision === 'unknown' ? 'Policy engine returned an unknown decision; approval required before execution.' : ''
185
- );
186
-
187
- return {
188
- allowed: decision === 'allow',
189
- blocked: decision === 'block',
190
- approvalRequired: decision === 'approval_required' || decision === 'unknown',
191
- decision,
192
- reason,
193
- source,
194
- confidence: Number.isFinite(Number(value.confidence)) ? Number(value.confidence) : null,
195
- policyId: firstString(value.policyId, value.policy_id, value.ruleId, value.rule_id, value.id),
196
- severity: firstString(value.severity, value.level, value.threat_level, value.threatLevel),
197
- score: Number.isFinite(Number(value.score))
198
- ? Number(value.score)
199
- : (Number.isFinite(Number(value.threat_score)) ? Number(value.threat_score) : null),
200
- evidence: normalizeEvidence(value),
201
- raw: value,
202
- };
203
- }
204
-
205
- function normalizePolicyAction(input = {}) {
206
- const event = asObject(input);
207
- return {
208
- ...normalizeProviderAction({
209
- ...event,
210
- provider: firstString(event.provider, event.agentRuntime, event.runtime, 'policy-engine'),
211
- toolName: firstString(event.toolName, event.tool_name, event.name),
212
- input: asObject(event.toolInput || event.input || event.arguments || event.args),
213
- }),
214
- policyContext: asObject(event.policyContext || event.policy_context),
215
- };
216
- }
217
-
218
- function createPolicyEngineGuard({
219
- policyCheck,
220
- executeTool,
221
- gateCheck,
222
- onDecision,
223
- source = 'policy-engine',
224
- } = {}) {
225
- if (typeof policyCheck !== 'function') {
226
- throw new TypeError('createPolicyEngineGuard requires a policyCheck function');
227
- }
228
- if (typeof executeTool !== 'function') {
229
- throw new TypeError('createPolicyEngineGuard requires an executeTool function');
230
- }
231
-
232
- return async function guardedPolicyTool(input = {}) {
233
- const normalizedAction = normalizePolicyAction(input);
234
- const policyDecision = normalizePolicyDecision(await policyCheck(normalizedAction), { source });
235
- const gateDecision = typeof gateCheck === 'function'
236
- ? normalizePolicyDecision(await gateCheck({ normalizedAction, policyDecision }), { source: 'thumbgate' })
237
- : null;
238
- const effectiveDecision = gateDecision && !gateDecision.allowed ? gateDecision : policyDecision;
239
-
240
- if (typeof onDecision === 'function') {
241
- await onDecision({ normalizedAction, policyDecision, gateDecision, effectiveDecision });
242
- }
243
-
244
- if (!effectiveDecision.allowed) {
245
- const error = new Error(effectiveDecision.reason || 'ThumbGate blocked this action before execution.');
246
- error.code = effectiveDecision.approvalRequired ? 'THUMBGATE_APPROVAL_REQUIRED' : 'THUMBGATE_BLOCKED';
247
- error.thumbgate = { normalizedAction, policyDecision, gateDecision, effectiveDecision };
248
- throw error;
249
- }
250
-
251
- return executeTool(input, { normalizedAction, policyDecision, gateDecision, effectiveDecision });
252
- };
253
- }
254
-
255
- module.exports = {
256
- createPolicyEngineGuard,
257
- extractPolicyDecision,
258
- normalizePolicyAction,
259
- normalizePolicyDecision,
260
- };
@@ -1,26 +0,0 @@
1
- {
2
- "cases": [
3
- {
4
- "id": "checkout-link-grounding",
5
- "traceId": "trace_checkout_001",
6
- "question": "Is the Pro checkout link working?",
7
- "response": "The Pro checkout link is working because the checkout diagnostic confirms Stripe Pro checkout is reachable.",
8
- "retrievedContexts": [
9
- "Stripe Pro checkout diagnostic confirms the Pro checkout link is reachable and returns a valid checkout target.",
10
- "The workflow sprint checkout is intake-led and should not expose a stale payment link."
11
- ],
12
- "reference": "The Pro checkout link is reachable when the Stripe diagnostic passes."
13
- },
14
- {
15
- "id": "letta-tool-gate",
16
- "traceId": "trace_letta_001",
17
- "question": "Should Letta execute a force push tool call?",
18
- "response": "ThumbGate blocks force push before execution for Letta tool calls.",
19
- "retrievedContexts": [
20
- "ThumbGate's Letta adapter wraps Letta tool calls and runs gate-check before the executor is called.",
21
- "Force push to main is a blocked high-risk git action."
22
- ],
23
- "reference": "ThumbGate blocks high-risk Letta tool calls before execution."
24
- }
25
- ]
26
- }
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // Insert 'dashboard' and '--open' as the subcommands/arguments
5
- process.argv.splice(2, 0, 'dashboard', '--open');
6
-
7
- require('./cli.js');
@@ -1,15 +0,0 @@
1
- ---
2
- name: dashboard
3
- description: Open the local HTTP dashboard for the current project in your web browser.
4
- ---
5
-
6
- # Open Dashboard
7
-
8
- Open the local HTTP dashboard for the current project in your web browser.
9
-
10
- ## Instructions
11
- Execute the following command in the project directory to open the browser dashboard scoped to the current repository:
12
- ```bash
13
- thumbgate-dashboard
14
- ```
15
-
@@ -1,15 +0,0 @@
1
- ---
2
- name: thumbgate-dashboard
3
- description: Open the local HTTP dashboard for the current project in your web browser.
4
- ---
5
-
6
- # Open Scoped ThumbGate Dashboard
7
-
8
- Open the local HTTP dashboard for the current project in your web browser.
9
-
10
- ## Instructions
11
- Execute the following command in the project directory to open the browser dashboard:
12
- ```bash
13
- thumbgate-dashboard
14
- ```
15
-
@@ -1,23 +0,0 @@
1
- {
2
- "version": 1,
3
- "lessons": [
4
- {
5
- "id": "builtin-response-quality-shallow-positive-closeout",
6
- "title": "MISTAKE: Assistant gave shallow acknowledgement after user said thumbs up",
7
- "content": "What went wrong: Assistant gave shallow acknowledgement after positive feedback, such as thumbs up, perfect, good, or thank you, instead of staying quiet or giving an evidence checkpoint.\nHow to avoid: If the previous user message is positive feedback and the proposed final response is a low-value social closeout, block it and require either silence-level brevity or a compact evidence checkpoint with proof, result, residual risk, and next state.\nAction needed: Enforce this at the final-response boundary, not only as PreToolUse context.\nReasoning: Stored lessons and retrieval are not enough when the model can still ignore the lesson at generation time.",
8
- "category": "error",
9
- "importance": "high",
10
- "tags": [
11
- "feedback",
12
- "negative",
13
- "response-quality",
14
- "final-response",
15
- "positive-feedback",
16
- "shallow-closeout",
17
- "enforcement"
18
- ],
19
- "timestamp": "2026-06-20T19:01:58.000Z",
20
- "source": "packaged-builtin"
21
- }
22
- ]
23
- }
@@ -1,98 +0,0 @@
1
- {
2
- "version": 1,
3
- "defaultLane": "local_classical",
4
- "lanes": {
5
- "deterministic": {
6
- "description": "Regex, allow/deny lists, protected paths, branch rules, and exact policy checks. Always runs first.",
7
- "maxLatencyMs": 25,
8
- "cloudAllowed": false,
9
- "useFor": [
10
- "secret patterns",
11
- "force-push",
12
- "destructive SQL",
13
- "protected operating files",
14
- "known repeated command signatures"
15
- ]
16
- },
17
- "semantic_cache": {
18
- "description": "Cached decision for semantically equivalent repeats where wording or PII changed but action meaning did not.",
19
- "maxLatencyMs": 50,
20
- "cloudAllowed": false,
21
- "requiresProvenance": true,
22
- "useFor": [
23
- "semantic repeat blocks",
24
- "cached approvals",
25
- "prompt variants with same action meaning",
26
- "PII-normalized duplicate checks"
27
- ]
28
- },
29
- "local_classical": {
30
- "description": "Fast local text routing for high-volume, low-ambiguity feedback and gate labels.",
31
- "maxLatencyMs": 250,
32
- "cloudAllowed": false,
33
- "minExamples": 40,
34
- "useFor": [
35
- "routine feedback triage",
36
- "known error classes",
37
- "low-risk support labels",
38
- "bulk import classification"
39
- ]
40
- },
41
- "local_semantic": {
42
- "description": "Local semantic/FTS recall for near-miss lessons, fuzzy duplicates, and low-data labels.",
43
- "maxLatencyMs": 750,
44
- "cloudAllowed": false,
45
- "useFor": [
46
- "near-duplicate lessons",
47
- "sparse labels",
48
- "cross-session recurrence",
49
- "similar command intent"
50
- ]
51
- },
52
- "llm_judge": {
53
- "description": "Budget-capped LLM review for ambiguous, high-value decisions where semantics matter.",
54
- "maxLatencyMs": 10000,
55
- "cloudAllowed": true,
56
- "requiresEvidence": true,
57
- "useFor": [
58
- "ambiguous policy mapping",
59
- "multi-document evidence review",
60
- "rubric critique",
61
- "structured dataset provenance review"
62
- ]
63
- },
64
- "rubric_gate": {
65
- "description": "Completion blocker for failed rubrics, missing evidence, and loop-until-done harness caps.",
66
- "maxLatencyMs": 500,
67
- "cloudAllowed": false,
68
- "requiresEvidence": true,
69
- "useFor": [
70
- "failed rubric criteria",
71
- "missing done evidence",
72
- "critic review failure",
73
- "workflow completion claims"
74
- ]
75
- },
76
- "human_review": {
77
- "description": "Stop and ask for approval when the action is high-risk, private, or too ambiguous for automated routing.",
78
- "maxLatencyMs": null,
79
- "cloudAllowed": false,
80
- "requiresEvidence": true,
81
- "useFor": [
82
- "production credentials",
83
- "customer data",
84
- "regulated workflows",
85
- "unbounded external posting",
86
- "payment or refund changes"
87
- ]
88
- }
89
- },
90
- "thresholds": {
91
- "classicalMinExamples": 40,
92
- "lowLatencyBudgetMs": 300,
93
- "llmMinLatencyBudgetMs": 2000,
94
- "highRiskAmbiguity": 0.65,
95
- "mediumAmbiguity": 0.35,
96
- "largeBatchRows": 50
97
- }
98
- }
@@ -1,61 +0,0 @@
1
- {
2
- "$comment": "Sentinel manifest for post-deploy verification of top-level marketing pages. Each entry is curled against the live production URL after every push to main; if the sentinel string is missing from the response body, the deploy is flagged as broken and the workflow comments on the associated PR. Adding a new top-level marketing page? Add it here so the deploy-verify workflow catches a route regression before a real visitor does. Keep sentinel strings short and stable (visible body copy, not styling classes or hashed assets).",
3
- "version": 1,
4
- "pages": [
5
- {
6
- "route": "/",
7
- "sentinel": "Stop paying for the same AI mistake twice",
8
- "description": "Home page hero (lifeblood — never regress)"
9
- },
10
- {
11
- "route": "/pro",
12
- "sentinel": "ThumbGate Pro",
13
- "description": "Pro landing page"
14
- },
15
- {
16
- "route": "/dashboard",
17
- "sentinel": "ThumbGate Dashboard",
18
- "description": "Dashboard demo (already enforced by /dashboard step; included here for symmetry with PR comment surface)"
19
- },
20
- {
21
- "route": "/federal",
22
- "sentinel": "ThumbGate",
23
- "description": "Federal lead-gen page (SBIR / GSA arrivals)"
24
- },
25
- {
26
- "route": "/numbers",
27
- "sentinel": "ThumbGate",
28
- "description": "First-party numbers / data transparency page"
29
- },
30
- {
31
- "route": "/ai-malpractice-prevention",
32
- "sentinel": "Pre-Execution Controls for Legal AI Agents",
33
- "description": "Legal AI intake risk-controls page for law-firm pilot conversations"
34
- },
35
- {
36
- "route": "/learn/background-agent-control-layer",
37
- "sentinel": "Background agents need a control layer outside the model",
38
- "description": "Background-agent AI-SDLC control-layer positioning page"
39
- },
40
- {
41
- "route": "/llm-context.md",
42
- "sentinel": "## What ThumbGate Is",
43
- "description": "Canonical declarative summary AI crawlers read"
44
- },
45
- {
46
- "route": "/robots.txt",
47
- "sentinel": "User-agent",
48
- "description": "Crawl directives (mandatory per Google's 2026-05-15 AI features guide)"
49
- },
50
- {
51
- "route": "/sitemap.xml",
52
- "sentinel": "<urlset",
53
- "description": "XML sitemap for search-engine discoverability"
54
- },
55
- {
56
- "route": "/about",
57
- "sentinel": "Igor Ganapolsky",
58
- "description": "About page for GEO discoverability"
59
- }
60
- ]
61
- }