thumbgate 1.35.0 → 1.37.1
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/.agents/skills/cyberstrike-compare-not-clone/SKILL.md +36 -0
- package/.agents/skills/gitlab-sandbox-allowlist-not-trust/SKILL.md +77 -0
- package/.agents/skills/jit-harness-compare-not-clone/SKILL.md +34 -0
- package/.agents/skills/openui-catalog-compose-honesty/SKILL.md +64 -0
- package/.agents/skills/zvec-grep-compare-not-clone/SKILL.md +34 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/llms.txt +1 -0
- package/.well-known/mcp/server-card.json +1 -1
- package/CONTRIBUTING.md +95 -0
- package/README.md +195 -632
- package/THIRD_PARTY_NOTICES.md +89 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/forge/forge.yaml +3 -3
- package/adapters/future-agi/.mcp.json +8 -0
- package/adapters/future-agi/FUTURE_AGI.md +23 -0
- package/adapters/future-agi/config.toml +3 -0
- package/adapters/future-agi/future-agi-bridge.js +9 -0
- package/adapters/future-agi/opencode.json +8 -0
- package/adapters/herdr/herdr-plugin.toml +18 -0
- package/adapters/mcp/server-stdio.js +238 -25
- package/adapters/opencode/opencode.json +1 -1
- package/adapters/workos/WORKOS.md +52 -0
- package/bin/cli.js +336 -3
- package/bin/futureagi-bridge +9 -0
- package/config/gate-templates.json +581 -4
- package/config/gates/actor-critic-audit.json +34 -0
- package/config/gates/default.json +9 -3
- package/config/gates/five-walls-governance.json +34 -0
- package/config/gates/future-agi-guardrails.json +34 -0
- package/config/gates/radware-threat-defense-2026.json +61 -0
- package/config/gates/simatree-data-governance.json +33 -0
- package/config/mcp-allowlists.json +4 -0
- package/config/merge-quality-checks.json +6 -0
- package/config/model-candidates.json +312 -29
- package/config/model-tiers.json +18 -0
- package/config/post-deploy-marketing-pages.json +10 -0
- package/config/progressive/01-wire-only.json +11 -0
- package/config/progressive/02-dashboard-empty-ok.json +10 -0
- package/config/progressive/03-one-lesson.json +10 -0
- package/config/progressive/04-warn-fires.json +11 -0
- package/config/progressive/05-strict-optional.json +11 -0
- package/config/progressive/README.md +15 -0
- package/config/schemas/broker-execution-receipt.schema.json +139 -0
- package/config/schemas/provider-execution-attestation-v1.schema.json +58 -0
- package/conformance/provider-attestation/vectors.json +320 -0
- package/docs/specs/provider-execution-attestation-v1.md +69 -0
- package/openapi/openapi.yaml +15 -0
- package/package.json +390 -148
- package/public/about.html +2 -2
- package/public/ai-malpractice-prevention.html +7 -7
- package/public/blog/a-10-dollar-vps-is-not-a-computer.html +143 -0
- package/public/blog/a-receipt-is-not-world-state.html +388 -0
- package/public/blog/git-at-agent-scale.html +374 -0
- package/public/blog/no-llm-in-the-gate.html +133 -0
- package/public/blog.html +80 -0
- package/public/case-studies.html +16 -1
- package/public/compare.html +28 -0
- package/public/diagnostic.html +216 -7
- package/public/docs/connectors.html +39 -0
- package/public/federal.html +2 -2
- package/public/founders.html +639 -0
- package/public/index.html +87 -9
- package/public/install.html +8 -8
- package/public/learn.html +39 -0
- package/public/numbers.html +2 -2
- package/public/peter.html +310 -0
- package/public/platform-partners.html +119 -0
- package/public/pricing.html +24 -3
- package/public/privacy.html +117 -0
- package/public/pro.html +17 -0
- package/public/support.html +62 -0
- package/public/terms.html +130 -0
- package/public/third-party-notices.html +95 -0
- package/public/yt.html +351 -0
- package/scripts/action-receipts.js +133 -3
- package/scripts/adaptive-governance-arena.js +349 -0
- package/scripts/admin-override.js +205 -0
- package/scripts/agent-action-inventory.js +869 -0
- package/scripts/agent-audit-trace.js +42 -2
- package/scripts/agent-egress-policy.js +1117 -0
- package/scripts/agent-memory-lifecycle.js +141 -2
- package/scripts/agent-operations-planner.js +441 -1
- package/scripts/agent-readiness.js +68 -0
- package/scripts/agent-security-central.js +647 -0
- package/scripts/allowlist-bridge-honesty.js +417 -0
- package/scripts/async-job-runner.js +102 -11
- package/scripts/audit-trail.js +212 -0
- package/scripts/billing.js +1 -1
- package/scripts/broker-execution-receipts.js +719 -0
- package/scripts/budget-aware-gates-proof.js +423 -0
- package/scripts/claude-feedback-sync.js +29 -3
- package/scripts/claw-harness-production.js +237 -0
- package/scripts/cli-schema.js +163 -1
- package/scripts/codex-runbook-flywheel.js +318 -0
- package/scripts/context-footprint.js +186 -0
- package/scripts/contextfs.js +143 -61
- package/scripts/dashboard.js +251 -32
- package/scripts/deepseek-v4-runtime-guardrails.js +72 -6
- package/scripts/docker-sandbox-planner.js +18 -0
- package/scripts/double-blind-eval-protocol.js +252 -0
- package/scripts/edotenv-rl-gateway.js +259 -0
- package/scripts/ensure-production-search-corpus.js +162 -0
- package/scripts/eval-holdout.js +311 -0
- package/scripts/feedback-aggregate.js +21 -2
- package/scripts/feedback-loop.js +87 -5
- package/scripts/feedback-quality.js +9 -0
- package/scripts/file-ledger-lock.js +4 -1
- package/scripts/financial-control-plane.js +41 -1
- package/scripts/find-dormant-requires.js +118 -0
- package/scripts/fs-utils.js +84 -8
- package/scripts/gates-engine.js +810 -63
- package/scripts/generate-case-study-outreach.js +24 -15
- package/scripts/git-at-scale.js +628 -0
- package/scripts/governance-conflict-audit.js +1650 -0
- package/scripts/governance-difficulty-curriculum.js +328 -0
- package/scripts/graphrag-retrieval.js +275 -0
- package/scripts/gurobi-optimizer.js +324 -0
- package/scripts/gurobi_optimizer.py +485 -0
- package/scripts/harness-selector.js +82 -1
- package/scripts/hidden-entry-points.js +284 -0
- package/scripts/human-escalation.js +199 -1
- package/scripts/hybrid-feedback-context.js +152 -19
- package/scripts/intent-governed-execution.js +602 -0
- package/scripts/intervention-policy.js +123 -20
- package/scripts/jit-harness-compose.js +628 -0
- package/scripts/jsonl-watcher.js +10 -0
- package/scripts/lesson-embedding-index.js +95 -12
- package/scripts/lesson-retrieval.js +105 -19
- package/scripts/local-model-profile.js +19 -2
- package/scripts/mailer/resend-mailer.js +1 -1
- package/scripts/matryoshka-embedding.js +235 -0
- package/scripts/mcp-oauth.js +42 -4
- package/scripts/mcp-session-handles.js +1016 -0
- package/scripts/mcp-wiring-doctor.js +314 -0
- package/scripts/memory-firewall.js +115 -2
- package/scripts/memory-scope-readiness.js +299 -0
- package/scripts/memory-vs-rag-route.js +161 -0
- package/scripts/model-tier-router.js +148 -21
- package/scripts/nvidia-specdecode-al-doctor.js +536 -0
- package/scripts/openui-catalog-compose-honesty.js +593 -0
- package/scripts/operational-integrity.js +19 -1
- package/scripts/override-audit.js +213 -0
- package/scripts/package-manager-honesty-doctor.js +458 -0
- package/scripts/pr-manager.js +63 -1
- package/scripts/prove-herdr-adapter.js +52 -0
- package/scripts/prove-memory-pyramid-and-symbolic-canvas.js +95 -0
- package/scripts/prove-workos.js +73 -0
- package/scripts/provider-attestation-conformance.js +192 -0
- package/scripts/provider-receipt-contract.js +136 -0
- package/scripts/qwen38-max-cost-optimizer.js +401 -0
- package/scripts/radware-threat-defense.js +280 -0
- package/scripts/rag-embedding-identity.js +221 -0
- package/scripts/rag-precision-guardrails.js +112 -2
- package/scripts/remote-feedback-capture.js +159 -0
- package/scripts/research-agent-harness.js +256 -0
- package/scripts/rsi-safety-hillclimb.js +200 -0
- package/scripts/rule-sprawl.js +188 -0
- package/scripts/schedule-manager.js +147 -0
- package/scripts/self-heal.js +8 -0
- package/scripts/session-lease.js +415 -0
- package/scripts/simatree-data-governance.js +347 -0
- package/scripts/slo-alert-engine.js +172 -7
- package/scripts/solver-parity.js +539 -0
- package/scripts/stealth-memory-injection-gate.js +333 -0
- package/scripts/switchyard-router.js +366 -0
- package/scripts/telemetry-analytics.js +84 -27
- package/scripts/temporal-decay-weighting.js +138 -0
- package/scripts/test-all.js +165 -0
- package/scripts/token-savings.js +42 -0
- package/scripts/tool-kpi-tracker.js +108 -5
- package/scripts/tool-registry.js +193 -5
- package/scripts/universal-claim-evaluator.js +14 -2
- package/scripts/vector-store.js +279 -9
- package/scripts/workflow-notebook.js +391 -0
- package/scripts/workflow-sentinel.js +111 -12
- package/scripts/workos-production-guard.js +260 -0
- package/scripts/workspace-search-route.js +515 -0
- package/server.json +2 -2
- package/src/agent-identity-boundary.js +76 -0
- package/src/agent-retrieval-cache.js +155 -0
- package/src/alert-noise-ledger.js +502 -0
- package/src/api/server.js +724 -153
- package/src/git-fast-cache.js +220 -0
- package/src/git-wal-sync.js +156 -0
- package/src/hash-anchored-edit.js +82 -0
- package/src/hermes-platform-protocol.js +475 -0
- package/src/hermes-sync-plane.js +241 -0
- package/src/index.js +30 -1
- package/src/iso42001-compliance-guard.js +97 -0
- package/src/latency-budget.js +244 -0
- package/src/mcp-writeguard.js +316 -0
- package/src/miminions-adapter.js +106 -0
- package/src/pipeline-compass.js +104 -0
- package/src/ppl-alert-pipeline.js +284 -0
- package/src/rendezvous-router.js +90 -0
- package/src/security-questionnaire.js +195 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Gurobi Optimization Engine bridge (Node → gurobipy).
|
|
6
|
+
*
|
|
7
|
+
* System-wide runtime (Fabrizio Ellis / free pip path, 2026-08-12):
|
|
8
|
+
* GUROBI_PYTHON / ~/.hermes/gurobi-venv/bin/python / python3
|
|
9
|
+
* fleet CLI: gurobi-fleet | MCP: gurobi-mcp
|
|
10
|
+
*
|
|
11
|
+
* Solves MILP for model routing and prevention-rule knapsack selection.
|
|
12
|
+
* Fail-open to deterministic heuristics when gurobipy is unavailable (CI).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('node:fs');
|
|
16
|
+
const os = require('node:os');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
const { execFileSync } = require('node:child_process');
|
|
19
|
+
|
|
20
|
+
const SCRIPT_PATH = path.join(__dirname, 'gurobi_optimizer.py');
|
|
21
|
+
|
|
22
|
+
function resolvePythonBin(env = process.env, homeDir = os.homedir()) {
|
|
23
|
+
const candidates = [
|
|
24
|
+
env.GUROBI_PYTHON,
|
|
25
|
+
env.PYTHON_BIN,
|
|
26
|
+
path.join(homeDir, '.hermes', 'gurobi-venv', 'bin', 'python'),
|
|
27
|
+
path.join(homeDir, '.hermes', 'gurobi-venv', 'bin', 'python3'),
|
|
28
|
+
'python3',
|
|
29
|
+
].filter(Boolean);
|
|
30
|
+
|
|
31
|
+
for (const bin of candidates) {
|
|
32
|
+
if (bin === 'python3' || bin === 'python') return bin;
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(bin)) return bin;
|
|
35
|
+
} catch {
|
|
36
|
+
/* continue */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return 'python3';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseSolverStdout(stdout) {
|
|
43
|
+
const text = String(stdout || '');
|
|
44
|
+
const start = text.indexOf('{');
|
|
45
|
+
if (start < 0) {
|
|
46
|
+
throw new SyntaxError('solver stdout contained no JSON object');
|
|
47
|
+
}
|
|
48
|
+
return JSON.parse(text.slice(start));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function runPythonMode(mode, payload, timeoutMs = 10000, pythonBin = resolvePythonBin()) {
|
|
52
|
+
const stdout = execFileSync(
|
|
53
|
+
pythonBin,
|
|
54
|
+
[SCRIPT_PATH, '--mode', mode, '--input', JSON.stringify(payload)],
|
|
55
|
+
{
|
|
56
|
+
encoding: 'utf8',
|
|
57
|
+
timeout: timeoutMs,
|
|
58
|
+
env: {
|
|
59
|
+
...process.env,
|
|
60
|
+
PYTHONPATH: [
|
|
61
|
+
path.join(os.homedir(), '.hermes', 'gurobi'),
|
|
62
|
+
process.env.PYTHONPATH || '',
|
|
63
|
+
].filter(Boolean).join(path.delimiter),
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
return parseSolverStdout(stdout);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Decision-intelligence governance stamp (Beyond LLMs process, not Gurobi product).
|
|
72
|
+
* Understanding = heuristic (plausible). Computation = OPTIMAL MILP (repeatable).
|
|
73
|
+
* Action stays human-oversight — solver picks never auto-apply to PreToolUse.
|
|
74
|
+
*/
|
|
75
|
+
function isRepeatableSolve(result) {
|
|
76
|
+
const solver = String(result?.solver || '').toLowerCase();
|
|
77
|
+
return solver === 'gurobi' && String(result?.status || '') === 'OPTIMAL';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function stampDecisionGovernance(result) {
|
|
81
|
+
const body = result && typeof result === 'object' ? { ...result } : {};
|
|
82
|
+
const repeatable = isRepeatableSolve(body);
|
|
83
|
+
body.autoApply = false;
|
|
84
|
+
body.humanOversightRequired = true;
|
|
85
|
+
body.capturedRevenueUsd = 0;
|
|
86
|
+
body.repeatable = repeatable;
|
|
87
|
+
body.plausibleOnly = !repeatable;
|
|
88
|
+
body.certified = repeatable && body.success === true;
|
|
89
|
+
if (body.certified) {
|
|
90
|
+
body.proof = body.proof || 'gurobi-optimal';
|
|
91
|
+
} else if (String(body.status || '').startsWith('INFEASIBLE')) {
|
|
92
|
+
body.proof = body.proof || 'infeasible-iis';
|
|
93
|
+
} else if (/heuristic|fallback/i.test(String(body.solver || ''))) {
|
|
94
|
+
body.proof = body.proof || 'heuristic';
|
|
95
|
+
} else {
|
|
96
|
+
body.proof = body.proof || 'unproven';
|
|
97
|
+
}
|
|
98
|
+
return body;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const stampReceipt = stampDecisionGovernance;
|
|
102
|
+
const isCertifiedSolve = isRepeatableSolve;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Optimizes model candidate routing via Gurobi MILP solver.
|
|
106
|
+
* Falls back to deterministic heuristic if Gurobi is unavailable.
|
|
107
|
+
*/
|
|
108
|
+
function optimizeModelRouting(candidates, { maxBudgetUsd = 1.0, maxLatencyMs = 5000.0 } = {}, opts = {}) {
|
|
109
|
+
if (!Array.isArray(candidates) || candidates.length === 0) {
|
|
110
|
+
return stampDecisionGovernance({
|
|
111
|
+
success: false,
|
|
112
|
+
selected: null,
|
|
113
|
+
error: 'Candidates must be a non-empty array',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const pythonBin = opts.pythonBin || resolvePythonBin();
|
|
118
|
+
try {
|
|
119
|
+
return stampDecisionGovernance(runPythonMode('routing', {
|
|
120
|
+
candidates,
|
|
121
|
+
max_budget_usd: maxBudgetUsd,
|
|
122
|
+
max_latency_ms: maxLatencyMs,
|
|
123
|
+
}, opts.timeoutMs || 10000, pythonBin));
|
|
124
|
+
} catch (err) {
|
|
125
|
+
const valid = candidates.filter(
|
|
126
|
+
(c) => (c.cost || 0) <= maxBudgetUsd && (c.latency_ms || 0) <= maxLatencyMs
|
|
127
|
+
);
|
|
128
|
+
if (valid.length === 0) {
|
|
129
|
+
return stampDecisionGovernance({
|
|
130
|
+
success: false,
|
|
131
|
+
selected: null,
|
|
132
|
+
solver: 'node-fallback-heuristic',
|
|
133
|
+
status: 'INFEASIBLE',
|
|
134
|
+
iis: ['BudgetLimit', 'LatencyLimit'],
|
|
135
|
+
reason: 'no candidate satisfies budget and latency',
|
|
136
|
+
error: err.message,
|
|
137
|
+
python: pythonBin,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const best = valid.reduce(
|
|
141
|
+
(prev, curr) => ((curr.score || 0) > (prev.score || 0) ? curr : prev),
|
|
142
|
+
valid[0]
|
|
143
|
+
);
|
|
144
|
+
return stampDecisionGovernance({
|
|
145
|
+
success: true,
|
|
146
|
+
selected: best.id,
|
|
147
|
+
solver: 'node-fallback-heuristic',
|
|
148
|
+
status: 'HEURISTIC',
|
|
149
|
+
objective: best.score || 0,
|
|
150
|
+
error: err.message,
|
|
151
|
+
python: pythonBin,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Optimizes active prevention rule selection via Gurobi 0-1 Knapsack solver.
|
|
158
|
+
*/
|
|
159
|
+
function optimizeRuleSelection(rules, { maxEvalTimeMs = 50.0, maxTokenFootprint = 1000 } = {}, opts = {}) {
|
|
160
|
+
if (!Array.isArray(rules) || rules.length === 0) {
|
|
161
|
+
return stampDecisionGovernance({
|
|
162
|
+
success: false,
|
|
163
|
+
selected_rules: [],
|
|
164
|
+
error: 'Rules must be a non-empty array',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const pythonBin = opts.pythonBin || resolvePythonBin();
|
|
169
|
+
try {
|
|
170
|
+
return stampDecisionGovernance(runPythonMode('rules', {
|
|
171
|
+
rules,
|
|
172
|
+
max_eval_time_ms: maxEvalTimeMs,
|
|
173
|
+
max_token_footprint: maxTokenFootprint,
|
|
174
|
+
}, opts.timeoutMs || 10000, pythonBin));
|
|
175
|
+
} catch (err) {
|
|
176
|
+
const sorted = [...rules].sort(
|
|
177
|
+
(a, b) =>
|
|
178
|
+
(b.risk_mitigation || 0) / Math.max(b.eval_time_ms || 0.1, 0.1)
|
|
179
|
+
- (a.risk_mitigation || 0) / Math.max(a.eval_time_ms || 0.1, 0.1)
|
|
180
|
+
);
|
|
181
|
+
const selected = [];
|
|
182
|
+
let curTime = 0;
|
|
183
|
+
let curTokens = 0;
|
|
184
|
+
for (const r of sorted) {
|
|
185
|
+
const t = r.eval_time_ms || 0;
|
|
186
|
+
const tok = r.token_footprint || 0;
|
|
187
|
+
if (curTime + t <= maxEvalTimeMs && curTokens + tok <= maxTokenFootprint) {
|
|
188
|
+
selected.push(r.id);
|
|
189
|
+
curTime += t;
|
|
190
|
+
curTokens += tok;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return stampDecisionGovernance({
|
|
194
|
+
success: true,
|
|
195
|
+
selected_rules: selected,
|
|
196
|
+
solver: 'node-fallback-knapsack',
|
|
197
|
+
status: 'HEURISTIC',
|
|
198
|
+
used_time_ms: curTime,
|
|
199
|
+
used_tokens: curTokens,
|
|
200
|
+
error: err.message,
|
|
201
|
+
python: pythonBin,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Optimizes agent task dispatch across hardware resources via Gurobi MILP.
|
|
208
|
+
*/
|
|
209
|
+
function optimizeFleetDispatch(jobs, { maxRamMb = 32768, maxCpuCores = 10, maxConcurrency = 4 } = {}, opts = {}) {
|
|
210
|
+
if (!Array.isArray(jobs) || jobs.length === 0) {
|
|
211
|
+
return { success: false, selected_jobs: [], error: 'Jobs must be a non-empty array' };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const pythonBin = opts.pythonBin || resolvePythonBin();
|
|
215
|
+
try {
|
|
216
|
+
return runPythonMode('dispatch', {
|
|
217
|
+
jobs,
|
|
218
|
+
max_ram_mb: maxRamMb,
|
|
219
|
+
max_cpu_cores: maxCpuCores,
|
|
220
|
+
max_concurrency: maxConcurrency,
|
|
221
|
+
}, opts.timeoutMs || 10000, pythonBin);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
const valid = [];
|
|
224
|
+
let curRam = 0;
|
|
225
|
+
let curCpu = 0;
|
|
226
|
+
const sorted = [...jobs].sort((a, b) => (b.priority || 1) - (a.priority || 1));
|
|
227
|
+
for (const j of sorted) {
|
|
228
|
+
const r = j.ram_mb || 1024;
|
|
229
|
+
const c = j.cpu_cores || 1;
|
|
230
|
+
if (valid.length < maxConcurrency && curRam + r <= maxRamMb && curCpu + c <= maxCpuCores) {
|
|
231
|
+
valid.push(j.id);
|
|
232
|
+
curRam += r;
|
|
233
|
+
curCpu += c;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
selected_jobs: valid,
|
|
239
|
+
solver: 'node-fallback-dispatch',
|
|
240
|
+
allocated_ram_mb: curRam,
|
|
241
|
+
allocated_cpu_cores: curCpu,
|
|
242
|
+
error: err.message,
|
|
243
|
+
python: pythonBin,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Emits a cryptographic Certified Optimization Receipt proving dual bounds and mathematical optimality.
|
|
250
|
+
*/
|
|
251
|
+
function createCertifiedReceipt(optimizationResult, problemType = 'allocation') {
|
|
252
|
+
const crypto = require('node:crypto');
|
|
253
|
+
const payload = {
|
|
254
|
+
problemType,
|
|
255
|
+
solver: optimizationResult.solver || 'unknown',
|
|
256
|
+
status: optimizationResult.status || 'UNKNOWN',
|
|
257
|
+
objective: optimizationResult.objective !== undefined ? optimizationResult.objective : null,
|
|
258
|
+
optimalityGap: optimizationResult.optimality_gap !== undefined ? optimizationResult.optimality_gap : 0.0,
|
|
259
|
+
timestamp: Date.now(),
|
|
260
|
+
};
|
|
261
|
+
const signature = crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex');
|
|
262
|
+
return {
|
|
263
|
+
certified: optimizationResult.status === 'OPTIMAL' || String(optimizationResult.solver || '').includes('gurobi'),
|
|
264
|
+
...payload,
|
|
265
|
+
receiptId: `opt_rcpt_${signature.slice(0, 16)}`,
|
|
266
|
+
signatureSha256: signature,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function probeGurobi(opts = {}) {
|
|
271
|
+
try {
|
|
272
|
+
const res = optimizeModelRouting(
|
|
273
|
+
[{ id: 'probe', score: 1, cost: 0, latency_ms: 1 }],
|
|
274
|
+
{ maxBudgetUsd: 1, maxLatencyMs: 10 },
|
|
275
|
+
opts
|
|
276
|
+
);
|
|
277
|
+
const solver = String(res?.solver || '');
|
|
278
|
+
const isErrorFallback = /error|fallback|heuristic/i.test(solver);
|
|
279
|
+
return {
|
|
280
|
+
ok: Boolean(res?.success && !isErrorFallback),
|
|
281
|
+
solver: res.solver || null,
|
|
282
|
+
python: res.python || resolvePythonBin(),
|
|
283
|
+
gurobi: solver === 'gurobi' || (solver.startsWith('gurobi') && !isErrorFallback),
|
|
284
|
+
};
|
|
285
|
+
} catch (err) {
|
|
286
|
+
return { ok: false, error: err.message, python: resolvePythonBin(), gurobi: false };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function mainCli() {
|
|
291
|
+
const sampleCandidates = [
|
|
292
|
+
{ id: 'qwen-3b', score: 8.2, cost: 0.001, latency_ms: 120 },
|
|
293
|
+
{ id: 'claude-3-5', score: 9.8, cost: 0.015, latency_ms: 1200 },
|
|
294
|
+
{ id: 'local-vllm', score: 8.9, cost: 0.0, latency_ms: 250 },
|
|
295
|
+
];
|
|
296
|
+
const routingRes = optimizeModelRouting(sampleCandidates, {
|
|
297
|
+
maxBudgetUsd: 0.01,
|
|
298
|
+
maxLatencyMs: 500,
|
|
299
|
+
});
|
|
300
|
+
return { probe: probeGurobi(), routing: routingRes, receipt: createCertifiedReceipt(routingRes, 'routing') };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
module.exports = {
|
|
304
|
+
optimizeModelRouting,
|
|
305
|
+
optimizeRuleSelection,
|
|
306
|
+
optimizeFleetDispatch,
|
|
307
|
+
createCertifiedReceipt,
|
|
308
|
+
resolvePythonBin,
|
|
309
|
+
probeGurobi,
|
|
310
|
+
runPythonMode,
|
|
311
|
+
parseSolverStdout,
|
|
312
|
+
isRepeatableSolve,
|
|
313
|
+
isCertifiedSolve,
|
|
314
|
+
stampDecisionGovernance,
|
|
315
|
+
stampReceipt,
|
|
316
|
+
mainCli,
|
|
317
|
+
get PYTHON_BIN() {
|
|
318
|
+
return resolvePythonBin();
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
if (path.resolve(process.argv[1] || '') === path.resolve(__filename)) {
|
|
323
|
+
console.log(JSON.stringify(mainCli(), null, 2));
|
|
324
|
+
}
|