diff --git a/AGENTS.md b/AGENTS.md index e762ced..c505a91 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -429,6 +429,13 @@ and the instance it yields, and ask for the rule. The maintainer answers the rul here, and the instance follows from it in the chunk. A rule that keeps collecting instances is wrong: rewrite it rather than append to it. +Which output the audience expects — README goal 5 — is settled by a reader panel rather than +asked: three fresh-context readers, one per README persona the conversion serves, each given only +`## Audience` and the input, writing what they expect before picking among outputs the goals +allow, rendered, shuffled, with no rationale and nothing saying what is implemented. Three agreeing +settle it; otherwise four more read, five of seven settle it, and less is a missing goal, asked. +The verdict lands in the item it settles (the maintainer, 2026-09-25). + ### Rules the loop has settled (the maintainer, 2026-09-18) - A finding inside the chunk's item is fixed in the chunk. Outside it, a new `todo.md` item, always diff --git a/README.md b/README.md index 17737ee..d654dc7 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ represent. In priority order. -1. **Lossless first.** The round-trip holds for every document, node types this version does not - know included; one that has no spelling is refused and says where, never silently reduced. +1. **Lossless first.** The round-trip holds for every document the lossless pair converts, node + types this version does not know included; one that has no spelling is refused and says where, never silently reduced. Every goal below gives way to this one. 2. **Three formats, ADF the hub.** ADF, one markdown flavour, one HTML dialect, markdown↔HTML composing through ADF — four conversions to keep correct, never a fifth, and never a fourth @@ -34,9 +34,13 @@ In priority order. escapable, so the flavour is opt-in. 4. **Output a person can edit.** A node CommonMark can spell gets that spelling; the directive form carries only what CommonMark cannot hold. -5. **Failures are values.** Nothing throws, and `code` is a closed list — as much a contract as +5. **Lossy conversion keeps the content.** `adfToPlainMarkdown` and `plainMarkdownToAdf` drop what + plain markdown cannot hold — format, design, structure — never content: what a reader of the + rendered document sees or follows, its text, images and link targets. What is dropped goes the + way the audience expects. +6. **Failures are values.** Nothing throws, and `code` is a closed list — as much a contract as the emitted formats are. -6. **Nothing in the way.** No runtime dependencies, no I/O, no configuration, no host API: ESM on +7. **Nothing in the way.** No runtime dependencies, no I/O, no configuration, no host API: ESM on any ES2022 engine, in a browser as readily as on a server. ## Audience diff --git a/todo.md b/todo.md index 388410d..244987c 100644 --- a/todo.md +++ b/todo.md @@ -213,16 +213,23 @@ chunk clearing a §11 seam. spelling, attributes dropped. - `mention` and `status` become their text, the mention's `@` kept; `emoji` its text or else its `shortName`; `date` its ISO date in UTC (`2026-09-13`); `inlineCard`, `blockCard` and - `embedCard` a link to their `url`, dropped when they carry only `data`; a `mediaSingle` - holding an external image stays `![alt](url)`; `media`, `mediaGroup` and `mediaInline` their - `alt` text or nothing; `caption` its text as a paragraph; `extension`, `inlineExtension` and - `syncBlock` their `text` attribute or nothing; `placeholder` nothing; a node no row names, or - one standing where no spelling holds it, its blocks or its text. + `embedCard` a link to their `url`, or to their `data`'s `url` named by its `name` — the name + alone without a `url`; an external image, wherever it stands, `![alt](url)`; `media`, + `mediaGroup` and `mediaInline` holding a stored file their `alt` text; `caption` its text as + a paragraph; `extension` and `inlineExtension` their `text` attribute; `placeholder` nothing, + its text being the editor's prompt rather than the document's; a node no row names, or one + standing where no spelling holds it, its blocks or its text. + - Content the document only references — a stored file with no `alt`, an extension with no + `text`, a `syncBlock`, a card with neither `url` nor `data` naming one — leaves MARKER. - A table stays a pipe table: the first row becomes the header, a cell's blocks join on one line - with spaces, and spans and the cells they cover drop. + with spaces, and a span keeps its cell under its header by empty cells in the columns and + rows it covered, padding at most to the table's cell count. + - A list stays a list: where CommonMark cannot hold a block inside an item, what gives way is + what a reader does not see — the spaces of a whitespace-only code line, a rule's spelling. - `code`, `em`, `link`, `strike` and `strong` stay and every other mark drops, keeping its text — - `subsup` too, since `~2~` is a strike on GitHub; a link no CommonMark escape writes becomes its - text, and a mark run CommonMark's flanking or matching cannot spell drops its mark. + `subsup` too, since `~2~` is a strike on GitHub; a link no CommonMark escape writes has its + `href` percent-encoded until one does, and a mark run CommonMark's flanking or matching cannot + spell drops its mark. - A newline in text becomes a hard break and edge whitespace is trimmed; carriage returns and null characters are removed; a paragraph line opening with a code span whose backticks would read as a fence loses the code mark; an empty paragraph drops, and adjacent lists of one type