@flashyos/verify
v0.4.0
Published
Re-verify every sealed settlement on the FlashyOS network: fetch the public feed, recompute each sha256, exit 0 only if the books check out. Verify, don't trust — including us.
Maintainers
Readme
@flashyos/verify
██
██
██████
██
██
██Don't trust us. Check. FlashyOS publishes every settled cross-org collaboration as a frozen canonical payload plus its sha256 — this package is the ~200 lines that let anyone on earth verify we aren't lying:
npx @flashyos/verifyfetches the public settlement feed,
recomputes every hash, and exits 0 only if the whole record checks out.
Run it in your CI. Run it before you trust a number we publish. That's what
it's for.
The rule
sha256(settlementPayload) === settlementHashPayloads are JSON with keys sorted at every level, frozen at resolution time and never recomputed from live rows. The verifier also refuses a payload that is self-consistent but not in canonical form — the shape a re-serialize-and-re-hash forgery would take.
As a library
import { verifySettlement, verifyNetwork } from '@flashyos/verify';
const results = await verifyNetwork(); // the live public feed
const one = verifySettlement(record); // pure, no network
// { ok, claimed, recomputed, canonical, ... } — per record, never aggregateZero dependencies: node:crypto and fetch. Fork it, pin it, rewrite it
in your language of choice — the rule is one line, and the point of this
package is that you don't have to take our word for the other 199.
In a browser
@flashyos/verify reaches node:crypto for its digest, so a client component
importing the package root dies in the bundler. The browser gets its own door:
import { verifyNetwork, verifySettlement } from '@flashyos/verify/browser'
// Every function is async, for one reason: crypto.subtle is.
const results = await verifyNetwork()Same canonicalization, same rules, same verdicts — the digest is computed by
WebCrypto instead of Node, and browser.test.ts hashes the same inputs through
both and fails if a single byte differs. There is no second implementation of
sha256 here, because two implementations of the seal is exactly the drift that
would make honest records look forged.
crypto.subtle needs a secure context. Over plain http the digest throws with
a message saying so, rather than returning something a page would render as a
verdict.
This entry exists because it was missing. flashynetwork.com told readers to run
npx @flashyos/verify on five pages and imported none of it — the property
whose whole argument is check us could not check itself in front of a reader.
Validating a handshake
Any org on the mesh serves a discovery document at
/.well-known/flashyos.json — who it is, what it can do, what it wants,
and how to join. This package validates it:
import { validateHandshake, WELL_KNOWN_PATH, type Handshake } from '@flashyos/verify';
const res = await fetch(`https://goldrush.example${WELL_KNOWN_PATH}`);
const { valid, errors } = validateHandshake(await res.json());
if (!valid) console.error(errors); // every error names the field and the ruleA minimal valid document is just mesh (the literal "flashyos/1") and
org (slug + name); capabilities, wants, api, and join are
optional, and unknown top-level keys are allowed and ignored — forward
compatibility is part of the contract. The same contract ships as a JSON
Schema at schema/flashyos.wellknown.schema.json,
so sites can serve it and non-TypeScript stacks can validate structure
without installing this package.
Verifying a receipt
The platform also seals a Portable Receipt for every completed initiative task — the same rule as settlements, canonical JSON + sha256 — so an agent can carry proof of its work anywhere. Verify one offline:
import { verifyReceipt, RECEIPT_VERSION, type Receipt } from '@flashyos/verify';
const { valid, errors } = verifyReceipt(payload, hash);
if (!valid) console.error(errors); // every error names the field and the ruleA flashyos/receipt/1 payload carries receipt (the literal
"flashyos/receipt/1"), taskId, initiativeId, initiativeName,
orgSlug, title, evidenceUrl (https), completedAt (ISO-8601), and
optionally evidenceNote — the key is simply absent when there is none.
Unlike the handshake, unknown keys are rejected: a receipt is a sealed
attestation, not an extensible document. The hash comparison is
case-insensitive; everything else is exact.
Who did the work: agentName or completedBy
Exactly one of the two is present. agentName is the machine that did it;
completedBy is a person, as an identity id — person/michael — which
resolves in the directory the estate publishes, so "who completed this" has
a checkable answer rather than a display name that means nothing to the
counterparty reading it. A receipt carrying both, or neither, is refused.
Pin @flashyos/verify at ^0.4.0 if you verify receipts a person
completed. The contract version does not move for this — every receipt
sealed before it is valid here byte for byte — but the package version
does, because a verifier published earlier rejects a person receipt as
missing agentName. A contract version says what shape a document is; a
package version says what will refuse it. PERSON_DOER_SINCE is exported
so the figure can be read from code, and a test asserts this README and
that constant agree.
What this package refuses to contain
No API keys, no private feeds, no way to write anything. A verifier that can also publish is a conflict of interest in an npm tarball.
⚡ The Strike
sha256: e0f4fdca786e76baab90d7cb08fd0f61fac5b7c09a2d78a3e06a9150b04a8424The preimage is the rule, exactly as this README states it — one line, no
trailing newline. Verify it yourself (you have the tool for that now), then
open an issue titled ⚡ STRIKE with the preimage. And run the CLI against
a fully green feed at least once: the last line it prints is only ever
earned, never configured.
License
Apache-2.0. The rules are open; the network that seals settlements live is a product. Verify ours, run your own.
