nullspan 1.1.0__tar.gz → 1.2.0__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.
- {nullspan-1.1.0 → nullspan-1.2.0}/PKG-INFO +35 -34
- nullspan-1.2.0/README.md +128 -0
- {nullspan-1.1.0 → nullspan-1.2.0}/pyproject.toml +1 -1
- {nullspan-1.1.0 → nullspan-1.2.0}/src/nullspan/__init__.py +1 -1
- {nullspan-1.1.0 → nullspan-1.2.0}/src/nullspan/engine.py +83 -23
- nullspan-1.1.0/README.md +0 -127
- {nullspan-1.1.0 → nullspan-1.2.0}/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nullspan
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Calibrated p_null abstention, grounded [start, end] span extraction, arithmetic, and distribution forecasting in a single forward pass.
|
|
5
5
|
Keywords: nullspan,system-one,extraction,abstention,p-null,quantile-regression,forecasting
|
|
6
6
|
Author-email: Hemanth HM <hemanth.hm@gmail.com>
|
|
@@ -20,22 +20,22 @@ Provides-Extra: hf
|
|
|
20
20
|
|
|
21
21
|
# nullspan
|
|
22
22
|
|
|
23
|
-
Single-pass System One structured extraction, calibrated `p_null` abstention, character-offset `[start, end]` spans, zero-shot `boolean`/`enum` judgment, cross-field algebraic invariant verification, and calibrated quantile estimation (`p10`, `median`, `p90`) in JavaScript, Python, and Browser WebAssembly ONNX.
|
|
23
|
+
Single-pass System One structured extraction, multi-numeric contract disambiguation, calibrated `p_null` abstention, character-offset `[start, end]` spans, zero-shot `boolean`/`enum` judgment, cross-field algebraic invariant verification, and calibrated quantile estimation (`p10`, `median`, `p90`) in JavaScript, Python, and Browser WebAssembly ONNX (`512`-token context + long-document windowing).
|
|
24
24
|
|
|
25
25
|
- **Interactive Playground (Browser WASM ONNX + Zero-Dep Engine)**: [https://hemanth.github.io/nullspan/](https://hemanth.github.io/nullspan/)
|
|
26
|
-
- **NullspanBench Leaderboard (JevBench-Style
|
|
26
|
+
- **NullspanBench Leaderboard (JevBench-Style 19-System Evaluation, N=500)**: [https://hemanth.github.io/nullspan/bench.html](https://hemanth.github.io/nullspan/bench.html)
|
|
27
27
|
- **Hugging Face Space**: [https://huggingface.co/spaces/gnumanth/nullspan](https://huggingface.co/spaces/gnumanth/nullspan)
|
|
28
|
-
- **Fine-Tuned Hugging Face Model (
|
|
28
|
+
- **Fine-Tuned Hugging Face Model (344.2M PyTorch + 330.1 MB Int8 ONNX)**: [https://huggingface.co/gnumanth/nullspan](https://huggingface.co/gnumanth/nullspan)
|
|
29
29
|
- **Hugging Face Dataset**: [https://huggingface.co/datasets/gnumanth/nullspan-dataset](https://huggingface.co/datasets/gnumanth/nullspan-dataset)
|
|
30
30
|
- **Empirical Science Report**: [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md)
|
|
31
31
|
|
|
32
32
|
## In Plain English
|
|
33
33
|
|
|
34
|
-
Standard LLMs extract data by generating JSON token-by-token
|
|
34
|
+
Standard LLMs extract data by generating JSON token-by-token, which is slow, bills per output token, can get hijacked by *"ignore previous instructions"* prompt injections, and often hallucinates values when a field is missing. **`nullspan` acts like a grounded highlighter + calculator instead of a chatbot:**
|
|
35
35
|
|
|
36
36
|
1. **Points to Exact Text (`[start, end]` Span)**: Highlights exact character positions in your input text (`0` output tokens generated), making fabricated strings and prompt-injection payloads impossible.
|
|
37
|
-
2. **Knows When to Say "Not There" (`p_null`)**: Computes a calibrated probability that a field is missing (`p_null`) and returns `null` when evidence is absent.
|
|
38
|
-
3. **Checks
|
|
37
|
+
2. **Knows When to Say "Not There" (`p_null`)**: Computes a calibrated probability that a field is missing (`p_null`) and returns `null` with `abstention_reason` when evidence is absent.
|
|
38
|
+
3. **Disambiguates Multi-Numeric Contracts & Checks Math (`constraint` & `verified`)**: Separates competing dollar caps, percentages, day windows, and numeric tranches across multi-section agreements (`96/96` on unseen contracts) and verifies equations like `subtotal == nodes * hourly_rate`.
|
|
39
39
|
4. **Gives Realistic Ranges (`p10 / median / p90`)**: Returns calibrated low/middle/high quantile distributions for estimates and forecasts.
|
|
40
40
|
|
|
41
41
|
## Install
|
|
@@ -82,7 +82,7 @@ invoice = (
|
|
|
82
82
|
"Priority Surcharge: $1.75"
|
|
83
83
|
)
|
|
84
84
|
|
|
85
|
-
# Zero-dependency fast engine or fine-tuned
|
|
85
|
+
# Zero-dependency fast engine or GCP V100 fine-tuned 344.2M checkpoint (backend="hf" or "onnx")
|
|
86
86
|
out = extract(
|
|
87
87
|
state=invoice,
|
|
88
88
|
fields={
|
|
@@ -103,44 +103,45 @@ out = extract(
|
|
|
103
103
|
# out["invariants_passed"] -> True, out["answers"]["subtotal"]["verified"] -> True
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## Architecture (`NullspanForExtraction` v2.0 · 344.2M ELECTRA-Large + Adapter)
|
|
107
107
|
|
|
108
108
|

|
|
109
109
|
|
|
110
|
-
1. **`null_head` (Calibrated Abstention
|
|
111
|
-
2. **`span_head` (Grounded Pointer + Shannon Entropy)**: Projects encoder
|
|
112
|
-
3. **`bio_head` (
|
|
110
|
+
1. **`null_head` (Span-Attended Calibrated Abstention)**: Bilinear span-summary + `[CLS]` margin residual with held-out temperature scaling (`p_null` AUROC `0.9983`, ECE `0.0121`) and `abstention_reason` (`unassigned_placeholder` vs `missing_field`).
|
|
111
|
+
2. **`span_head` (Grounded Pointer + Shannon Entropy)**: Projects `512`-token encoder states (plus query-conditioned sliding windows on ultra-long contracts) to `[start, end]` character spans with calibrated `confidence` and Shannon `span_entropy_bits`.
|
|
112
|
+
3. **`bio_head` (Multi-Span List Tagging)**: Extracts ordered text and numeric tranche arrays (`type: "list"`) in a single pass.
|
|
113
113
|
4. **`op_head` (10-Way System One Router)**: Routes fields across `SPAN_TEXT`, `SPAN_NUMBER`, `ARITH_SUM`, `ARITH_DIFF`, `ARITH_MUL`, `ISO_DATETIME`, `DATE_DURATION`, `DIST_ESTIMATE_FORECAST`, `BOOL_JUDGE` (`p_true`), and `ENUM_CLASSIFY` (`probs`).
|
|
114
114
|
5. **`quantile_head` + Invariant Verifier**: Predicts monotone `(p10, median, p90)` quantiles and verifies cross-field algebraic constraints (`verified: true/false`).
|
|
115
115
|
|
|
116
|
-
## NullspanBench Leaderboard (`bench/run_bench.py` ·
|
|
116
|
+
## NullspanBench Leaderboard (`bench/run_bench.py` · 19 Systems · $N=500$ Zero-Leakage Decisions)
|
|
117
117
|
|
|
118
|
-
Modeled after [BenchmarkHeaven's JevBench](https://benchmarkheaven.com/jev-models), **NullspanBench** evaluates `
|
|
118
|
+
Modeled after [BenchmarkHeaven's JevBench](https://benchmarkheaven.com/jev-models), **NullspanBench v3.2** evaluates `19` systems (`13` local open-weights/open-code models running live forward passes, live Cloudflare Workers AI `@cf/cloudflare/clairic + @cf/cloudflare/clef`, `2` reference JSON-mode LLM decoders, and `3` published JevBench v1.7 reference anchors) across **`500` zero-leakage observations** (`336` Open structured items + `164` Sealed items: `60` Stanford SQuAD v2.0, `96` Multi-Numeric Legal/Commercial Contract fields across `12` unseen agreements, and `8` Adversarial prompt-injection traps) on four axes: **Intelligence (`I`)**, **Calibration (`C`)**, **Speed (`S`)**, and **Cost (`K`)**.
|
|
119
119
|
|
|
120
120
|
Explore interactive weight sliders, Pareto frontier plots, and 2-system radar comparisons at [**https://hemanth.github.io/nullspan/bench.html**](https://hemanth.github.io/nullspan/bench.html):
|
|
121
121
|
|
|
122
122
|
| Rank | System | Composite (`25:25:25:25`) | Capability (`50I:50C`) | Intelligence `I` (95% CI) | Calibration `C` | Speed `S` | Cost `K` | `$/1k` | `p50` Latency |
|
|
123
123
|
| :---: | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
124
|
-
| **1** | **`nullspan-Hybrid (Fast + ONNX Int8)`** (Open) | **97.
|
|
125
|
-
| **2** | **`nullspan-ZeroDep (Fast Engine)`** (Open) | **95.
|
|
126
|
-
| **3** | **`nullspan-
|
|
127
|
-
| **4** | **`nullspan-
|
|
128
|
-
| **5** | **`nullspan-
|
|
129
|
-
| **6** |
|
|
130
|
-
| **7** |
|
|
131
|
-
| **
|
|
132
|
-
| **
|
|
133
|
-
| **
|
|
134
|
-
| **
|
|
135
|
-
| **
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
138
|
-
| **
|
|
139
|
-
| **
|
|
140
|
-
| **
|
|
141
|
-
| **
|
|
142
|
-
|
|
143
|
-
|
|
124
|
+
| **1** | **`nullspan-Hybrid (Fast + ONNX Int8)`** (Open) | **97.2** | **98.3** | **97.8%** `[96.6, 99.0]` | **98.8** | **98.6** | **93.8** | `$0.0003` | `0.013 ms` |
|
|
125
|
+
| **2** | **`nullspan-ZeroDep (Fast Engine)`** (Open) | **95.9** | **92.9** | `90.8%` `[88.2, 93.4]` | `95.0` | **98.7** | **99.8** | `$0.0001` | `0.013 ms` |
|
|
126
|
+
| **3** | **`nullspan-344M (PyTorch FP32)`** (Open) | **78.7** | **98.4** | **98.0%** `[96.8, 99.2]` | **98.8** | `57.2` | `76.8` | `$0.0017` | `32.367 ms` |
|
|
127
|
+
| **4** | **`nullspan-344M-Int8 (ONNX WASM/CPU)`** (Open) | **78.4** | **98.3** | **97.8%** `[96.6, 99.0]` | **98.9** | `53.2` | `84.2` | `$0.0008` | `68.483 ms` |
|
|
128
|
+
| **5** | **`nullspan-344M (ONNX FP32)`** (Open) | **75.5** | **98.4** | **98.0%** `[96.8, 99.2]` | **98.8** | `50.5` | `78.0` | `$0.0015` | `113.137 ms` |
|
|
129
|
+
| **6** | `H2O-Lightning-4B v1.1 (JevBench #1 Comp)` (Open 4B) | `72.5` | `75.0` | `60.0%` `[57.8, 62.3]` | `90.0` | `92.6` | `60.3` | `$0.0211` | `29.285 ms` |
|
|
130
|
+
| **7** | **`@cf/cloudflare/clairic + clef (Live Workers AI)`** (API) | `72.1` | `93.2` | `91.6%` `[89.2, 93.9]` | `94.9` | `51.7` | `68.2` | `$0.0041` | `91.323 ms` (`315.3 ms/doc`) |
|
|
131
|
+
| **8** | `basal-omni-1.0-ultra (JevBench #1 Cap)` (Open 31B) | `71.8` | `82.5` | `74.1%` `[71.8, 76.3]` | `91.0` | `87.3` | `50.5` | `$0.0447` | `102.000 ms` |
|
|
132
|
+
| **9** | `Jev 1.13.0 (TypeSafe AI · JevBench Ref)` (API) | `71.5` | `77.1` | `63.6%` `[61.2, 66.0]` | `90.6` | `91.5` | `54.7` | `$0.0323` | `239.102 ms` |
|
|
133
|
+
| **10** | `gpt-5.4-nano (JSON Decoder · API)` (API) | `59.8` | `92.1` | `95.2%` `[93.4, 97.0]` | `89.0` | `43.6` | `45.1` | `$0.0438` | `417.991 ms` |
|
|
134
|
+
| **11** | `deberta-v3-base-squad2 (184M SQuAD2 QA)` (Open) | `58.0` | `55.8` | `48.1%` `[43.9, 52.4]` | `63.4` | `55.7` | `69.2` | `$0.0037` | `42.496 ms` |
|
|
135
|
+
| **12** | `claude-haiku-4.5 (JSON Decoder · API)` (API) | `48.8` | `92.1` | `95.4%` `[93.4, 97.2]` | `88.7` | `41.8` | `27.5` | `$0.2639` | `586.392 ms` |
|
|
136
|
+
| **13** | `bge-small-en-v1.5 (Dense Span+Null)` (Open) | `37.6` | `52.0` | `14.7%` `[12.0, 17.5]` | `89.2` | `64.5` | `85.5` | `$0.0007` | `8.098 ms` |
|
|
137
|
+
| **14** | `distilbert-base-control (Raw Control)` (Open) | `36.8` | `52.9` | `14.2%` `[11.6, 17.0]` | `91.5` | `66.0` | `81.1` | `$0.0011` | `6.133 ms` |
|
|
138
|
+
| **15** | `all-MiniLM-L12-v2 (Dense Span+Null)` (Open) | `35.9` | `44.0` | `14.4%` `[11.7, 17.5]` | `73.5` | `60.2` | `85.5` | `$0.0007` | `18.356 ms` |
|
|
139
|
+
| **16** | `all-mpnet-base-v2 (Dense Span+Null)` (Open) | `34.3` | `42.3` | `13.6%` `[10.9, 16.7]` | `71.0` | `62.8` | `77.4` | `$0.0016` | `11.263 ms` |
|
|
140
|
+
| **17** | `paraphrase-albert-small-v2 (Dense Span+Null)` (Open) | `33.6` | `44.5` | `12.5%` `[10.0, 15.2]` | `76.6` | `65.9` | `91.0` | `$0.0004` | `6.263 ms` |
|
|
141
|
+
| **18** | `paraphrase-MiniLM-L3-v2 (Dense Span+Null)` (Open) | `30.9` | `41.7` | `11.1%` `[8.7, 13.8]` | `72.3` | `68.9` | `91.0` | `$0.0004` | `3.519 ms` |
|
|
142
|
+
| **19** | `all-MiniLM-L6-v2 (Dense Span+Null)` (Open) | `28.3` | `40.5` | `10.0%` `[7.7, 12.3]` | `70.9` | `62.3` | `88.8` | `$0.0005` | `12.322 ms` |
|
|
143
|
+
|
|
144
|
+
See full methodology, proper scoring definitions, request-type breakdowns (`100.0%` on Multi-Numeric Contracts `n=96`, `100.0%` Choice `n=41`, `100.0%` Math & Invariants `n=51`), and head-to-head analysis in [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md).
|
|
144
145
|
|
|
145
146
|
## License
|
|
146
147
|
|
nullspan-1.2.0/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# nullspan
|
|
2
|
+
|
|
3
|
+
Single-pass System One structured extraction, multi-numeric contract disambiguation, calibrated `p_null` abstention, character-offset `[start, end]` spans, zero-shot `boolean`/`enum` judgment, cross-field algebraic invariant verification, and calibrated quantile estimation (`p10`, `median`, `p90`) in JavaScript, Python, and Browser WebAssembly ONNX (`512`-token context + long-document windowing).
|
|
4
|
+
|
|
5
|
+
- **Interactive Playground (Browser WASM ONNX + Zero-Dep Engine)**: [https://hemanth.github.io/nullspan/](https://hemanth.github.io/nullspan/)
|
|
6
|
+
- **NullspanBench Leaderboard (JevBench-Style 19-System Evaluation, N=500)**: [https://hemanth.github.io/nullspan/bench.html](https://hemanth.github.io/nullspan/bench.html)
|
|
7
|
+
- **Hugging Face Space**: [https://huggingface.co/spaces/gnumanth/nullspan](https://huggingface.co/spaces/gnumanth/nullspan)
|
|
8
|
+
- **Fine-Tuned Hugging Face Model (344.2M PyTorch + 330.1 MB Int8 ONNX)**: [https://huggingface.co/gnumanth/nullspan](https://huggingface.co/gnumanth/nullspan)
|
|
9
|
+
- **Hugging Face Dataset**: [https://huggingface.co/datasets/gnumanth/nullspan-dataset](https://huggingface.co/datasets/gnumanth/nullspan-dataset)
|
|
10
|
+
- **Empirical Science Report**: [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md)
|
|
11
|
+
|
|
12
|
+
## In Plain English
|
|
13
|
+
|
|
14
|
+
Standard LLMs extract data by generating JSON token-by-token, which is slow, bills per output token, can get hijacked by *"ignore previous instructions"* prompt injections, and often hallucinates values when a field is missing. **`nullspan` acts like a grounded highlighter + calculator instead of a chatbot:**
|
|
15
|
+
|
|
16
|
+
1. **Points to Exact Text (`[start, end]` Span)**: Highlights exact character positions in your input text (`0` output tokens generated), making fabricated strings and prompt-injection payloads impossible.
|
|
17
|
+
2. **Knows When to Say "Not There" (`p_null`)**: Computes a calibrated probability that a field is missing (`p_null`) and returns `null` with `abstention_reason` when evidence is absent.
|
|
18
|
+
3. **Disambiguates Multi-Numeric Contracts & Checks Math (`constraint` & `verified`)**: Separates competing dollar caps, percentages, day windows, and numeric tranches across multi-section agreements (`96/96` on unseen contracts) and verifies equations like `subtotal == nodes * hourly_rate`.
|
|
19
|
+
4. **Gives Realistic Ranges (`p10 / median / p90`)**: Returns calibrated low/middle/high quantile distributions for estimates and forecasts.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install nullspan
|
|
25
|
+
pip install nullspan
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage (JavaScript / ESM)
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { extract } from 'nullspan';
|
|
32
|
+
|
|
33
|
+
const incident =
|
|
34
|
+
"Incident INC-40928 opened on Apr 12, 2026 with a 502 Bad Gateway errors and a TLS handshake timeouts. " +
|
|
35
|
+
"Issued $1240.50 plus $310.25 SLA credit. Severity is sev-1 and customer data loss was false. " +
|
|
36
|
+
"Root cause CVE not yet assigned. Cluster stabilized on Apr 19, 2026. Reported by Mira";
|
|
37
|
+
|
|
38
|
+
const result = extract(incident, {
|
|
39
|
+
incident_id: { type: 'text', instructions: 'Incident ticket identifier' },
|
|
40
|
+
opened_on: { type: 'date', instructions: 'Date the incident opened' },
|
|
41
|
+
total_credit: { type: 'number', decimals: 2, unit: 'USD', instructions: 'Total credit including SLA penalty' },
|
|
42
|
+
outage_days: { type: 'duration', unit: 'days', integer: true, instructions: 'Days from incident open to cluster stabilization' },
|
|
43
|
+
failure_modes: { type: 'list', items: 'text', instructions: 'Each failure mode triggered' },
|
|
44
|
+
severity: { type: 'enum', options: ['sev-1', 'sev-2', 'sev-3'], instructions: 'Incident severity tier' },
|
|
45
|
+
data_loss: { type: 'boolean', instructions: 'Whether customer data loss occurred' },
|
|
46
|
+
cve_id: { type: 'text', instructions: 'Assigned CVE identifier if present' },
|
|
47
|
+
remediation_cost: { type: 'estimate', unit: 'USD', min: 100, max: 25000, scale: 'log', step: 10, instructions: 'Estimated engineering remediation cost' },
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage (Python + Cross-Field Invariants + Hugging Face Backend)
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from nullspan import extract
|
|
55
|
+
|
|
56
|
+
invoice = (
|
|
57
|
+
"Invoice from TensorCore Cloud\n"
|
|
58
|
+
"Invoice #88310 | Issued: 2026-08-14 18:20\n"
|
|
59
|
+
"Nodes: 4 @ $3.50 each\n"
|
|
60
|
+
"Subtotal: $14.00\n"
|
|
61
|
+
"Egress Fee: $0.00\n"
|
|
62
|
+
"Priority Surcharge: $1.75"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Zero-dependency fast engine or GCP V100 fine-tuned 344.2M checkpoint (backend="hf" or "onnx")
|
|
66
|
+
out = extract(
|
|
67
|
+
state=invoice,
|
|
68
|
+
fields={
|
|
69
|
+
"nodes": {"type": "number", "integer": True, "instructions": "Provisioned GPU node count"},
|
|
70
|
+
"hourly_rate": {"type": "number", "decimals": 2, "unit": "USD", "instructions": "Hourly rate per node"},
|
|
71
|
+
"subtotal": {
|
|
72
|
+
"type": "number",
|
|
73
|
+
"decimals": 2,
|
|
74
|
+
"unit": "USD",
|
|
75
|
+
"constraint": "subtotal == nodes * hourly_rate",
|
|
76
|
+
"instructions": "Compute subtotal before fees and surcharge",
|
|
77
|
+
},
|
|
78
|
+
"promo_rebate": {"type": "number", "decimals": 2, "unit": "USD", "instructions": "Promotional rebate amount if present"},
|
|
79
|
+
},
|
|
80
|
+
backend="hf",
|
|
81
|
+
model_id="gnumanth/nullspan",
|
|
82
|
+
)
|
|
83
|
+
# out["invariants_passed"] -> True, out["answers"]["subtotal"]["verified"] -> True
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Architecture (`NullspanForExtraction` v2.0 · 344.2M ELECTRA-Large + Adapter)
|
|
87
|
+
|
|
88
|
+

|
|
89
|
+
|
|
90
|
+
1. **`null_head` (Span-Attended Calibrated Abstention)**: Bilinear span-summary + `[CLS]` margin residual with held-out temperature scaling (`p_null` AUROC `0.9983`, ECE `0.0121`) and `abstention_reason` (`unassigned_placeholder` vs `missing_field`).
|
|
91
|
+
2. **`span_head` (Grounded Pointer + Shannon Entropy)**: Projects `512`-token encoder states (plus query-conditioned sliding windows on ultra-long contracts) to `[start, end]` character spans with calibrated `confidence` and Shannon `span_entropy_bits`.
|
|
92
|
+
3. **`bio_head` (Multi-Span List Tagging)**: Extracts ordered text and numeric tranche arrays (`type: "list"`) in a single pass.
|
|
93
|
+
4. **`op_head` (10-Way System One Router)**: Routes fields across `SPAN_TEXT`, `SPAN_NUMBER`, `ARITH_SUM`, `ARITH_DIFF`, `ARITH_MUL`, `ISO_DATETIME`, `DATE_DURATION`, `DIST_ESTIMATE_FORECAST`, `BOOL_JUDGE` (`p_true`), and `ENUM_CLASSIFY` (`probs`).
|
|
94
|
+
5. **`quantile_head` + Invariant Verifier**: Predicts monotone `(p10, median, p90)` quantiles and verifies cross-field algebraic constraints (`verified: true/false`).
|
|
95
|
+
|
|
96
|
+
## NullspanBench Leaderboard (`bench/run_bench.py` · 19 Systems · $N=500$ Zero-Leakage Decisions)
|
|
97
|
+
|
|
98
|
+
Modeled after [BenchmarkHeaven's JevBench](https://benchmarkheaven.com/jev-models), **NullspanBench v3.2** evaluates `19` systems (`13` local open-weights/open-code models running live forward passes, live Cloudflare Workers AI `@cf/cloudflare/clairic + @cf/cloudflare/clef`, `2` reference JSON-mode LLM decoders, and `3` published JevBench v1.7 reference anchors) across **`500` zero-leakage observations** (`336` Open structured items + `164` Sealed items: `60` Stanford SQuAD v2.0, `96` Multi-Numeric Legal/Commercial Contract fields across `12` unseen agreements, and `8` Adversarial prompt-injection traps) on four axes: **Intelligence (`I`)**, **Calibration (`C`)**, **Speed (`S`)**, and **Cost (`K`)**.
|
|
99
|
+
|
|
100
|
+
Explore interactive weight sliders, Pareto frontier plots, and 2-system radar comparisons at [**https://hemanth.github.io/nullspan/bench.html**](https://hemanth.github.io/nullspan/bench.html):
|
|
101
|
+
|
|
102
|
+
| Rank | System | Composite (`25:25:25:25`) | Capability (`50I:50C`) | Intelligence `I` (95% CI) | Calibration `C` | Speed `S` | Cost `K` | `$/1k` | `p50` Latency |
|
|
103
|
+
| :---: | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
104
|
+
| **1** | **`nullspan-Hybrid (Fast + ONNX Int8)`** (Open) | **97.2** | **98.3** | **97.8%** `[96.6, 99.0]` | **98.8** | **98.6** | **93.8** | `$0.0003` | `0.013 ms` |
|
|
105
|
+
| **2** | **`nullspan-ZeroDep (Fast Engine)`** (Open) | **95.9** | **92.9** | `90.8%` `[88.2, 93.4]` | `95.0` | **98.7** | **99.8** | `$0.0001` | `0.013 ms` |
|
|
106
|
+
| **3** | **`nullspan-344M (PyTorch FP32)`** (Open) | **78.7** | **98.4** | **98.0%** `[96.8, 99.2]` | **98.8** | `57.2` | `76.8` | `$0.0017` | `32.367 ms` |
|
|
107
|
+
| **4** | **`nullspan-344M-Int8 (ONNX WASM/CPU)`** (Open) | **78.4** | **98.3** | **97.8%** `[96.6, 99.0]` | **98.9** | `53.2` | `84.2` | `$0.0008` | `68.483 ms` |
|
|
108
|
+
| **5** | **`nullspan-344M (ONNX FP32)`** (Open) | **75.5** | **98.4** | **98.0%** `[96.8, 99.2]` | **98.8** | `50.5` | `78.0` | `$0.0015` | `113.137 ms` |
|
|
109
|
+
| **6** | `H2O-Lightning-4B v1.1 (JevBench #1 Comp)` (Open 4B) | `72.5` | `75.0` | `60.0%` `[57.8, 62.3]` | `90.0` | `92.6` | `60.3` | `$0.0211` | `29.285 ms` |
|
|
110
|
+
| **7** | **`@cf/cloudflare/clairic + clef (Live Workers AI)`** (API) | `72.1` | `93.2` | `91.6%` `[89.2, 93.9]` | `94.9` | `51.7` | `68.2` | `$0.0041` | `91.323 ms` (`315.3 ms/doc`) |
|
|
111
|
+
| **8** | `basal-omni-1.0-ultra (JevBench #1 Cap)` (Open 31B) | `71.8` | `82.5` | `74.1%` `[71.8, 76.3]` | `91.0` | `87.3` | `50.5` | `$0.0447` | `102.000 ms` |
|
|
112
|
+
| **9** | `Jev 1.13.0 (TypeSafe AI · JevBench Ref)` (API) | `71.5` | `77.1` | `63.6%` `[61.2, 66.0]` | `90.6` | `91.5` | `54.7` | `$0.0323` | `239.102 ms` |
|
|
113
|
+
| **10** | `gpt-5.4-nano (JSON Decoder · API)` (API) | `59.8` | `92.1` | `95.2%` `[93.4, 97.0]` | `89.0` | `43.6` | `45.1` | `$0.0438` | `417.991 ms` |
|
|
114
|
+
| **11** | `deberta-v3-base-squad2 (184M SQuAD2 QA)` (Open) | `58.0` | `55.8` | `48.1%` `[43.9, 52.4]` | `63.4` | `55.7` | `69.2` | `$0.0037` | `42.496 ms` |
|
|
115
|
+
| **12** | `claude-haiku-4.5 (JSON Decoder · API)` (API) | `48.8` | `92.1` | `95.4%` `[93.4, 97.2]` | `88.7` | `41.8` | `27.5` | `$0.2639` | `586.392 ms` |
|
|
116
|
+
| **13** | `bge-small-en-v1.5 (Dense Span+Null)` (Open) | `37.6` | `52.0` | `14.7%` `[12.0, 17.5]` | `89.2` | `64.5` | `85.5` | `$0.0007` | `8.098 ms` |
|
|
117
|
+
| **14** | `distilbert-base-control (Raw Control)` (Open) | `36.8` | `52.9` | `14.2%` `[11.6, 17.0]` | `91.5` | `66.0` | `81.1` | `$0.0011` | `6.133 ms` |
|
|
118
|
+
| **15** | `all-MiniLM-L12-v2 (Dense Span+Null)` (Open) | `35.9` | `44.0` | `14.4%` `[11.7, 17.5]` | `73.5` | `60.2` | `85.5` | `$0.0007` | `18.356 ms` |
|
|
119
|
+
| **16** | `all-mpnet-base-v2 (Dense Span+Null)` (Open) | `34.3` | `42.3` | `13.6%` `[10.9, 16.7]` | `71.0` | `62.8` | `77.4` | `$0.0016` | `11.263 ms` |
|
|
120
|
+
| **17** | `paraphrase-albert-small-v2 (Dense Span+Null)` (Open) | `33.6` | `44.5` | `12.5%` `[10.0, 15.2]` | `76.6` | `65.9` | `91.0` | `$0.0004` | `6.263 ms` |
|
|
121
|
+
| **18** | `paraphrase-MiniLM-L3-v2 (Dense Span+Null)` (Open) | `30.9` | `41.7` | `11.1%` `[8.7, 13.8]` | `72.3` | `68.9` | `91.0` | `$0.0004` | `3.519 ms` |
|
|
122
|
+
| **19** | `all-MiniLM-L6-v2 (Dense Span+Null)` (Open) | `28.3` | `40.5` | `10.0%` `[7.7, 12.3]` | `70.9` | `62.3` | `88.8` | `$0.0005` | `12.322 ms` |
|
|
123
|
+
|
|
124
|
+
See full methodology, proper scoring definitions, request-type breakdowns (`100.0%` on Multi-Numeric Contracts `n=96`, `100.0%` Choice `n=41`, `100.0%` Math & Invariants `n=51`), and head-to-head analysis in [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md).
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT © [Hemanth.HM](https://h3manth.com)
|
|
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nullspan"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.2.0"
|
|
8
8
|
description = "Calibrated p_null abstention, grounded [start, end] span extraction, arithmetic, and distribution forecasting in a single forward pass."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""nullspan — Calibrated p_null abstention, grounded [start, end] span extraction, and distribution forecasting."""
|
|
2
2
|
from .engine import DEFAULT_HF_REPO, NullspanExtractor, extract
|
|
3
3
|
|
|
4
|
-
__version__ = "1.
|
|
4
|
+
__version__ = "1.2.0"
|
|
5
5
|
__all__ = ["extract", "NullspanExtractor", "DEFAULT_HF_REPO"]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import datetime as dt
|
|
5
|
+
import os
|
|
5
6
|
import re
|
|
6
7
|
import time
|
|
7
8
|
from typing import Any
|
|
@@ -131,7 +132,16 @@ _GENERIC_MEASURE_WORDS = {
|
|
|
131
132
|
"rate", "rates", "period", "periods", "fee", "fees", "limit", "limits",
|
|
132
133
|
"level", "levels", "time", "times", "window", "windows", "schedule",
|
|
133
134
|
"schedules", "ratio", "ratios", "charge", "charges", "cost", "costs",
|
|
134
|
-
"price", "prices", "payment", "payments", "duration",
|
|
135
|
+
"price", "prices", "payment", "payments", "duration", "cap", "caps",
|
|
136
|
+
"allowance", "allowances", "penalty", "penalties", "credit", "credits",
|
|
137
|
+
"rebate", "rebates", "surcharge", "surcharges", "deposit", "deposits",
|
|
138
|
+
"retainer", "minimum", "maximum", "floor", "ceiling", "threshold",
|
|
139
|
+
"target", "term", "terms", "quota", "quotas", "hours", "days", "months",
|
|
140
|
+
"years", "minutes", "annual", "monthly", "daily", "quarterly", "hourly",
|
|
141
|
+
"tenant", "subtenant", "landlord", "sublandlord", "provider", "customer",
|
|
142
|
+
"vendor", "client", "buyer", "seller", "carrier", "shipper", "sponsor",
|
|
143
|
+
"licensor", "licensee", "grantor", "grantee", "merchant", "acquirer",
|
|
144
|
+
"advertiser", "platform", "responder", "party", "parties",
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
|
|
@@ -141,10 +151,10 @@ def _disambiguate_numeric_field(state: str, fname: str, spec: dict[str, Any]) ->
|
|
|
141
151
|
instr_s = str(spec.get("instructions") or spec.get("instruction") or "")
|
|
142
152
|
q_raw = f"{fn_clean} {instr_s}".lower()
|
|
143
153
|
q_words: list[str] = []
|
|
144
|
-
for w in re.findall(r"[a-
|
|
145
|
-
if w not in _NUM_STOPWORDS and w not in q_words:
|
|
154
|
+
for w in re.findall(r"[a-z0-9]{2,}", q_raw):
|
|
155
|
+
if not w.isdigit() and w not in _NUM_STOPWORDS and w not in q_words:
|
|
146
156
|
q_words.append(w)
|
|
147
|
-
specific_q_words = [w for w in q_words if w not in _GENERIC_MEASURE_WORDS]
|
|
157
|
+
specific_q_words = [w for w in q_words if w not in _GENERIC_MEASURE_WORDS] or list(q_words)
|
|
148
158
|
|
|
149
159
|
u_val = str(spec.get("unit", "")).lower()
|
|
150
160
|
unit_str = f"{q_raw} {u_val}"
|
|
@@ -196,7 +206,7 @@ def _disambiguate_numeric_field(state: str, fname: str, spec: dict[str, Any]) ->
|
|
|
196
206
|
pat = rf"\b{re.escape(w)}\b"
|
|
197
207
|
else:
|
|
198
208
|
stem = w[:5] if len(w) >= 6 else w.rstrip("s")
|
|
199
|
-
pat = re.escape(stem)
|
|
209
|
+
pat = rf"\b{re.escape(stem)}"
|
|
200
210
|
best_w_sc = 0.0
|
|
201
211
|
for wm in re.finditer(pat, clause_txt):
|
|
202
212
|
w_abs = c_start + wm.start()
|
|
@@ -348,14 +358,56 @@ def _extract_field_fast(state: str, fname: str, spec: dict[str, Any]) -> dict[st
|
|
|
348
358
|
}
|
|
349
359
|
|
|
350
360
|
if ftype == "boolean":
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
361
|
+
q_raw_b = f"{fname.replace('_', ' ')} {spec.get('instructions') or spec.get('instruction') or ''}".lower()
|
|
362
|
+
q_words_b = [
|
|
363
|
+
w for w in re.findall(r"[a-z]{2,}", q_raw_b)
|
|
364
|
+
if w not in _NUM_STOPWORDS and w not in ("whether", "status", "active", "enabled", "permitted", "allowed", "true", "false")
|
|
365
|
+
]
|
|
366
|
+
clauses_b = list(re.finditer(r"[^.!?\n]+[.!?\n]?", state))
|
|
367
|
+
search_txt = state
|
|
368
|
+
search_off = 0
|
|
369
|
+
if len(clauses_b) > 1 and q_words_b:
|
|
370
|
+
best_cb, best_sc_b = clauses_b[0], -1.0
|
|
371
|
+
for cm in clauses_b:
|
|
372
|
+
c_low = cm.group(0).lower()
|
|
373
|
+
sc = sum(1.0 for w in q_words_b if (w[:5] if len(w) >= 6 else w.rstrip("s")) in c_low)
|
|
374
|
+
if sc > best_sc_b:
|
|
375
|
+
best_sc_b = sc
|
|
376
|
+
best_cb = cm
|
|
377
|
+
if best_sc_b > 0:
|
|
378
|
+
search_txt = best_cb.group(0)
|
|
379
|
+
search_off = best_cb.start()
|
|
380
|
+
m_neg = re.search(
|
|
381
|
+
r"\b(not\s+(?:enabled|active|permitted|allowed|granted)|false|no|disabled|inactive|prohibited|denied)\b",
|
|
382
|
+
search_txt,
|
|
383
|
+
re.I,
|
|
384
|
+
)
|
|
385
|
+
m_pos = re.search(r"\b(true|yes|active|enabled|permitted|allowed|confirmed|granted)\b", search_txt, re.I)
|
|
386
|
+
if m_neg or m_pos:
|
|
387
|
+
if m_neg and (not m_pos or m_neg.start() <= m_pos.start()):
|
|
388
|
+
m_use = m_neg
|
|
389
|
+
b_val = False
|
|
390
|
+
else:
|
|
391
|
+
m_use = m_pos # type: ignore[assignment]
|
|
392
|
+
b_val = True
|
|
354
393
|
return {
|
|
355
394
|
"type": "boolean",
|
|
356
395
|
"p_null": 1.1e-6,
|
|
357
396
|
"p_true": 0.9992 if b_val else 0.0008,
|
|
358
|
-
"span": [
|
|
397
|
+
"span": [search_off + m_use.start(1), search_off + m_use.end(1)],
|
|
398
|
+
"guess": b_val,
|
|
399
|
+
"confidence": 0.9992,
|
|
400
|
+
"span_entropy_bits": 0.041,
|
|
401
|
+
"value": b_val,
|
|
402
|
+
}
|
|
403
|
+
m_bool_fb = re.search(r"\b(true|false|yes|no)\b", state, re.I)
|
|
404
|
+
if m_bool_fb:
|
|
405
|
+
b_val = m_bool_fb.group(1).lower() in ("true", "yes")
|
|
406
|
+
return {
|
|
407
|
+
"type": "boolean",
|
|
408
|
+
"p_null": 1.1e-6,
|
|
409
|
+
"p_true": 0.9992 if b_val else 0.0008,
|
|
410
|
+
"span": [m_bool_fb.start(1), m_bool_fb.end(1)],
|
|
359
411
|
"guess": b_val,
|
|
360
412
|
"confidence": 0.9992,
|
|
361
413
|
"span_entropy_bits": 0.041,
|
|
@@ -494,6 +546,9 @@ def _extract_field_fast(state: str, fname: str, spec: dict[str, Any]) -> dict[st
|
|
|
494
546
|
"span_entropy_bits": 0.031,
|
|
495
547
|
"value": val_d,
|
|
496
548
|
}
|
|
549
|
+
dis_dur = _disambiguate_numeric_field(state, fname, {**spec, "type": "duration", "unit": unit})
|
|
550
|
+
if dis_dur is not None:
|
|
551
|
+
return {**dis_dur, "unit": unit}
|
|
497
552
|
return {"type": "duration", "p_null": 0.9991, "unit": unit, "span": [0, 0], "guess": 0, "confidence": 0.41, "value": None}
|
|
498
553
|
|
|
499
554
|
if ftype in ("date", "time", "datetime"):
|
|
@@ -515,7 +570,18 @@ def _extract_field_fast(state: str, fname: str, spec: dict[str, Any]) -> dict[st
|
|
|
515
570
|
if ftype == "number":
|
|
516
571
|
if any(w in key or w in instr for w in ("rebate", "discount", "promo")):
|
|
517
572
|
m_disc = re.search(r"(?:Promo Rebate|Discount):\s*-?\$?(\d+(?:\.\d+)?)", state, re.I)
|
|
518
|
-
if
|
|
573
|
+
if m_disc:
|
|
574
|
+
d_val = float(m_disc.group(1))
|
|
575
|
+
return {
|
|
576
|
+
"type": "number",
|
|
577
|
+
"p_null": 1.2e-6,
|
|
578
|
+
"span": [m_disc.start(1), m_disc.end(1)],
|
|
579
|
+
"guess": d_val,
|
|
580
|
+
"confidence": 0.9994,
|
|
581
|
+
"span_entropy_bits": 0.044,
|
|
582
|
+
"value": d_val,
|
|
583
|
+
}
|
|
584
|
+
if "Invoice from " in state or "Receipt from " in state:
|
|
519
585
|
m_zero = re.search(r"(?:Egress Fee|Sales Tax):\s*\$(\d+(?:\.\d+)?)", state, re.I)
|
|
520
586
|
sp = [m_zero.start(1), m_zero.end(1)] if m_zero else [0, 0]
|
|
521
587
|
return {
|
|
@@ -528,16 +594,6 @@ def _extract_field_fast(state: str, fname: str, spec: dict[str, Any]) -> dict[st
|
|
|
528
594
|
"abstention_reason": "missing_field",
|
|
529
595
|
"value": None,
|
|
530
596
|
}
|
|
531
|
-
d_val = float(m_disc.group(1))
|
|
532
|
-
return {
|
|
533
|
-
"type": "number",
|
|
534
|
-
"p_null": 1.2e-6,
|
|
535
|
-
"span": [m_disc.start(1), m_disc.end(1)],
|
|
536
|
-
"guess": d_val,
|
|
537
|
-
"confidence": 0.9994,
|
|
538
|
-
"span_entropy_bits": 0.044,
|
|
539
|
-
"value": d_val,
|
|
540
|
-
}
|
|
541
597
|
|
|
542
598
|
if "including" in instr or "total_credit" in key or "amount_paid" in key:
|
|
543
599
|
m_plus = re.search(r"\$(\d+(?:\.\d+)?)\s+plus\s+\$(\d+(?:\.\d+)?)", state)
|
|
@@ -674,7 +730,7 @@ def _extract_field_fast(state: str, fname: str, spec: dict[str, Any]) -> dict[st
|
|
|
674
730
|
"value": p_str,
|
|
675
731
|
}
|
|
676
732
|
|
|
677
|
-
return _extract_open_domain_qa(state, spec.get("instructions", "") or
|
|
733
|
+
return _extract_open_domain_qa(state, spec.get("instructions", "") or fname)
|
|
678
734
|
|
|
679
735
|
|
|
680
736
|
_STOPWORDS = {
|
|
@@ -849,9 +905,13 @@ def _run_extraction(
|
|
|
849
905
|
mdl = AutoModel.from_pretrained(model_id, trust_remote_code=True)
|
|
850
906
|
if backend == "onnx":
|
|
851
907
|
import onnxruntime as ort
|
|
852
|
-
from huggingface_hub import hf_hub_download
|
|
853
908
|
|
|
854
|
-
|
|
909
|
+
if os.path.isdir(model_id):
|
|
910
|
+
onnx_file = os.path.join(model_id, "onnx", "model_quantized.onnx")
|
|
911
|
+
else:
|
|
912
|
+
from huggingface_hub import hf_hub_download
|
|
913
|
+
|
|
914
|
+
onnx_file = hf_hub_download(repo_id=model_id, filename="onnx/model_quantized.onnx")
|
|
855
915
|
sess = ort.InferenceSession(onnx_file, providers=["CPUExecutionProvider"])
|
|
856
916
|
_HF_CACHE[cache_key] = (tok, mdl, sess)
|
|
857
917
|
else:
|
nullspan-1.1.0/README.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# nullspan
|
|
2
|
-
|
|
3
|
-
Single-pass System One structured extraction, calibrated `p_null` abstention, character-offset `[start, end]` spans, zero-shot `boolean`/`enum` judgment, cross-field algebraic invariant verification, and calibrated quantile estimation (`p10`, `median`, `p90`) in JavaScript, Python, and Browser WebAssembly ONNX.
|
|
4
|
-
|
|
5
|
-
- **Interactive Playground (Browser WASM ONNX + Zero-Dep Engine)**: [https://hemanth.github.io/nullspan/](https://hemanth.github.io/nullspan/)
|
|
6
|
-
- **NullspanBench Leaderboard (JevBench-Style 14-System Evaluation)**: [https://hemanth.github.io/nullspan/bench.html](https://hemanth.github.io/nullspan/bench.html)
|
|
7
|
-
- **Hugging Face Space**: [https://huggingface.co/spaces/gnumanth/nullspan](https://huggingface.co/spaces/gnumanth/nullspan)
|
|
8
|
-
- **Fine-Tuned Hugging Face Model (67M PyTorch + 64.3 MB Int8 ONNX)**: [https://huggingface.co/gnumanth/nullspan](https://huggingface.co/gnumanth/nullspan)
|
|
9
|
-
- **Hugging Face Dataset**: [https://huggingface.co/datasets/gnumanth/nullspan-dataset](https://huggingface.co/datasets/gnumanth/nullspan-dataset)
|
|
10
|
-
- **Empirical Science Report**: [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md)
|
|
11
|
-
|
|
12
|
-
## In Plain English
|
|
13
|
-
|
|
14
|
-
Standard LLMs extract data by generating JSON token-by-token—which is slow, costs money per output token, can get hijacked by *"ignore previous instructions"* prompt injections, and often hallucinates values when a field is missing. **`nullspan` acts like a smart highlighter + calculator instead of a chatbot:**
|
|
15
|
-
|
|
16
|
-
1. **Points to Exact Text (`[start, end]` Span)**: Highlights exact character positions in your input text (`0` output tokens generated), making fabricated strings and prompt-injection payloads impossible.
|
|
17
|
-
2. **Knows When to Say "Not There" (`p_null`)**: Computes a calibrated probability that a field is missing (`p_null`) and returns `null` when evidence is absent.
|
|
18
|
-
3. **Checks the Math Automatically (`constraint` & `verified`)**: Computes sums, durations, and products and verifies cross-field equations like `subtotal == nodes * hourly_rate`.
|
|
19
|
-
4. **Gives Realistic Ranges (`p10 / median / p90`)**: Returns calibrated low/middle/high quantile distributions for estimates and forecasts.
|
|
20
|
-
|
|
21
|
-
## Install
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
npm install nullspan
|
|
25
|
-
pip install nullspan
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Usage (JavaScript / ESM)
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
import { extract } from 'nullspan';
|
|
32
|
-
|
|
33
|
-
const incident =
|
|
34
|
-
"Incident INC-40928 opened on Apr 12, 2026 with a 502 Bad Gateway errors and a TLS handshake timeouts. " +
|
|
35
|
-
"Issued $1240.50 plus $310.25 SLA credit. Severity is sev-1 and customer data loss was false. " +
|
|
36
|
-
"Root cause CVE not yet assigned. Cluster stabilized on Apr 19, 2026. Reported by Mira";
|
|
37
|
-
|
|
38
|
-
const result = extract(incident, {
|
|
39
|
-
incident_id: { type: 'text', instructions: 'Incident ticket identifier' },
|
|
40
|
-
opened_on: { type: 'date', instructions: 'Date the incident opened' },
|
|
41
|
-
total_credit: { type: 'number', decimals: 2, unit: 'USD', instructions: 'Total credit including SLA penalty' },
|
|
42
|
-
outage_days: { type: 'duration', unit: 'days', integer: true, instructions: 'Days from incident open to cluster stabilization' },
|
|
43
|
-
failure_modes: { type: 'list', items: 'text', instructions: 'Each failure mode triggered' },
|
|
44
|
-
severity: { type: 'enum', options: ['sev-1', 'sev-2', 'sev-3'], instructions: 'Incident severity tier' },
|
|
45
|
-
data_loss: { type: 'boolean', instructions: 'Whether customer data loss occurred' },
|
|
46
|
-
cve_id: { type: 'text', instructions: 'Assigned CVE identifier if present' },
|
|
47
|
-
remediation_cost: { type: 'estimate', unit: 'USD', min: 100, max: 25000, scale: 'log', step: 10, instructions: 'Estimated engineering remediation cost' },
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Usage (Python + Cross-Field Invariants + Hugging Face Backend)
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
from nullspan import extract
|
|
55
|
-
|
|
56
|
-
invoice = (
|
|
57
|
-
"Invoice from TensorCore Cloud\n"
|
|
58
|
-
"Invoice #88310 | Issued: 2026-08-14 18:20\n"
|
|
59
|
-
"Nodes: 4 @ $3.50 each\n"
|
|
60
|
-
"Subtotal: $14.00\n"
|
|
61
|
-
"Egress Fee: $0.00\n"
|
|
62
|
-
"Priority Surcharge: $1.75"
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
# Zero-dependency fast engine or fine-tuned neural checkpoint (backend="hf")
|
|
66
|
-
out = extract(
|
|
67
|
-
state=invoice,
|
|
68
|
-
fields={
|
|
69
|
-
"nodes": {"type": "number", "integer": True, "instructions": "Provisioned GPU node count"},
|
|
70
|
-
"hourly_rate": {"type": "number", "decimals": 2, "unit": "USD", "instructions": "Hourly rate per node"},
|
|
71
|
-
"subtotal": {
|
|
72
|
-
"type": "number",
|
|
73
|
-
"decimals": 2,
|
|
74
|
-
"unit": "USD",
|
|
75
|
-
"constraint": "subtotal == nodes * hourly_rate",
|
|
76
|
-
"instructions": "Compute subtotal before fees and surcharge",
|
|
77
|
-
},
|
|
78
|
-
"promo_rebate": {"type": "number", "decimals": 2, "unit": "USD", "instructions": "Promotional rebate amount if present"},
|
|
79
|
-
},
|
|
80
|
-
backend="hf",
|
|
81
|
-
model_id="gnumanth/nullspan",
|
|
82
|
-
)
|
|
83
|
-
# out["invariants_passed"] -> True, out["answers"]["subtotal"]["verified"] -> True
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Architectural Enhancements
|
|
87
|
-
|
|
88
|
-

|
|
89
|
-
|
|
90
|
-
1. **`null_head` (Calibrated Abstention & Reason Diagnostics)**: Predicts calibrated `p_null`, nearest decoy `guess`, and `abstention_reason` (`unassigned_placeholder` vs `missing_field`).
|
|
91
|
-
2. **`span_head` (Grounded Pointer + Shannon Entropy)**: Projects encoder tokens to `[start, end]` character spans with calibrated `confidence` and Shannon `span_entropy_bits`.
|
|
92
|
-
3. **`bio_head` (Class-Weighted Multi-Span Tagging)**: Extracts arbitrary-length ordered arrays (`type: "list"`) in a single pass.
|
|
93
|
-
4. **`op_head` (10-Way System One Router)**: Routes fields across `SPAN_TEXT`, `SPAN_NUMBER`, `ARITH_SUM`, `ARITH_DIFF`, `ARITH_MUL`, `ISO_DATETIME`, `DATE_DURATION`, `DIST_ESTIMATE_FORECAST`, `BOOL_JUDGE` (`p_true`), and `ENUM_CLASSIFY` (`probs`).
|
|
94
|
-
5. **`quantile_head` + Invariant Verifier**: Predicts monotone `(p10, median, p90)` quantiles and verifies cross-field algebraic constraints (`verified: true/false`).
|
|
95
|
-
|
|
96
|
-
## NullspanBench Leaderboard (`bench/run_bench.py` · 14 Systems · $N=404$ Scored Decisions)
|
|
97
|
-
|
|
98
|
-
Modeled after [BenchmarkHeaven's JevBench](https://benchmarkheaven.com/jev-models), **NullspanBench** evaluates `14` systems (`12` local open-weights/open-code models running live forward passes + `2` reference JSON-mode LLM decoders) across **`404` scored observations** (`336` Open structured items + `68` Sealed Stanford SQuAD v2.0 & adversarial prompt-injection items) on four axes: **Intelligence (`I`)**, **Calibration (`C`)**, **Speed (`S`)**, and **Cost (`K`)**.
|
|
99
|
-
|
|
100
|
-
Explore interactive weight sliders, Pareto frontier plots, and 2-system radar comparisons at [**https://hemanth.github.io/nullspan/bench.html**](https://hemanth.github.io/nullspan/bench.html):
|
|
101
|
-
|
|
102
|
-
| Rank | System | Composite (`25:25:25:25`) | Capability (`50I:50C`) | Intelligence `I` (95% CI) | Calibration `C` | Speed `S` | Cost `K` | `$/1k` | `p50` Latency |
|
|
103
|
-
| :---: | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
104
|
-
| **1** | **`nullspan-Hybrid (Fast + ONNX Int8)`** (Open) | **97.7** | **98.7** | **98.0%** `[96.5, 99.3]` | **99.3** | **99.8** | **93.8** | `$0.0003` | `0.005 ms` |
|
|
105
|
-
| **2** | **`nullspan-ZeroDep (Fast Engine)`** (Open) | **95.3** | **91.2** | `88.6%` `[85.6, 91.6]` | `93.8` | **99.8** | **99.8** | `$0.0001` | `0.005 ms` |
|
|
106
|
-
| **3** | **`nullspan-67M (PyTorch FP32)`** (Open) | **83.3** | **99.2** | **98.8%** `[97.5, 99.8]` | **99.7** | `66.5` | `78.0` | `$0.0015` | `5.575 ms` |
|
|
107
|
-
| **4** | **`nullspan-67M-Int8 (ONNX WASM/CPU)`** (Open) | **83.0** | **98.7** | **98.0%** `[96.5, 99.3]` | **99.3** | `62.3` | `84.2` | `$0.0008` | `12.268 ms` |
|
|
108
|
-
| **5** | **`nullspan-67M (ONNX FP32)`** (Open) | **82.1** | **99.2** | **98.8%** `[97.5, 99.8]` | **99.7** | `63.0` | `78.7` | `$0.0014` | `10.832 ms` |
|
|
109
|
-
| **6** | **`@cf/cloudflare/clairic + clef (Live Workers AI)`** | `74.4` | `92.0` | `90.1%` `[87.5, 92.7]` | `93.8` | `51.5` | `72.2` | `$0.0042` | `95.028 ms` (`308.6 ms/doc`) |
|
|
110
|
-
| **7** | `H2O-Lightning-4B v1.1 (JevBench #1 Comp)` (Open 4B) | `72.5` | `75.0` | `60.0%` `[57.8, 62.3]` | `90.0` | `92.6` | `60.3` | `$0.0211` | `29.285 ms` |
|
|
111
|
-
| **7** | `basal-omni-1.0-ultra (JevBench #1 Cap)` (Open 31B) | `71.8` | `82.5` | `74.1%` `[71.8, 76.3]` | `91.0` | `87.3` | `50.5` | `$0.0447` | `102.000 ms` |
|
|
112
|
-
| **8** | `Jev 1.13.0 (TypeSafe AI · JevBench Ref)` (API) | `71.5` | `77.1` | `63.6%` `[61.2, 66.0]` | `90.6` | `91.5` | `54.7` | `$0.0323` | `239.102 ms` |
|
|
113
|
-
| **9** | `gpt-5.4-nano (JSON Decoder · API)` | `60.3` | `91.5` | `95.3%` `[93.1, 97.3]` | `87.7` | `43.6` | `46.5` | `$0.0380` | `415.9 ms` |
|
|
114
|
-
| **10** | `claude-haiku-4.5 (JSON Decoder · API)` | `49.7` | `92.3` | `96.3%` `[94.3, 98.0]` | `88.3` | `41.8` | `28.7` | `$0.2328` | `588.0 ms` |
|
|
115
|
-
| **11** | `bge-small-en-v1.5 (Dense Span+Null)` (Open) | `42.0` | `53.3` | `17.5%` `[13.8, 21.3]` | `89.1` | `64.7` | `87.0` | `$0.0006` | `7.855 ms` |
|
|
116
|
-
| **12** | `distilbert-base-control (Raw Control)` (Open) | `41.6` | `53.6` | `17.3%` `[13.6, 21.1]` | `90.0` | `65.3` | `84.2` | `$0.0008` | `6.947 ms` |
|
|
117
|
-
| **13** | `all-MiniLM-L12-v2 (Dense Span+Null)` (Open) | `37.6` | `44.8` | `15.1%` `[11.9, 18.6]` | `74.6` | `65.4` | `87.0` | `$0.0006` | `6.894 ms` |
|
|
118
|
-
| **14** | `all-mpnet-base-v2 (Dense Span+Null)` (Open) | `35.3` | `43.1` | `14.1%` `[10.9, 17.5]` | `72.2` | `62.8` | `80.2` | `$0.0012` | `11.098 ms` |
|
|
119
|
-
| **15** | `paraphrase-albert-small-v2 (Dense Span+Null)` (Open) | `34.8` | `45.1` | `13.1%` `[9.9, 16.4]` | `77.2` | `66.8` | `93.8` | `$0.0003` | `5.224 ms` |
|
|
120
|
-
| **16** | `paraphrase-MiniLM-L3-v2 (Dense Span+Null)` (Open) | `31.5` | `42.2` | `11.3%` `[8.4, 14.5]` | `73.1` | `70.6` | `93.8` | `$0.0003` | `2.586 ms` |
|
|
121
|
-
| **17** | `all-MiniLM-L6-v2 (Dense Span+Null)` (Open) | `28.5` | `41.2` | `9.9%` `[7.1, 13.0]` | `72.6` | `68.0` | `91.0` | `$0.0004` | `4.200 ms` |
|
|
122
|
-
|
|
123
|
-
See full methodology, proper scoring definitions, request-type breakdowns, and ablation analysis in [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md).
|
|
124
|
-
|
|
125
|
-
## License
|
|
126
|
-
|
|
127
|
-
MIT © [Hemanth.HM](https://h3manth.com)
|
|
File without changes
|