thumbgate 1.30.0 → 1.34.0
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.
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +54 -16
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/forge/forge.yaml +3 -3
- package/adapters/mcp/server-stdio.js +105 -10
- package/adapters/opencode/opencode.json +1 -1
- package/bench/observability-eval-suite.json +2 -2
- package/bin/cli.js +168 -31
- package/config/evals/generation-quality-golden.json +95 -0
- package/config/evals/rag-answer-quality-golden.json +91 -0
- package/config/evals/retrieval-hybrid-ablation.json +66 -0
- package/config/evals/retrieval-ranking-golden.json +522 -0
- package/config/gates/claim-verifiers.example.json +42 -0
- package/config/gates/claim-verifiers.json +25 -0
- package/config/gates/default.json +217 -50
- package/config/mcp-allowlists.json +233 -206
- package/config/model-tiers.json +7 -2
- package/glama.json +6 -0
- package/hooks/hooks.json +1 -1
- package/package.json +69 -12
- package/public/assets/diagrams/before-after.svg +17 -16
- package/public/assets/diagrams/hero-thumbs.svg +68 -0
- package/public/assets/diagrams/loop.svg +19 -13
- package/public/assets/diagrams/self-improving-thumbs-loop.svg +105 -0
- package/public/compare.html +1 -0
- package/public/dashboard.html +126 -28
- package/public/evaluations.html +1 -1
- package/public/index.html +142 -13
- package/public/numbers.html +3 -2
- package/public/pricing.html +143 -30
- package/scripts/a-plus-evidence-scorecard.js +303 -0
- package/scripts/agent-readiness.js +110 -0
- package/scripts/async-eval-observability.js +36 -11
- package/scripts/audit-trail.js +37 -1
- package/scripts/auto-promote-gates.js +149 -34
- package/scripts/auto-wire-hooks.js +20 -8
- package/scripts/cli-schema.js +14 -0
- package/scripts/colbert-style-maxsim.js +236 -0
- package/scripts/cross-encoder-reranker.js +356 -126
- package/scripts/dashboard-chat.js +350 -17
- package/scripts/document-intake.js +283 -7
- package/scripts/eval-quality-suite.js +204 -0
- package/scripts/feedback-loop.js +115 -7
- package/scripts/feedback-paths.js +32 -13
- package/scripts/feedback-quality.js +53 -0
- package/scripts/feedback-schema.js +3 -0
- package/scripts/file-ledger-lock.js +130 -0
- package/scripts/filesystem-search.js +17 -7
- package/scripts/financial-control-plane.js +1514 -0
- package/scripts/gates-engine.js +202 -7
- package/scripts/gemini-embedding-policy.js +1 -0
- package/scripts/harness-tool-names.js +70 -0
- package/scripts/hook-runtime.js +15 -3
- package/scripts/hook-stop-anti-claim.js +63 -3
- package/scripts/human-escalation.js +353 -41
- package/scripts/lesson-db.js +16 -5
- package/scripts/lesson-embedding-index.js +67 -20
- package/scripts/lesson-embedding-maintenance.js +177 -0
- package/scripts/lesson-reranker.js +55 -9
- package/scripts/lesson-retrieval.js +305 -29
- package/scripts/lesson-search.js +22 -8
- package/scripts/llm-client.js +304 -15
- package/scripts/model-tier-router.js +593 -0
- package/scripts/pragmatic-hybrid-search.js +379 -0
- package/scripts/provider-action-normalizer.js +11 -4
- package/scripts/rag-document-pipeline.js +461 -0
- package/scripts/rag-structured-output.js +441 -0
- package/scripts/ragas-style-metrics.js +351 -0
- package/scripts/request-envelope.js +178 -0
- package/scripts/rerank-pipeline.js +370 -0
- package/scripts/rerank-quality-eval.js +155 -0
- package/scripts/retrieval-hybrid-ablation.js +120 -0
- package/scripts/retrieval-quality-tier.js +118 -0
- package/scripts/secret-scanner.js +395 -4
- package/scripts/self-distill-agent.js +7 -1
- package/scripts/self-healing-check.js +25 -0
- package/scripts/skill-packs.js +183 -0
- package/scripts/slow-loop.js +72 -0
- package/scripts/statusline-links.js +1 -1
- package/scripts/statusline.sh +8 -1
- package/scripts/telemetry-analytics.js +13 -1
- package/scripts/thumbgate-search.js +98 -6
- package/scripts/tier-budget-guard.js +186 -0
- package/scripts/tool-registry.js +141 -5
- package/scripts/universal-claim-evaluator.js +767 -0
- package/scripts/vector-store.js +154 -17
- package/scripts/verify-marketing-pages-deployed.js +85 -3
- package/scripts/workflow-sentinel.js +77 -11
- package/server.json +44 -0
- package/smithery.yaml +17 -0
- package/src/api/server.js +196 -13
|
@@ -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.
|
|
4
|
+
"version": "1.34.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky",
|
|
7
7
|
"email": "ig5973700@gmail.com",
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# ThumbGate
|
|
2
2
|
|
|
3
|
+
[](https://mcptoplist.com/server/glama%2FIgorGanapolsky%2FThumbGate)
|
|
4
|
+
|
|
3
5
|
<p align="center">
|
|
4
6
|
<a href="https://thumbgate.ai">
|
|
5
7
|
<img src="public/assets/brand/thumbgate-icon-512.png" alt="ThumbGate" width="128" height="128" />
|
|
@@ -28,6 +30,19 @@ Accepted feedback is stored as local lessons. Repeated concrete failures can bec
|
|
|
28
30
|
npx thumbgate init # auto-detects the supported agent and wires its integration
|
|
29
31
|
```
|
|
30
32
|
|
|
33
|
+
### MCP / Glama / registry install (stdio)
|
|
34
|
+
|
|
35
|
+
Directories and clients that install ThumbGate as an MCP server must start **stdio MCP**, not the HTTP API:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx -y thumbgate serve
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Equivalent: `npx -y thumbgate mcp`
|
|
42
|
+
- Do **not** use `npm start` for MCP — that launches the hosted HTTP API (`src/api/server.js`), not the agent-facing stdio server.
|
|
43
|
+
- Canonical package metadata: `server.json` (`runtimeHint: npx` + `packageArguments: ["serve"]`), Smithery: `smithery.yaml`, maintainers: `glama.json`.
|
|
44
|
+
- Product name is **ThumbGate** only (npm: `thumbgate`). Retired legacy package aliases are not active product surfaces.
|
|
45
|
+
|
|
31
46
|
Works with **Claude Code, Cursor, Codex, Gemini CLI, Amp, Cline, OpenCode** and MCP-compatible agents after their integration is configured. Free tier: 2 feedback captures/day (10 total) and up to 3 active auto-promoted prevention rules. [Pro: $19/mo or $149/yr](https://thumbgate.ai/checkout/pro?utm_source=github&utm_medium=readme) is the individual tier for unlimited rules, history-aware lessons, feedback sessions, a personal dashboard, and DPO export. Enterprise is custom and scoped after intake; hosted team sync and a hosted org dashboard are not in the current general-availability runtime.
|
|
32
47
|
|
|
33
48
|
[](https://github.com/IgorGanapolsky/ThumbGate/actions/workflows/ci.yml)
|
|
@@ -256,6 +271,11 @@ evaluation/observability—is maintained in
|
|
|
256
271
|
architecture exists, what can fail, how it is measured and secured, how it is
|
|
257
272
|
deployed, and what evidence is required before claiming it works.
|
|
258
273
|
|
|
274
|
+
The full framework decision and one end-to-end RAG request—tenant authorization,
|
|
275
|
+
query transformation, parent-child retrieval, hybrid fusion, reranking,
|
|
276
|
+
structured generation, evaluation, and tracing—are documented in
|
|
277
|
+
[`docs/RAG_PRODUCTION_ARCHITECTURE.md`](./docs/RAG_PRODUCTION_ARCHITECTURE.md).
|
|
278
|
+
|
|
259
279
|
### Retrieval & latency: local-first, zero network hops
|
|
260
280
|
|
|
261
281
|
ThumbGate's latency advantage is structural, not a tuned cloud cluster: there is no retrieval service and no model on the enforcement path, so the gate decision never leaves your machine.
|
|
@@ -302,22 +322,40 @@ Each recommendation ships with the benchmark commands to run next: feedback-deri
|
|
|
302
322
|
|
|
303
323
|
## Install for Your Agent
|
|
304
324
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
|
311
|
-
|
|
312
|
-
| **
|
|
313
|
-
| **
|
|
314
|
-
| **
|
|
315
|
-
| **
|
|
316
|
-
| **
|
|
317
|
-
| **
|
|
318
|
-
| **
|
|
319
|
-
|
|
320
|
-
|
|
325
|
+
Enforcement depends on what the harness lets us intercept, so the table says which
|
|
326
|
+
you get. This distinction is real: with a pre-tool hook ThumbGate stops the action
|
|
327
|
+
before it runs; over MCP only, ThumbGate answers `gate_check` and the agent decides
|
|
328
|
+
whether to obey.
|
|
329
|
+
|
|
330
|
+
| Agent | Command | Enforcement |
|
|
331
|
+
|-------|---------|-------------|
|
|
332
|
+
| **Claude Code** | `npx thumbgate init --agent claude-code` | Hard — PreToolUse hook |
|
|
333
|
+
| **Codex** | `npx thumbgate init --agent codex` | Hard — `pre_tool_use` hook |
|
|
334
|
+
| **Gemini CLI** | `npx thumbgate init --agent gemini` | Hard — PreToolUse hook |
|
|
335
|
+
| **ForgeCode** | `npx thumbgate init --agent forge` | Hard — `pre_tool_use` trigger |
|
|
336
|
+
| **Cursor** | `npx thumbgate init --agent cursor` | Advisory — MCP `gate_check` |
|
|
337
|
+
| **Cline** (Roo Code successor) | `npx thumbgate init --agent cline` | Advisory — MCP `gate_check` + `.clinerules` |
|
|
338
|
+
| **OpenCode** | `npx thumbgate init --agent opencode` | Advisory — MCP `gate_check` |
|
|
339
|
+
| **Any MCP agent** | `npx thumbgate serve` | Advisory — MCP `gate_check` |
|
|
340
|
+
| **Amp** | `npx thumbgate init --agent amp` | Feedback capture only |
|
|
341
|
+
| **Claude Desktop** | [Download extension bundle](https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb) | Advisory — MCP |
|
|
342
|
+
| **VS Code / Open VSX** | [plugins/vscode-extension/README.md](plugins/vscode-extension/README.md) | See plugin README |
|
|
343
|
+
| **Antigravity-compatible** | [plugins/antigravity-extension/INSTALL.md](plugins/antigravity-extension/INSTALL.md) | See plugin README |
|
|
344
|
+
| **JetBrains** | [plugins/jetbrains-plugin/README.md](plugins/jetbrains-plugin/README.md) | See plugin README |
|
|
345
|
+
|
|
346
|
+
**Advisory means the agent can ignore it.** Harnesses without a pre-tool hook expose no
|
|
347
|
+
interception point, so ThumbGate cannot stop the call itself — it returns a verdict the
|
|
348
|
+
agent is instructed to honor. Treat advisory coverage as a strong default, not a
|
|
349
|
+
guarantee, and prefer a hard-enforcement harness for anything irreversible.
|
|
350
|
+
|
|
351
|
+
The gate is **model-agnostic**: verdicts come from deterministic policy evaluation over
|
|
352
|
+
the proposed tool call (`scripts/gates-engine.js`), never from an LLM. Swapping the model
|
|
353
|
+
behind any harness does not change what is allowed.
|
|
354
|
+
|
|
355
|
+
> **Enforcement posture:** ThumbGate ships **warn-by-default** — a matched gate is logged
|
|
356
|
+
> and surfaced, not blocked. Set `THUMBGATE_STRICT_ENFORCEMENT=1` to hard-block. The
|
|
357
|
+
> `gate_check` tool reports `warn` (never `allow`) when a gate matched but posture
|
|
358
|
+
> downgraded it, so an agent is never told a flagged action is fine.
|
|
321
359
|
|
|
322
360
|
### Install scope: machine-wide vs per-project
|
|
323
361
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.34.0", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.34.0", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -9,12 +9,12 @@ version: "1"
|
|
|
9
9
|
skills:
|
|
10
10
|
thumbgate-gate-check:
|
|
11
11
|
description: "ThumbGate PreToolUse gate — blocks known-bad tool calls"
|
|
12
|
-
command: "npx --yes --package thumbgate@1.
|
|
12
|
+
command: "npx --yes --package thumbgate@1.34.0 thumbgate gate-check"
|
|
13
13
|
trigger: pre_tool_use
|
|
14
14
|
|
|
15
15
|
thumbgate-feedback:
|
|
16
16
|
description: "ThumbGate feedback capture — logs user prompt context"
|
|
17
|
-
command: "npx --yes --package thumbgate@1.
|
|
17
|
+
command: "npx --yes --package thumbgate@1.34.0 thumbgate hook-auto-capture"
|
|
18
18
|
trigger: user_prompt
|
|
19
19
|
|
|
20
20
|
mcp:
|
|
@@ -23,6 +23,6 @@ mcp:
|
|
|
23
23
|
args:
|
|
24
24
|
- "--yes"
|
|
25
25
|
- "--package"
|
|
26
|
-
- "thumbgate@1.
|
|
26
|
+
- "thumbgate@1.34.0"
|
|
27
27
|
- "thumbgate"
|
|
28
28
|
- "serve"
|
|
@@ -95,6 +95,19 @@ const {
|
|
|
95
95
|
listEscalations,
|
|
96
96
|
requestEscalation,
|
|
97
97
|
} = require('../../scripts/human-escalation');
|
|
98
|
+
const {
|
|
99
|
+
createPurchaseRequisition,
|
|
100
|
+
getFinancialControlRuntimeOptions,
|
|
101
|
+
getRuntimePrincipal,
|
|
102
|
+
listPurchaseRequisitions,
|
|
103
|
+
reconcilePurchaseLedger,
|
|
104
|
+
reservePurchaseRequisition,
|
|
105
|
+
settlePurchaseRequisition,
|
|
106
|
+
} = require('../../scripts/financial-control-plane');
|
|
107
|
+
const MCP_FINANCIAL_PRINCIPAL = getRuntimePrincipal();
|
|
108
|
+
const MCP_FINANCIAL_OPTIONS = getFinancialControlRuntimeOptions({
|
|
109
|
+
authenticatedPrincipal: MCP_FINANCIAL_PRINCIPAL,
|
|
110
|
+
});
|
|
98
111
|
const { recordReasoningTrace } = require('../../scripts/agent-reasoning-traces');
|
|
99
112
|
const { recordToolCall } = require('../../scripts/tool-kpi-tracker');
|
|
100
113
|
const {
|
|
@@ -133,9 +146,7 @@ const {
|
|
|
133
146
|
throw error;
|
|
134
147
|
},
|
|
135
148
|
}));
|
|
136
|
-
const {
|
|
137
|
-
searchThumbgate,
|
|
138
|
-
} = require('../../scripts/thumbgate-search');
|
|
149
|
+
const { searchThumbgateAsync } = require('../../scripts/thumbgate-search');
|
|
139
150
|
const {
|
|
140
151
|
buildMultimodalRetrievalPlan,
|
|
141
152
|
} = require('../../scripts/multimodal-retrieval-plan');
|
|
@@ -317,7 +328,7 @@ const {
|
|
|
317
328
|
finalizeSession: finalizeFeedbackSession,
|
|
318
329
|
} = require('../../scripts/feedback-session');
|
|
319
330
|
|
|
320
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.
|
|
331
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.34.0' };
|
|
321
332
|
const COMMERCE_CATEGORIES = [
|
|
322
333
|
'product_recommendation',
|
|
323
334
|
'brand_compliance',
|
|
@@ -971,14 +982,14 @@ async function callToolInner(name, args) {
|
|
|
971
982
|
return buildSuggestFixResponse(args);
|
|
972
983
|
case 'retrieve_lessons': {
|
|
973
984
|
// Cross-encoder reranking: retrieve more candidates, then rerank for precision
|
|
974
|
-
const {
|
|
975
|
-
|
|
985
|
+
const { retrieveWithReranking } = loadOptionalModule(path.join(__dirname, '../../scripts/cross-encoder-reranker'), () => ({
|
|
986
|
+
retrieveWithReranking: async (toolName, actionContext, options = {}) => retrieveRelevantLessons(
|
|
976
987
|
toolName,
|
|
977
988
|
actionContext,
|
|
978
989
|
{ maxResults: options.maxResults || 5 },
|
|
979
990
|
),
|
|
980
991
|
}));
|
|
981
|
-
return toTextResult(
|
|
992
|
+
return toTextResult(await retrieveWithReranking(
|
|
982
993
|
args.toolName,
|
|
983
994
|
args.actionContext || '',
|
|
984
995
|
{
|
|
@@ -987,6 +998,9 @@ async function callToolInner(name, args) {
|
|
|
987
998
|
scope: args.scope,
|
|
988
999
|
requireScope: args.requireScope === true,
|
|
989
1000
|
includeShared: args.includeShared !== false,
|
|
1001
|
+
metadataFilters: args.filters,
|
|
1002
|
+
queryRewrite: args.queryRewrite !== false,
|
|
1003
|
+
includeRetrievalMeta: args.includeRetrievalMeta === true,
|
|
990
1004
|
},
|
|
991
1005
|
));
|
|
992
1006
|
}
|
|
@@ -1009,11 +1023,13 @@ async function callToolInner(name, args) {
|
|
|
1009
1023
|
}
|
|
1010
1024
|
case 'search_thumbgate':
|
|
1011
1025
|
enforceLimit('search_thumbgate');
|
|
1012
|
-
return toTextResult(
|
|
1026
|
+
return toTextResult(await searchThumbgateAsync({
|
|
1013
1027
|
query: args.query,
|
|
1014
1028
|
limit: args.limit,
|
|
1015
1029
|
source: args.source,
|
|
1016
1030
|
signal: args.signal,
|
|
1031
|
+
metadataFilters: args.filters,
|
|
1032
|
+
queryRewrite: args.queryRewrite !== false,
|
|
1017
1033
|
}));
|
|
1018
1034
|
case 'import_document':
|
|
1019
1035
|
return toTextResult(importDocument({
|
|
@@ -1038,6 +1054,61 @@ async function callToolInner(name, args) {
|
|
|
1038
1054
|
}
|
|
1039
1055
|
return toTextResult(document);
|
|
1040
1056
|
}
|
|
1057
|
+
case 'gate_check': {
|
|
1058
|
+
// Same engine the PreToolUse hook uses, so an MCP client and a hook cannot
|
|
1059
|
+
// disagree about whether an action is allowed.
|
|
1060
|
+
const { runAsync } = require('../../scripts/gates-engine');
|
|
1061
|
+
const { canonicalizeToolCall } = require('../../scripts/harness-tool-names');
|
|
1062
|
+
const canonical = canonicalizeToolCall(args.tool_name, args.tool_input || {});
|
|
1063
|
+
const raw = await runAsync({
|
|
1064
|
+
tool_name: canonical.toolName,
|
|
1065
|
+
tool_input: canonical.toolInput,
|
|
1066
|
+
});
|
|
1067
|
+
let decision = 'allow';
|
|
1068
|
+
let reason = '';
|
|
1069
|
+
let flagged = false;
|
|
1070
|
+
try {
|
|
1071
|
+
const parsed = JSON.parse(raw);
|
|
1072
|
+
const hook = parsed.hookSpecificOutput || {};
|
|
1073
|
+
const verdict = hook.permissionDecision || parsed.decision || '';
|
|
1074
|
+
reason = hook.permissionDecisionReason || parsed.reason || hook.additionalContext || '';
|
|
1075
|
+
// The hook wire format says "deny"; the documented tool contract says "block".
|
|
1076
|
+
if (verdict === 'deny' || verdict === 'block') {
|
|
1077
|
+
decision = 'block';
|
|
1078
|
+
flagged = true;
|
|
1079
|
+
} else if (/\[GATE:/.test(reason)) {
|
|
1080
|
+
// A gate MATCHED but the warn-by-default posture downgraded it. Reporting
|
|
1081
|
+
// "allow" here is how this tool would become theater: .clinerules tells the
|
|
1082
|
+
// agent to abort only on "block", so a matched rm -rf / would have been run
|
|
1083
|
+
// with the warning text ignored. "warn" is the honest third state.
|
|
1084
|
+
decision = 'warn';
|
|
1085
|
+
flagged = true;
|
|
1086
|
+
}
|
|
1087
|
+
} catch (_) {
|
|
1088
|
+
// Unparseable engine output must never read as "allow" — fail closed.
|
|
1089
|
+
decision = 'error';
|
|
1090
|
+
reason = 'gate engine returned unparseable output';
|
|
1091
|
+
}
|
|
1092
|
+
const strict = process.env.THUMBGATE_STRICT_ENFORCEMENT === '1';
|
|
1093
|
+
return {
|
|
1094
|
+
content: [{
|
|
1095
|
+
type: 'text',
|
|
1096
|
+
text: JSON.stringify({
|
|
1097
|
+
decision,
|
|
1098
|
+
flagged,
|
|
1099
|
+
enforcement: strict ? 'strict' : 'warn-by-default',
|
|
1100
|
+
guidance: decision === 'block'
|
|
1101
|
+
? 'Do NOT run this action. Surface the reason to the user.'
|
|
1102
|
+
: decision === 'warn'
|
|
1103
|
+
? 'A policy gate matched but enforcement is warn-by-default. Do NOT run this action without explicit user confirmation; show them the reason.'
|
|
1104
|
+
: decision === 'error'
|
|
1105
|
+
? 'Gate evaluation failed. Treat as unsafe and ask the user.'
|
|
1106
|
+
: 'No policy gate matched.',
|
|
1107
|
+
reason,
|
|
1108
|
+
}, null, 2),
|
|
1109
|
+
}],
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1041
1112
|
case 'feedback_stats':
|
|
1042
1113
|
return toTextResult(analyzeFeedback(undefined, { humanOnly: true }));
|
|
1043
1114
|
case 'diagnose_failure':
|
|
@@ -1310,6 +1381,20 @@ async function callToolInner(name, args) {
|
|
|
1310
1381
|
return toTextResult(requestEscalation(args));
|
|
1311
1382
|
case 'list_human_escalations':
|
|
1312
1383
|
return toTextResult(listEscalations({ status: args.status }).slice(0, Number(args.limit || 20)));
|
|
1384
|
+
case 'create_purchase_requisition':
|
|
1385
|
+
return toTextResult(createPurchaseRequisition(args, MCP_FINANCIAL_OPTIONS));
|
|
1386
|
+
case 'list_purchase_requisitions': {
|
|
1387
|
+
const rows = listPurchaseRequisitions(MCP_FINANCIAL_OPTIONS)
|
|
1388
|
+
.filter((entry) => !args.status || entry.status === args.status)
|
|
1389
|
+
.slice(0, Number(args.limit || 20));
|
|
1390
|
+
return toTextResult(rows);
|
|
1391
|
+
}
|
|
1392
|
+
case 'reserve_purchase_requisition':
|
|
1393
|
+
return toTextResult(reservePurchaseRequisition(args, MCP_FINANCIAL_OPTIONS));
|
|
1394
|
+
case 'settle_purchase_requisition':
|
|
1395
|
+
return toTextResult(settlePurchaseRequisition(args, MCP_FINANCIAL_OPTIONS));
|
|
1396
|
+
case 'reconcile_purchase_ledger':
|
|
1397
|
+
return toTextResult(reconcilePurchaseLedger(MCP_FINANCIAL_OPTIONS));
|
|
1313
1398
|
case 'verify_claim':
|
|
1314
1399
|
return toTextResult(verifyClaimEvidence(args.claim, { goalContract: args.goalContract }));
|
|
1315
1400
|
case 'require_evidence_for_claim': {
|
|
@@ -1324,6 +1409,9 @@ async function callToolInner(name, args) {
|
|
|
1324
1409
|
const missingActions = hasMatchingChecks
|
|
1325
1410
|
? Array.from(new Set(verification.checks.flatMap((check) => check.missing || [])))
|
|
1326
1411
|
: [];
|
|
1412
|
+
const factualMismatches = Array.isArray(verification.universal && verification.universal.checks)
|
|
1413
|
+
? verification.universal.checks.filter((check) => !check.passed)
|
|
1414
|
+
: [];
|
|
1327
1415
|
try {
|
|
1328
1416
|
const { recordAuditEvent } = require('../../scripts/audit-trail');
|
|
1329
1417
|
recordAuditEvent({
|
|
@@ -1335,13 +1423,16 @@ async function callToolInner(name, args) {
|
|
|
1335
1423
|
goalContract: verification.goalContract && verification.goalContract.matched
|
|
1336
1424
|
? verification.goalContract
|
|
1337
1425
|
: null,
|
|
1426
|
+
universalParsed: verification.universal ? verification.universal.parsedCount : 0,
|
|
1338
1427
|
},
|
|
1339
1428
|
decision: blocking ? 'deny' : 'allow',
|
|
1340
1429
|
gateId: verification.goalContract && verification.goalContract.matched
|
|
1341
1430
|
? 'completion_goal_contract'
|
|
1342
|
-
: 'completion_claim',
|
|
1431
|
+
: (factualMismatches.length > 0 ? 'completion_claim_factual' : 'completion_claim'),
|
|
1343
1432
|
message: blocking
|
|
1344
|
-
?
|
|
1433
|
+
? (factualMismatches.length > 0
|
|
1434
|
+
? `Completion claim blocked — factual mismatch/unconfigured: ${factualMismatches.map((c) => c.message).join('; ')}`
|
|
1435
|
+
: `Completion claim blocked — missing evidence: ${missingActions.join(', ') || 'unknown'}`)
|
|
1345
1436
|
: `Completion claim verified (${verification.verified ? 'evidence present' : 'no matching gate'})`,
|
|
1346
1437
|
source: 'completion-gate',
|
|
1347
1438
|
});
|
|
@@ -1355,6 +1446,8 @@ async function callToolInner(name, args) {
|
|
|
1355
1446
|
missingActions,
|
|
1356
1447
|
checks: verification.checks,
|
|
1357
1448
|
goalContract: verification.goalContract,
|
|
1449
|
+
universal: verification.universal,
|
|
1450
|
+
factualMismatches,
|
|
1358
1451
|
sessionId: args.sessionId || null,
|
|
1359
1452
|
});
|
|
1360
1453
|
}
|
|
@@ -1419,6 +1512,7 @@ async function callToolInner(name, args) {
|
|
|
1419
1512
|
mcp: args.mcp,
|
|
1420
1513
|
mcpToolCall: args.mcpToolCall,
|
|
1421
1514
|
budget: args.budget,
|
|
1515
|
+
financialControl: args.financialControl,
|
|
1422
1516
|
usage: args.usage,
|
|
1423
1517
|
}, {
|
|
1424
1518
|
provider: args.provider,
|
|
@@ -1428,6 +1522,7 @@ async function callToolInner(name, args) {
|
|
|
1428
1522
|
tokenEstimate: args.tokenEstimate,
|
|
1429
1523
|
costUsd: args.costUsd,
|
|
1430
1524
|
budget: args.budget,
|
|
1525
|
+
financialControl: args.financialControl,
|
|
1431
1526
|
repoPath: args.repoPath,
|
|
1432
1527
|
baseBranch: args.baseBranch,
|
|
1433
1528
|
affectedFiles: changedFiles.length > 0 ? changedFiles : undefined,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"id": "checkout-link-grounding",
|
|
5
5
|
"traceId": "trace_checkout_001",
|
|
6
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.",
|
|
7
|
+
"response": "The Pro checkout link is working because the checkout diagnostic confirms Stripe Pro checkout is reachable [context-1].",
|
|
8
8
|
"retrievedContexts": [
|
|
9
9
|
"Stripe Pro checkout diagnostic confirms the Pro checkout link is reachable and returns a valid checkout target.",
|
|
10
10
|
"The workflow sprint checkout is intake-led and should not expose a stale payment link."
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"id": "letta-tool-gate",
|
|
16
16
|
"traceId": "trace_letta_001",
|
|
17
17
|
"question": "Should Letta execute a force push tool call?",
|
|
18
|
-
"response": "ThumbGate blocks force push before execution for Letta tool calls.",
|
|
18
|
+
"response": "ThumbGate blocks force push before execution for Letta tool calls [context-1].",
|
|
19
19
|
"retrievedContexts": [
|
|
20
20
|
"ThumbGate's Letta adapter wraps Letta tool calls and runs gate-check before the executor is called.",
|
|
21
21
|
"Force push to main is a blocked high-risk git action."
|