Hi,
Two millers get the same order. One sack of wheat, two sacks of barley. Each stacks the sacks in his own corner of the warehouse, winds a cord around the stack and presses a wax seal over the knot.
Both stacks hold the same grain. Both seals are intact. And the two seals do not match, because wax is pressed over an arrangement, never over the cargo.
A month later the merchant opens his ledger, sees a seal that does not fit, and concludes somebody tampered. Nobody did. The wax cannot tell a thief from a miller who stacked the barley first.
Every hash in decentralized AI is that wax, and the system reading it has no judge, only a notary. So what is a notary supposed to say when the seal does not fit?
Listen:
Apple Podcasts: https://podcasts.apple.com/kg/podcast/plain-strata/id6783455764?i=1000796915791
YouTube: https://youtu.be/d9Os_m0LTps
The full piece, no need to click through:
On 2 October 2026 a cloud provider shipped a gate. DigitalOcean's Managed Agents puts more than sixteen thousand tools behind one endpoint and holds sensitive operations until a person approves them. Picture what that gate is for. A piece of software wants to buy a dataset. The gate stops it, renders the request for a human, and waits. The human reads a small block of text: who is selling, which dataset, how much money. They click approve.
The block of text the human read and the block of bytes the machine then executes are not necessarily the same object. They can differ by a space after a colon, or by whether the amount was printed as one hundred or as one hundred point zero. No attacker is involved. The person approved what they saw, the machine ran what it was handed, and the signature around the approval checks out against one of those and not the other.
A fingerprint is taken over bytes. It is never taken over meaning.
It is the floor under every instrument this field has built for checking work it did not do itself. A hash, which is what people mean when they say fingerprint, works like this: run any block of numbers through a fixed grinder and out comes a short value that changes completely if one bit of the input changes. That property is why the field loves it, and why the metaphor misleads. A real fingerprint identifies a person through a change of clothes, a haircut, twenty years. A hash identifies one string of bytes. Change a space and it is a different person.
So the moment a protocol writes the hash of a document somewhere and expects anyone to re-derive it later, that document's exact printing becomes as load-bearing as the choice of signature algorithm. And if the specification never said which printing, that field gets filled in by accident, differently, by each implementation, in the order they happen to be written.
A model runs for forty minutes on somebody else's machine and produces a record of thousands of steps. Putting that record on a public ledger is absurd on cost alone, because a ledger is a shared spreadsheet that nobody is allowed to lie to and everybody keeps a copy of. So the ledger holds a small fixed-size value derived from the work, and anybody who later wants to argue re-derives that value and compares. That is one instance of a shape running through the whole field: the chain cannot see the world directly, so it hires a stake-weighted, economically constrained set of observers to look at the world for it. The ledger is a notary rather than a judge. It certifies who said what and when, and takes no view on whether it was fair.
The small value is called a commitment. Publishing it commits you: you can prove later that you had this exact thing earlier, and you cannot quietly swap it, because the grinder would emit something different. A training run publishes one per step so a stranger can replay that step and compare, and a registry of software agents stores a pointer to a description file plus a hash of it. All of this rests on an assumption nobody writes down: that two honest parties handing the same document to the same grinder get the same answer back.
Canonical comes from the Greek kanon, a measuring rod, a carpenter's straightedge. From the rod it became the rule, and from the rule the list of things the rule admits, which is how we get the canon of scripture, the books that passed a standard. That history corrects the engineering instinct. A canonical form is not the correct form. It is the form the rod happens to admit, somebody picked it, and the arbitrariness costs nothing as long as everyone measures against the same stick. Half the confusion here comes from hearing canonical as proper, then arguing about which form is better, when the only property that matters is that there is one.
Serialize comes from the Latin series, a row or a chain, from serere, to join. To serialize is to take something with shape, a map, a tree, a graph, and lay it out as a single row so it can travel down a wire. The whole problem sits inside that word. A map has no row. It is a set of pairs with no order among them, so laying it in a row requires a choice that is not present in the data. Serialization adds information, and the added information is not part of what you meant but is part of what you hashed.
Go back some centuries, to a mill. Two millers receive the same order. One sack of wheat, two sacks of barley, held for a merchant who collects next month. Each stacks the three sacks in his own corner of the warehouse, winds a cord twice around the stack, and presses his wax seal over the knot. If anybody opens the stack, the wax cracks.
Miller A stacked the wheat on the bottom. Miller B stacked the barley on the bottom. Both stacks hold the same grain, both seals are intact, and the two seals are different physical objects, because a seal is pressed over an arrangement and not over a cargo. If the merchant's book records miller A's impression and he checks it against miller B's stack, the impression does not match, and the honest conclusion from the evidence in front of him is tampering. Nothing was tampered with. The grain is fine. The arrangement differed, and the wax cannot tell him which of those two things happened.
The cargo is the logical document, the field names and values, the thing the two parties agree about. The arrangement is the serialization, the stacking order and the turns of the cord, none of it in the merchant's order and all of it in the wax. The seal is the hash: it touches the cord and the fold, and it cannot know that stacking order was just logistics, because from where the wax sits there is no such category. So the mill writes a rule. Wheat on the bottom, cord twice around clockwise from the left, knot on top, then the wax. The rule makes the grain no safer and stops no thief. It makes the seal mean something to somebody who was not there, which is the only thing a seal is ever for.
The second failure in that warehouse is the one with teeth. Each sack carries a paper tag, and the clerk records the shipment by gluing the tags end to end into one strip and pressing the wax over the strip. The tags read WHEAT and 2BARLEY, so the strip reads WHEAT2BARLEY. A different shipment, tagged WHEAT2 and BARLEY, glues into an identical strip and takes an identical seal. The rule was followed, and two different cargoes share one impression. The fix is to write each tag's letter count in front of it. The count says nothing about grain. It says where one field stops and the next begins. One rule makes a seal reproducible, a second rule makes it unambiguous, and most protocols write only the first.
A validator receives a document and a commitment, grinds the document, and compares. The values differ. Ask what the validator actually knows, and the answer is close to nothing. It does not know the other party lied, because an honest party whose serializer orders fields differently produces exactly this evidence. It does not know its own machinery is broken, because the machinery is working perfectly. It does not know the document is wrong, because the document may be correct to the byte while the commitment was computed over a different printing of the same cargo. And it cannot separate any of those from a proxy in the middle that re-encoded the document in transit, which load balancers, gateways and logging layers do routinely and consider a courtesy.
That last one introduces a party verification designs keep leaving out. A failed check has two obvious owners, the thing being checked and the thing doing the checking. This one has a third: the path between them. The channel. A schema offering passed, failed, or could not check records a serialization disagreement as failed, which is a false accusation, or as could not check, which throws away the one detail that would let anybody fix it. The honest sentence is that the bytes I received do not grind to your commitment and I cannot tell which of us is wrong. Nobody has built a place to put it.
Take the smallest cargo, a record with two fields, and count its printings.
Field order first. The common document format for all of this, JSON, explicitly says its objects are unordered, so no printing is more correct than another. Then languages differ: Python keeps the order you inserted, Go deliberately randomizes it to stop you depending on it, JavaScript mostly keeps insertion order except that number-like keys get hoisted and sorted. The same program, translated, emits different bytes.
Whitespace second, the quiet killer. Indentation, newlines, a space after the colon, a space after the comma. Python's default writer puts a space after both, most other languages put neither, and that one difference changes every hash of every document any default-configured Python service ever signed.
Numbers third, and numbers are where it gets strange. JSON has one number type and sets no limit on precision, while nearly every implementation reads numbers into a sixty-four-bit binary floating point value and prints them back. So one, one point zero, and one point zero zero zero are three printings of one value, and whether they survive a round trip is a property of the library. Worse at the edges: that format holds whole numbers exactly only up to about nine quadrillion, so an identifier above that line can come back out as a neighbouring number. Which matters, because the main standard for fixing all of this, RFC 8785, the JSON Canonicalization Scheme published in 2020, adopts JavaScript's number model wholesale. A large integer therefore has no faithful canonical form, and the specification's own advice is to carry such values as text instead. So the canonical form reaches back up into your data design and tells you which shapes you are allowed to use. That is why this is a mechanism and not a detail: fixing the printing changes the document.
The rest stack up quickly. Text normalization survives every other fix: the letter e with an acute accent exists as one character and also as a plain e followed by a combining accent, same glyph, same meaning, different bytes, and nearly every canonicalization standard declines to handle it and says the layer above should, which means nobody does. Then duplicate field names, which parsers resolve by taking the first, taking the last, or refusing, so two implementations read one document as two different cargoes. And the encoding itself, including the byte order mark, three invisible bytes at the front of a stream, fatal to a hash.
The first answer is to canonicalize: define exactly one byte sequence per logical document and make every implementation produce it. That is RFC 8785, which sorts the field names, emits no whitespace, prints numbers by one named algorithm and escapes strings minimally. Its weakness is structural: every new implementation in every new language is a fresh chance for two parties to disagree, and the disagreement arrives as a signature failure at the worst possible moment, looking exactly like an attack.
The second answer is to stop canonicalizing and sign the bytes you actually saw. The cleanest version is DSSE, the Dead Simple Signing Envelope, out of work on software supply chains. The payload travels as an opaque parcel and the signature covers the parcel, so verification checks the signature first and reads the contents afterwards. Nothing is re-derived, so there is nothing to disagree about, and the cost is that the exact bytes must travel with the signature forever. Its encoding writes each field's length in front of it before joining them, which is the mill's second rule invented again.
The third answer is to use an encoding with one form by construction. Do not have many ways to print a number, have one. Ethereum's internal encodings work this way, which is why the machine at the bottom of that chain never had to argue about canonical forms: there is no optional whitespace in a fixed-width word. The hybrid worth naming is EIP-712, the typed structured data signing used by wallets, which does not canonicalize a document at all. It defines a type system, hashes each structure field by field in declared order, and binds the result to a separator naming the contract, the chain and the version. What a human is shown is only a display format, and the thing signed never existed as a document.
One meaning, many bodies, and a checker that can only see bodies.
Its hostile version is the look-alike domain name, two addresses that render identically and resolve to different servers. And it shows up one layer below all of this, in the arithmetic, because adding floating point numbers is not associative, so thousands of processor cores racing to sum the same values in a different order disagree at the far end of the decimals. Canonical serialization is that problem on the wire; reproducible arithmetic is that problem inside the chip.
Three properties hide inside the word canonical. Determinism: same implementation, same input, same bytes, weak and nearly free. Canonicality: every conforming implementation, same logical value, same bytes. Injectivity: no two different logical values produce the same bytes. Nobody asks for that one, and it has the teeth. Glue the fields a and l to ice underscore admin and you get alice underscore admin; glue alice to underscore admin and you get the same string. One hash, two cargoes, and whoever controls one field chooses which cargo the other party believes they authorized. That is also behind a rule in Merkle trees that looks arbitrary the first time you meet it. A Merkle tree is how one commitment covers thousands of items: hash the items, hash the hashes in pairs, repeat until one value sits at the top. Items and internal pairs must carry different markers, because otherwise an internal pair's hash is also a valid item hash and the same top value fits a tree of a different shape.
The rule that picks a canonical form is arbitrary. Sorting field names by one text encoding's code units is not better than sorting by another; it is what one committee wrote down. And that arbitrary choice is load-bearing for a structure whose entire selling point is that nothing has to be trusted. Underneath the cryptography and the economics there is a convention, and conventions hold only because people keep them. The measuring rod is the right image: its length is arbitrary, and a market with one rod is honest in a way that a market with two honest rods is not.
The sharper point is about meaning. Meaning does not survive transport. Only bodies do. Every verification instrument in this field checks bodies while talking about meanings, and the gap between the two is where every interesting failure lives. A checker sees what arrived. It never sees what was meant.
DigitalOcean's gate renders the call for a human: seller, identifier, amount, pretty-printed with indentation and a space after each colon, because a person has to read it. That rendering is a printing. Whitespace. The approval the gate signs is computed over the gate's own serialization rather than over the rendering, so if its writer and the executor's writer disagree about field order, or about whether one hundred carries a decimal point, the approval verifies against one printing and the executor runs another.
The money moves over x402, the agent payment protocol built on an HTTP status code reserved in the nineteen nineties for payment and left unused for twenty-nine years, governed since 14 July 2026 by the x402 Foundation at the Linux Foundation. Its second version carries a signature over the payment instruction in an HTTP header, which is the most hostile place in computing to carry exact bytes, because proxies fold whitespace, change case, re-encode, split and rejoin. The second answer earns its keep here: a signed parcel survives a tidy-minded intermediary, and a re-derived object does not, which makes every courteous proxy a denial of service.
The seller looks the buyer up in a registry of software agents: an entry on a chain pointing at a description file, plus a hash of that file. Re-fetching the file and re-grinding it is the only operation that makes that claim mean anything, and mostly it cannot be performed. A study published on 8 July 2026 found about 170,000 such registrations across three chains, with only three to fifteen percent exposing a valid file at a live address, which is usually told as a story about abandonment. It is also a story about fingerprints: an entry whose file cannot be fetched has a hash as its only remaining content, committing to a printing nobody can produce any more.
Then the dispute. The seller says the dataset never arrived properly, a validator fetches the record, grinds it, gets a mismatch, and that is the channel's failure or the other party's, with three available answers that cannot say which. And the amount and the recipient were two fields joined before hashing, so without a length in front of each, injectivity fails and a sibling pair of fields hashes identically, which is what EIP-712's separator is for. Every link in that chain is a place where a document two parties would call the same document has two bodies.
Whether a canonical form can be specified safely at all for a format with an unbounded number type, or whether canonicalizing is always a constraint on your data design wearing a serializer's clothes. The standard's own advice, to carry large integers as text, points at the second reading.
And a second: what a registry of checks should be allowed to say once the channel is admitted as a party that can be at fault. A notary who can say the document I was handed may not be the document you sent is doing something closer to judging, and this whole arrangement depends on the notary not judging.
The two voices are AI. The research and writing are mine.
Decentralized AI, layer by layer.
Dastan,
You just read issue #28 of Plain Strata. You can also browse the full archives of this newsletter.