# WoC Record Canonicalization — Recipe v1.0

This is the exact recipe that produces the bytes every WoC record signature
covers. It is the single-implementation canonicalization shared by the
signer (the kernel records-publish op), the server reader, and the browser
verify panel. This document restates it for an independent third party;
the shipped `verifier.mjs` implements it inline and proves the restatement
is byte-exact by verifying the shipped signatures.

## Algorithm

Given a record object (JSON):

1. **Exclude three fields** from the object, wherever present:
   - `signature` (it is what is being verified),
   - `signing` (metadata about the act, not the claims),
   - `derivation` (display metadata; the signature covers
     `dependency_manifest_sha256` instead).
2. **Sort object keys recursively** — every object's keys are sorted
   lexicographically (by UTF-16 code unit), at every depth. Arrays keep
   their order (order is meaning in a list; it is not meaning in a map).
3. **Serialize with `JSON.stringify` semantics** — no whitespace, no
   indentation, standard JSON escaping, `UTF-8` bytes.
4. That string is the **canonical form**. Numbers and strings serialize
   per `JSON.stringify` (double quotes, backslash escapes).

Everything else — including `public_key` (so the signature covers the
exact key the reader verifies against) and `dependency_manifest_sha256`
(the signed digest of the artifact/observation dependency manifest) — is
INSIDE the signed scope.

## Signature

- Algorithm: **Ed25519** (`node:crypto` `verify(null, digest, key, sig)`).
- The digest is **SHA-256 of the canonical form's UTF-8 bytes**.
- The signature is stored base64. The public key is embedded in the record
  as `public_key` (SPKI PEM) and must be recognized in `issuer-trust.json`
  (production store for production records; fixture store for fixtures).

## Worked example (the shipped fixture)

`fixture.json` (Example Dental, LLC, synthetic conformance fixture) under
this recipe yields canonical bytes whose SHA-256 is
`ac7d2ccf1e00993806b70036f2475395d7f661fc36b6e56e12c0a8a8155e3327`, and
`fixture.sig` verifies over exactly those bytes with the fixture key
(`woc-fixture-2026-09` in the fixture store). The shipped production
record `record-mo-dental-013494@2.json` yields canonical SHA-256
`9be5b7503f8105da5362c130814f3bc014da9a5f13f820cf5cacfa79b18b7ee8` and
verifies with `woc-int1-2026-09` (int1).

## Implementation pin (cross-repo law)

The implementation is a pure isomorphic ESM module shared verbatim between
two repos — `woc/lib/records/canonical-form.mjs` and
`acn-mcp-server/kernel/records_canonical_form.mjs` — pinned byte-identical
by posture tests in both repos at sha256
`96f8a27c76d9e91a762e18100f4bc8ec36492cd6360cce8adbbe0cf9239947fe`.
If any call site canonicalizes independently, every visitor would see a
false mismatch on our own proof pages — so the pin makes drift a red test
in either repo. This document and the inline implementation in
`verifier.mjs` are checked against that module by the same signatures:
if the restatement here were wrong, the shipped signatures would not
verify under it.