Five artifacts. Every byte accounted for.
An evidence claim you cannot re-derive is a story. This page specifies the five artifacts this program produces, byte layout and domain tag for each, and the exact command that recomputes them from the artifact alone — no server, no account, no trust in whoever handed you the file. If a recomputation does not match, the artifact is void. That is the only authority any of these have.
The artifact has to survive the company that made it.
The usual way to record a hardware transaction is a row in someone's system. That row is true for exactly as long as the system exists, the account works, and nobody with write access wants it to say something else. It cannot be checked by the counterparty, cannot be checked in five years, and cannot be checked at all if the company is gone.
So the record here is a file, and the file carries its own proof. Everything is SHA-256 over a canonically serialised body with a domain-separation tag in front of it. Canonical serialisation is RFC 8785 JSON Canonicalization Scheme, so that two implementations in two languages produce the same bytes for the same object and therefore the same hash (RFC 8785). The hash is FIPS 180-4 SHA-256 (FIPS 180-4).
Every hash in this program is SHA256(tag || JCS(body)), never
SHA256(JCS(body)). Without a tag, a body that happens to be
valid in two contexts produces one hash that means two things, and an attacker can
present a value computed for one purpose as if it were computed for another. The tag
makes each hash usable in exactly one place. There are six of them and they are listed
in full below.
| Tag | Covers | Defined in |
|---|---|---|
| SCGR1|rubric| | the grading source itself — pins which rubric a grade came from | grading.py |
| SCGR1|obs| | one party's observation sheet plus its hiding nonce | station.py |
| SCGR1|grade| | the derived grade bound to the rubric and the merged sheet | grading.py |
| SCDA1|commit| | a sealed price with its round, unit, party and role | attestation.py |
| SCDA1|record| | one entry in the append-only chain | attestation.py |
| SCST1|policy| | the settlement policy, frozen before any reveal | station.py |
One rule, applied five times.
# every artifact in this program digest = SHA256( TAG || JCS(body) ) # JCS: keys sorted by UTF-16 code unit, no whitespace, # integers only — no floats anywhere in any body JCS({"b":2,"a":1}) -> {"a":1,"b":2}
Two constraints do more work than they look like they should. No floats: every quantity is an integer — cents, basis points, percentage points, counts — because floating-point serialisation is not reproducible across languages and a canonical form that is not reproducible is not canonical. No optional fields: a body either has a key or the artifact is malformed, so two implementations cannot disagree about whether an absent key means false or means unknown.
Ordering is the third constraint and it is the one enforced at runtime rather than in the format. Artifacts 1 and 2 must both exist before artifact 3 can be created at all, and the test station lets you try to violate that and watch it refuse.
Layout, tag, and the command that checks it.
Observation sheet
SCGR1|obs|What one person, or one script, saw on one machine. Sixty-six fields, all of them counts against a defined threshold or readings taken off the hardware. Each party produces one and seals it before either can see the other's — that is the commitment in phase one of the protocol.
obs = 66 fields — 37 bool, 23 int, 4 enum, 1 list, 1 str nonce = 32 random bytes, hex # hiding: without it a sheet is guessable rubric = "91ffd026…a336f79" # SHA256(SCGR1|rubric| || grading source) sheet_hash = SHA256( "SCGR1|obs|" || JCS({obs, nonce, rubric}) )
The rubric field inside the sheet is what stops a sheet from
being replayed under a different rubric version. Change one threshold in
grading.py and every previously sealed sheet stops verifying
against the new one, loudly, which is the correct behaviour.
The nonce is not decoration. A used-laptop observation sheet has a small enough space of plausible values that an adversary holding only the hash could enumerate it. Thirty-two bytes from a CSPRNG makes that infeasible (NIST SP 800-90A r1).
Station.reveal_sheet — recomputes and compares in constant timeGrade binding
SCGR1|grade|The artifact that makes the grade a fact rather than an opinion. It binds three things that cannot afterwards be separated: which rubric was used, which merged observation sheet it was applied to, and what came out.
grade = 11 keys exactly — f, c, s, tier, code, defect_load, battery_health_pct, f_label, c_label, s_label, tier_label rubric = rubric_hash merged = the conservative merge of both sheets grade_token = SHA256( "SCGR1|grade|" || JCS({grade, rubric, merged}) )
Exactly eleven keys. Anything the interface adds for display — the human-readable reasons a grade came out the way it did, for instance — is outside the hashed body. A display field that leaks into the token would make two honest implementations produce different tokens for the same grade, and the browser grader on this site fails its own self-check if that ever happens.
The merge is conservative: pointwise worst of the two sheets. Where the parties disagree, the resulting grade is never better than either party observed. That is a deliberate asymmetry — it means the sealed-sheet mechanism cannot be gamed by optimistic reporting, only by pessimistic reporting, which costs the reporter money.
Station.publish_grade, after both reveals reconcilegrading.py — re-derive from the two sheets, re-hash, compareSettlement record
SCDA1|commit|Two sealed prices and the arithmetic that turns them into one number. Each side commits first; neither can move after seeing the other. The commitment body carries enough context that it cannot be lifted into a different round, a different unit, or attributed to the other party.
protocol = "sovereign-circuit/dual-attestation/1" round_id # this round only asset_id # this unit only party_id # this party only role = "holder" | "inspector" amount_cents # integer. never a float. never a string. grade # the published grade_token — binds price to condition nonce = 32 bytes, hex commitment = SHA256( "SCDA1|commit|" || JCS(body) )
Five of those eight fields exist only to prevent replay. Strip
round_id and a commitment from last month is valid today;
strip role and either side can claim the other's number; strip
grade and the whole ordering guarantee collapses, because a
price sealed before the grade existed would still verify.
Settlement is then a pure function of the two amounts and a policy hash frozen before either reveal. Inside the tolerance band it is the midpoint, with a bonus when both sides independently verified condition. Outside the band it escalates to a published index rather than to negotiation. All rounding is half-up on integer cents, and the divisor for the spread is the lower of the two amounts, so the spread is measured against the more conservative valuation.
verify_reveal — constant-time comparison against the published commitmentCustody log
SCDA1|record|An append-only chain covering everything that happened to a unit: received, graded, wiped, configured, placed, failed, replaced, recovered. Each entry commits to the previous entry's hash, so an entry cannot be inserted, removed or reordered without changing every hash after it.
prev # entry_hash of the previous entry; genesis for the first seq # 0, 1, 2, … — checked against position, not trusted body # the event itself entry_hash = SHA256( "SCDA1|record|" || JCS({prev, seq, body}) )
Verification walks the chain from genesis and checks three things per entry: that
prev equals the running head, that
seq equals the index, and that the recomputed hash matches the
stored one. Any single failure fails the whole chain — there is no partial credit,
because a log that is trustworthy up to entry forty is not a trustworthy log.
This is the structure behind every append-only transparency log, and the honest thing to say about the version here is what it does not yet have. There is no third-party timestamp, so the chain proves order but not date (RFC 3161 is the intended remedy). There is no Merkle inclusion proof, so a verifier must hold the whole chain rather than a proof about one entry (RFC 6962 is the intended remedy). Both are named gaps, not oversights.
Chain.append, once per custody eventChain.verify — full walk from genesisEvidence pack
SNEC/1.0 → SNEV/1.0The one artifact that is not about a price. An evidence pack is what a security claim looks like when it has to be checkable: a collector runs on the machine, captures the specific state that would falsify the claim, and writes it out with a manifest. A separate verifier — written to be run by someone who does not trust the collector — reads the pack and reports pass or fail per check.
pack/ manifest.json # check ids, per-check verdict, collector version, hashes host/ # identity, OS build, patch level network/ # interfaces, routes, listeners, egress reachability service/ # bind addresses — the air-gap claim lives or dies here storage/ # wipe standard + certificate id, SMART readings tailnet/ # device approval, lock state, ACL grants in force
The verifier is deliberately a separate program by a separate path. A collector that reports its own success is a log, not evidence. This split is also how the false positive described on the doctrine page was found: the verifier was itself tested, one check was flagging a healthy configuration as a failure because of how a command formats its output, and a verifier that cries wolf is worse than no verifier at all.
Two rules are hard-coded because they are the two ways a private network accidentally
becomes a public one: a service is never bound to
0.0.0.0, and the tailnet is never exposed with
funnel
(Tailscale Funnel — which is exactly
the feature that makes a node reachable from the open internet). A pack that shows
either fails, and no amount of other passing checks compensates.
Nothing here needs our permission to check.
Two of the five formats can be verified from this page right now, with no download and no account. The rubric hash is recomputed in your browser when the grader loads, and it fails visibly if it does not match the value published in the specification. The eight settlement vectors are replayed in your browser when the station loads, against an independent JavaScript implementation of the same arithmetic — if the two implementations ever disagree, the page says so instead of hiding it.
Every hash on this board was computed over a synthetic observation sheet. The formats are fixed, the arithmetic is pinned, the guards refuse correctly — and not one real machine has been graded by two real people. Until that happens, this page specifies a format rather than documenting a practice, and it should be read that way.
The three things that would change that, in order:
- One unit, two graders, independently. Produces the first two real observation sheets and the first real reconciliation — including, most usefully, the first real disagreement.
- One collector run on a real node. Turns the evidence-pack format from a specification into an artifact somebody can fail.
- One batch of about twenty units. Turns the calibration thresholds from defensible guesses into numbers with a distribution behind them. Which thresholds →