logitgate 0.2.0__tar.gz → 0.2.2__tar.gz

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 (49) hide show
  1. logitgate-0.2.2/PKG-INFO +357 -0
  2. logitgate-0.2.2/README.md +302 -0
  3. {logitgate-0.2.0 → logitgate-0.2.2}/pyproject.toml +1 -1
  4. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/__init__.py +13 -1
  5. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/base.py +38 -0
  6. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/ollama.py +5 -3
  7. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/openai_compat.py +7 -3
  8. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/cascade.py +279 -94
  9. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/debiasing/permutation.py +2 -2
  10. logitgate-0.2.2/src/logitgate/exceptions.py +29 -0
  11. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/gates/ast_gate.py +20 -4
  12. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/gates/judge_gate.py +30 -28
  13. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/gates/logit_gate.py +51 -17
  14. logitgate-0.2.2/src/logitgate.egg-info/PKG-INFO +357 -0
  15. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate.egg-info/SOURCES.txt +1 -0
  16. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_cascade.py +50 -0
  17. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_usability_and_validation.py +95 -0
  18. logitgate-0.2.0/PKG-INFO +0 -1236
  19. logitgate-0.2.0/README.md +0 -1181
  20. logitgate-0.2.0/src/logitgate.egg-info/PKG-INFO +0 -1236
  21. {logitgate-0.2.0 → logitgate-0.2.2}/LICENSE +0 -0
  22. {logitgate-0.2.0 → logitgate-0.2.2}/setup.cfg +0 -0
  23. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/__init__.py +0 -0
  24. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/dory_pytorch.py +0 -0
  25. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/llamacpp.py +0 -0
  26. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/backends/recurrent.py +0 -0
  27. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/cli.py +0 -0
  28. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/config.py +0 -0
  29. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/debiasing/__init__.py +0 -0
  30. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/debiasing/inversion.py +0 -0
  31. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/debiasing/softmax.py +0 -0
  32. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/gates/__init__.py +0 -0
  33. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/gates/base.py +0 -0
  34. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/integrations/__init__.py +0 -0
  35. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/integrations/deepeval.py +0 -0
  36. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/integrations/langgraph.py +0 -0
  37. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/integrations/pytest_plugin.py +0 -0
  38. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/models.py +0 -0
  39. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/py.typed +0 -0
  40. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate/snapshot.py +0 -0
  41. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate.egg-info/dependency_links.txt +0 -0
  42. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate.egg-info/entry_points.txt +0 -0
  43. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate.egg-info/requires.txt +0 -0
  44. {logitgate-0.2.0 → logitgate-0.2.2}/src/logitgate.egg-info/top_level.txt +0 -0
  45. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_ast_gate.py +0 -0
  46. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_backends_and_cli.py +0 -0
  47. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_debiasing_math.py +0 -0
  48. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_integrations.py +0 -0
  49. {logitgate-0.2.0 → logitgate-0.2.2}/tests/test_logit_gate.py +0 -0
