10 - lossy conversion keeps the content, and a reader panel settles what the audience expects #127

Merged
lilleman merged 3 commits from 10-goals into main 2026-09-25 18:57:21 +02:00
3 changed files with 41 additions and 14 deletions
+7
View File
@@ -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
+10 -4
View File
@@ -23,8 +23,9 @@ 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 conversions take, 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 +35,14 @@ 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. Content the document only
references is marked where it stood, by a note that reads as the converter's and names what was
left out. 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
+24 -10
View File
@@ -15,14 +15,15 @@ Start a session with: `Read AGENTS.md and todo.md, then do what todo.md's "Next
states, which wins over where an item's bullet sits: a newly filed item is written beside the
one it came in with, not at its own place in the order. Where that item has no release, the
planning chunk §15 describes.
3. In flight: nothing.
3. In flight: 10a on the local branch `10a` (worktree `../adf-codec-10a`, `8a3a83f`), built before
item 10's rows were rewritten on 2026-09-25; rework it against them.
4. Before stopping, rewrite this section: the in-flight line, and the prompt itself wherever the
session found it wrong or short.
## Milestones
Shipping order: 3h, 3i, 3j, 5a, 5b, 5c, 5d, 5 → `0.1.0` (shipped 2026-09-05); 3k, 11, 4, 12, 13, 4b,
4c, 14, 15, 16, 18, 4d, 28, 17, 29, 19, 20, 21, 22, 32, 23, 24, 25, 30, 26, 27, 10, 6, 7, 31, 5f, 5g →
4c, 14, 15, 16, 18, 4d, 28, 17, 29, 19, 20, 21, 22, 32, 23, 24, 25, 30, 26, 27, 10, 6, 7, 31, 33, 5f, 5g →
`0.2.0`;
8, 9 → TBD; 5e last.
The numbering is the order the work was planned in, not the order it ships. Everything known and
@@ -43,6 +44,8 @@ HTML doubles the importers and the file count they touch, and 25 to 27 because t
panel says the next reader pays for.
29 and 30 come from 17's prose pass (2026-09-20). 29 reads first because every goal is what a later
ask is settled against, 19's included; 30 sits beside 25, the other chunk rereading AGENTS.md.
33 comes from 10a (2026-09-25) and reads beside 31, the other chunk about what the pipeline
measures.
31 comes from 20's gate runs (2026-09-21) and reads beside 5f, the other chunk putting a measured
number under the pipeline. 32 comes from 21's review (2026-09-21) and reads beside 22, the other
chunk clearing a §11 seam.
@@ -56,6 +59,9 @@ chunk clearing a §11 seam.
upward, so the first raise to the measured figure reddens a run that changed nothing. Make
the measurement repeatable, or state the number the floor may be raised to and why it is not
the measured one.
- [ ] **33 — A carried mark run costs the line one re-emit (`0.2.0`).** `adfToMarkdown` spends 23 s
on one paragraph of 2000 × `un` plus `**-r**`: each run its flanking cannot spell re-emits the
whole line before riding the carry, quadratic in the runs (§11 Bounds). Make it linear.
- [x] **24 — The conformance gates have a directory (`0.2.0`).**
- [x] **25 — AGENTS.md §8 and §11 are findable (`0.2.0`).**
- [x] **26 — The two mutable structures say what they guarantee (`0.2.0`).**
@@ -213,16 +219,24 @@ 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 an italic note
naming it: `*(image not included)*`, `*(jira-issues-table not included)*`.
- 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