Nuts and Bolts
Who hands in what, which parts come from an AI, what arithmetic runs on the numbers, and how all of it turns into one of three answers: hold, fold, or go forward. Written so a tenth grader can follow it, with the real tables underneath.
Imagine you are about to spend four million dollars on a shipment, and seven facts have to be true for that to be a good idea. Some of those facts come from a testing lab that measured them. Some come from a computer model that estimated them. Some come from the seller, who has an obvious reason to sound confident. And some are just… missing, though a summary written by an AI made it look like they were covered.
Corobate does one thing: it makes you label where every fact came from, scores each one, and then refuses to let the whole decision look stronger than its weakest necessary fact. Then it seals that record so nobody — including you — can quietly change it afterward, and so anyone else can re-run the same arithmetic on their own computer and get the identical answer. The output is a receipt. Not a log entry that says "approved." A receipt that shows the work.
Every input on a receipt carries an originator id. You can always tell who or what produced a number, and what class of trust that origin is allowed to earn.
| Originator | ID recorded on the receipt | What it contributes | Best class it can earn | Why it's capped there |
|---|---|---|---|---|
| The human decision-maker (a buyer, an underwriter, a compliance lead) |
actor:human:dokoro@meridiangrid.example |
The question being decided, which fields are required, the pass/caution thresholds, and any judgment note | seller-asserted for their own claims | You do not get to grade your own homework. A person can set the policy but cannot self-certify a fact. |
| An AI model (a sourcing copilot, a document-extraction model, an LLM summarizer) |
actor:ai:sourcing-copilot/v4 · prompt_sha256:9f2c… |
Values pulled out of PDFs, draft summaries, suggested classifications, risk narratives | modeled — never verified | A model produces a plausible answer, which is not the same as a measured one. Confident wording earns nothing. |
| An accredited test lab | actor:org:LAB-DE-0447 · report:TR-88214 |
Measured values plus a report number that can be looked up in the accreditation register | verified | Someone independent physically measured it and put their accreditation behind the number. |
| A certification body (e.g. an ISO 14067 verifier) |
actor:org:TUV-SUD-0036 · cert:CFV-2026-1188 |
A verification statement, keyed to a certificate ID | verified — only if the ID checks out | The certificate number is checked against the issuer's public register. No register hit, no verified class. |
| The seller or supplier | actor:org:VOLTCORE-DE-8812 |
Declared specifications, datasheet values, self-reported percentages | seller-asserted | They may well be telling the truth. They also have an interest in the answer. The receipt says so out loud. |
| A government or registry feed | actor:sys:eu-eprtr · fetched:2026-07-07T14:12Z |
Published datasets, filings, registration status | verified | Public, addressable, re-fetchable by the person checking your work. |
| A sensor or telemetry stream | actor:sys:bms-fleet-telemetry · device:BMS-7741-Q2 |
Directly measured readings with their own timestamps | verified while fresh | A real measurement — but a real measurement from eleven months ago is a memory, not a reading. Age caps it. |
| Nobody | — | Nothing. The field is empty. | missing | A blank is recorded as a blank, with a reliability of zero. It is never quietly skipped. |
Five delivery paths. All five end in the same place: a labeled, timestamped input record.
| Path | Used by | What it looks like | What the engine records |
|---|---|---|---|
| 1. Intake form | Humans | A web grid: one row per required fact, with a value box, a class dropdown, an evidence-source box, and a date | The typed value, who typed it, when, and the class they chose (which the engine may downgrade but never upgrade) |
| 2. Document upload | Labs, certifiers, suppliers | A signed PDF or test report; values extracted, then the report/certificate number resolved against the issuer's register | The value, the document hash, the register lookup result, and the resolution timestamp |
| 3. Allowlisted fetch | Registries, government feeds, ERP systems | A pull from an approved URL, mapped into fields by a field map — configuration, not code | The URL, the fetch time, the field map version, and a cache/freshness state |
| 4. Streaming telemetry | Sensors, fleet systems, BMS | A live feed of readings with device IDs and observation times | The reading, the device id, the observation time, and whether it was inside the freshness window |
| 5. In-process SDK call | AI agents, host applications | A function call from inside your own application; nothing leaves your network | The model/agent id, the input values, and a MODELED class stamped automatically |
In the live battery demo, path 1 is the editable grid you see on screen, and every row you edit is written to a visible file you can open. That is deliberate. If you cannot see the inputs, the receipt is just a different kind of black box.
Seven operations. Each one is arithmetic you could do on paper, which is the point — anyone can check it.
Class determines the starting reliability. These are the defaults; a policy can tighten them but not loosen them past their class.
| Class | Starting reliability | Stored internally as | In plain words |
|---|---|---|---|
| verified | 0.95 | 9500 bp | Someone independent checked it and you can go check them. |
| modeled | 0.80 | 8000 bp | Calculated or estimated from other things. Good, not measured. |
| seller-asserted | 0.50 | 5000 bp | An interested party said so. |
| missing | 0.00 | 0 bp | Nothing there. |
Why "bp"? Reliability is stored as a whole number of basis points (hundredths of a percent) rather than a decimal. Decimals drift between programming languages and processors — 0.1 + 0.2 does not equal 0.3 on most computers. Whole numbers don't drift. That is what makes a receipt built on our machine reproduce on yours.
Where it doesn't hold yet. The discipline is not applied everywhere. The canonical encoder writes a number using whatever formatting its own language produces, so Node and CPython disagree on a value like 0.000001 — and the recalibration receipts carry rounded floats, not basis points. Row sort order diverges too, when an astral-plane name meets a name in U+E000–U+FFFF: JavaScript sorts by UTF-16 code unit, CPython by code point. Our CPython port matches the JavaScript one exactly on all twelve seeded parity vectors, which are built to keep those two cases apart, and would not match on either of them. Carrying every number as an integer in fixed minor units is the fix; it changes the hash of every receipt ever issued, which makes it a versioned break rather than a patch, and it has not been made. We would rather you read this here than discover it.
If an input is older than the freshness window for its field, its reliability is capped at 0.40 no matter how good its class was, and a named reason is written down.
Any input observed after the decision's cutoff time is rejected outright. This is what stops a receipt from being quietly improved later with information nobody had at the time — the single most common way "we did our diligence" turns out to be false.
Sometimes reliability isn't a class default — it's earned from history: "this source has been right 9 times out of 10." Corobate does not use 9/10 = 0.90. It uses the Wilson lower bound, which asks a harder question: given only ten tries, how low could the true success rate plausibly still be?
| Track record | Naive rate | Wilson lower bound (95%) | What it's telling you |
|---|---|---|---|
| 9 right out of 10 | 0.90 | 0.60 | Ten tries isn't much. Don't bet like it's 90%. |
| 90 right out of 100 | 0.90 | 0.83 | Same percentage, ten times the evidence, much stronger claim. |
| 900 right out of 1000 | 0.90 | 0.88 | Now the sample is big enough that the discount nearly disappears. |
The plain-English version: a good record built on a handful of tries is not the same as a good record built on a thousand. Averages hide that. The Wilson bound refuses to.
Only the inputs marked sufficiency-critical count toward the verdict. The default combining rule is the minimum. Two other rules are available, and all three share one property: adding a weaker input can never raise the score. (Mathematicians call that monotone. Everyone else calls it "no laundering.")
Here is the real battery example from the demo. Five facts are marked critical:
| Critical input | Class | Reliability | Where it came from |
|---|---|---|---|
| Carbon footprint | verified | 0.94 | ISO 14067 verification, certificate resolved |
| Hazardous substances | verified | 0.96 | Accredited lab, REACH screening |
| Cobalt origin | modeled | 0.72 | Book-and-claim mass balance, not physical traceability |
| State-of-health algorithm disclosure | missing | 0.00 | Never supplied |
| Renewable energy share in manufacturing | missing | 0.00 | Never supplied |
Fill in the two blanks with verified evidence and re-run — nothing else changes:
Then get real physical traceability on the cobalt (0.93 verified) instead of a book-and-claim allocation:
Notice what just happened: the receipt told you exactly which one thing to go fix to move the verdict. That's the operational payoff. "Confidence 0.61" tells you nothing. "Bound by cobalt origin, because it's a book-and-claim allocation" tells you what to buy, ask for, or walk away from.
| Combining rule | On the same five numbers | Character | When you'd choose it |
|---|---|---|---|
| Minimum (default) | 0.72 | Weakest link governs; other inputs are ignored once the floor is set | Safety and compliance gates, where one failure is a failure |
| Product | 0.59 | Strictest — every weakness compounds (0.94 × 0.96 × 0.72 × 0.95 × 0.95) | Chains where each step must independently hold, like custody transfers |
| Soft-minimum | just under 0.72 | Mostly the minimum, pulled a little lower when several inputs are weak at once | Portfolio scoring where "three mediocre inputs" should rank below "one mediocre input" |
The thresholds are written on the receipt before the answer, so nobody can move the goalposts afterward.
Alongside the verdict the receipt lists every coverage gap by name, every seller-asserted claim by name, and — if it abstained — the specific reason code (stale field, excessive age, failed freshness, unverified source, source outage). Refusing to answer is a first-class result, not an error.
Now the record is frozen. Three separate mechanisms, each protecting against a different kind of after-the-fact story.
| Mechanism | Stops this story | How you'd catch it |
|---|---|---|
| Canonical encoding + SHA-256 | "We never changed that number." | Recompute the hash. One altered character changes it completely. |
| Hash chain | "That receipt was always in the file." | Every later receipt's link breaks if an earlier one is edited or reordered. |
| RFC 3161 anchor | "We had that evidence at the time." | A timestamping authority outside your control signs the chain head. Your clock isn't part of the argument. Status: the public demo ships a self-signed demonstration token, labelled as such; production anchoring is a configuration. |
| Cross-machine reproduction | "You'd have to trust our software." | The auditor re-runs the arithmetic on their own hardware, running none of our code, and gets the identical hash. |
The complete pipeline, in order, with the standard behind each step.
The "Written against" column names the specification passage each operation was written against, in a filed application whose claims have not been examined. It is a reading aid, not an examined claim-to-code correlation, and no inference about claim scope should be drawn from it.
| # | Operation | Tool / algorithm | Written against | What it prevents |
|---|---|---|---|---|
| 1 | Admit & classify | Four-class provenance labeling; unlabeled inputs rejected | Claim 1, 2 | Unsourced numbers entering the record |
| 2 | Resolve citations | Register lookup on certificate / report IDs | Claim 1 (verified class conditions) | Fabricated or unresolvable references |
| 3 | Freshness check | Age comparison; cap at 0.40; named reason | Claims 6, 23 | Stale data presented as current |
| 4 | Point-in-time gate | Reject observed_at > period_end | Claims 10, 27 | Hindsight quietly improving the record |
| 5 | Score | Class tier, or Wilson score lower bound on a track record | Claims 4, 26 | Small-sample overconfidence |
| 6 | Aggregate | Monotone function: minimum, soft-minimum, or product | Claims 3, 34 | Averaging a weak link out of existence |
| 7 | Decide | Threshold comparison, thresholds sealed in advance | Claim 29 | Moving the goalposts after the fact |
| 8 | Abstain | Named abstention reason codes | Claims 5, 6, 33 | Silent guessing when evidence is thin |
| 9 | Encode | Type-tagged, byte-length-prefixed injective encoding (attest-canon/2); integers in fixed minor units | Claims 1, 15, 21 | Two different input sets producing identical bytes; float drift across machines |
| 10 | Hash | SHA-256 | FIPS 180-4 | Undetectable edits |
| 11 | Chain | Append-only hash chain (Merkle tree / authenticated dictionary also supported) | Claim 7 | Reordering, backdating, silent deletion |
| 12 | Anchor | RFC 3161 time-stamp token over the chain head | RFC 3161; claims 8, 25, 44 | Disputes about when the record existed |
| 13 | Prove inclusion | Ordered path of entry hashes recomputed by the verifier | Claims 1, 22 | Having to trust the vendor's word |
| 14 | Reproduce cross-machine | Independent re-derivation on a different architecture, running none of our code | Claims 1, 22, 30 | "It only verifies inside their system" |
| 15 | Recalibrate | Post-hoc backtest with Benjamini–Hochberg false-discovery-rate control | Claims 38, 39 | Tuning your criteria to random noise |
| Field on the receipt | Who supplies it | Who derives it |
|---|---|---|
decision_id, question, domain | Caller | — |
critical[] (which fields are required) | Caller's policy | — |
threshold_approve, threshold_caution | Caller's policy | — |
inputs[].value, .provenance, .source, .observed_at | Caller / originator | Class may be downgraded by the engine, never upgraded |
inputs[].reliability | — | Engine (class tier, freshness cap, Wilson bound) |
confidence.value, bound_by | — | Engine |
verdict, reasons[], coverage_gaps[] | — | Engine |
receipt_hash, chain.entry_hash, anchor | — | Engine + external timestamping authority |
A verdict is not a decision. It's the input to one. Here's the mapping that turns a number into an action.
| Receipt says | And the missing evidence is… | Your move | What it looks like in practice |
|---|---|---|---|
| withheld | obtainable — the supplier has it, it just hasn't been produced | hold — abstain | Pause the release. Issue a named evidence request with a deadline. The receipt is the request: it names exactly which field, why it failed, and what class would clear it. |
| withheld | not obtainable — it doesn't exist, or the counterparty won't produce it | fold — walk away | Re-source. The receipt documents that you asked, what was refused, and when — which is the difference between a business decision and a later allegation of negligence. |
| caution | present but weak — modeled or seller-asserted where you wanted verified | go, with conditions | Proceed on a smaller commitment: staged release, holdback, contractual representation naming the weak field, or an added inspection at receipt. |
| approve | nothing critical is weak | go forward | Full commitment. And a sealed record showing the basis, so that if it goes wrong anyway, the question is "was the process sound?" — which you can answer. |
See the whole thing play out with names, dates and dollar figures in the exemplary scenario.
U.S. Patent Application No. 19/747,068 — patent pending. Four independent claims, each covering a different way the same idea gets used. Below: what each one says, in ordinary language, and where you can see it on a receipt.
| Pending claim (as filed) | What it covers, plainly | Where you see it |
|---|---|---|
| 1 system | The whole machine: take in evidence from several different sources, force each one into a provenance class (and reject anything unclassifiable), write it down in an unforgeable format, score it so the result is capped by the weakest necessary input, seal it before the outcome is known, and let an outsider re-derive the whole thing on a different kind of computer without running any of your software. | Every receipt. The inputs[] block, confidence, bound_by, and the fact that the browser verifier reproduces the hash. |
| 22 method | The same sequence described as a set of steps rather than as a machine — so it's covered however it's deployed. | The five-step process in the demo. |
| 30 SDK | Doing all of it from inside somebody else's application, as an embedded kit that hands back the proof through an API. Claim 31 adds: without any input value ever leaving the host's network. | The integration path in For Technicians. |
| 38 flywheel | Learning from what actually happened afterward — measuring which inputs really predicted outcomes, keeping only the signals that survive a statistical test for false discoveries, and applying the new weights only going forward, so old sealed receipts still reproduce exactly as issued. | Backtests and recursive improvement. |
And the dependent claims that carry most of the day-to-day behavior:
| Pending claim (as filed) | In plain language | The failure it addresses |
|---|---|---|
| 3, 34 | The combining rule must be minimum, soft-minimum, or product — all of which are "monotone," meaning adding a weaker input can never raise the score. | Averaging: three strong numbers hiding one fatal one. |
| 4, 26 | Reliability earned from a track record uses the Wilson score lower bound, not the raw success rate. | "Nine out of ten" sounding like ninety percent certainty. |
| 5, 23, 33 | Abstaining is an explicit, recorded, sealed result with a named reason — not an error and not a blank. | Systems that guess rather than admit they don't know. |
| 6 | The named reasons include stale field, excessive age, failed freshness, unverified source, and source outage — and the verifier reproduces the outage reason from the sealed entry. | A data feed going down and the system silently substituting something older. |
| 7, 44 | The tamper-evident structure can be a hash chain, a Merkle tree, or an authenticated dictionary; the anchor can be a hash-chain ledger, an RFC 3161 authority, a trusted-execution-environment attestation, or a zero-knowledge inclusion proof. | Lock-in to one vendor's ledger. |
| 8, 25 | The head of the chain gets timestamped by an outside authority whose token independently reproduces that head. | Backdating. |
| 9, 35 | The engine's version number is sealed into the record. | "We ran that on a newer version" — you can't, the version is in the hash. |
| 10, 27, 40 | The point-in-time rule: nothing dated after the decision's cutoff may enter the record. | Look-ahead. The most common way a backtest lies to you. |
| 15, 21 | The encoding is injective: duplicate field names are rejected, and no value containing a delimiter can be arranged to produce the same bytes as a genuinely different set of inputs. | Smuggling a different meaning into an identical-looking record. |
| 17, 18 | When the engine updates itself, the update only ships if a battery of tests reproduces byte-identically against a sealed baseline manifest — otherwise it's disqualified, naming the changed files. | An engine change quietly altering how past decisions would score. |
| 29 | The attestation certificate carries an unqualified, qualified, or withheld opinion, and a qualified opinion is mandatory whenever a critical finding is seller-asserted, stale, or absent — naming each unverified finding. | Clean-looking sign-offs resting on unverified claims. |
| 42, 43, 45 | Even a cryptographically perfect computation proof (a secure-enclave attestation or zero-knowledge proof) does not lift the weakest-link cap — and only counts as verified if it actually binds to the chain head. | Impressive cryptography being used to launder weak underlying data. |