helix-grounding 0.1.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.
- helix_grounding-0.1.0/.gitignore +34 -0
- helix_grounding-0.1.0/LICENSE +21 -0
- helix_grounding-0.1.0/PKG-INFO +225 -0
- helix_grounding-0.1.0/README.md +193 -0
- helix_grounding-0.1.0/docs/ARCHITECTURE.md +229 -0
- helix_grounding-0.1.0/docs/BUSINESS_MODEL.md +136 -0
- helix_grounding-0.1.0/docs/CASE_STUDY.html +265 -0
- helix_grounding-0.1.0/docs/DECISION_LOG.md +1455 -0
- helix_grounding-0.1.0/docs/FIRST_USERS.md +214 -0
- helix_grounding-0.1.0/docs/MARKET_RESEARCH.html +537 -0
- helix_grounding-0.1.0/docs/OLLAMA_SETUP.md +123 -0
- helix_grounding-0.1.0/docs/PUBLISHING.md +201 -0
- helix_grounding-0.1.0/docs/ROADMAP.md +108 -0
- helix_grounding-0.1.0/pyproject.toml +77 -0
- helix_grounding-0.1.0/scripts/diagnose_env.py +48 -0
- helix_grounding-0.1.0/scripts/export_diagrams.py +61 -0
- helix_grounding-0.1.0/scripts/reproduce_d036.py +110 -0
- helix_grounding-0.1.0/scripts/set_repo_url.py +56 -0
- helix_grounding-0.1.0/src/helix_api/__init__.py +1 -0
- helix_grounding-0.1.0/src/helix_api/app.py +172 -0
- helix_grounding-0.1.0/src/helix_api/audit.py +73 -0
- helix_grounding-0.1.0/src/helix_api/auth.py +121 -0
- helix_grounding-0.1.0/src/helix_bom/__init__.py +1 -0
- helix_grounding-0.1.0/src/helix_bom/agent.py +618 -0
- helix_grounding-0.1.0/src/helix_bom/cli.py +238 -0
- helix_grounding-0.1.0/src/helix_bom/components.py +66 -0
- helix_grounding-0.1.0/src/helix_bom/diagrams.py +226 -0
- helix_grounding-0.1.0/src/helix_bom/examples/sample_bom.csv +12 -0
- helix_grounding-0.1.0/src/helix_bom/ingest.py +355 -0
- helix_grounding-0.1.0/src/helix_grounding/__init__.py +74 -0
- helix_grounding-0.1.0/src/helix_grounding/claims.py +136 -0
- helix_grounding-0.1.0/src/helix_grounding/domains/__init__.py +12 -0
- helix_grounding-0.1.0/src/helix_grounding/domains/bom.py +169 -0
- helix_grounding-0.1.0/src/helix_grounding/domains/invoice.py +151 -0
- helix_grounding-0.1.0/src/helix_grounding/extractors.py +397 -0
- helix_grounding-0.1.0/src/helix_grounding/truth.py +179 -0
- helix_grounding-0.1.0/src/helix_grounding/verifier.py +152 -0
- helix_grounding-0.1.0/src/helix_llm/__init__.py +1 -0
- helix_grounding-0.1.0/src/helix_llm/client.py +124 -0
- helix_grounding-0.1.0/tests/fixtures/altium_with_pricing.csv +7 -0
- helix_grounding-0.1.0/tests/fixtures/kicad_grouped.csv +11 -0
- helix_grounding-0.1.0/tests/fixtures/spreadsheet_european.csv +4 -0
- helix_grounding-0.1.0/tests/sandbox/test_bom_review_clean_case_sandbox.py +63 -0
- helix_grounding-0.1.0/tests/sandbox/test_bom_review_realistic_scale_sandbox.py +132 -0
- helix_grounding-0.1.0/tests/sandbox/test_bom_review_sandbox.py +66 -0
- helix_grounding-0.1.0/tests/sandbox/test_component_lookup_sandbox.py +30 -0
- helix_grounding-0.1.0/tests/sandbox/test_grounding_safety_net_sandbox.py +149 -0
- helix_grounding-0.1.0/tests/sandbox/test_interconnect_diagram_sandbox.py +36 -0
- helix_grounding-0.1.0/tests/sandbox/test_llm_client_sandbox.py +49 -0
- helix_grounding-0.1.0/tests/sandbox/test_orchestrator_realistic_scale_sandbox.py +90 -0
- helix_grounding-0.1.0/tests/sandbox/test_orchestrator_sandbox.py +86 -0
- helix_grounding-0.1.0/tests/sandbox/test_tier_gating_sandbox.py +75 -0
- helix_grounding-0.1.0/tests/sandbox/test_variated_1_over_budget_only_sandbox.py +48 -0
- helix_grounding-0.1.0/tests/sandbox/test_variated_2_multi_lead_time_sandbox.py +67 -0
- helix_grounding-0.1.0/tests/sandbox/test_variated_3_physical_fit_only_sandbox.py +47 -0
- helix_grounding-0.1.0/tests/sandbox/test_visual_diagrams_sandbox.py +71 -0
- helix_grounding-0.1.0/tests/test_api_auth.py +203 -0
- helix_grounding-0.1.0/tests/test_bom_cli.py +214 -0
- helix_grounding-0.1.0/tests/test_bom_ingest.py +306 -0
- helix_grounding-0.1.0/tests/test_case_study.py +23 -0
- helix_grounding-0.1.0/tests/test_diagram_fixes.py +130 -0
- helix_grounding-0.1.0/tests/test_grounding.py +357 -0
- helix_grounding-0.1.0/tests/test_invoice_domain.py +304 -0
- helix_grounding-0.1.0/tests/test_offline_guarantee.py +148 -0
- helix_grounding-0.1.0/tests/test_sandbox_suite.py +51 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Secrets — never commit. There is a populated .env in AI_CODE/; committing it
|
|
2
|
+
# would put the key in history permanently, where deleting the file later does
|
|
3
|
+
# not remove it.
|
|
4
|
+
.env
|
|
5
|
+
.env.*
|
|
6
|
+
!.env.example
|
|
7
|
+
*.pem
|
|
8
|
+
*.key
|
|
9
|
+
|
|
10
|
+
# Build artefacts
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
*.egg-info/
|
|
14
|
+
|
|
15
|
+
# Python
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.py[cod]
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.venv/
|
|
20
|
+
venv/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
|
|
25
|
+
# Local databases and generated output
|
|
26
|
+
*.sqlite
|
|
27
|
+
*.sqlite3
|
|
28
|
+
*.db
|
|
29
|
+
diagram_output/
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
Thumbs.db
|
|
33
|
+
desktop.ini
|
|
34
|
+
.DS_Store
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert Brandon Spiva
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: helix-grounding
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Catch the numbers an AI made up, without asking another AI
|
|
5
|
+
Project-URL: Documentation, https://github.com/CARC-Program/helix-grounding#readme
|
|
6
|
+
Project-URL: Source, https://github.com/CARC-Program/helix-grounding
|
|
7
|
+
Project-URL: Changelog, https://github.com/CARC-Program/helix-grounding/blob/main/docs/DECISION_LOG.md
|
|
8
|
+
Author: Helix Labs
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-safety,bom,evals,grounding,guardrails,hallucination,llm,validation,verification
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
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: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
26
|
+
Requires-Dist: twine; extra == 'dev'
|
|
27
|
+
Provides-Extra: llm
|
|
28
|
+
Requires-Dist: anthropic>=0.40; extra == 'llm'
|
|
29
|
+
Requires-Dist: ollama>=0.3; extra == 'llm'
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0; extra == 'llm'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# helix-grounding
|
|
34
|
+
|
|
35
|
+
**Catch the numbers an AI made up — without asking another AI.**
|
|
36
|
+
|
|
37
|
+
A language model states a figure that isn't in its source data. In anything
|
|
38
|
+
touching money, specifications, or deadlines, that's not a quality issue —
|
|
39
|
+
it's a liability.
|
|
40
|
+
|
|
41
|
+
The usual defence is to check the output with another model: LLM-as-judge,
|
|
42
|
+
semantic entailment, embedding similarity. All three are probabilistic, all
|
|
43
|
+
three cost an inference call, and all three can be wrong themselves.
|
|
44
|
+
|
|
45
|
+
This doesn't do that. It extracts every currency amount, measurement,
|
|
46
|
+
identifier, quantity, percentage and date from generated text and checks each
|
|
47
|
+
against values computed from your source data. For that class of claim the
|
|
48
|
+
answer is decidable: a value is in the set or it isn't. **No model call, no
|
|
49
|
+
judgement, no confidence score.**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install helix-grounding
|
|
53
|
+
helix-bom demo # see it catch something, no file needed
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from helix_grounding import Verifier, GroundTruth, ClaimKind
|
|
58
|
+
|
|
59
|
+
truth = GroundTruth().allow_many(ClaimKind.CURRENCY, [18.00, 22.00, 40.00])
|
|
60
|
+
report = Verifier().verify(model_output, truth)
|
|
61
|
+
|
|
62
|
+
if not report.is_grounded:
|
|
63
|
+
print(report.summary())
|
|
64
|
+
# -> UNGROUNDED: 1 of 4 claims not found in source data — $36.00 (currency)
|
|
65
|
+
retry = base_prompt + report.correction_note()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The correction names the specific invented value and quotes the sentence it
|
|
69
|
+
appeared in, because a blind re-roll reproduces the same error at roughly the
|
|
70
|
+
same rate.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## See it work on your own file
|
|
75
|
+
|
|
76
|
+
The package ships a complete worked example: a bill-of-materials reviewer
|
|
77
|
+
built on the library. `helix-bom demo` runs it against a bundled sample;
|
|
78
|
+
point it at your own CSV export when you want a real answer.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
helix-bom review my_bom.csv --budget 10
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
BOM total: $13.81 (budget $10.00)
|
|
86
|
+
|
|
87
|
+
Findings:
|
|
88
|
+
[CRITICAL] BOM total ($13.81) exceeds stated budget ($10.00) by $3.81.
|
|
89
|
+
[WARNING] ARM Cortex-M4 MCU has a stated lead time of 120 days — this is a
|
|
90
|
+
real supply-chain risk that can silently become the critical path.
|
|
91
|
+
|
|
92
|
+
NOT CHECKED (3):
|
|
93
|
+
physical fit
|
|
94
|
+
no component dimensions in the submitted data — standard EDA exports
|
|
95
|
+
carry footprints, not millimetres
|
|
96
|
+
|
|
97
|
+
These are not passes. Supply the missing columns to check them.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
It reads what KiCad, Altium and spreadsheets actually export: preamble lines
|
|
101
|
+
before the header, semicolon delimiters, do-not-populate rows, and `1.234,56`
|
|
102
|
+
versus `1,234.56` decided per file rather than per cell.
|
|
103
|
+
|
|
104
|
+
**A check that couldn't run is never reported as a pass.** `--strict` makes
|
|
105
|
+
"couldn't check" a non-zero exit; `--json` emits the same for a machine.
|
|
106
|
+
|
|
107
|
+
### Your BOM never leaves your machine
|
|
108
|
+
|
|
109
|
+
A bill of materials exposes a design, its costs and its suppliers. Reading
|
|
110
|
+
and reviewing one here is **entirely offline** — no upload, no telemetry, no
|
|
111
|
+
account, no network call of any kind.
|
|
112
|
+
|
|
113
|
+
That is not a promise, it is a test. `tests/test_offline_guarantee.py`
|
|
114
|
+
disables Python's socket layer outright and then runs the real code path
|
|
115
|
+
end to end, so any attempt to reach the network by any library at any depth
|
|
116
|
+
is a hard failure rather than a quiet one. It also asserts the block itself
|
|
117
|
+
works, because a guard that silently stops guarding is worse than none.
|
|
118
|
+
|
|
119
|
+
The only component that can reach out is the optional narrative writer, and
|
|
120
|
+
it defaults to a model running on your own hardware.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## A real fabrication, caught
|
|
125
|
+
|
|
126
|
+
Not a demo — a model actually wrote both of these while reviewing a BOM:
|
|
127
|
+
|
|
128
|
+
> "the Bosch BME680 at **$3.10** is slightly cheaper than your current part at
|
|
129
|
+
> **$2.40**"
|
|
130
|
+
|
|
131
|
+
> "The ESP32-S3 module at **$3.40** has a lead time concern"
|
|
132
|
+
|
|
133
|
+
The second is caught: $3.20 is the real price, and $3.40 appears nowhere in
|
|
134
|
+
the source data.
|
|
135
|
+
|
|
136
|
+
**The first passes the check — and should.** Both numbers are real. What's
|
|
137
|
+
false is the word *cheaper*, a claim about the *relation* between two values.
|
|
138
|
+
No value-checker can see that, and a library claiming otherwise would be
|
|
139
|
+
misrepresenting its own scope. It's prevented a different way: the comparison
|
|
140
|
+
is computed in Python before the prompt is built, so the model is only asked
|
|
141
|
+
to phrase an answer that's already correct.
|
|
142
|
+
|
|
143
|
+
Reproduce both yourself:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
python scripts/reproduce_d036.py
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Full write-up: `docs/CASE_STUDY.html`.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## What it can't do
|
|
154
|
+
|
|
155
|
+
Stated plainly, because a validation layer that quietly misses a category is
|
|
156
|
+
worse than none — it manufactures false confidence.
|
|
157
|
+
|
|
158
|
+
- **Judgement claims are out of scope.** Whether advice is good, whether a
|
|
159
|
+
summary is complete, whether a conclusion follows. Those need an
|
|
160
|
+
LLM-as-judge layer. This is not one.
|
|
161
|
+
- **Identifiers need a vocabulary.** No lexical rule separates a part number
|
|
162
|
+
from a standards name — `RS485` and `BME280` are the same shape. A default
|
|
163
|
+
vocabulary of known non-identifiers ships in, and is meant to be extended.
|
|
164
|
+
- **Amounts written as words** ("thirty-six dollars") aren't caught. Symbol
|
|
165
|
+
and suffix forms are: `$36`, `36 dollars`, `36 USD`.
|
|
166
|
+
- **Relative dates are out of scope** ("next Tuesday", "in 30 days") — those
|
|
167
|
+
depend on what *now* means, which makes them judgement claims.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Your own data
|
|
172
|
+
|
|
173
|
+
A domain adapter turns your data into a `GroundTruth`. The core never learns
|
|
174
|
+
what your data is — two ship as reference implementations, and a third is a
|
|
175
|
+
new file, not a change to the verifier.
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from helix_grounding.domains.invoice import ground_truth_for_invoice
|
|
179
|
+
|
|
180
|
+
report = Verifier().verify(summary, ground_truth_for_invoice(invoice))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Invoices exercise a shape a BOM never does: a *chain*, where line totals feed
|
|
184
|
+
a subtotal, the subtotal feeds a discount, the remainder feeds a tax. Every
|
|
185
|
+
intermediate is a figure a model will quote, so the adapter permits the whole
|
|
186
|
+
working — not just the answer.
|
|
187
|
+
|
|
188
|
+
Adding that second domain is what forced date support into the core. Before
|
|
189
|
+
it, a fabricated due date produced no claim at all and passed straight
|
|
190
|
+
through.
|
|
191
|
+
|
|
192
|
+
**Zero runtime dependencies, deliberately.** The argument for this library is
|
|
193
|
+
that checking a model's output shouldn't require another model. A dependency
|
|
194
|
+
on an inference client would undercut that.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
Python 3.10+.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
pip install -e ".[dev]"
|
|
204
|
+
pytest
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
161 tests, nothing skipped, no database and no services required.
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
src/helix_grounding/ the library
|
|
211
|
+
domains/ bom.py, invoice.py — add a vertical here
|
|
212
|
+
src/helix_bom/ the worked example: ingest, checks, CLI
|
|
213
|
+
src/helix_llm/ optional model client (local Ollama, or Anthropic)
|
|
214
|
+
docs/ decision log, architecture, business model, case study
|
|
215
|
+
PUBLISHING.md — GitHub + PyPI release checklist
|
|
216
|
+
FIRST_USERS.md — how to get the first users
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`docs/DECISION_LOG.md` is 45 decisions with the reasoning attached, including
|
|
220
|
+
the bugs that produced the design above. It is the most useful file here for
|
|
221
|
+
understanding *why* rather than *what*.
|
|
222
|
+
|
|
223
|
+
## Licence
|
|
224
|
+
|
|
225
|
+
MIT.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# helix-grounding
|
|
2
|
+
|
|
3
|
+
**Catch the numbers an AI made up — without asking another AI.**
|
|
4
|
+
|
|
5
|
+
A language model states a figure that isn't in its source data. In anything
|
|
6
|
+
touching money, specifications, or deadlines, that's not a quality issue —
|
|
7
|
+
it's a liability.
|
|
8
|
+
|
|
9
|
+
The usual defence is to check the output with another model: LLM-as-judge,
|
|
10
|
+
semantic entailment, embedding similarity. All three are probabilistic, all
|
|
11
|
+
three cost an inference call, and all three can be wrong themselves.
|
|
12
|
+
|
|
13
|
+
This doesn't do that. It extracts every currency amount, measurement,
|
|
14
|
+
identifier, quantity, percentage and date from generated text and checks each
|
|
15
|
+
against values computed from your source data. For that class of claim the
|
|
16
|
+
answer is decidable: a value is in the set or it isn't. **No model call, no
|
|
17
|
+
judgement, no confidence score.**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install helix-grounding
|
|
21
|
+
helix-bom demo # see it catch something, no file needed
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from helix_grounding import Verifier, GroundTruth, ClaimKind
|
|
26
|
+
|
|
27
|
+
truth = GroundTruth().allow_many(ClaimKind.CURRENCY, [18.00, 22.00, 40.00])
|
|
28
|
+
report = Verifier().verify(model_output, truth)
|
|
29
|
+
|
|
30
|
+
if not report.is_grounded:
|
|
31
|
+
print(report.summary())
|
|
32
|
+
# -> UNGROUNDED: 1 of 4 claims not found in source data — $36.00 (currency)
|
|
33
|
+
retry = base_prompt + report.correction_note()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The correction names the specific invented value and quotes the sentence it
|
|
37
|
+
appeared in, because a blind re-roll reproduces the same error at roughly the
|
|
38
|
+
same rate.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## See it work on your own file
|
|
43
|
+
|
|
44
|
+
The package ships a complete worked example: a bill-of-materials reviewer
|
|
45
|
+
built on the library. `helix-bom demo` runs it against a bundled sample;
|
|
46
|
+
point it at your own CSV export when you want a real answer.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
helix-bom review my_bom.csv --budget 10
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
BOM total: $13.81 (budget $10.00)
|
|
54
|
+
|
|
55
|
+
Findings:
|
|
56
|
+
[CRITICAL] BOM total ($13.81) exceeds stated budget ($10.00) by $3.81.
|
|
57
|
+
[WARNING] ARM Cortex-M4 MCU has a stated lead time of 120 days — this is a
|
|
58
|
+
real supply-chain risk that can silently become the critical path.
|
|
59
|
+
|
|
60
|
+
NOT CHECKED (3):
|
|
61
|
+
physical fit
|
|
62
|
+
no component dimensions in the submitted data — standard EDA exports
|
|
63
|
+
carry footprints, not millimetres
|
|
64
|
+
|
|
65
|
+
These are not passes. Supply the missing columns to check them.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
It reads what KiCad, Altium and spreadsheets actually export: preamble lines
|
|
69
|
+
before the header, semicolon delimiters, do-not-populate rows, and `1.234,56`
|
|
70
|
+
versus `1,234.56` decided per file rather than per cell.
|
|
71
|
+
|
|
72
|
+
**A check that couldn't run is never reported as a pass.** `--strict` makes
|
|
73
|
+
"couldn't check" a non-zero exit; `--json` emits the same for a machine.
|
|
74
|
+
|
|
75
|
+
### Your BOM never leaves your machine
|
|
76
|
+
|
|
77
|
+
A bill of materials exposes a design, its costs and its suppliers. Reading
|
|
78
|
+
and reviewing one here is **entirely offline** — no upload, no telemetry, no
|
|
79
|
+
account, no network call of any kind.
|
|
80
|
+
|
|
81
|
+
That is not a promise, it is a test. `tests/test_offline_guarantee.py`
|
|
82
|
+
disables Python's socket layer outright and then runs the real code path
|
|
83
|
+
end to end, so any attempt to reach the network by any library at any depth
|
|
84
|
+
is a hard failure rather than a quiet one. It also asserts the block itself
|
|
85
|
+
works, because a guard that silently stops guarding is worse than none.
|
|
86
|
+
|
|
87
|
+
The only component that can reach out is the optional narrative writer, and
|
|
88
|
+
it defaults to a model running on your own hardware.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## A real fabrication, caught
|
|
93
|
+
|
|
94
|
+
Not a demo — a model actually wrote both of these while reviewing a BOM:
|
|
95
|
+
|
|
96
|
+
> "the Bosch BME680 at **$3.10** is slightly cheaper than your current part at
|
|
97
|
+
> **$2.40**"
|
|
98
|
+
|
|
99
|
+
> "The ESP32-S3 module at **$3.40** has a lead time concern"
|
|
100
|
+
|
|
101
|
+
The second is caught: $3.20 is the real price, and $3.40 appears nowhere in
|
|
102
|
+
the source data.
|
|
103
|
+
|
|
104
|
+
**The first passes the check — and should.** Both numbers are real. What's
|
|
105
|
+
false is the word *cheaper*, a claim about the *relation* between two values.
|
|
106
|
+
No value-checker can see that, and a library claiming otherwise would be
|
|
107
|
+
misrepresenting its own scope. It's prevented a different way: the comparison
|
|
108
|
+
is computed in Python before the prompt is built, so the model is only asked
|
|
109
|
+
to phrase an answer that's already correct.
|
|
110
|
+
|
|
111
|
+
Reproduce both yourself:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
python scripts/reproduce_d036.py
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Full write-up: `docs/CASE_STUDY.html`.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## What it can't do
|
|
122
|
+
|
|
123
|
+
Stated plainly, because a validation layer that quietly misses a category is
|
|
124
|
+
worse than none — it manufactures false confidence.
|
|
125
|
+
|
|
126
|
+
- **Judgement claims are out of scope.** Whether advice is good, whether a
|
|
127
|
+
summary is complete, whether a conclusion follows. Those need an
|
|
128
|
+
LLM-as-judge layer. This is not one.
|
|
129
|
+
- **Identifiers need a vocabulary.** No lexical rule separates a part number
|
|
130
|
+
from a standards name — `RS485` and `BME280` are the same shape. A default
|
|
131
|
+
vocabulary of known non-identifiers ships in, and is meant to be extended.
|
|
132
|
+
- **Amounts written as words** ("thirty-six dollars") aren't caught. Symbol
|
|
133
|
+
and suffix forms are: `$36`, `36 dollars`, `36 USD`.
|
|
134
|
+
- **Relative dates are out of scope** ("next Tuesday", "in 30 days") — those
|
|
135
|
+
depend on what *now* means, which makes them judgement claims.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Your own data
|
|
140
|
+
|
|
141
|
+
A domain adapter turns your data into a `GroundTruth`. The core never learns
|
|
142
|
+
what your data is — two ship as reference implementations, and a third is a
|
|
143
|
+
new file, not a change to the verifier.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from helix_grounding.domains.invoice import ground_truth_for_invoice
|
|
147
|
+
|
|
148
|
+
report = Verifier().verify(summary, ground_truth_for_invoice(invoice))
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Invoices exercise a shape a BOM never does: a *chain*, where line totals feed
|
|
152
|
+
a subtotal, the subtotal feeds a discount, the remainder feeds a tax. Every
|
|
153
|
+
intermediate is a figure a model will quote, so the adapter permits the whole
|
|
154
|
+
working — not just the answer.
|
|
155
|
+
|
|
156
|
+
Adding that second domain is what forced date support into the core. Before
|
|
157
|
+
it, a fabricated due date produced no claim at all and passed straight
|
|
158
|
+
through.
|
|
159
|
+
|
|
160
|
+
**Zero runtime dependencies, deliberately.** The argument for this library is
|
|
161
|
+
that checking a model's output shouldn't require another model. A dependency
|
|
162
|
+
on an inference client would undercut that.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
Python 3.10+.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pip install -e ".[dev]"
|
|
172
|
+
pytest
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
161 tests, nothing skipped, no database and no services required.
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
src/helix_grounding/ the library
|
|
179
|
+
domains/ bom.py, invoice.py — add a vertical here
|
|
180
|
+
src/helix_bom/ the worked example: ingest, checks, CLI
|
|
181
|
+
src/helix_llm/ optional model client (local Ollama, or Anthropic)
|
|
182
|
+
docs/ decision log, architecture, business model, case study
|
|
183
|
+
PUBLISHING.md — GitHub + PyPI release checklist
|
|
184
|
+
FIRST_USERS.md — how to get the first users
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`docs/DECISION_LOG.md` is 45 decisions with the reasoning attached, including
|
|
188
|
+
the bugs that produced the design above. It is the most useful file here for
|
|
189
|
+
understanding *why* rather than *what*.
|
|
190
|
+
|
|
191
|
+
## Licence
|
|
192
|
+
|
|
193
|
+
MIT.
|