The honesty contract
If you call
/api/zeq/computeor/api/zeq/prove, read this page — it governs exactly what your code receives back.
Every numeric answer must come from your data. Where the machine does not have what it needs, it says so — it does not fill the gap and hand you a number wearing a proof.
What changed
Before, a missing required input was silently replaced by a default:
POST /api/zeq/compute
{ "domain": "general-relativity", "operators": ["GR37"], "inputs": {} }
// BEFORE — no mass was supplied
{ "value": 2970.4641, "unit": "m", "zeqProof": "2bab00fa…" }
2970.4641 m is 2G·(2e30)/c². No mass was supplied. The solver used
2e30, computed on it, and stamped the result with a valid zeqProof. The proof
was not lying — it proves the computation ran. It simply was not proof of what a
reader assumes it proves.
Now:
// AFTER
{
"value": null,
"inputError": {
"code": "MISSING_INPUT",
"message": "missing required input \"M\" (accepted: M, mass)",
"missing": "M",
"accepts": "M, mass",
"why": "This value determines the answer. Supplying a default would fabricate the result."
}
}
The 7-step envelope agrees with itself:
step 4 COMPUTE : degraded "refused: missing required input \"M\" (accepted: M, mass)"
step 5 VERIFY : degraded precision_ok: false, has_solution: false
The three classes
Not every absent input is an error. The distinction is whether a preference was expressed:
| class | meaning | behaviour |
|---|---|---|
| required | the quantity the question is about (M, v, n_e, L/C/R) | value: null + inputError. Never invented. |
| conditional | only the operator that uses it needs it | r_s = 2GM/c² needs no r; GR35's dilation does |
| assumed | a defensible standard condition (g, room temperature, 1 atm, electron mass) | computed and declared in assumed |
| optional | absence genuinely means the stated value | no field; e = 0 really is a circular orbit |
assumed — read it
When the machine supplies a standard condition on your behalf, it tells you:
POST /api/zeq/compute
{ "domain": "quantum-mechanics", "operators": ["QM9"], "inputs": { "v": 1e6 } }
{
"value": 7.2738951e-10,
"unit": "m",
"assumed": {
"m": "9.1093837015e-31 — electron mass (particle unspecified) (assumed: you did not supply it)"
}
}
7.2738951e-10 m is h/(m_e·v) — an electron's de Broglie wavelength. You
never said electron. The answer is defensible; the silence would not have been.
If assumed is present, the number rests on a condition you did not state.
Decide whether it is the one you meant.
No closed form? The master-equation fallback
A missing required input is refused (above). But a well-formed query for an operator that
simply has no scalar closed form is different — and the machine does not stop at a bare
null. It integrates the HULYAS master equation (RK4 numerical integration — the same
directive that powers zeq_solve) over the inputs you supplied and returns a real,
deterministic field energy. Same inputs → same value; different inputs → different value.
This is transparently disclosed so it can never be mistaken for the operator's own physics — the master-equation block in the response carries a plain note:
NUMERICAL FALLBACK (no closed form matched these inputs)
The value above was produced by RK4 integration of the HULYAS
master equation on the inputs you supplied — NOT by evaluating the
operator formula printed above.
A dedicated closed-form solver is never overridden by the fallback — it only catches operators that would otherwise have no numerical answer. See the solvers for the coverage map (33 dedicated solvers; everything else routes here).
When a scalar cannot answer — honest refusal
Some operators cannot be expressed by a single number at all. For those the machine refuses and names what it needs rather than fabricating one:
| situation | example | what you get |
|---|---|---|
| a series / matrix is required | beta Cov/Var, portfolio variance, historical VaR; network clustering, PageRank, betweenness | value: null + "needs a return series" / "needs the graph structure" |
| a field / PDE is required | acoustic wave PDE, coupled-mode photonics | "use the ODE / field path (zeq_solve)" |
| the wrong input was supplied | de Broglie / E = hν given only a mass | names the input needed (p/v, f/λ) — computes correctly once supplied |
| the operator does not exist | a typo'd or invented operator ID | UNKNOWN_OPERATOR — never silently computed as if it were real |
Every refusal is surfaced by VERIFY and marked no-solution. A
neutral audit across all 1,606 catalogued operators finds a 100% honesty net: every
operator either computes a real value (closed-form or ODE fallback) or names exactly what it
needs. None fabricate.
Never guess a key name
Ask which inputs an operator takes:
curl -sX POST https://zeq.dev/api/zeq/operator-spec \
-H 'Content-Type: application/json' \
-d '{"operator":"GR37"}'
{
"solver": "solveGR",
"required": [{ "key": "M", "aliases": ["M","mass"], "note": "every answer from this solver needs it" }],
"conditional": [{ "key": "r", "aliases": ["r","radius"], "note": "required only by the operator that uses it" }]
}
No key required. Aliases are equivalent: {"mass": 1.989e30} and
{"M": 1.989e30} both give 2954.1266 m, and doubling the mass doubles the
radius exactly.
Migrating
valuemay benull. If your code does arithmetic on it, guard for that.- Check
inputErrorfirst. It names the missing quantity and every alias it accepts — usually the fix is one key. - Check
assumed. Present means the answer depends on something you did not supply. - A refusal is not a failure. HTTP is still 200; the envelope, the zeqond and the proof are all intact. It is an answer about your question, not about the machine.
Why
Never say "trust me" — every claim needs a zeqProof.
A proof over an invented input is worse than no proof: it makes a fabricated number look audited. The framework would rather return nothing than return something you cannot trace to your own data.