Specification
Azoth
Chemical-engineering calculations in Python and Rust, where every number carries its provenance.
- What
- A chemical-engineering calculation library in Python and Rust, written twice by hand from one declaration, where every result carries its provenance.
- Why
- In process safety, the dangerous number is rarely obviously wrong. It is reasonable, it is in the right units, and it has no history — so it gets used. A library that returns a bare float is optimised for that failure. Azoth makes a number unable to be anonymous: it carries its source and verification state, and a calculation that cannot be supported refuses instead of returning a plausible default. The library is built so the unsourced number cannot exist.
- The combination
- One declaration → two hand-written kernels (Rust and Python) compared in CI → per-result provenance → typed refusal as a first-class outcome; a disagreement is a finding, not a fallback.
The difference
Table 1. A number, with and without a record.What changes when the result carries its own history.
| Measure | A plain calculation | An Azoth result |
|---|---|---|
| Value | A float. | A float plus its identity, source, verification state, skipped checks, and kernel hashes. |
| Implementation | One code path. | Two hand-written kernels (Rust and Python) from one declaration, compared in CI. |
| Disagreement | A fallback, or unnoticed. | Recorded as a finding. |
| Unsupported input | A plausible default, or an exception with no field. | A typed refusal naming the field. |
Design intent, not current coverage: v0.1.1, not on PyPI, not for design work yet; everything ported ships as unverified.
Design
- A disagreement is a finding, not a fallback. Two hand-written kernels from one declaration are compared in CI; a difference is recorded rather than resolved by choosing one. This catches implementation drift, not a shared specification error.
- No result is anonymous. Each result carries its identity, source, verification state, skipped checks, and kernel hashes.
- Unsupported answers are refused. Typed errors name the offending field rather than returning a plausible default.
- Agent-exposed results keep their provenance. Data access is sealed at load, not at use, and results exposed over MCP carry the same record.
Provenance
Port of NeqSim (Apache-2.0), with documented divergences. Original to this work: the specification, dual generation, provenance layer, typed refusal, sealed data access, and the Lean-checked foundations. Azoth is AGPL-3.0-or-later.
Evidence
| Measure | Value | Source |
|---|---|---|
| Upstream issues filed | 97 (80 closed, 17 open) | NeqSim issue search |
| Provenance tests | 259 | Azoth repository |
As of October 2026. These are upstream issues filed against NeqSim, not an Equinor engagement.
TOML specificationGenerated Rust and PythonDual kernelsProvenance recordCLI · UI · MCP · agents
Limits
- v0.1.1; not on PyPI; incomplete port coverage; everything ported ships as
unverified; the standalone simulator is an aim, not a status. - Not for design work yet: shipped Crane K-factor coefficients are estimated dummy values; a pressure drop can be wrong by a factor of two while looking reasonable.
- Lean covers foundations only — dimensional calculus, unit vocabulary, two derivative formulas, keycard non-amplification. Physics kernels are measured, not proved.
- One upstream issue did not reproduce in situ. This is a self-audit, not a third-party audit.
- AGPL-3.0-or-later has commercial implications for proprietary integration.