@@ -0,0 +1,357 @@
1
+ Metadata-Version: 2.4
2
+ Name: logitgate
3
+ Version: 0.2.2
4
+ Summary: Fast, calibrated first-token logit evaluation and 3-layer cascaded routing for LLMs.
5
+ Author-email: Jason Bradley <jasonbdly@gmail.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/jasonbdly/LogitGate
8
+ Project-URL: Repository, https://github.com/jasonbdly/LogitGate
9
+ Project-URL: Mirror, https://gitlab.com/jasonbdly/logitgate
10
+ Keywords: llm,evaluation,logprobs,logits,calibration,cascaded-routing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3.15
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: pydantic>=2.0.0
26
+ Requires-Dist: httpx>=0.23.0
27
+ Requires-Dist: typing-extensions>=4.0.0
28
+ Provides-Extra: openai
29
+ Requires-Dist: openai>=1.0.0; extra == "openai"
30
+ Provides-Extra: deepeval
31
+ Requires-Dist: deepeval>=1.0.0; extra == "deepeval"
32
+ Provides-Extra: langgraph
33
+ Requires-Dist: langgraph>=0.0.1; extra == "langgraph"
34
+ Provides-Extra: llamacpp
35
+ Requires-Dist: llama-cpp-python>=0.2.0; extra == "llamacpp"
36
+ Provides-Extra: recurrent
37
+ Requires-Dist: torch>=2.0.0; extra == "recurrent"
38
+ Requires-Dist: transformers>=4.40.0; extra == "recurrent"
39
+ Provides-Extra: pytest
40
+ Requires-Dist: pytest>=8.0.0; extra == "pytest"
41
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "pytest"
42
+ Provides-Extra: test
43
+ Requires-Dist: pytest>=8.0.0; extra == "test"
44
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
45
+ Provides-Extra: all
46
+ Requires-Dist: openai>=1.0.0; extra == "all"
47
+ Requires-Dist: deepeval>=1.0.0; extra == "all"
48
+ Requires-Dist: langgraph>=0.0.1; extra == "all"
49
+ Requires-Dist: llama-cpp-python>=0.2.0; extra == "all"
50
+ Requires-Dist: torch>=2.0.0; extra == "all"
51
+ Requires-Dist: transformers>=4.40.0; extra == "all"
52
+ Requires-Dist: pytest>=8.0.0; extra == "all"
53
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "all"
54
+ Dynamic: license-file
55
+
56
+ # LogitGate (`logitgate`)
57
+
58
+ [![PyPI version](https://img.shields.io/pypi/v/logitgate.svg?color=blue)](https://pypi.org/project/logitgate/)
59
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
60
+ [![Python 3.10–3.15](https://img.shields.io/badge/python-3.10--3.15-blue.svg)](https://www.python.org/downloads/)
61
+ [![PEP 561 Typed](https://img.shields.io/badge/typing-PEP%20561-blueviolet.svg)](src/logitgate/py.typed)
62
+ [![Typechecked: mypy](https://img.shields.io/badge/typechecked-mypy-blue.svg)](pyproject.toml)
63
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
64
+ [![GitLab CI](https://gitlab.com/jasonbdly/logitgate/badges/main/pipeline.svg)](https://gitlab.com/jasonbdly/logitgate/-/pipelines)
65
+
66
+ **Fast, calibrated first-token logit evaluation and 3-layer cascaded routing for LLMs.**
67
+
68
+ LogitGate replaces slow, multi-token LLM-as-a-judge critiques (5–20s) with calibrated first-token logit gates (**36–110 ms**) and a 3-layer cascaded routing pipeline (`ASTGate >> LogitGate >> JudgeGate`), saving 90%–98% of evaluation tokens and wall-clock time while canceling token prior and positional biases.
69
+
70
+ ---
71
+
72
+ ## How It Works in 60 Seconds
73
+
74
+ When evaluating whether an LLM output satisfies a rubric, traditional frameworks prompt a model to generate a 200–500 word critique before outputting `PASS` or `FAIL`. This takes **5 to 20 seconds**, consumes hundreds of tokens, and suffers from recency and positional biases.
75
+
76
+ `LogitGate` uses a **3-layer cascaded pipeline**:
77
+
78
+ ```
79
+ Candidate Artifact
80
+ │
81
+ ▼
82
+ ┌──────────────────────────────────────┐
83
+ │ Layer 0: ASTGate / ContractGate ├──► [FAIL: syntax/schema, <0.1ms]
84
+ └──────────────────┬───────────────────┘
85
+ │ Passed
86
+ ▼
87
+ ┌──────────────────────────────────────┐
88
+ │ Layer 1: LogitGate ├──► [PASS: P >= 0.85, ~40–110ms]
89
+ └──────────────────┬───────────────────┤
90
+ │ Ambiguous └──► [FAIL: P <= 0.20, ~40–110ms]
91
+ │ (0.20 < P < 0.85)
92
+ ▼
93
+ ┌──────────────────────────────────────┐
94
+ │ Layer 2: JudgeGate ├──► [Actionable Diagnostic Report]
95
+ └──────────────────────────────────────┘
96
+ ```
97
+
98
+ 1. **Layer 0 (`ASTGate` / `ContractGate`)**: Deterministic checks in **<0.1 ms** on CPU (Python AST syntax, JSON/Pydantic schemas, regex patterns, acyclic DAG topology). Failures reject immediately with zero LLM overhead.
99
+ 2. **Layer 1 (`LogitGate` / `ChoiceGate` / `ScoreGate`)**: Reads **first-token log-probabilities (`max_tokens=1`)** in **~36–41 ms on GPU** (~170 ms on CPU). To eliminate pretraining label bias, it averages forward and reverse passes in log-odds space ($\bar{L} = \frac{L_1 + L_2}{2T}$).
100
+ 3. **Layer 2 (`JudgeGate`)**: Only when Layer 1 confidence is genuinely ambiguous (between 20% and 85%) or requires failure diagnostics does the pipeline escalate to generating a full text critique.
101
+
102
+ ---
103
+
104
+ ## Installation
105
+
106
+ ```bash
107
+ # Core package (zero dependencies except pydantic & httpx)
108
+ pip install logitgate
109
+
110
+ # With optional framework integrations:
111
+ pip install "logitgate[openai]" # OpenAI, vLLM, and compatible endpoints
112
+ pip install "logitgate[llamacpp]" # In-process llama.cpp (zero background daemon)
113
+ pip install "logitgate[langgraph]" # LangGraph conditional edge routing
114
+ pip install "logitgate[deepeval]" # DeepEval System-1 metrics
115
+ pip install "logitgate[recurrent]" # Elastic recurrent looping (NVIDIA Dory-4B)
116
+ pip install "logitgate[all]" # All integrations
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 30-Second Quickstart
122
+
123
+ ### 1. Single Atomic Rubric (3-Layer Cascaded Fast Path)
124
+
125
+ ```python
126
+ from logitgate import ASTGate, LogitGate, JudgeGate
127
+
128
+ # Compose the 3-layer pipeline using the >> operator
129
+ cascade = (
130
+ # Layer 0: Ensure valid Python syntax without LLM calls (<0.1ms)
131
+ ASTGate(syntax=True)
132
+ # Layer 1: First-token debiased logit gate (~40-90ms, 0 CoT tokens)
133
+ >> LogitGate(
134
+ rubric="Does the function calculate Fibonacci numbers using recursion?",
135
+ pass_threshold=0.85,
136
+ fail_threshold=0.20,
137
+ )
138
+ # Layer 2: Escalated diagnostic judge (only fires if Layer 1 is ambiguous or failing)
139
+ >> JudgeGate(trigger="on_ambiguous_only")
140
+ )
141
+
142
+ candidate_code = """
143
+ def fibonacci(n: int) -> int:
144
+ if n <= 0:
145
+ return 0
146
+ elif n == 1:
147
+ return 1
148
+ return fibonacci(n - 1) + fibonacci(n - 2)
149
+ """
150
+
151
+ verdict = cascade.evaluate(candidate_code)
152
+
153
+ print(f"Passed: {verdict.passed}") # True
154
+ print(f"Confidence: {verdict.probability:.4f}") # e.g., 0.9982
155
+ print(f"Triggered Layer: {verdict.triggered_layer}") # LogitGate (bypassed Layer 2!)
156
+ print(f"Latency: {verdict.total_latency_ms:.1f}ms") # ~86ms
157
+ print(f"Tokens Generated: {verdict.total_tokens_generated}") # 0 tokens!
158
+ ```
159
+
160
+ ### 2. Multi-Rubric Batching (Prefix-Preserved KV-Cache Reuse)
161
+
162
+ When verifying multiple criteria against a candidate artifact, **do not combine them into a single monolithic compound rubric** (which dilutes logit signals and conflates orthogonal requirements). Instead, evaluate isolated atomic rubrics in a single batch using `evaluate_batch`.
163
+
164
+ The candidate code is anchored at Token 0, sharing 95–99% of prefix tokens in KV cache across all checks:
165
+
166
+ ```python
167
+ from logitgate import LogitGate
168
+
169
+ # Best Practice: Keep rubrics atomic — evaluate multiple criteria via evaluate_batch
170
+ rubrics = [
171
+ "Does the function calculate Fibonacci numbers recursively?",
172
+ "Does the function explicitly handle non-positive inputs (n <= 0)?",
173
+ "Does the function include parameter and return type annotations?",
174
+ ]
175
+
176
+ gate = LogitGate("Base rubric")
177
+
178
+ # Evaluates all 3 rubrics in a single batch reusing the shared KV-cache prefix
179
+ verdicts = gate.evaluate_batch(candidate_code, rubrics)
180
+
181
+ for rubric, v in zip(rubrics, verdicts):
182
+ status = "PASS" if v.passed else "FAIL"
183
+ print(f"[{status}] P={v.probability:.4f} | {rubric}")
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Core Gates Quick Reference
189
+
190
+ | Gate | Layer | Latency | Tokens Generated | Purpose & Behavior |
191
+ | :--- | :---: | :---: | :---: | :--- |
192
+ | **`ASTGate`** | Layer 0 | **< 0.1 ms** | 0 | Sub-millisecond deterministic checks: Python syntax, forbidden imports, regex, acyclic DAGs, custom callables. |
193
+ | **`ContractGate`** | Layer 0 | **< 0.1 ms** | 0 | General-domain contract validation: Pydantic models, JSON Schemas, length bounds, required sections. |
194
+ | **`LogitGate`** | Layer 1 | **~40–110 ms** | 0 | Calibrated binary classification from first-token logits using symmetric log-odds debiasing ($\bar{L} = \frac{L_1 + L_2}{2T}$). |
195
+ | **`ChoiceGate`** | Layer 1 | **~40–120 ms** | 0 | Discrete K-ary routing and intent classification across arbitrary string options with permutation averaging. |
196
+ | **`ScoreGate`** | Layer 1 | **~50–160 ms** | 0 | Continuous probability-weighted rubric scoring (𝔼[S] = Σ s · P(s)) with inverted scale debiasing. |
197
+ | **`JudgeGate`** | Layer 2 | **1.5–5.0 s** | 60–300 | Generative System-2 reasoning judge with reason-then-verdict parsing and self-healing 1-token logit probes. |
198
+ | **`Cascade`** | 0 $\to$ 2 | **~40–120 ms\*** | 0\* | Chained pipeline (`gate_a >> gate_b`). Fast passes short-circuit Layer 2 entirely. |
199
+
200
+ *\*Typical latency on non-ambiguous inputs.*
201
+
202
+ ---
203
+
204
+ ## Benchmark Highlights
205
+
206
+ Across a 24-item multi-domain suite (RAG groundedness, customer support policy, SQL safety, and Python security), `LogitGate` resolves **95.8%–100.0% of cases at Layers 0 and 1**, avoiding multi-token generation:
207
+
208
+ | Evaluation Approach | Typical Latency | Generated Tokens | Extra GPU VRAM | Bias Cancellation | Speedup |
209
+ | :--- | :---: | :---: | :---: | :---: | :---: |
210
+ | **Generative LLM Judge** *(G-Eval, MT-Bench)* | 1,500ms – 8,000ms | 100 – 600 CoT tokens | 0 GB (Shared) | ❌ None | 1.0x |
211
+ | **Fine-Tuned Judge Models** *(Prometheus 2, Selene)* | 800ms – 3,500ms | 80 – 300 CoT tokens | 14 GB – 48 GB (Dedicated) | ❌ Susceptible to bias | 2.5x |
212
+ | **`LogitGate` 3-Layer Cascade** | **36ms – 113ms** | **0 CoT tokens** | **0 GB (Reuses generator)** | **✅ Symmetric Log-Odds** | **10x – 17x** |
213
+
214
+ ### CPU-Only CI/CD Champion: `llama3.2:3b` in Q4_K_M
215
+ - **In-Process `llama.cpp`**: Cold-starts in **3.2 seconds** inside your Python process (zero external background daemon), allocating only **2.36 GB RAM**.
216
+ - **Performance**: Evaluates 2-pass symmetric debiased gating in **815 ms** on CPU with **$\rho = 0.8487$** continuous scoring correlation.
217
+ - **Thread Scaling Law**: CPU execution saturates at **2 threads** (112 ms forward pass) due to memory bandwidth limits.
218
+
219
+ ---
220
+
221
+ ## In-Depth Documentation Index
222
+
223
+ For complete research data, mathematical derivations, and production recipes, explore our modular documentation:
224
+
225
+ - 📊 **[Empirical Benchmarks & Falsification Studies](docs/benchmarks.md)**:
226
+ - 24-item multi-domain cascade efficiency & token savings
227
+ - Fair pure-CPU CI/CD runner benchmarks (10-item CI suite)
228
+ - Compact models on CPU (1B–3B vs 4B baseline)
229
+ - In-process `llama.cpp` vs Ollama daemon & thread scaling sweeps
230
+ - Hardened 32-item adversarial benchmark suite ($N=5$)
231
+ - Falsification boundaries: reasoning depth, context length (16k), and context window squeezing
232
+ - Elastic recurrent layer-looping (NVIDIA Dory-4B, RTX 5090 vs RTX 4070)
233
+ - 🏗️ **[3-Layer Architecture & Deployment Topologies](docs/architecture.md)**:
234
+ - Execution mechanics, lookahead policy, and monotonic failure preservation
235
+ - System requirements across 0-GPU, Consumer GPU, and Enterprise hardware
236
+ - 3 deployment topologies to prevent KV-cache eviction and thrashing
237
+ - 📐 **[Mathematical Foundations & Symmetric Debiasing](docs/math_and_debiasing.md)**:
238
+ - Analytical proof of prior token bias cancellation in log-odds space
239
+ - Probability averaging vs. log-odds space contrast
240
+ - Prefix-preserving attention inversion & missing-token bounded floor
241
+ - Temperature calibration ($T$) and Brier score minimization
242
+ - 💡 **[Production Use Cases & Best Practices](docs/use_cases.md)**:
243
+ - CI/CD final merge gates vs local inner loop
244
+ - Reproducing CI failures locally via `VerdictSnapshot` and `logitgate explain`
245
+ - RAG hallucination guardrails & LangGraph agent intent routing
246
+ - Candidate-prefix isolated batching (`evaluate_batch`) vs monolithic prompt anti-patterns
247
+ - 🔌 **[Framework Integrations](docs/integrations.md)**:
248
+ - Pytest `@check` test decorator
249
+ - DeepEval `LogitGateSystemOneModel` and `LogitGateMetric`
250
+ - LangGraph conditional edge routing (`as_conditional_edge`)
251
+
252
+ ---
253
+
254
+ ## Common Recipes
255
+
256
+ ### Multi-Rubric Batch Evaluation (`evaluate_batch`)
257
+ Evaluates multiple rubrics against a single candidate artifact while anchoring the candidate at Token 0 to share 95–99% of prefix tokens in KV-cache:
258
+
259
+ ```python
260
+ from logitgate import LogitGate
261
+
262
+ gate = LogitGate("Base rubric")
263
+
264
+ rubrics = [
265
+ "Does the code include full type annotations?",
266
+ "Does the code avoid mutable default arguments?",
267
+ "Does the code implement proper error handling?",
268
+ ]
269
+
270
+ candidate_code = "def fetch(url: str, timeout: int = 10) -> str: pass"
271
+ verdicts = gate.evaluate_batch(candidate_code, rubrics)
272
+
273
+ for rubric, v in zip(rubrics, verdicts):
274
+ print(f"[{'PASS' if v.passed else 'FAIL'}] P={v.probability:.2f} | {rubric}")
275
+ ```
276
+
277
+ ### Discrete Multi-Way Routing (`ChoiceGate`)
278
+ Routes requests across $K$ options in ~40–90 ms without generating JSON:
279
+
280
+ ```python
281
+ from logitgate import ChoiceGate
282
+
283
+ router = ChoiceGate(
284
+ question="Route this incoming user request to the appropriate specialist:",
285
+ options={
286
+ "A": "Database and SQL query optimizations",
287
+ "B": "Authentication and user permissions",
288
+ "C": "Billing, invoices, and payment processing",
289
+ },
290
+ )
291
+
292
+ verdict = router.evaluate("My credit card was charged twice for invoice #902.")
293
+ print(f"Selected route: {verdict.choice}") # 'C'
294
+ print(f"Probabilities: {verdict.choice_probabilities}")
295
+ ```
296
+
297
+ ### Continuous Rubric Scoring (`ScoreGate`)
298
+ Calculates a smooth expected score (𝔼[S] ∈ [1.0, 5.0]) using first-token softmax weights:
299
+
300
+ ```python
301
+ from logitgate import ScoreGate
302
+
303
+ scorer = ScoreGate(
304
+ rubric="Rate the architectural code quality from 1 (disastrous) to 5 (flawless):",
305
+ scale=(1, 5),
306
+ symmetric_debiasing=True, # Evaluates 1->5 and 5->1 to eliminate scale anchoring
307
+ )
308
+
309
+ verdict = scorer.evaluate("def add(a, b): return a + b")
310
+ print(f"Expected Score: {verdict.score:.2f} / 5.00")
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Command-Line Interface (CLI)
316
+
317
+ ```bash
318
+ # Evaluate candidate text directly
319
+ logitgate eval --rubric "Must not contain shell commands" --candidate "echo 'hello'"
320
+
321
+ # Evaluate candidate from a file with Layer 0 AST check and JSON output
322
+ logitgate eval --rubric "Must be valid Python" --file script.py --ast-syntax --json
323
+
324
+ # Pipe candidate directly via standard input
325
+ cat schema.json | logitgate eval --rubric "Must be valid JSON schema"
326
+
327
+ # Replay and explain a frozen failure snapshot from CI
328
+ logitgate explain .logitgate/failures/latest.json
329
+
330
+ # Auto-calibrate model temperature on micro-dataset
331
+ logitgate calibrate --backend "ollama://localhost:11434" --model "qwen2.5:14b"
332
+ ```
333
+
334
+ ---
335
+
336
+ ## BibTeX Citation
337
+
338
+ If you use LogitGate in your research or production systems, please cite it as follows:
339
+
340
+ ```bibtex
341
+ @software{logitgate2026,
342
+ author = {Jason Bradley},
343
+ title = {LogitGate: Calibrated First-Token Logit Evaluation and Cascaded Routing for LLMs},
344
+ year = {2026},
345
+ version = {0.2.2},
346
+ url = {https://github.com/jasonbdly/LogitGate},
347
+ license = {Apache-2.0}
348
+ }
349
+ ```
350
+
351
+ ---
352
+
353
+ ## Contributing & License
354
+
355
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for local development setup and testing procedures.
356
+
357
+ LogitGate is licensed under the [Apache License 2.0](LICENSE).
@@ -0,0 +1,302 @@
1
+ # LogitGate (`logitgate`)
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/logitgate.svg?color=blue)](https://pypi.org/project/logitgate/)
4
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
5
+ [![Python 3.10–3.15](https://img.shields.io/badge/python-3.10--3.15-blue.svg)](https://www.python.org/downloads/)
6
+ [![PEP 561 Typed](https://img.shields.io/badge/typing-PEP%20561-blueviolet.svg)](src/logitgate/py.typed)
7
+ [![Typechecked: mypy](https://img.shields.io/badge/typechecked-mypy-blue.svg)](pyproject.toml)
8
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
9
+ [![GitLab CI](https://gitlab.com/jasonbdly/logitgate/badges/main/pipeline.svg)](https://gitlab.com/jasonbdly/logitgate/-/pipelines)
10
+
11
+ **Fast, calibrated first-token logit evaluation and 3-layer cascaded routing for LLMs.**
12
+
13
+ LogitGate replaces slow, multi-token LLM-as-a-judge critiques (5–20s) with calibrated first-token logit gates (**36–110 ms**) and a 3-layer cascaded routing pipeline (`ASTGate >> LogitGate >> JudgeGate`), saving 90%–98% of evaluation tokens and wall-clock time while canceling token prior and positional biases.
14
+
15
+ ---
16
+
17
+ ## How It Works in 60 Seconds
18
+
19
+ When evaluating whether an LLM output satisfies a rubric, traditional frameworks prompt a model to generate a 200–500 word critique before outputting `PASS` or `FAIL`. This takes **5 to 20 seconds**, consumes hundreds of tokens, and suffers from recency and positional biases.
20
+
21
+ `LogitGate` uses a **3-layer cascaded pipeline**:
22
+
23
+ ```
24
+ Candidate Artifact
25
+ │
26
+ ▼
27
+ ┌──────────────────────────────────────┐
28
+ │ Layer 0: ASTGate / ContractGate ├──► [FAIL: syntax/schema, <0.1ms]
29
+ └──────────────────┬───────────────────┘
30
+ │ Passed
31
+ ▼
32
+ ┌──────────────────────────────────────┐
33
+ │ Layer 1: LogitGate ├──► [PASS: P >= 0.85, ~40–110ms]
34
+ └──────────────────┬───────────────────┤
35
+ │ Ambiguous └──► [FAIL: P <= 0.20, ~40–110ms]
36
+ │ (0.20 < P < 0.85)
37
+ ▼
38
+ ┌──────────────────────────────────────┐
39
+ │ Layer 2: JudgeGate ├──► [Actionable Diagnostic Report]
40
+ └──────────────────────────────────────┘
41
+ ```
42
+
43
+ 1. **Layer 0 (`ASTGate` / `ContractGate`)**: Deterministic checks in **<0.1 ms** on CPU (Python AST syntax, JSON/Pydantic schemas, regex patterns, acyclic DAG topology). Failures reject immediately with zero LLM overhead.
44
+ 2. **Layer 1 (`LogitGate` / `ChoiceGate` / `ScoreGate`)**: Reads **first-token log-probabilities (`max_tokens=1`)** in **~36–41 ms on GPU** (~170 ms on CPU). To eliminate pretraining label bias, it averages forward and reverse passes in log-odds space ($\bar{L} = \frac{L_1 + L_2}{2T}$).
45
+ 3. **Layer 2 (`JudgeGate`)**: Only when Layer 1 confidence is genuinely ambiguous (between 20% and 85%) or requires failure diagnostics does the pipeline escalate to generating a full text critique.
46
+
47
+ ---
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ # Core package (zero dependencies except pydantic & httpx)
53
+ pip install logitgate
54
+
55
+ # With optional framework integrations:
56
+ pip install "logitgate[openai]" # OpenAI, vLLM, and compatible endpoints
57
+ pip install "logitgate[llamacpp]" # In-process llama.cpp (zero background daemon)
58
+ pip install "logitgate[langgraph]" # LangGraph conditional edge routing
59
+ pip install "logitgate[deepeval]" # DeepEval System-1 metrics
60
+ pip install "logitgate[recurrent]" # Elastic recurrent looping (NVIDIA Dory-4B)
61
+ pip install "logitgate[all]" # All integrations
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 30-Second Quickstart
67
+
68
+ ### 1. Single Atomic Rubric (3-Layer Cascaded Fast Path)
69
+
70
+ ```python
71
+ from logitgate import ASTGate, LogitGate, JudgeGate
72
+
73
+ # Compose the 3-layer pipeline using the >> operator
74
+ cascade = (
75
+ # Layer 0: Ensure valid Python syntax without LLM calls (<0.1ms)
76
+ ASTGate(syntax=True)
77
+ # Layer 1: First-token debiased logit gate (~40-90ms, 0 CoT tokens)
78
+ >> LogitGate(
79
+ rubric="Does the function calculate Fibonacci numbers using recursion?",
80
+ pass_threshold=0.85,
81
+ fail_threshold=0.20,
82
+ )
83
+ # Layer 2: Escalated diagnostic judge (only fires if Layer 1 is ambiguous or failing)
84
+ >> JudgeGate(trigger="on_ambiguous_only")
85
+ )
86
+
87
+ candidate_code = """
88
+ def fibonacci(n: int) -> int:
89
+ if n <= 0:
90
+ return 0
91
+ elif n == 1:
92
+ return 1
93
+ return fibonacci(n - 1) + fibonacci(n - 2)
94
+ """
95
+
96
+ verdict = cascade.evaluate(candidate_code)
97
+
98
+ print(f"Passed: {verdict.passed}") # True
99
+ print(f"Confidence: {verdict.probability:.4f}") # e.g., 0.9982
100
+ print(f"Triggered Layer: {verdict.triggered_layer}") # LogitGate (bypassed Layer 2!)
101
+ print(f"Latency: {verdict.total_latency_ms:.1f}ms") # ~86ms
102
+ print(f"Tokens Generated: {verdict.total_tokens_generated}") # 0 tokens!
103
+ ```
104
+
105
+ ### 2. Multi-Rubric Batching (Prefix-Preserved KV-Cache Reuse)
106
+
107
+ When verifying multiple criteria against a candidate artifact, **do not combine them into a single monolithic compound rubric** (which dilutes logit signals and conflates orthogonal requirements). Instead, evaluate isolated atomic rubrics in a single batch using `evaluate_batch`.
108
+
109
+ The candidate code is anchored at Token 0, sharing 95–99% of prefix tokens in KV cache across all checks:
110
+
111
+ ```python
112
+ from logitgate import LogitGate
113
+
114
+ # Best Practice: Keep rubrics atomic — evaluate multiple criteria via evaluate_batch
115
+ rubrics = [
116
+ "Does the function calculate Fibonacci numbers recursively?",
117
+ "Does the function explicitly handle non-positive inputs (n <= 0)?",
118
+ "Does the function include parameter and return type annotations?",
119
+ ]
120
+
121
+ gate = LogitGate("Base rubric")
122
+
123
+ # Evaluates all 3 rubrics in a single batch reusing the shared KV-cache prefix
124
+ verdicts = gate.evaluate_batch(candidate_code, rubrics)
125
+
126
+ for rubric, v in zip(rubrics, verdicts):
127
+ status = "PASS" if v.passed else "FAIL"
128
+ print(f"[{status}] P={v.probability:.4f} | {rubric}")
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Core Gates Quick Reference
134
+
135
+ | Gate | Layer | Latency | Tokens Generated | Purpose & Behavior |
136
+ | :--- | :---: | :---: | :---: | :--- |
137
+ | **`ASTGate`** | Layer 0 | **< 0.1 ms** | 0 | Sub-millisecond deterministic checks: Python syntax, forbidden imports, regex, acyclic DAGs, custom callables. |
138
+ | **`ContractGate`** | Layer 0 | **< 0.1 ms** | 0 | General-domain contract validation: Pydantic models, JSON Schemas, length bounds, required sections. |
139
+ | **`LogitGate`** | Layer 1 | **~40–110 ms** | 0 | Calibrated binary classification from first-token logits using symmetric log-odds debiasing ($\bar{L} = \frac{L_1 + L_2}{2T}$). |
140
+ | **`ChoiceGate`** | Layer 1 | **~40–120 ms** | 0 | Discrete K-ary routing and intent classification across arbitrary string options with permutation averaging. |
141
+ | **`ScoreGate`** | Layer 1 | **~50–160 ms** | 0 | Continuous probability-weighted rubric scoring (𝔼[S] = Σ s · P(s)) with inverted scale debiasing. |
142
+ | **`JudgeGate`** | Layer 2 | **1.5–5.0 s** | 60–300 | Generative System-2 reasoning judge with reason-then-verdict parsing and self-healing 1-token logit probes. |
143
+ | **`Cascade`** | 0 $\to$ 2 | **~40–120 ms\*** | 0\* | Chained pipeline (`gate_a >> gate_b`). Fast passes short-circuit Layer 2 entirely. |
144
+
145
+ *\*Typical latency on non-ambiguous inputs.*
146
+
147
+ ---
148
+
149
+ ## Benchmark Highlights
150
+
151
+ Across a 24-item multi-domain suite (RAG groundedness, customer support policy, SQL safety, and Python security), `LogitGate` resolves **95.8%–100.0% of cases at Layers 0 and 1**, avoiding multi-token generation:
152
+
153
+ | Evaluation Approach | Typical Latency | Generated Tokens | Extra GPU VRAM | Bias Cancellation | Speedup |
154
+ | :--- | :---: | :---: | :---: | :---: | :---: |
155
+ | **Generative LLM Judge** *(G-Eval, MT-Bench)* | 1,500ms – 8,000ms | 100 – 600 CoT tokens | 0 GB (Shared) | ❌ None | 1.0x |
156
+ | **Fine-Tuned Judge Models** *(Prometheus 2, Selene)* | 800ms – 3,500ms | 80 – 300 CoT tokens | 14 GB – 48 GB (Dedicated) | ❌ Susceptible to bias | 2.5x |
157
+ | **`LogitGate` 3-Layer Cascade** | **36ms – 113ms** | **0 CoT tokens** | **0 GB (Reuses generator)** | **✅ Symmetric Log-Odds** | **10x – 17x** |
158
+
159
+ ### CPU-Only CI/CD Champion: `llama3.2:3b` in Q4_K_M
160
+ - **In-Process `llama.cpp`**: Cold-starts in **3.2 seconds** inside your Python process (zero external background daemon), allocating only **2.36 GB RAM**.
161
+ - **Performance**: Evaluates 2-pass symmetric debiased gating in **815 ms** on CPU with **$\rho = 0.8487$** continuous scoring correlation.
162
+ - **Thread Scaling Law**: CPU execution saturates at **2 threads** (112 ms forward pass) due to memory bandwidth limits.
163
+
164
+ ---
165
+
166
+ ## In-Depth Documentation Index
167
+
168
+ For complete research data, mathematical derivations, and production recipes, explore our modular documentation:
169
+
170
+ - 📊 **[Empirical Benchmarks & Falsification Studies](docs/benchmarks.md)**:
171
+ - 24-item multi-domain cascade efficiency & token savings
172
+ - Fair pure-CPU CI/CD runner benchmarks (10-item CI suite)
173
+ - Compact models on CPU (1B–3B vs 4B baseline)
174
+ - In-process `llama.cpp` vs Ollama daemon & thread scaling sweeps
175
+ - Hardened 32-item adversarial benchmark suite ($N=5$)
176
+ - Falsification boundaries: reasoning depth, context length (16k), and context window squeezing
177
+ - Elastic recurrent layer-looping (NVIDIA Dory-4B, RTX 5090 vs RTX 4070)
178
+ - 🏗️ **[3-Layer Architecture & Deployment Topologies](docs/architecture.md)**:
179
+ - Execution mechanics, lookahead policy, and monotonic failure preservation
180
+ - System requirements across 0-GPU, Consumer GPU, and Enterprise hardware
181
+ - 3 deployment topologies to prevent KV-cache eviction and thrashing
182
+ - 📐 **[Mathematical Foundations & Symmetric Debiasing](docs/math_and_debiasing.md)**:
183
+ - Analytical proof of prior token bias cancellation in log-odds space
184
+ - Probability averaging vs. log-odds space contrast
185
+ - Prefix-preserving attention inversion & missing-token bounded floor
186
+ - Temperature calibration ($T$) and Brier score minimization
187
+ - 💡 **[Production Use Cases & Best Practices](docs/use_cases.md)**:
188
+ - CI/CD final merge gates vs local inner loop
189
+ - Reproducing CI failures locally via `VerdictSnapshot` and `logitgate explain`
190
+ - RAG hallucination guardrails & LangGraph agent intent routing
191
+ - Candidate-prefix isolated batching (`evaluate_batch`) vs monolithic prompt anti-patterns
192
+ - 🔌 **[Framework Integrations](docs/integrations.md)**:
193
+ - Pytest `@check` test decorator
194
+ - DeepEval `LogitGateSystemOneModel` and `LogitGateMetric`
195
+ - LangGraph conditional edge routing (`as_conditional_edge`)
196
+
197
+ ---
198
+
199
+ ## Common Recipes
200
+
201
+ ### Multi-Rubric Batch Evaluation (`evaluate_batch`)
202
+ Evaluates multiple rubrics against a single candidate artifact while anchoring the candidate at Token 0 to share 95–99% of prefix tokens in KV-cache:
203
+
204
+ ```python
205
+ from logitgate import LogitGate
206
+
207
+ gate = LogitGate("Base rubric")
208
+
209
+ rubrics = [
210
+ "Does the code include full type annotations?",
211
+ "Does the code avoid mutable default arguments?",
212
+ "Does the code implement proper error handling?",
213
+ ]
214
+
215
+ candidate_code = "def fetch(url: str, timeout: int = 10) -> str: pass"
216
+ verdicts = gate.evaluate_batch(candidate_code, rubrics)
217
+
218
+ for rubric, v in zip(rubrics, verdicts):
219
+ print(f"[{'PASS' if v.passed else 'FAIL'}] P={v.probability:.2f} | {rubric}")
220
+ ```
221
+
222
+ ### Discrete Multi-Way Routing (`ChoiceGate`)
223
+ Routes requests across $K$ options in ~40–90 ms without generating JSON:
224
+
225
+ ```python
226
+ from logitgate import ChoiceGate
227
+
228
+ router = ChoiceGate(
229
+ question="Route this incoming user request to the appropriate specialist:",
230
+ options={
231
+ "A": "Database and SQL query optimizations",
232
+ "B": "Authentication and user permissions",
233
+ "C": "Billing, invoices, and payment processing",
234
+ },
235
+ )
236
+
237
+ verdict = router.evaluate("My credit card was charged twice for invoice #902.")
238
+ print(f"Selected route: {verdict.choice}") # 'C'
239
+ print(f"Probabilities: {verdict.choice_probabilities}")
240
+ ```
241
+
242
+ ### Continuous Rubric Scoring (`ScoreGate`)
243
+ Calculates a smooth expected score (𝔼[S] ∈ [1.0, 5.0]) using first-token softmax weights:
244
+
245
+ ```python
246
+ from logitgate import ScoreGate
247
+
248
+ scorer = ScoreGate(
249
+ rubric="Rate the architectural code quality from 1 (disastrous) to 5 (flawless):",
250
+ scale=(1, 5),
251
+ symmetric_debiasing=True, # Evaluates 1->5 and 5->1 to eliminate scale anchoring
252
+ )
253
+
254
+ verdict = scorer.evaluate("def add(a, b): return a + b")
255
+ print(f"Expected Score: {verdict.score:.2f} / 5.00")
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Command-Line Interface (CLI)
261
+
262
+ ```bash
263
+ # Evaluate candidate text directly
264
+ logitgate eval --rubric "Must not contain shell commands" --candidate "echo 'hello'"
265
+
266
+ # Evaluate candidate from a file with Layer 0 AST check and JSON output
267
+ logitgate eval --rubric "Must be valid Python" --file script.py --ast-syntax --json
268
+
269
+ # Pipe candidate directly via standard input
270
+ cat schema.json | logitgate eval --rubric "Must be valid JSON schema"
271
+
272
+ # Replay and explain a frozen failure snapshot from CI
273
+ logitgate explain .logitgate/failures/latest.json
274
+
275
+ # Auto-calibrate model temperature on micro-dataset
276
+ logitgate calibrate --backend "ollama://localhost:11434" --model "qwen2.5:14b"
277
+ ```
278
+
279
+ ---
280
+
281
+ ## BibTeX Citation
282
+
283
+ If you use LogitGate in your research or production systems, please cite it as follows:
284
+
285
+ ```bibtex
286
+ @software{logitgate2026,
287
+ author = {Jason Bradley},
288
+ title = {LogitGate: Calibrated First-Token Logit Evaluation and Cascaded Routing for LLMs},
289
+ year = {2026},
290
+ version = {0.2.2},
291
+ url = {https://github.com/jasonbdly/LogitGate},
292
+ license = {Apache-2.0}
293
+ }
294
+ ```
295
+
296
+ ---
297
+
298
+ ## Contributing & License
299
+
300
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for local development setup and testing procedures.
301
+
302
+ LogitGate is licensed under the [Apache License 2.0](LICENSE).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "logitgate"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Fast, calibrated first-token logit evaluation and 3-layer cascaded routing for LLMs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"