# AAC sub-spec — Canonical serialization and interchange Normative refinement of [SPEC §7–§8](../SPEC.md). Reference: `aac_core::{BackupManager, ExportFormat, MigrationEngine, ImportFormat}`. A user's customization — added words, custom symbols, personal phrases, the exact geometry their muscle memory has learned — is the most valuable and least portable thing in assistive technology. This sub-spec makes portability a property of the standard. ## 1. Canonical form A board MUST have a canonical serialization. JSON is the interchange encoding; the canonical form (sorted keys, normalized number forms) MUST round-trip **byte-identically** through a conforming serializer. Content identity MAY be expressed as a content address over the canonical bytes; two boards with equal canonical bytes are the same board. ## 2. Export — `ExportFormat` A conforming engine MUST export to: - `OpenBoardFormat` (`.obz`) — the open board interchange format, for cross-tool portability; - `NativeJson` — full-fidelity canonical JSON (§1), the lossless form. It MAY additionally export `PrintablePdf` — a low-tech paper backup, so a voice survives a dead battery. A round-trip through `NativeJson` MUST be lossless; a round-trip through `OpenBoardFormat` MUST preserve cell positions, content, actions, and symbol references, and MUST report any field it cannot represent as a non-fatal warning rather than dropping it silently. ## 3. Ingest — `ImportFormat` Interchange is **one-directional and additive**: the engine reads existing work into the substrate so a user never starts over, and it does not compete with the tools that produced that work. A conforming engine SHOULD ingest `OpenBoardFormat` and `Cboard`, and MAY ingest other community and vendor exports (`Csv`, and others as they are added). On ingest: 1. **Positions** present in the source MUST be preserved (motor stability — [`motor_stability.md`](motor_stability.md)). Positions **absent** from the source MUST be assigned deterministically by row-major fill and then fixed, so the same import always yields the same geometry. 2. **Unknown or unsupported fields** MUST be surfaced as non-fatal warnings, never silently discarded where they affect meaning. 3. A format the engine **cannot yet read** MUST fail explicitly — a named "format not yet supported" error — never partially and silently. The reference returns `MigrationError::FormatNotYetSupported(name)` for formats whose readers are not yet implemented. ## 4. No lock-in A user MUST be able to take everything with them. An implementation that can export `NativeJson` but cannot re-import it, or that loses positions on its own round-trip, is non-conformant. The guarantee is symmetric: what goes in comes out, and what comes out goes back in.