<!-- Generated from sources/appendices/v1/appendix-canonical-form.aeon; do not edit. -->

<a id="appendix-canonical-aeon-form"></a>
# Appendix — Canonical AEON Form

**Appendix to:** AEON Specification v1

<a id="overview"></a>
## Overview

Canonical AEON defines a deterministic textual representation suitable for hashing, diffing, signing, and reproducible builds.

Canonical form is **optional** for parsing but REQUIRED for canonical emitters.

<a id="document-structure"></a>
## Document Structure

<a id="header"></a>
### Header

If no header exists, emit the default:

```aeon
aeon:header = {
  encoding = "utf-8"
  mode = "transport"
  profile = "core"
  version = "1.0"
}
```

Header fields sorted lexicographically.

<a id="top-level-order"></a>
### Top-Level Order

1. `aeon:header` first
2. All other bindings in lexicographic order

This ordering is not formatter-only advice:

- a structured header appearing after any body binding is invalid input;
- canonicalization MUST reject such input rather than reordering it into a valid document.

<a id="keys-and-objects"></a>
## Keys and Objects

- Object keys sorted lexicographically
- Attribute keys sorted lexicographically
- One key per line in multi-line objects

Canonical layout is structure-sensitive:

- inline object forms may remain inline when the enclosing canonical layout is inline;
- when an enclosing object or list is rendered as multiline canonical layout, nested object values also canonically expand to multiline object blocks rather than remaining inline;
- key sorting still applies at every level regardless of whether the object is rendered inline or multiline.

<a id="lists"></a>
## Lists

- Element order preserved (never reordered)
- Single-line for simple scalars, multi-line for complex values

When a list is rendered multiline, complex object elements canonically expand to multiline object blocks.

<a id="scalars"></a>
## Scalars

<a id="numbers"></a>
### Numbers

- Canonicalization of `:n` values is value-normalizing while preserving the
  broad representation family chosen by the author:
  
  - integer family
  - decimal family
  - exponent family
- Remove all `_` separators
- No leading `+` sign
- Leading-dot decimals gain an explicit zero (`.5` → `0.5`)
- Decimal-family values trim redundant trailing fractional zeroes, but retain at
  least one fractional digit (`10.00` → `10.0`)
- Exponent-family values use lowercase `e`
- Exponent-family values remove redundant exponent sign and leading exponent
  zeroes (`1.0E+03` → `1e3`)
- Zero follows the same family model rather than a special ad hoc rule:
  
  - integer zero → `0` or `-0`
  - decimal zero → `0.0` or `-0.0`
  - exponent zero → `0e0` or `-0e0`

```aeon
// Non-canonical → Canonical
1_000_000   → 1000000
1.2300      → 1.23
.10         → 0.10
.5          → 0.5
1.0E+03     → 1e3
10.00       → 10.0
0.0e+0      → 0e0
```

<a id="radix"></a>
### Radix

- Canonicalization of `:radix[...]` values remains representation-preserving
  rather than value-normalizing
- `_` separators are removed from the canonical payload
- the remaining digit sequence, decimal point placement, and leading zero width
  are otherwise preserved

```aeon
// Non-canonical → Canonical
%10_00      → %1000
%10.00      → %10.00
%0010.00    → %0010.00
```

<a id="booleans"></a>
### Booleans

Always `true` or `false` (lowercase).

<a id="toggle"></a>
### Toggle

Preserve original literal (`yes`, `on`, etc.).

<a id="base-literals"></a>
### Base Literals

- Hex: lowercase (`#ff00aa`)
- Remove `_` separators

<a id="strings"></a>
### Strings

- Always double quotes (`"`)
- Minimal escaping
- Raw line breaks → `\n`
- Non-ASCII preserved as UTF-8

Multiline semantic strings canonically emit as spaces-only trimticks:

- canonical output never uses tabs in the trimtick gutter
- canonical equality is determined by the resulting trimmed string value
- single-line strings continue to emit as ordinary quoted strings
- trimticks may collapse to ordinary quoted strings in inline canonical contexts
- one-line normalized trimticks in inline containers emit as ordinary quoted strings
- multiline trimticks rendered inside inline object or attribute forms emit as escaped quoted strings rather than multiline trimtick blocks

<a id="separator-literals"></a>
### Separator Literals

Canonical separator literals:

- No whitespace between `=` and `^`
- No raw whitespace outside quoted segments
- Raw segments are emitted verbatim
- Quoted segments use canonical quoted-string escaping

```aeon
// Non-canonical → Canonical
size:sep["x"] =^300x250   → size:sep["x"] = ^300x250
```

Quoted segments preserve their string content:

```aeon
data:sep["|"] = ^"one "|" two"   // preserved as-is
```

<a id="references"></a>
## References

References MUST preserve semantic intent:

- clone references remain clone references (`~...`)
- pointer references remain pointer references (`~>...`)

Canonical form MUST NOT:

- Change a clone-intent reference into a pointer-intent reference or vice versa
- Inline or resolve references
- Alter the logical value graph

Canonical reference rendering also applies these normalizations:

- explicit root prefixes are elided when redundant (`~$.a` → `~a`, `~>$.a` → `~>a`)
- quoted member or attribute selectors may collapse to bare identifier form when the decoded segment is already a canonical bare identifier (`~a.@.["meta"]` → `~a.@.meta`)

<a id="node-heads"></a>
## Node Heads

Canonical node-head ordering is:

- `tag@{...}:datatype`

Canonical form preserves this order for node heads in the same way it preserves `key@{...}:type` ordering for bindings.

<a id="whitespace"></a>
## Whitespace

- 2-space indentation (no tabs)
- One space around `=`
- LF line endings (`\n`)
- Opening brace on same line as binding
- Closing brace on own line

```aeon
user = {
  name = "Patrik"
  age = 49
}
```

<a id="non-goals"></a>
## Non-Goals

Canonical form does NOT:

- Alter the logical value graph
- Inline references
- Change types
- Add or remove bindings (except default header)

---

## Related documents

- [AEON Specification v1](./aeon-core-v1.md)
- [AEON v1 Value Types Reference](./aeon-core-v1-value-types.md)
- [v1 Supersession Table](./aeon-v1-supersession-table.md)
