# Decisions ## Plain markdown is a flavour of the grammar 2026-09-27, the maintainer. Goal 2. Valid while the plain flavour's spellings are ones the markdown grammar can read and write. The lossy pair is the plain flavour: the markdown grammar's reader and writer with the flavour set, its spellings — alerts, callouts, task markers, `==` — read and written there, so a marker line and a backslash reach them intact; what the flavour cannot spell reduces ADF→ADF ahead of the writer. ## The round-trip is the product 2026-08-23, real payloads 2026-09-15, the maintainer. Goal 1. Valid while a consumer saves back through the lossless pair. `markdownToAdf(adfToMarkdown(doc))` and `htmlToAdf(adfToHtml(doc))` must equal `doc` — anything less silently destroys content an editor could not represent, in a document it did not author. When losslessness and readability conflict, losslessness wins. Round-trip equality is a property tested over a checked-in corpus (`corpus/README.md`), not a claim made in prose. Its real payloads are invented content written in Atlassian's editor on the maintainer's test site, so none is sanitized and a mention keeps the test user's real account id. ## Markdown in is a canonical fixpoint 2026-08-23, the maintainer. Goals 1 and 4. Valid while markdown input may be written by hand. The other direction is a canonical fixpoint, not byte-identity: human markdown normalizes, the way back yields the library's canonical spelling, and that spelling round-trips byte-identically — where there is a way back. CommonMark spells some things the flavour has no escape for — a paragraph opening with a code span whose backticks read back as a fence — so a parse succeeding does not imply a spellable document; `corpus/commonmark-spec/exceptions.json` names those. ## Equality is editor-normal 2026-08-24, the maintainer. Goal 1. Valid while markdown cannot tell apart the ADF shapes this merges. "Equals" is structural equality over editor-normal ADF — adjacent text nodes with identical marks and no attributes merged, JSON number semantics, an empty attrs object, marks array or content array the absent key — the only domain markdown can restore. `todo.md` item 40 replaces this with deep equality (2026-09-28, the maintainer). ## Unknown nodes ride the carry 2026-08-23, extended to misplaced known nodes 2026-08-26, the maintainer. Goal 1. Valid while ADF holds nodes, or node positions, this library does not spell. An unknown ADF node is carried opaquely — raw JSON rides a dedicated syntax in both formats and restores to a deep-equal node. The round-trip holds for documents newer than the library. So does a known node no section spells where it stands: a markdown serializer spells a node by type without checking its position, and refusing loses a document ADF itself keeps in an `unsupportedBlock`. Where a container's own spelling cannot hold the child it has — a `bulletList` holding other than `listItem`, a `codeBlock` other than text — the error result names that instead. ## Foreign HTML sorts three ways 2026-08-23, the sort 2026-09-20, the maintainer. Goals 1 and 4. Valid while ADF holds no node for a bare container, a comment or a script. Lands with `todo.md` item 6. Every foreign element `htmlToAdf` and `markdownToAdf` read sorts one of three ways, never a silent drop of content: - A container around document content that ADF has no node for unwraps to its children, its own attributes dropped: `
text
` keeps `text`, losing the alignment. - Content ADF cannot hold is an error result naming it. A comment is one: a person wrote those words, and neither of Atlassian's schemas holds them — `annotation`'s `inlineComment` carries an id, `placeholder` is the editor's own hint, `extension` names a vendor app. - What is not document content drops whole: `