# Canonicalization Integrity verification in HEXT depends on deterministic serialization before hashing. ## Overview Before computing `state_hash` (`hext:Seal/@stateHash`), a `hext:Document` MUST be normalized to **Canonical XML**. The same document, regardless of insignificant formatting differences in the source file, MUST produce the same byte sequence after canonicalization. ## Canonical XML Rules Canonicalization MUST eliminate the following non-semantic differences: - Attribute ordering - Insignificant whitespace - Line-ending differences (CR, LF, CRLF) - Duplicate or reordered namespace declarations Implementations SHOULD use W3C Canonical XML (C14N) or an algorithm that produces equivalent deterministic output for the same logical document. ## State Hash The final seal stores the document integrity hash: | Field | XML attribute | Format | |---|---|---| | `sealed_at` | `hext:Seal/@sealedAt` | ISO 8601 UTC | | `state_hash` | `hext:Seal/@stateHash` | `sha256:` + 64 lowercase hex characters | Computation: ``` state_hash = SHA-256( CanonicalXML( hext:Document ) ) ``` The hash prefix `sha256:` is part of the stored value. ## Ledger Entry Hashes Each ledger entry carries a chain hash: | Field | XML attribute | Description | |---|---|---| | `t` | `hext:Entry/@t` | Unix timestamp (seconds) | | `type` | `hext:Entry/@type` | `AI`, `HUMAN`, `REVIEW`, `APPROVAL`, or `SYSTEM` | | `delta` | `hext:Entry/@delta` | Change magnitude (optional) | | `hash` | `hext:Entry/@hash` | Chain hash for this step | The integrity chain follows a one-way sequence: ``` [Genesis Content] (H_0) │ ▼ [Ledger Entry 1] (H_1 = SHA256(H_0 + Delta_1)) │ ▼ [Ledger Entry 2] (H_2 = SHA256(H_1 + Delta_2)) │ ▼ [Final Seal] (state_hash = H_n) ``` ## Deterministic Serialization Requirements Canonicalization implementations: - MUST be deterministic for a given logical document - MUST NOT mutate semantic content during normalization - MUST use the normalization rules associated with the document's declared specification version ## Grandfather Clause (Backward Compatibility) Canonical XML normalization applies **prospectively** to documents sealed under HEXT v2.1.0 and later. Documents sealed under earlier formats (including legacy Markdown-hosted `.hxt` v0.1.0) retain the hash rules valid at seal time. Verifiers MUST select normalization rules based on the document's declared version: - XML documents: `hext:Document/@specVersion` - Markdown-hosted documents: context from the metadata block or historical convention Verifiers SHALL NOT retroactively apply v2.1.0+ canonical XML rules to pre-v2.1.0 sealed objects. ### Legacy v0.1.0 Rules The reference implementations in `hxt.py` and `hxt.js` implement the v0.1.0 Markdown-hosted rules: 1. Remove any existing HEXT metadata block. 2. Use only the Markdown body above ``. 3. Trim trailing whitespace immediately before the marker block. 4. Compute SHA-256 on the normalized body bytes. These rules remain valid for all v0.1.0 documents. ## Verification Workflow 1. Parse the document (XML or Markdown-hosted). 2. Construct the Object Graph. 3. Select canonicalization rules by declared version. 4. Compute expected `state_hash`. 5. Compare with `hext:Seal/@stateHash` (or `final_seal.state_hash` in legacy form). 6. Verify ledger chain continuity. See [tools/validator/](../tools/validator/) for placeholder validation tooling. ## Further Reading - [SPECIFICATION.md — Integrity Chain](../SPECIFICATION.md#integrity-chain) - [Object Graph Model](object-graph.md)