From 82da5e573bf37f48c878554e517aeaf8f750859a Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 5 Nov 2026 18:31:58 +0100 Subject: [PATCH] Draft the 0.3.0 announcement posts and bring the comparison table to the latest versions --- README.md | 6 +- converter-comparison/run.sh | 7 +- docs/announcement-posts.md | 127 ++++++++++++++++++++++++++++++++++++ todo.md | 70 ++++++++------------ 4 files changed, 160 insertions(+), 50 deletions(-) create mode 100644 docs/announcement-posts.md diff --git a/README.md b/README.md index 7cfdb4e..ebdc4cb 100644 --- a/README.md +++ b/README.md @@ -249,10 +249,10 @@ place, and on CI failing a change that breaks a guarantee. Serves [Goals](#goals) 3. The first table lists every npm package that runs in Node, converts ADF to or from markdown, whatever its downloads: one that starts and converts anything is listed, and its row says where it fails ordinary input. A wrapper or fork of a listed package is left out. The list -comes from npm searches on 2026-10-28 for "adf markdown", "markdown to adf", "adf to markdown", +comes from npm searches on 2026-11-05 for "adf markdown", "markdown to adf", "adf to markdown", "atlassian document format" and "adf converter". -On 2026-10-28, [`converter-comparison/`](https://github.com/larvit/adf-codec/tree/main/converter-comparison) +On 2026-11-05, [`converter-comparison/`](https://github.com/larvit/adf-codec/tree/main/converter-comparison) ran each package's published code, at the version the table names, with its default options. A package writing markdown got a document holding marks, a link, a mention, a status, a panel and a list, and a document holding a node type it cannot know. A package reading markdown got markdown @@ -276,7 +276,7 @@ holding the same marks and link. | `marklassian` 1.2.1 | markdown to ADF | – | – | markdown | 1 | | `md-adf` 0.2.2 | both ways, with a warning for each fallback | a different document: the mention and the status come back as text, the marks in the other order, the panel as a quote | dropped with its text, with a warning | markdown | 5 | | `md-to-adf` 0.6.4 | markdown to ADF; fails ordinary input: each list item is written as a list of its own | – | – | markdown | 2 | -| `mdast-util-from-adf` 2.3.0 | ADF to an mdast tree, which `mdast-util-to-markdown` 2.2.1 writes as markdown; throws on a status | – | throws | markdown | 3 | +| `mdast-util-from-adf` 2.3.0 | ADF to an mdast tree, which `mdast-util-to-markdown` 2.2.2 writes as markdown; throws on a status | – | throws | markdown | 3 | The next table lists converters this comparison does not run: other ecosystems' libraries, Atlassian's own paths, and one npm package that needs a browser. Each row is what the project's diff --git a/converter-comparison/run.sh b/converter-comparison/run.sh index 60b5c04..d0b97d2 100755 --- a/converter-comparison/run.sh +++ b/converter-comparison/run.sh @@ -1,15 +1,16 @@ #!/bin/sh # Keep these versions and --before in step with the README's comparison table. +# --before reads a bare date as midnight UTC, so the day after the run date keeps that day's publishes. set -eu here=$(cd "$(dirname "$0")" && pwd) node_image=node:26.13.0-alpine3.24 docker run --rm --memory 2g --memory-swap 2g --ulimit core=0 -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$here:/comparison:ro" -w /tmp \ "$node_image" sh -c ' - npm install --before=2026-10-29 --ignore-scripts --no-audit --no-fund --silent \ + npm install --before=2026-11-06 --ignore-scripts --no-audit --no-fund --silent \ @atlaskit/editor-json-transformer@10.0.0 \ @atlaskit/editor-markdown-transformer@6.3.1 \ @faulander/md2adf@1.0.0 \ - @larvit/adf-codec@0.2.0 \ + @larvit/adf-codec@0.3.0 \ @nthings.dev/adf4j-wasm@1.0.2 \ @wrtnlabs/markdown-to-adf@1.0.2 \ adf-converter@0.1.0 \ @@ -24,5 +25,5 @@ docker run --rm --memory 2g --memory-swap 2g --ulimit core=0 -u "$(id -u):$(id - md-adf@0.2.2 \ md-to-adf@0.6.4 \ mdast-util-from-adf@2.3.0 \ - mdast-util-to-markdown@2.2.1 && + mdast-util-to-markdown@2.2.2 && cp /comparison/compare.mjs . && node compare.mjs' diff --git a/docs/announcement-posts.md b/docs/announcement-posts.md new file mode 100644 index 0000000..aafbec4 --- /dev/null +++ b/docs/announcement-posts.md @@ -0,0 +1,127 @@ +# Announcement posts for 0.3.0 + +Drafts for the maintainer to post, one per place. Each post opens with the asker's problem, says how +the package solves it, then links the repository, whose README opens on what the package is, and the +[comparison table](https://github.com/larvit/adf-codec#other-adf-converters). The Turndown sample in +the first post ran against `0.3.0` on 2026-11-05. Each post says its author maintains the package. + +Delete this file once the posts are out. + +## jira.atlassian.com + +### JRACLOUD-77436, "Provide a public REST API endpoint to convert between ADF, HTML, Markup and Markdown" + +Plain text, so it pastes into Jira's comment editor whatever its mode. + +> For those who need the conversion now, in Node, Forge or a browser: `@larvit/adf-codec` converts +> markdown to ADF and ADF to markdown or HTML, with no Atlaskit, no React and no dependencies. The +> Atlaskit transformer's `encode` throws "This is not implemented yet"; here `adfToPortableMarkdown` +> and `adfToLosslessMarkdown` write the markdown, and `losslessMarkdownToAdf` reads the lossless one +> back to the same document, panels, mentions, statuses and unknown node types included. Every call +> returns a result and never throws. I maintain it. +> +> https://github.com/larvit/adf-codec +> How it compares with the other npm packages, run on their published code: +> https://github.com/larvit/adf-codec#other-adf-converters +> +> It is JavaScript, so it doesn't answer the Python request above. + +## Atlassian developer community + +### Topic 96176, "Is there a way to convert from HTML to ADF using TypeScript on NodeJS?" + +> `@atlaskit/editor-markdown-transformer` doesn't load as ESM in plain Node, so the Turndown route +> above stops at the import. I maintain [`@larvit/adf-codec`](https://github.com/larvit/adf-codec), +> which reads markdown into ADF with no Atlaskit, no React and no dependencies, as ESM that runs in +> Node, Forge and browsers. It takes the place of the Atlaskit transformer in that route: +> +> ```ts +> import TurndownService from 'turndown' +> import { portableMarkdownToAdf } from '@larvit/adf-codec' +> +> const markdown = new TurndownService({ headingStyle: 'atx' }).turndown(html) +> const adf = portableMarkdownToAdf(markdown) // { ok: true, value: } or { ok: false, error } +> ``` +> +> A call returns a result and never throws. `htmlToAdf` reads only the HTML that its own `adfToHtml` +> writes, so arbitrary HTML still goes through markdown first. It also writes ADF back out as +> markdown or HTML. [How it compares with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters), +> run on their published code. + +### Topic 99408, "HTML to ADF Conversion" + +> If you can write the content as markdown, or turn the HTML into markdown first, an ADF body is one +> call: `portableMarkdownToAdf(markdown)` from [`@larvit/adf-codec`](https://github.com/larvit/adf-codec) +> (I maintain it) returns `{ ok: true, value }` with a document you can send as `description`, and +> `{ ok: false, error }` with a line and a node path when the input is wrong. For HTML, run it +> through Turndown first. The package has no dependencies and runs in Node, Forge and browsers. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +### Topic 82496, "Converting to ADF(Atlassian Document Format)" + +> A package now does the markdown to ADF part in Node, Forge and browsers without Atlaskit: +> [`@larvit/adf-codec`](https://github.com/larvit/adf-codec), which I maintain. +> `portableMarkdownToAdf(markdown)` reads CommonMark plus GFM's tables, task lists and alerts, and +> returns the document or an error naming the line. ADF out to markdown or HTML works too, and +> `adfToLosslessMarkdown` followed by `losslessMarkdownToAdf` gives back the document it started +> from. HTML in is not general: turn it into markdown first, for example with Turndown. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +### Topic 86214, "Add a comment in Rovo action" + +> The Atlaskit transformers don't bundle in the Forge backend, but a plain function does: +> [`@larvit/adf-codec`](https://github.com/larvit/adf-codec) (I maintain it) turns the markdown an +> agent writes into a valid ADF comment body, with no Atlaskit, no React and no dependencies: +> `const body = portableMarkdownToAdf(markdown)`, then send `body.value` as the comment's `body` +> when `body.ok`. Headings, lists, tables, code blocks, links and marks all come out as ADF nodes, +> and an invalid input returns an error instead of throwing. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +### Topic 100699, "Guidance on unmaintained markdown-confluence project" + +> To the question of what else converts markdown to ADF and back: [`@larvit/adf-codec`](https://github.com/larvit/adf-codec), +> which I maintain. It is a library, so it doesn't publish to Confluence or ship an Obsidian plugin. +> It reads markdown into ADF (CommonMark, GFM tables, task lists and alerts, Obsidian callouts) and +> writes ADF back as markdown, and the lossless pair gives back the original document, panels, +> mentions, statuses, macros and node types it doesn't know included. Models can edit that markdown, +> since it is markdown, which suits the MD to ADF need for LLMs mentioned above. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +### Topic 101278, "Rovo MCP Server: no attachment-upload tool, and `description` drops ADF media nodes on edit" + +> I can't change what the server accepts, but a client that reads ADF over REST can avoid the loss +> itself. [`@larvit/adf-codec`](https://github.com/larvit/adf-codec) (I maintain it) writes ADF as +> markdown in which media nodes, mentions, panels, statuses, macros and unknown node types are kept +> as small `!adf:` spellings, and reads that markdown back to the same document. The model edits the +> markdown, and `losslessMarkdownToAdf` gives ADF to send, with the media node still in it. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +## GitHub, `atlassian/atlassian-mcp-server` + +Both issues are closed. Post only if you want to; the maintainers answered #161 with an HTML format +of their own. + +### Issue 60, "Editing content via Rovo MCP causes the loss of all ADF-rich content" + +> For anyone building their own client around this problem: [`@larvit/adf-codec`](https://github.com/larvit/adf-codec) +> (I maintain it) writes ADF as markdown that keeps Smart Links, mentions, dates, statuses, panels, +> expands, task lists, media, layouts, extensions and node types it doesn't know, and reads the +> edited markdown back to ADF. An unedited document comes back deep-equal. It has no dependencies +> and runs in Node, Deno, Bun and browsers. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +### Issue 161, "Lossless markdown round-trip for Confluence macros and large-page support via file-path parameter" (optional) + +> The first proposal, macros surviving a markdown round-trip, is what [`@larvit/adf-codec`](https://github.com/larvit/adf-codec) +> (I maintain it) does for any client: `adfToLosslessMarkdown` writes a macro as an `!adf:extension` +> line holding its key, type and parameters, and `losslessMarkdownToAdf` restores it exactly. +> [Comparison with the other npm packages](https://github.com/larvit/adf-codec#other-adf-converters). + +## Left out + +- Topic 96638 (a heading in a comment through the Atlassian CLI): the failure is the CLI's, not a + conversion. +- Stack Overflow: the questions found are from 2021 to 2024, answered, and in PHP and C#, + which this JavaScript package doesn't serve: 74559262 (HTML to ADF), 74547915 (ADF to HTML, whose + answer is `expand=renderedFields`), 71693304 (parsing ADF in C#), 72553636, 68102225 and 78261178. + None asks for ADF to markdown. A new question with its own answer would be the way in, if you want one. diff --git a/todo.md b/todo.md index fa0ee99..e1b1ed0 100644 --- a/todo.md +++ b/todo.md @@ -12,33 +12,32 @@ | ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score | |---|---|---|---|---|---|---|---|---|---|---|---| -| 73 | 0.4.0 | | | **Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.** | 1 | 2 | 2 | 3 | 2 | 3 by 8 | 16.9 | -| 153 | 0.4.0 | 73 | question | **Decide whether `src/markdown/` root may import `emit/`, `parse/` or `portable/`, and hold the answer in `.oxlintrc.json` and §The source parts by ADF and format.** | 1 | 2 | 2 | 3 | 2 | code health by 3 | 26.2 | -| 156 | 0.4.0 | 73 | | **Stop a leg's container when its script is interrupted, so Ctrl-C ends `ci.sh` or `mutation-tests/run.sh` at once.** | 1 | 2 | 1 | 2 | 1 | code health by 2 | 20.9 | -| 128 | 0.4.0 | 73 | | **Pin the portable flavour's block reading and writing with tests: callout titles past one line, a link beside other marks in a title, the nesting limit of callouts and task lists, refusals inside tasks and their paths, and empty or non-paragraph tasks.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 | -| 75 | 0.4.0 | 73 | | **Make the generated-markdown property write block carries as `adf:` fences, canonical and hostile.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 17.4 | -| 154 | 0.4.0 | 73 | | **Pair highlights over the inline reader's pieces by their offsets before building nodes, so no placeholder text node stands in for a delimiter.** | 2 | 1 | 2 | 3 | 4 | code health by 4 | 17.4 | -| 155 | 0.4.0 | 73 | | **Have `closeBracket` return the link, image or literal bracket it builds, and apply it to the scan in one caller.** | 2 | 1 | 2 | 3 | 4 | code health by 4 | 17.4 | -| 162 | 0.4.0 | 73 | | **Pin each rule of the emphasis sweep with a hand-worked line, so every mutant that lets a pair fall where the one-run-per-pass reference keeps it fails a test.** | 2 | 1 | 1 | 2 | 4 | code health by 4 | 17.4 | -| 45 | 0.4.0 | 73 | defect | **Replace `isAdfDocument` with a reader returning `Result`.** | 2 | 1 | 3 | 4 | 3 | 1 by 2 | 13.1 | -| 127 | 0.4.0 | 73 | principle | **Hold what `entity-references.test.ts`, `json-text.test.ts` and `result.test.ts` check by asserting outcomes, so none reads source text.** | 2 | 2 | 1 | 3 | 3 | code health by 2 | 13.1 | -| 159 | 0.4.0 | 73 | | **Delete `taskBlocks`'s branch that writes the task marker as its own paragraph, once a test shows no block task item reaches it.** | 1 | 1 | 1 | 1 | 1 | code health by 1 | 10.5 | -| 144 | 0.4.0 | 73 | | **Give every container `docker-runner.sh` and `publish.sh` start a memory limit and an equal swap limit, sized from the largest a gate leg measurably needs.** | 1 | 1 | 1 | 1 | 2 | code health by 1 | 8.7 | -| 143 | 0.4.0 | 73 | defect | **Keep, in `adfToPortableMarkdown`, the link around a note, so a linked stored image writes every target.** | 2 | 1 | 3 | 4 | 3 | 7 by 1 | 6.5 | -| 112 | 0.4.0 | 73 | | **Pad a GFM pipe table's short rows with empty cells, read its body rows holding no pipe, and read a one-column table without leading pipes in `portableMarkdownToAdf`.** | 2 | 1 | 2 | 3 | 3 | 4 by 4 | 6.2 | -| 80 | 0.4.0 | 73 | | **Name the node's path and the attribute key when `not-an-adf-document` refuses a node inside the document.** | 2 | 1 | 2 | 3 | 3 | 6 by 4 | 6.0 | -| 81 | 0.4.0 | 73 | | **Fail the gate unless the README's error tables list exactly the codes `ConvertErrorCode` holds.** | 1 | 1 | 1 | 1 | 2 | 3 by 2 | 4.2 | -| 147 | 0.4.0 | 73 | | **Ship `adfToPlainText`, writing a document's content with no markup, under a README goal for plain text.** | 2 | 2 | 1 | 3 | 4 | 3 by 4 | 4.2 | -| 141 | 0.4.0 | 73 | decision | **Write `strike` as HTML in `adfToHtml` and read it back in `htmlToAdf`, in place of the carry element.** | 1 | 1 | 1 | 1 | 2 | 6 by 2 | 4.0 | -| 135 | 0.4.0 | 73 | | **Write media, media groups and captions as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 2 | 2.0 | -| 136 | 0.4.0 | 73 | | **Write underline, text and background colours, subscript, superscript, alignment and indentation as HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 2 | 2.0 | -| 134 | 0.4.0 | 73 | decision | **Write panels, expands, task lists and decision lists as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 5 | 6 by 3 | 1.8 | -| 46 | 0.4.0 | 73, 134, 135, 136 | | **Publish the bundle size in the README, failing the release pipeline when it drifts.** | 2 | 2 | 1 | 3 | 4 | 3 by 3 | 3.2 | -| 51 | 0.4.0 | 73 | | **Match a reference label to its definition under Unicode case folding.** | 2 | 1 | 2 | 3 | 4 | 4 by 2 | 2.1 | -| 148 | 0.4.0 | 73 | | **Ship conversion between ADF and Jira wiki markup both ways, under a README goal for wiki markup.** | 3 | 2 | 2 | 5 | 7 | 3 by 5 | 0.9 | -| 149 | 0.4.0 | 73 | | **Read any HTML into ADF, in a call or option a developer panel picks, under a README goal for foreign HTML.** | 3 | 2 | 2 | 5 | 7 | 3 by 5 | 0.9 | -| 77 | 0.4.0 | 73 | decision | **Read the input once into a plain copy, so an accessor property or a throwing Proxy yields `not-an-adf-document` and every call returns a result.** | 3 | 1 | 3 | 5 | 4 | | 0.0 | -| 107 | 0.4.0 | 73 | decision | **Spell the block carry's JSON so its length stays linear in the node's JSON.** | 3 | 1 | 3 | 5 | 5 | | 0.0 | +| 153 | 0.4.0 | | question | **Decide whether `src/markdown/` root may import `emit/`, `parse/` or `portable/`, and hold the answer in `.oxlintrc.json` and §The source parts by ADF and format.** | 1 | 2 | 2 | 3 | 2 | code health by 3 | 26.2 | +| 156 | 0.4.0 | | | **Stop a leg's container when its script is interrupted, so Ctrl-C ends `ci.sh` or `mutation-tests/run.sh` at once.** | 1 | 2 | 1 | 2 | 1 | code health by 2 | 20.9 | +| 128 | 0.4.0 | | | **Pin the portable flavour's block reading and writing with tests: callout titles past one line, a link beside other marks in a title, the nesting limit of callouts and task lists, refusals inside tasks and their paths, and empty or non-paragraph tasks.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 | +| 75 | 0.4.0 | | | **Make the generated-markdown property write block carries as `adf:` fences, canonical and hostile.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 17.4 | +| 154 | 0.4.0 | | | **Pair highlights over the inline reader's pieces by their offsets before building nodes, so no placeholder text node stands in for a delimiter.** | 2 | 1 | 2 | 3 | 4 | code health by 4 | 17.4 | +| 155 | 0.4.0 | | | **Have `closeBracket` return the link, image or literal bracket it builds, and apply it to the scan in one caller.** | 2 | 1 | 2 | 3 | 4 | code health by 4 | 17.4 | +| 162 | 0.4.0 | | | **Pin each rule of the emphasis sweep with a hand-worked line, so every mutant that lets a pair fall where the one-run-per-pass reference keeps it fails a test.** | 2 | 1 | 1 | 2 | 4 | code health by 4 | 17.4 | +| 45 | 0.4.0 | | defect | **Replace `isAdfDocument` with a reader returning `Result`.** | 2 | 1 | 3 | 4 | 3 | 1 by 2 | 13.1 | +| 127 | 0.4.0 | | principle | **Hold what `entity-references.test.ts`, `json-text.test.ts` and `result.test.ts` check by asserting outcomes, so none reads source text.** | 2 | 2 | 1 | 3 | 3 | code health by 2 | 13.1 | +| 159 | 0.4.0 | | | **Delete `taskBlocks`'s branch that writes the task marker as its own paragraph, once a test shows no block task item reaches it.** | 1 | 1 | 1 | 1 | 1 | code health by 1 | 10.5 | +| 144 | 0.4.0 | | | **Give every container `docker-runner.sh` and `publish.sh` start a memory limit and an equal swap limit, sized from the largest a gate leg measurably needs.** | 1 | 1 | 1 | 1 | 2 | code health by 1 | 8.7 | +| 143 | 0.4.0 | | defect | **Keep, in `adfToPortableMarkdown`, the link around a note, so a linked stored image writes every target.** | 2 | 1 | 3 | 4 | 3 | 7 by 1 | 6.5 | +| 112 | 0.4.0 | | | **Pad a GFM pipe table's short rows with empty cells, read its body rows holding no pipe, and read a one-column table without leading pipes in `portableMarkdownToAdf`.** | 2 | 1 | 2 | 3 | 3 | 4 by 4 | 6.2 | +| 80 | 0.4.0 | | | **Name the node's path and the attribute key when `not-an-adf-document` refuses a node inside the document.** | 2 | 1 | 2 | 3 | 3 | 6 by 4 | 6.0 | +| 81 | 0.4.0 | | | **Fail the gate unless the README's error tables list exactly the codes `ConvertErrorCode` holds.** | 1 | 1 | 1 | 1 | 2 | 3 by 2 | 4.2 | +| 147 | 0.4.0 | | | **Ship `adfToPlainText`, writing a document's content with no markup, under a README goal for plain text.** | 2 | 2 | 1 | 3 | 4 | 3 by 4 | 4.2 | +| 141 | 0.4.0 | | decision | **Write `strike` as HTML in `adfToHtml` and read it back in `htmlToAdf`, in place of the carry element.** | 1 | 1 | 1 | 1 | 2 | 6 by 2 | 4.0 | +| 135 | 0.4.0 | | | **Write media, media groups and captions as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 2 | 2.0 | +| 136 | 0.4.0 | | | **Write underline, text and background colours, subscript, superscript, alignment and indentation as HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 2 | 2.0 | +| 134 | 0.4.0 | | decision | **Write panels, expands, task lists and decision lists as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 5 | 6 by 3 | 1.8 | +| 46 | 0.4.0 | 134, 135, 136 | | **Publish the bundle size in the README, failing the release pipeline when it drifts.** | 2 | 2 | 1 | 3 | 4 | 3 by 3 | 3.2 | +| 51 | 0.4.0 | | | **Match a reference label to its definition under Unicode case folding.** | 2 | 1 | 2 | 3 | 4 | 4 by 2 | 2.1 | +| 148 | 0.4.0 | | | **Ship conversion between ADF and Jira wiki markup both ways, under a README goal for wiki markup.** | 3 | 2 | 2 | 5 | 7 | 3 by 5 | 0.9 | +| 149 | 0.4.0 | | | **Read any HTML into ADF, in a call or option a developer panel picks, under a README goal for foreign HTML.** | 3 | 2 | 2 | 5 | 7 | 3 by 5 | 0.9 | +| 77 | 0.4.0 | | decision | **Read the input once into a plain copy, so an accessor property or a throwing Proxy yields `not-an-adf-document` and every call returns a result.** | 3 | 1 | 3 | 5 | 4 | | 0.0 | +| 107 | 0.4.0 | | decision | **Spell the block carry's JSON so its length stays linear in the node's JSON.** | 3 | 1 | 3 | 5 | 5 | | 0.0 | | 42 | 0.5.0 | | defect | **Trim a text leaf's trailing blanks in linear time.** | 1 | 1 | 2 | 2 | 2 | 9 by 3 | 26.2 | | 31 | 0.5.0 | | | **Make the branch-coverage figure repeat across runs of an unchanged tree.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 | | 57 | 0.5.0 | | | **Make each `ci.sh` leg build what it reads, so one leg run alone tests the current tree.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 | @@ -62,23 +61,6 @@ ## Details -### 73. Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions. - -Blocks every other `0.4.0` item (the maintainer, 2026-11-05): the posts announce `0.3.0` once it -is published, and they are cheap and best made right after the publish. Before posting, set -`converter-comparison/run.sh`'s pins to each package's latest version, `@larvit/adf-codec@0.3.0` -included, and `--before` to today, run it, and bring the README comparison table's versions and -date in step. - -Venues found 2026-10-28, each a thread a reply answers today: on the developer community, topics -96176, 99408, 82496, 100699, 101278, 86214 and 96638; on GitHub, `atlassian/atlassian-mcp-server` -issues 60 and 161. Finding Stack Overflow's ADF-to-markdown questions is part of this item. - -We draft each post for the place it goes. Each opens with the asker's problem and how the package -solves it, then links the GitHub repository, the README's comparison table and the README's -opening. The maintainer posts them once `0.3.0` is published (`docs/decisions.md` §Posts -announcing a release wait for its publish). Found while planning discoverability, 2026-10-04. - ### 153. Decide whether `src/markdown/` root may import `emit/`, `parse/` or `portable/`, and hold the answer in `.oxlintrc.json` and §The source parts by ADF and format. The writers read each escaped line back through `src/markdown/inline-content.ts`'s scan. A writer