thumbgate 1.34.3 → 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 +373 -5
- package/bin/futureagi-bridge +9 -0
- package/config/gate-templates.json +653 -4
- package/config/gates/actor-critic-audit.json +34 -0
- package/config/gates/default.json +21 -2
- 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 +10 -1
- package/config/model-candidates.json +382 -24
- 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 +401 -147
- 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/auto-promote-gates.js +178 -27
- 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-progress.js +111 -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-limits.js +27 -0
- package/scripts/dashboard.js +279 -9
- 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/gate-stats.js +2 -2
- package/scripts/gates-engine.js +859 -58
- 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 +802 -185
- 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,536 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* NVIDIA speculative-decoding AL/D doctor for ThumbGate.
|
|
6
|
+
*
|
|
7
|
+
* Steals measurable mechanics from:
|
|
8
|
+
* https://developer.nvidia.com/blog/co-designing-ai-models-using-speculative-decoding-for-faster-llm-inference/
|
|
9
|
+
*
|
|
10
|
+
* Transfers (only):
|
|
11
|
+
* - speedup ≈ AL / (1 + ρD) at low latency
|
|
12
|
+
* - attention draft length D = 128/G - 1
|
|
13
|
+
* - tile alignment: G × (1 + D) multiple of 128
|
|
14
|
+
* - increase D only while AL gains justify draft cost
|
|
15
|
+
* - pick draft mechanism by AL vs draft overhead (not brand)
|
|
16
|
+
*
|
|
17
|
+
* Does NOT clone TensorRT-LLM, EAGLE training, Model-Optimizer, or SPEED-Bench.
|
|
18
|
+
* Maps findings onto existing checkpoint-speculative-decoding-acceptance gate.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const path = require('node:path');
|
|
22
|
+
|
|
23
|
+
const ATTENTION_TILE = 128;
|
|
24
|
+
const DEFAULT_MIN_ACCEPT_LENGTH = 2;
|
|
25
|
+
const SOURCE_URL =
|
|
26
|
+
'https://developer.nvidia.com/blog/co-designing-ai-models-using-speculative-decoding-for-faster-llm-inference/';
|
|
27
|
+
|
|
28
|
+
function normalizeBoolean(value) {
|
|
29
|
+
if (value === true) return true;
|
|
30
|
+
if (value === false || value === undefined || value === null) return false;
|
|
31
|
+
return /^(1|true|yes|on)$/i.test(String(value).trim());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toNumber(value) {
|
|
35
|
+
if (value === undefined || value === null || value === '') return null;
|
|
36
|
+
const num = Number(value);
|
|
37
|
+
return Number.isFinite(num) ? num : null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function round4(value) {
|
|
41
|
+
return Number(Number(value).toFixed(4));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Guideline 2: when attention dominates decode, D = 128/G - 1.
|
|
46
|
+
* @param {number} queryHeadsPerKvHead G
|
|
47
|
+
* @returns {number|null}
|
|
48
|
+
*/
|
|
49
|
+
function optimalDraftLengthForAttention(queryHeadsPerKvHead) {
|
|
50
|
+
const g = Number(queryHeadsPerKvHead);
|
|
51
|
+
if (!Number.isFinite(g) || g <= 0) return null;
|
|
52
|
+
return Math.max(0, Math.floor(ATTENTION_TILE / g) - 1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Guideline 3: prefer D where G × (1 + D) is a multiple of 128.
|
|
57
|
+
*/
|
|
58
|
+
function isTileAligned(queryHeadsPerKvHead, draftLength) {
|
|
59
|
+
const g = Number(queryHeadsPerKvHead);
|
|
60
|
+
const d = Number(draftLength);
|
|
61
|
+
if (!Number.isFinite(g) || g <= 0 || !Number.isFinite(d) || d < 0) return false;
|
|
62
|
+
return (g * (1 + d)) % ATTENTION_TILE === 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Next tile-aligned draft length at or above candidate D (or null).
|
|
67
|
+
*/
|
|
68
|
+
function nearestTileAlignedDraftLength(queryHeadsPerKvHead, draftLength) {
|
|
69
|
+
const g = Number(queryHeadsPerKvHead);
|
|
70
|
+
let d = Math.max(0, Math.floor(Number(draftLength) || 0));
|
|
71
|
+
if (!Number.isFinite(g) || g <= 0) return null;
|
|
72
|
+
for (let i = 0; i < ATTENTION_TILE; i += 1) {
|
|
73
|
+
if (isTileAligned(g, d + i)) return d + i;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Draft overhead O_d = ρD */
|
|
79
|
+
function draftOverhead(draftDepthRatio, draftLength) {
|
|
80
|
+
const rho = Number(draftDepthRatio);
|
|
81
|
+
const d = Number(draftLength);
|
|
82
|
+
if (!Number.isFinite(rho) || rho < 0 || !Number.isFinite(d) || d < 0) return null;
|
|
83
|
+
return round4(rho * d);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Low-latency approximation: speedup = AL / (1 + ρD)
|
|
88
|
+
* AL ranges from 1 to 1+D (target always emits one ground-truth token).
|
|
89
|
+
*/
|
|
90
|
+
function theoreticalSpeedup(acceptLength, draftLength, draftDepthRatio) {
|
|
91
|
+
const al = Number(acceptLength);
|
|
92
|
+
const d = Number(draftLength);
|
|
93
|
+
const rho = draftDepthRatio === undefined || draftDepthRatio === null
|
|
94
|
+
? 0
|
|
95
|
+
: Number(draftDepthRatio);
|
|
96
|
+
if (!Number.isFinite(al) || al <= 0) return null;
|
|
97
|
+
if (!Number.isFinite(d) || d < 0) return null;
|
|
98
|
+
if (!Number.isFinite(rho) || rho < 0) return null;
|
|
99
|
+
const denom = 1 + (rho * d);
|
|
100
|
+
if (denom <= 0) return null;
|
|
101
|
+
return round4(al / denom);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Guideline 4 helper: raising D helps only while AL gain beats added draft cost.
|
|
106
|
+
* Compare speedup at (D, AL) vs (D+deltaD, AL+deltaAL) under fixed ρ.
|
|
107
|
+
*/
|
|
108
|
+
function shouldIncreaseDraftLength({
|
|
109
|
+
acceptLength,
|
|
110
|
+
draftLength,
|
|
111
|
+
draftDepthRatio = 0,
|
|
112
|
+
nextAcceptLength,
|
|
113
|
+
nextDraftLength,
|
|
114
|
+
}) {
|
|
115
|
+
const current = theoreticalSpeedup(acceptLength, draftLength, draftDepthRatio);
|
|
116
|
+
const next = theoreticalSpeedup(nextAcceptLength, nextDraftLength, draftDepthRatio);
|
|
117
|
+
if (current === null || next === null) return null;
|
|
118
|
+
return {
|
|
119
|
+
currentSpeedup: current,
|
|
120
|
+
nextSpeedup: next,
|
|
121
|
+
increase: next > current,
|
|
122
|
+
deltaSpeedup: round4(next - current),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Guideline 5 (ThumbGate-shaped): recommend a draft *class*, not a vendor stack.
|
|
128
|
+
* Never claims TensorRT/EAGLE/Model-Optimizer readiness.
|
|
129
|
+
*/
|
|
130
|
+
function recommendDraftMechanism(options = {}) {
|
|
131
|
+
const workload = String(options.workload || options.workloadType || 'agentic').trim().toLowerCase();
|
|
132
|
+
const latencyRegion = String(options.latencyRegion || options.latency || 'low').trim().toLowerCase();
|
|
133
|
+
const modelSize = String(options.modelSize || options.size || 'medium').trim().toLowerCase();
|
|
134
|
+
const repetitive = normalizeBoolean(options.repetitive)
|
|
135
|
+
|| /repetit|tool.?loop|code.?complete|suffix|ngram/.test(workload);
|
|
136
|
+
|
|
137
|
+
if (repetitive) {
|
|
138
|
+
return {
|
|
139
|
+
mechanism: 'suffix-ngram',
|
|
140
|
+
draftDepthRatioHint: 0,
|
|
141
|
+
reason: 'Repetitive agent/tool token streams get free O(1) drafts; no learned drafter to retrain after target fine-tunes.',
|
|
142
|
+
bestFor: 'high-repetition coding agents and tool-call loops',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (latencyRegion === 'low' && /small|tiny|7b|8b|3b/.test(modelSize)) {
|
|
147
|
+
return {
|
|
148
|
+
mechanism: 'parallel-draft-head',
|
|
149
|
+
draftDepthRatioHint: 0.05,
|
|
150
|
+
reason: 'Small targets at low latency: parallel draft heads keep O_d low even when AL is modest (DFlash/DSpark class).',
|
|
151
|
+
bestFor: 'batch-1 interactive small models',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (/large|70b|120b|405b|moe/.test(modelSize)) {
|
|
156
|
+
return {
|
|
157
|
+
mechanism: 'target-attached-mtp',
|
|
158
|
+
draftDepthRatioHint: 0.02,
|
|
159
|
+
reason: 'Large GPU targets: one-layer MTP-style heads keep draft overhead tiny relative to L_target while AL stays competitive.',
|
|
160
|
+
bestFor: 'large self-hosted targets on GPUs',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
mechanism: 'external-small-draft',
|
|
166
|
+
draftDepthRatioHint: 0.15,
|
|
167
|
+
reason: 'Default: small external draft can raise AL, but only if measured O_d still leaves AL/(1+ρD) above 1. Re-measure AL after every target fine-tune.',
|
|
168
|
+
bestFor: 'general agentic workloads with measured AL evidence',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function normalizeOptions(options = {}) {
|
|
173
|
+
const queryHeads = toNumber(options['query-heads'] || options.queryHeads);
|
|
174
|
+
const kvHeads = toNumber(options['kv-heads'] || options.kvHeads);
|
|
175
|
+
let g = toNumber(options['query-heads-per-kv'] || options.g || options.G);
|
|
176
|
+
if (g === null && queryHeads !== null && kvHeads !== null && kvHeads > 0) {
|
|
177
|
+
g = queryHeads / kvHeads;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
workload: String(options.workload || options.name || 'speculative-decoding').trim() || 'speculative-decoding',
|
|
182
|
+
model: String(options.model || 'target-model').trim() || 'target-model',
|
|
183
|
+
speculativeDecoding: normalizeBoolean(
|
|
184
|
+
options['speculative-decoding'] || options.speculative || options.mtp || options.eagle || options.enabled
|
|
185
|
+
),
|
|
186
|
+
acceptLength: toNumber(options['accept-length'] || options.al || options.AL),
|
|
187
|
+
draftLength: toNumber(options['draft-length'] || options.d || options.D),
|
|
188
|
+
draftDepthRatio: toNumber(options['draft-depth-ratio'] || options.rho || options['depth-ratio']),
|
|
189
|
+
claimedSpeedup: toNumber(options['claimed-speedup'] || options.speedup || options['claimed-x']),
|
|
190
|
+
minAcceptLength: toNumber(options['min-accept-length']) ?? DEFAULT_MIN_ACCEPT_LENGTH,
|
|
191
|
+
queryHeadsPerKvHead: g,
|
|
192
|
+
queryHeads,
|
|
193
|
+
kvHeads,
|
|
194
|
+
attentionDominated: normalizeBoolean(options['attention-dominated'] || options.attention),
|
|
195
|
+
latencyRegion: String(options['latency-region'] || options.latency || 'low').trim().toLowerCase() || 'low',
|
|
196
|
+
modelSize: String(options['model-size'] || options.size || 'medium').trim().toLowerCase() || 'medium',
|
|
197
|
+
repetitive: normalizeBoolean(options.repetitive),
|
|
198
|
+
nextAcceptLength: toNumber(options['next-accept-length'] || options['al-next']),
|
|
199
|
+
nextDraftLength: toNumber(options['next-draft-length'] || options['d-next']),
|
|
200
|
+
cacheCoherenceEval: normalizeBoolean(options['cache-coherence-eval'] || options['cache-eval']),
|
|
201
|
+
strict: normalizeBoolean(options.strict),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function buildFindings(options, metrics, mechanism) {
|
|
206
|
+
const findings = [];
|
|
207
|
+
|
|
208
|
+
if (options.speculativeDecoding && options.acceptLength === null) {
|
|
209
|
+
findings.push({
|
|
210
|
+
id: 'accept_length_missing',
|
|
211
|
+
severity: 'fail',
|
|
212
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
213
|
+
message: 'Speculative decoding is enabled but measured accept length (AL) is missing. SPEED-Bench-style AL evidence is required before treating speculation as a speedup.',
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (options.acceptLength !== null && options.acceptLength < options.minAcceptLength) {
|
|
218
|
+
findings.push({
|
|
219
|
+
id: 'accept_length_below_floor',
|
|
220
|
+
severity: 'fail',
|
|
221
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
222
|
+
message: `Accept length ${options.acceptLength} is below the floor ${options.minAcceptLength}. Do not route production traffic until AL recovers.`,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (
|
|
227
|
+
options.acceptLength !== null
|
|
228
|
+
&& options.draftLength !== null
|
|
229
|
+
&& options.acceptLength > (1 + options.draftLength)
|
|
230
|
+
) {
|
|
231
|
+
findings.push({
|
|
232
|
+
id: 'accept_length_impossible',
|
|
233
|
+
severity: 'fail',
|
|
234
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
235
|
+
message: `AL=${options.acceptLength} exceeds 1+D=${1 + options.draftLength}. Measured AL must be in [1, 1+D].`,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (
|
|
240
|
+
metrics.theoreticalSpeedup !== null
|
|
241
|
+
&& options.claimedSpeedup !== null
|
|
242
|
+
&& options.claimedSpeedup > metrics.theoreticalSpeedup + 1e-9
|
|
243
|
+
) {
|
|
244
|
+
findings.push({
|
|
245
|
+
id: 'claimed_speedup_over_theory',
|
|
246
|
+
severity: 'fail',
|
|
247
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
248
|
+
message: `Claimed speedup ${options.claimedSpeedup}x exceeds theoretical AL/(1+ρD)=${metrics.theoreticalSpeedup}x. Reject the throughput claim.`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (options.speculativeDecoding && !options.cacheCoherenceEval) {
|
|
253
|
+
findings.push({
|
|
254
|
+
id: 'cache_coherence_missing',
|
|
255
|
+
severity: 'warn',
|
|
256
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
257
|
+
message: 'Speculation enabled without cache-coherence / rollback evidence. Pair with require-hybrid-prefix-cache-coherence-eval before production.',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (options.attentionDominated && options.queryHeadsPerKvHead !== null) {
|
|
262
|
+
const optimal = metrics.attentionOptimalDraftLength;
|
|
263
|
+
if (optimal !== null && options.draftLength !== null) {
|
|
264
|
+
if (options.draftLength > optimal && !metrics.tileAligned) {
|
|
265
|
+
findings.push({
|
|
266
|
+
id: 'tile_underutilized',
|
|
267
|
+
severity: 'warn',
|
|
268
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
269
|
+
message: `Attention-dominated: D=${options.draftLength} exceeds D*=${optimal} and G×(1+D) is not a multiple of ${ATTENTION_TILE}. Prefer tile-aligned D=${metrics.tileAlignedDraftLength}.`,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
} else if (optimal !== null && options.draftLength === null) {
|
|
273
|
+
findings.push({
|
|
274
|
+
id: 'suggest_attention_draft_length',
|
|
275
|
+
severity: 'info',
|
|
276
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
277
|
+
message: `Attention-dominated workload: start with D=${optimal} (128/G - 1) for G=${options.queryHeadsPerKvHead}.`,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (metrics.draftIncreaseDecision && metrics.draftIncreaseDecision.increase === false) {
|
|
283
|
+
findings.push({
|
|
284
|
+
id: 'draft_increase_not_justified',
|
|
285
|
+
severity: 'warn',
|
|
286
|
+
gateId: 'checkpoint-speculative-decoding-acceptance',
|
|
287
|
+
message: `Guideline 4: raising D to ${options.nextDraftLength} drops speedup from ${metrics.draftIncreaseDecision.currentSpeedup}x to ${metrics.draftIncreaseDecision.nextSpeedup}x. Keep current D.`,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (mechanism && options.draftDepthRatio === null && mechanism.draftDepthRatioHint !== undefined) {
|
|
292
|
+
findings.push({
|
|
293
|
+
id: 'draft_depth_ratio_assumed',
|
|
294
|
+
severity: 'info',
|
|
295
|
+
gateId: null,
|
|
296
|
+
message: `No --draft-depth-ratio provided. Mechanism hint ρ≈${mechanism.draftDepthRatioHint} for ${mechanism.mechanism}; measure serve-time O_d before claiming speedup.`,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return findings;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function buildNvidiaSpecDecodeAlDoctorReport(rawOptions = {}) {
|
|
304
|
+
const options = normalizeOptions(rawOptions);
|
|
305
|
+
const rhoForTheory = options.draftDepthRatio === null ? 0 : options.draftDepthRatio;
|
|
306
|
+
const attentionOptimalDraftLength = optimalDraftLengthForAttention(options.queryHeadsPerKvHead);
|
|
307
|
+
const tileAligned = options.queryHeadsPerKvHead !== null && options.draftLength !== null
|
|
308
|
+
? isTileAligned(options.queryHeadsPerKvHead, options.draftLength)
|
|
309
|
+
: null;
|
|
310
|
+
const tileAlignedDraftLength = options.queryHeadsPerKvHead !== null
|
|
311
|
+
? nearestTileAlignedDraftLength(
|
|
312
|
+
options.queryHeadsPerKvHead,
|
|
313
|
+
options.draftLength ?? attentionOptimalDraftLength ?? 0
|
|
314
|
+
)
|
|
315
|
+
: null;
|
|
316
|
+
|
|
317
|
+
const mechanism = recommendDraftMechanism({
|
|
318
|
+
workload: options.workload,
|
|
319
|
+
latencyRegion: options.latencyRegion,
|
|
320
|
+
modelSize: options.modelSize,
|
|
321
|
+
repetitive: options.repetitive,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const metrics = {
|
|
325
|
+
acceptLength: options.acceptLength,
|
|
326
|
+
draftLength: options.draftLength,
|
|
327
|
+
draftDepthRatio: options.draftDepthRatio,
|
|
328
|
+
draftOverhead: draftOverhead(rhoForTheory, options.draftLength ?? 0),
|
|
329
|
+
theoreticalSpeedup: options.acceptLength !== null && options.draftLength !== null
|
|
330
|
+
? theoreticalSpeedup(options.acceptLength, options.draftLength, rhoForTheory)
|
|
331
|
+
: null,
|
|
332
|
+
claimedSpeedup: options.claimedSpeedup,
|
|
333
|
+
attentionOptimalDraftLength,
|
|
334
|
+
tileAligned,
|
|
335
|
+
tileAlignedDraftLength,
|
|
336
|
+
draftIncreaseDecision: (
|
|
337
|
+
options.acceptLength !== null
|
|
338
|
+
&& options.draftLength !== null
|
|
339
|
+
&& options.nextAcceptLength !== null
|
|
340
|
+
&& options.nextDraftLength !== null
|
|
341
|
+
)
|
|
342
|
+
? shouldIncreaseDraftLength({
|
|
343
|
+
acceptLength: options.acceptLength,
|
|
344
|
+
draftLength: options.draftLength,
|
|
345
|
+
draftDepthRatio: rhoForTheory,
|
|
346
|
+
nextAcceptLength: options.nextAcceptLength,
|
|
347
|
+
nextDraftLength: options.nextDraftLength,
|
|
348
|
+
})
|
|
349
|
+
: null,
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const findings = buildFindings(options, metrics, mechanism);
|
|
353
|
+
const failCount = findings.filter((f) => f.severity === 'fail').length;
|
|
354
|
+
const warnCount = findings.filter((f) => f.severity === 'warn').length;
|
|
355
|
+
const recommendedGateIds = [...new Set(
|
|
356
|
+
findings.map((f) => f.gateId).filter(Boolean)
|
|
357
|
+
)];
|
|
358
|
+
|
|
359
|
+
let status = 'ready';
|
|
360
|
+
if (failCount > 0) status = 'fail';
|
|
361
|
+
else if (warnCount > 0 || findings.some((f) => f.severity === 'info' && f.id !== 'draft_depth_ratio_assumed')) {
|
|
362
|
+
status = 'actionable';
|
|
363
|
+
} else if (
|
|
364
|
+
options.speculativeDecoding
|
|
365
|
+
&& options.acceptLength !== null
|
|
366
|
+
&& options.acceptLength >= options.minAcceptLength
|
|
367
|
+
&& (options.claimedSpeedup === null
|
|
368
|
+
|| metrics.theoreticalSpeedup === null
|
|
369
|
+
|| options.claimedSpeedup <= metrics.theoreticalSpeedup + 1e-9)
|
|
370
|
+
) {
|
|
371
|
+
status = 'ready';
|
|
372
|
+
} else if (!options.speculativeDecoding && options.acceptLength === null) {
|
|
373
|
+
status = 'ready';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
name: 'thumbgate-nvidia-specdecode-al-doctor',
|
|
378
|
+
status,
|
|
379
|
+
source: SOURCE_URL,
|
|
380
|
+
disclaimer: 'Process steal of AL/D co-design guidelines only. Not affiliated with NVIDIA. Does not ship TensorRT-LLM, EAGLE, or Model-Optimizer.',
|
|
381
|
+
workload: options.workload,
|
|
382
|
+
model: options.model,
|
|
383
|
+
metrics,
|
|
384
|
+
mechanism,
|
|
385
|
+
findings,
|
|
386
|
+
summary: {
|
|
387
|
+
failCount,
|
|
388
|
+
warnCount,
|
|
389
|
+
findingCount: findings.length,
|
|
390
|
+
recommendedGateCount: recommendedGateIds.length,
|
|
391
|
+
},
|
|
392
|
+
recommendedGates: recommendedGateIds,
|
|
393
|
+
nextActions: [
|
|
394
|
+
'Measure accept length (AL) on realistic agent prompts before claiming speculation speedup.',
|
|
395
|
+
'Use speedup ≈ AL/(1+ρD); reject claims above that ceiling.',
|
|
396
|
+
'For attention-heavy decode, start at D=128/G-1 and keep G×(1+D) tile-aligned.',
|
|
397
|
+
'Increase D only while measured AL gains beat added draft overhead.',
|
|
398
|
+
'Wire evidence through deepseek-v4-runtime-guardrails --speculative-decoding --accept-length=… and gate checkpoint-speculative-decoding-acceptance.',
|
|
399
|
+
],
|
|
400
|
+
exampleCommand:
|
|
401
|
+
'npx thumbgate nvidia-specdecode-al-doctor --speculative-decoding --accept-length=1.4 --draft-length=7 --draft-depth-ratio=0.05 --claimed-speedup=3 --query-heads-per-kv=8 --attention-dominated --json',
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function formatNvidiaSpecDecodeAlDoctorReport(report) {
|
|
406
|
+
const lines = [
|
|
407
|
+
'',
|
|
408
|
+
'ThumbGate NVIDIA Speculative-Decoding AL/D Doctor',
|
|
409
|
+
'-'.repeat(48),
|
|
410
|
+
`Status : ${report.status}`,
|
|
411
|
+
`Workload: ${report.workload}`,
|
|
412
|
+
`Model : ${report.model}`,
|
|
413
|
+
`Source : ${report.source}`,
|
|
414
|
+
`Findings: ${report.summary.findingCount} (fail=${report.summary.failCount}, warn=${report.summary.warnCount})`,
|
|
415
|
+
];
|
|
416
|
+
|
|
417
|
+
if (report.metrics.acceptLength !== null) lines.push(`AL : ${report.metrics.acceptLength}`);
|
|
418
|
+
if (report.metrics.draftLength !== null) lines.push(`D : ${report.metrics.draftLength}`);
|
|
419
|
+
if (report.metrics.draftDepthRatio !== null) lines.push(`ρ : ${report.metrics.draftDepthRatio}`);
|
|
420
|
+
if (report.metrics.theoreticalSpeedup !== null) {
|
|
421
|
+
lines.push(`Theory : ${report.metrics.theoreticalSpeedup}x (AL/(1+ρD))`);
|
|
422
|
+
}
|
|
423
|
+
if (report.metrics.claimedSpeedup !== null) lines.push(`Claimed : ${report.metrics.claimedSpeedup}x`);
|
|
424
|
+
if (report.metrics.attentionOptimalDraftLength !== null) {
|
|
425
|
+
lines.push(`D*(attn): ${report.metrics.attentionOptimalDraftLength}`);
|
|
426
|
+
}
|
|
427
|
+
if (report.metrics.tileAligned !== null) {
|
|
428
|
+
lines.push(`Tile OK : ${report.metrics.tileAligned ? 'yes' : 'no'}`);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
lines.push('', `Mechanism: ${report.mechanism.mechanism}`);
|
|
432
|
+
lines.push(` ${report.mechanism.reason}`);
|
|
433
|
+
|
|
434
|
+
if (report.findings.length > 0) {
|
|
435
|
+
lines.push('', 'Findings:');
|
|
436
|
+
for (const finding of report.findings) {
|
|
437
|
+
const gate = finding.gateId ? ` [${finding.gateId}]` : '';
|
|
438
|
+
lines.push(` - [${finding.severity}] ${finding.id}${gate}`);
|
|
439
|
+
lines.push(` ${finding.message}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
lines.push('', 'Next actions:');
|
|
444
|
+
for (const action of report.nextActions) lines.push(` - ${action}`);
|
|
445
|
+
lines.push('', `Example: ${report.exampleCommand}`);
|
|
446
|
+
lines.push(`Note: ${report.disclaimer}`, '');
|
|
447
|
+
return `${lines.join('\n')}\n`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function parseCliArgs(argv) {
|
|
451
|
+
const options = {};
|
|
452
|
+
for (const arg of argv) {
|
|
453
|
+
if (arg === '--json') {
|
|
454
|
+
options.json = true;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
if (arg === '--strict') {
|
|
458
|
+
options.strict = true;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (arg === '--help' || arg === '-h') {
|
|
462
|
+
options.help = true;
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const m = /^--([^=]+)(?:=(.*))?$/.exec(arg);
|
|
466
|
+
if (!m) continue;
|
|
467
|
+
const key = m[1];
|
|
468
|
+
const raw = m[2] === undefined ? true : m[2];
|
|
469
|
+
options[key] = raw;
|
|
470
|
+
}
|
|
471
|
+
return options;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function printHelp() {
|
|
475
|
+
process.stdout.write(`Usage: node scripts/nvidia-specdecode-al-doctor.js [flags]
|
|
476
|
+
|
|
477
|
+
Flags:
|
|
478
|
+
--speculative-decoding Speculation path is active
|
|
479
|
+
--accept-length=AL Measured acceptance length
|
|
480
|
+
--draft-length=D Draft tokens per target iteration
|
|
481
|
+
--draft-depth-ratio=ρ L_draft / L_target (default 0 for theory)
|
|
482
|
+
--claimed-speedup=X Throughput claim to check against AL/(1+ρD)
|
|
483
|
+
--min-accept-length=N Floor before production (default 2)
|
|
484
|
+
--query-heads-per-kv=G Attention group size G
|
|
485
|
+
--attention-dominated Apply D=128/G-1 + tile guidance
|
|
486
|
+
--latency-region=low|throughput Pareto region hint for mechanism pick
|
|
487
|
+
--model-size=small|medium|large Mechanism sizing hint
|
|
488
|
+
--repetitive Prefer suffix/n-gram drafts
|
|
489
|
+
--next-accept-length / --next-draft-length
|
|
490
|
+
Guideline-4 compare for raising D
|
|
491
|
+
--cache-coherence-eval Rollback/coherence evidence present
|
|
492
|
+
--strict Exit 1 on fail/actionable
|
|
493
|
+
--json Machine-readable report
|
|
494
|
+
|
|
495
|
+
Source: ${SOURCE_URL}
|
|
496
|
+
`);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function runCli(argv = process.argv.slice(2)) {
|
|
500
|
+
const args = parseCliArgs(argv);
|
|
501
|
+
if (args.help) {
|
|
502
|
+
printHelp();
|
|
503
|
+
return 0;
|
|
504
|
+
}
|
|
505
|
+
const report = buildNvidiaSpecDecodeAlDoctorReport(args);
|
|
506
|
+
if (args.json) {
|
|
507
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
508
|
+
} else {
|
|
509
|
+
process.stdout.write(formatNvidiaSpecDecodeAlDoctorReport(report));
|
|
510
|
+
}
|
|
511
|
+
if (args.strict && report.status !== 'ready') return 1;
|
|
512
|
+
if (report.status === 'fail') return 1;
|
|
513
|
+
return 0;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
module.exports = {
|
|
517
|
+
ATTENTION_TILE,
|
|
518
|
+
DEFAULT_MIN_ACCEPT_LENGTH,
|
|
519
|
+
SOURCE_URL,
|
|
520
|
+
optimalDraftLengthForAttention,
|
|
521
|
+
isTileAligned,
|
|
522
|
+
nearestTileAlignedDraftLength,
|
|
523
|
+
draftOverhead,
|
|
524
|
+
theoreticalSpeedup,
|
|
525
|
+
shouldIncreaseDraftLength,
|
|
526
|
+
recommendDraftMechanism,
|
|
527
|
+
normalizeOptions,
|
|
528
|
+
buildNvidiaSpecDecodeAlDoctorReport,
|
|
529
|
+
formatNvidiaSpecDecodeAlDoctorReport,
|
|
530
|
+
parseCliArgs,
|
|
531
|
+
runCli,
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(__filename)) {
|
|
535
|
+
process.exitCode = runCli(process.argv.slice(2));
|
|
536
|
+
}
|