From 5af77d0a5e8f29375ce9b0a70bb3f0b9b2799904 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Wed, 4 Nov 2026 20:47:10 +0100 Subject: [PATCH] Record that the first step checks every schema rule, and plan moving the writers' schema refusals there --- AGENTS.md | 2 +- docs/decisions.md | 44 ++++++++++++++++++++++++-------------------- src/adf/document.ts | 2 +- todo.md | 36 ++++++++++++++++++++++++++---------- 4 files changed, 52 insertions(+), 32 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 30c1d22..037ec50 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -59,7 +59,7 @@ In `docs/decisions.md`: - Posts announcing a release wait for its publish, and their drafts wait for the finished release - A chunk ruled worse merges where a plan item of its release already restores that code's reading, and that item takes the ruling's places - A chunk ruled worse that restructures the places takes a paired ruling after each restructure, against the same base, and merges once one is not worse -- Writers and carry readers refuse an inline card a link marks +- The first step checks the schema, and no converter does - The gate runs on Deno and Bun - The gate installs the tarball - Firefox reads the build diff --git a/docs/decisions.md b/docs/decisions.md index 354b845..884336e 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -297,7 +297,7 @@ besides hard breaks but no node that takes a link: the panel refused to have breaks alone still reads as its destination, then the breaks (§An image reads as an image only alone in its paragraph). `adfToLosslessMarkdown` writes a node holding a mark its type does not take as `!adf:carry`, so the round-trip holds, except an inline card a link marks, which is refused -(§Writers and carry readers refuse an inline card a link marks). +(§The first step checks the schema, and no converter does). ## A linked image is written `[![alt](url)](href)`, a captioned image as its directive @@ -442,7 +442,7 @@ it joins the second panel's `` to that portable spelling. HTML nests no `` in an ``, so no element can hold both a card's URL and the target of a link marking it. Every writer refuses such a card, and a carry element holding one, as the maintainer -chose on 2026-11-04 over a new spelling (§Writers and carry readers refuse an inline card a link marks). +chose on 2026-11-04 over a new spelling (§The first step checks the schema, and no converter does). A fifth panel (2026-11-04, three readers in the same roles, then four more for what the first three split on) was asked how to write a mention, emoji, status, date and inline card, which until then @@ -749,27 +749,31 @@ stays on `insideRun` alone, since it answers the parted line. A refactor that me so the chunk's later rulings read against that merge, the commit `larv-review ruling-base` prints. A restructure past a pass's round cap still goes unreviewed, so the PR summary names it. -## Writers and carry readers refuse an inline card a link marks +## The first step checks the schema, and no converter does -2026-11-04, replacing §No schema validation of 2026-08-23 (its mark refusal 2026-08-25), the -maintainer. Goal 1. Valid while Atlassian's schema gives a card no link mark. +2026-11-04, the maintainer. Goal 1 and code health. Valid while Atlassian's schema forbids shapes +a converter would otherwise meet. -Every writer refuses a document holding an `inlineCard` with a `link` mark, as -`unsupported-node-shape` at the card's path, wherever the card stands: in a node a writer carries, -or under a type the library does not know. Every carry reader, `losslessMarkdownToAdf` and -`htmlToAdf`, refuses a carried node holding one, so no reader builds a document a writer refuses. -The schema gives a card the `annotation` mark alone (§The node tables answer to Atlassian's -schema), and spelling the pair would take a new spelling in each format; HTML nests no `` in an -``. Another shape joins this entry only at the maintainer's word, once the schema forbids it and every format would -need a spelling for it. A node type, mark or attribute the schema does not name still rides the -carry. There is no full schema validation and no exported validator: `isAdfDocument` checks the -document's shape alone. A refusal that keeps the round-trip is no schema check and stays: a spelled -node carrying the same mark type twice is refused on its own terms, and input nesting a spelling -inside its own kind (`*(*a*)*`) names that mark once. +An Atlassian-schema rule the library applies is checked once, in the first step every call opens +with: `writableContent` for the writers, `carriedNode` for the carry readers `losslessMarkdownToAdf` +and `htmlToAdf`. A converter checks none, so a document one call refuses every call refuses, at +the same path, and what a converter holds is valid ADF. An `inlineCard` with a `link` mark is +refused there today, as `unsupported-node-shape` at the card's path, wherever it stands, since the +schema gives a card the `annotation` mark alone (§The node tables answer to Atlassian's schema) +and HTML nests no `` in an ``. `todo.md` item 167 moves the other refusals a writer makes on a schema +rule: a node holding a mark type twice, a node holding `text`, or `content` where it takes none, +and an inline node holding neither. -The earlier entry premised that the site a document is saved to validates it. A hand-built -document has not reached the site yet, and the viewer/editor persona relies on a refusal arriving -before the save. +A rule joins the first step as a refusal only where no format can spell the node whole. A node type, +mark or attribute the schema does not name, a known node where no section spells it +(§Unknown nodes ride the carry), and a mark a node cannot hold (§A mark skips a node that cannot +hold it) ride the carry, which keeps the round-trip. A limit of the engine or the flavour is no +schema rule and stays where it is met: nesting depth, output length and what a portable line can +spell. A reader refusing markdown or HTML it cannot read is no check of ADF and stays in the reader. + +The earlier entry kept the card refusal alone, premising that the site a document is saved to +validates the rest. A hand-built document has not reached the site yet, and the viewer/editor +persona relies on a refusal arriving before the save. ## The gate runs on Deno and Bun diff --git a/src/adf/document.ts b/src/adf/document.ts index 73e8a89..1299769 100644 --- a/src/adf/document.ts +++ b/src/adf/document.ts @@ -147,7 +147,7 @@ export function nodeMarks(node: { marks?: AdfMark[] }): readonly AdfMark[] { return node.marks ?? [] } -// Walks every node, carried or of an unknown type, so a link-marked card is refused wherever it stands (docs/decisions.md §Writers and carry readers refuse an inline card a link marks). +// Walks every node, carried or of an unknown type, so a link-marked card is refused wherever it stands (docs/decisions.md §The first step checks the schema, and no converter does). export function refusedShape(content: readonly AdfNode[]): ConvertError | undefined { type Step = { index: number; node: AdfNode; parent: Step | undefined } const pending: Step[] = content.map((node, index) => ({ index, node, parent: undefined })).reverse() diff --git a/todo.md b/todo.md index 0387610..f7260d9 100644 --- a/todo.md +++ b/todo.md @@ -6,7 +6,7 @@ `Bar = 0.1` -`Next ID = 167` +`Next ID = 168` ## Items @@ -17,6 +17,7 @@ | 165 | 0.3.0 | 164 | | **Have a reader panel seated from `## Audience` judge each feature-table row reasonable or not, and file an item for each row it rejects.** | 2 | 2 | 1 | 3 | 3 | 6 by 5 | 7.5 | | 132 | 0.3.0 | | | **Write tables as `` in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 5 | 6 by 4 | 2.4 | | 73 | 0.3.0 | 132, 163, 165 | | **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 | +| 167 | 0.3.0 | | decision | **Check every Atlassian-schema rule a writer refuses today in `writableContent`, and drop it from the writers.** | 3 | 1 | 2 | 4 | 5 | code health by 5 | 13.1 | | 72 | 0.3.0 | 132 | decision | **Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues and Actions off and its description pointing at GitHub.** | 1 | 2 | 1 | 2 | 1 | 3 by 1 | 2.5 | | 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 | @@ -26,7 +27,6 @@ | 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 | -| 68 | 0.4.0 | | defect | **Carry a non-text inline node holding `content` or `text`, a block holding `text`, and a leaf block holding `content`.** | 2 | 1 | 2 | 3 | 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 | @@ -106,6 +106,30 @@ solves it, then links the GitHub repository, the README's comparison table and t 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. +### 167. Check every Atlassian-schema rule a writer refuses today in `writableContent`, and drop it from the writers. + +The maintainer's call, 2026-11-04 (`docs/decisions.md` §The first step checks the schema, and no +converter does): the first step holds every schema check, "moved there from wherever else in the +code they are". It replaces item 68, which would have carried these shapes: a schema-forbidden +shape is refused once, with its path, in every writer. Move into `refusedShape`: + +- `emitLeaf` in `emit/inline-line.ts`: a node holding one mark type twice, and an inline node + holding neither `content` nor `text`. +- `emitDirectiveBlock` in `emit/adf-to-markdown.ts`: a node holding `text`, and a leaf block holding + `content`. +- The HTML and portable writers, which today write the first two without refusing: they refuse them + too, which is breaking for a document holding either (`CHANGELOG.md`, `MIGRATION.md`). +- Check `src/html/` and `src/markdown/portable/` for a refusal of this kind the grep of + `unsupported-node-shape` missed, and `carriedNode` for a rule the readers still build. + +Stays where it is: a limit of the engine or the flavour (nesting depth, output length, a portable +task list holding what no list item spells) and a reader's refusal of markdown or HTML it cannot +read. A node type, mark or attribute the schema does not name, a known node out of place and a mark +a node cannot hold keep riding the carry. Drop the refused shapes from the README's +`unsupported-node-shape` causes under writing and from `spec/flavour.md`; the property generators +build none of them. Lands with items 45, 77 and 80 where it can, since their reader walks every +node too, but needs none. + ### 72. Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues and Actions off and its description pointing at GitHub. Blocked by every other `0.3.0` item but 73 (the maintainer, 2026-10-05; moved to `0.3.0` 2026-10-28, @@ -183,14 +207,6 @@ boolean guard is the one export that does not, and it cannot say which branch re `not-an-adf-document`'s message already does. Breaking: `MIGRATION.md` shows the guard's replacement. -### 68. Carry a non-text inline node holding `content` or `text`, a block holding `text`, and a leaf block holding `content`. - -`emitLeaf` (`emit/inline-line.ts`) and `emitDirectiveBlock` (`emit/adf-to-markdown.ts`) -refuse these with `unsupported-node-shape`, though `isAdfDocument` accepts them and the carry -round-trips them; `docs/decisions.md` §The code list gives a cause the carry answers no code. Drop -them from the README's `unsupported-node-shape` cause "Writing, in `adfToLosslessMarkdown`". Found by the README-goals -audit, 2026-10-04. - ### 127. Hold what `entity-references.test.ts`, `json-text.test.ts` and `result.test.ts` check by asserting outcomes, so none reads source text. Technical principle "Assert the outcome", which bans scanning the source with `ast` or a regex.