36e - todo-history.md's decisions move to docs/decisions.md and it goes #141
@@ -1,8 +1,7 @@
|
|||||||
# Working in this repo
|
# Working in this repo
|
||||||
|
|
||||||
The rules for every collaborator, human or agent, and an index of the decisions a reader would
|
The rules for every collaborator, human or agent, and an index of the decisions a reader would
|
||||||
otherwise relitigate. Using the library: `README.md`. What is still to build: `todo.md`; a bare
|
otherwise relitigate. Using the library: `README.md`. What is still to build: `todo.md`.
|
||||||
`(28)` cites that item's entry in `todo-history.md`.
|
|
||||||
|
|
||||||
## Decisions
|
## Decisions
|
||||||
|
|
||||||
@@ -21,6 +20,7 @@ In `docs/decisions.md`:
|
|||||||
- Links
|
- Links
|
||||||
- Ids stay site-local
|
- Ids stay site-local
|
||||||
- Plain task ids come from position
|
- Plain task ids come from position
|
||||||
|
- The plain flavour's spellings
|
||||||
- The HTML dialect
|
- The HTML dialect
|
||||||
- No runtime dependencies
|
- No runtime dependencies
|
||||||
- Standards ship as data
|
- Standards ship as data
|
||||||
@@ -42,6 +42,7 @@ In `docs/decisions.md`:
|
|||||||
- The coverage floors
|
- The coverage floors
|
||||||
- The size ratchet
|
- The size ratchet
|
||||||
- Properties on a fixed seed
|
- Properties on a fixed seed
|
||||||
|
- The CommonMark suite checks three ways
|
||||||
- The flavour spec is read as a source
|
- The flavour spec is read as a source
|
||||||
- The node tables answer to Atlassian's schema
|
- The node tables answer to Atlassian's schema
|
||||||
- Nothing recurses unbounded
|
- Nothing recurses unbounded
|
||||||
@@ -49,6 +50,7 @@ In `docs/decisions.md`:
|
|||||||
- A retry loop checks its own termination
|
- A retry loop checks its own termination
|
||||||
- Readers scan by index
|
- Readers scan by index
|
||||||
- The spelling memo
|
- The spelling memo
|
||||||
|
- Cost fixes are measured, never timed
|
||||||
- Only the hard break holds a raw newline
|
- Only the hard break holds a raw newline
|
||||||
- Emphasis follows CommonMark's matching
|
- Emphasis follows CommonMark's matching
|
||||||
- Readable spellings take the `try` prefix
|
- Readable spellings take the `try` prefix
|
||||||
@@ -82,7 +84,7 @@ a hang. A leg added later owes the same marker, and a function a leg reaches cha
|
|||||||
with `&&`, because the `||` that captures the leg's status suspends `set -e` for everything it
|
with `&&`, because the `||` that captures the leg's status suspends `set -e` for everything it
|
||||||
calls. A leg whose output is both streamed and grepped keeps the copy in a `mktemp`
|
calls. A leg whose output is both streamed and grepped keeps the copy in a `mktemp`
|
||||||
file: `tee /dev/stderr` reopens fd 2, and under `./ci.sh > log 2>&1` the two offsets punch NUL
|
file: `tee /dev/stderr` reopens fd 2, and under `./ci.sh > log 2>&1` the two offsets punch NUL
|
||||||
holes through each other's lines (4d).
|
holes through each other's lines.
|
||||||
|
|
||||||
`PROPERTY_RUNS=<runs>` raises the property runs and randomizes the seed for local digging. The
|
`PROPERTY_RUNS=<runs>` raises the property runs and randomizes the seed for local digging. The
|
||||||
generators and run parameters properties share live in `src/conformance/property-harness.ts`,
|
generators and run parameters properties share live in `src/conformance/property-harness.ts`,
|
||||||
|
|||||||
+55
-8
@@ -11,12 +11,15 @@ a backslash reach them intact; what the flavour cannot spell reduces ADF→ADF a
|
|||||||
|
|
||||||
## The round-trip is the product
|
## The round-trip is the product
|
||||||
|
|
||||||
2026-08-23, the maintainer. Goal 1. Valid while a consumer saves back through the lossless pair.
|
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
|
`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.
|
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
|
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.
|
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
|
## Markdown in is a canonical fixpoint
|
||||||
|
|
||||||
@@ -131,6 +134,22 @@ position in document order, unique within the document and minted with no host A
|
|||||||
rejecting a missing `localId` takes the document and the same markdown reads to the same ids every
|
rejecting a missing `localId` takes the document and the same markdown reads to the same ids every
|
||||||
run.
|
run.
|
||||||
|
|
||||||
|
## The plain flavour's spellings
|
||||||
|
|
||||||
|
2026-09-14, panels 2026-09-25, the maintainer. Goal 5. Valid while GitHub's renderer is the one the
|
||||||
|
audience's markdown is read in.
|
||||||
|
|
||||||
|
README §Plain markdown's rows come from a survey of GitHub, GitLab, Gitea, Obsidian, Pandoc,
|
||||||
|
MkDocs, Docusaurus, Typora, Joplin, Logseq, Bear, Notion, Azure DevOps and Discord, GitHub's
|
||||||
|
renderer confirming each shape. Reader panels settled `error` as an error panel and the `==`
|
||||||
|
bounds (3 of 3), the external image's two forms (6 of 7), the omission notes and a rule opening a
|
||||||
|
list item dropping (3 of 3), and a list's numbering overflowing into bullets (3 of 3, 5 of 7).
|
||||||
|
Reading takes other tools' spellings, since it reads their output and writes none of them.
|
||||||
|
Rejected: `~sub~` and `^sup^` (`~2~` is a strike on GitHub, so `subsup` drops), underline and colour
|
||||||
|
spellings, raw HTML (`<details>`, `<mark>`), MkDocs `!!!` and the `:::` admonition family,
|
||||||
|
footnotes, definition lists, wikilinks, embeds, tags, comments, TOC tokens, spoilers, task states
|
||||||
|
past `[x]`/`[ ]`, and lifting bare URLs, `@name`, `:shortcode:` or ISO dates into nodes.
|
||||||
|
|
||||||
## The HTML dialect
|
## The HTML dialect
|
||||||
|
|
||||||
2026-08-23, the maintainer. Goals 4 and 7. Valid while HTML output is read by consumers styling it
|
2026-08-23, the maintainer. Goals 4 and 7. Valid while HTML output is read by consumers styling it
|
||||||
@@ -202,21 +221,24 @@ an npm consumer.
|
|||||||
|
|
||||||
## Public on npm
|
## Public on npm
|
||||||
|
|
||||||
2026-08-23, the maintainer. Goal 7. Valid while the package's source stays public beside it.
|
2026-08-23, the name 2026-09-01, the maintainer. Goals 2 and 7. Valid while the package's source
|
||||||
|
stays public beside it.
|
||||||
|
|
||||||
Published to public npm as `@larvit/adf-codec`. Public source: the Gitea repo goes public,
|
Published to public npm as `@larvit/adf-codec`. Public source: the Gitea repo goes public,
|
||||||
LICENSE in place, before the first publish.
|
LICENSE in place, before the first publish. A codec, since it converts both directions, and named
|
||||||
|
for the hub rather than the formats around it.
|
||||||
|
|
||||||
## The formats are API
|
## The formats are API
|
||||||
|
|
||||||
2026-08-23, content models 2026-09-16, the maintainer. Goals 1 and 6. Valid while consumers store
|
2026-08-23, strict input 2026-09-01, content models 2026-09-16, the maintainer. Goals 1 and 6.
|
||||||
what the library emits.
|
Valid while consumers store what the library emits.
|
||||||
|
|
||||||
The emitted markdown and HTML are contracts. After 1.0: previously-emitted output parsing
|
The emitted markdown and HTML are contracts. After 1.0: previously-emitted output parsing
|
||||||
differently, or not at all, is MAJOR; new syntax while old output still round-trips is MINOR.
|
differently, or not at all, is MAJOR; new syntax while old output still round-trips is MINOR.
|
||||||
Pre-1.0, normal 0.x rules. A spelled node's content model is part of that contract — leaf or
|
Pre-1.0, normal 0.x rules. A spelled node's content model is part of that contract — leaf or
|
||||||
container is the model, not the syntax — so giving a spelled node's model content it had not, or
|
container is the model, not the syntax — so giving a spelled node's model content it had not, or
|
||||||
taking it away, is MAJOR whatever ADF's own schema does.
|
taking it away, is MAJOR whatever ADF's own schema does. Input reads the canonical directive
|
||||||
|
spelling alone — spacing, key order, each value's spelling — since loosening it later is MINOR.
|
||||||
|
|
||||||
The error surface is a contract too; `README.md` §The errors states it to the consumer, and the
|
The error surface is a contract too; `README.md` §The errors states it to the consumer, and the
|
||||||
types in `src/result.ts` hold its shape.
|
types in `src/result.ts` hold its shape.
|
||||||
@@ -354,7 +376,9 @@ is the other's `127.0.0.1`; `--headless --screenshot` has no such channel, and l
|
|||||||
`dist/index.js` in a globals-stripped realm buys one by not running a browser. The leg re-checks
|
`dist/index.js` in a globals-stripped realm buys one by not running a browser. The leg re-checks
|
||||||
the conversions and nothing else — each fixture's emitted markdown, its parsed document, its error
|
the conversions and nothing else — each fixture's emitted markdown, its parsed document, its error
|
||||||
code — leaving the corpus's pairing, uniqueness, source positions and byte-level equality to the
|
code — leaving the corpus's pairing, uniqueness, source positions and byte-level equality to the
|
||||||
Node suite that owns them.
|
Node suite that owns them. `selenium/standalone-firefox` runs it over the smaller
|
||||||
|
`instrumentisto/geckodriver`: the leg is worth a current SpiderMonkey, and that image fell four
|
||||||
|
Firefox majors behind.
|
||||||
|
|
||||||
## The coverage floors
|
## The coverage floors
|
||||||
|
|
||||||
@@ -390,6 +414,18 @@ exits 0 on.
|
|||||||
Beside the corpus, properties run over documents generated from the node tables and over generated
|
Beside the corpus, properties run over documents generated from the node tables and over generated
|
||||||
markdown, on a fixed seed in the gate; a counterexample found becomes a round-trip fixture.
|
markdown, on a fixed seed in the gate; a counterexample found becomes a round-trip fixture.
|
||||||
|
|
||||||
|
## The CommonMark suite checks three ways
|
||||||
|
|
||||||
|
2026-08-27, the maintainer. Goals 1 and 8. Valid while the suite's answers are HTML ADF cannot be
|
||||||
|
compared against.
|
||||||
|
|
||||||
|
Each example is a named error or markdown that parses and emits to itself byte for byte; its
|
||||||
|
reference HTML's text, tags stripped and entities decoded, equals the parsed document's; and its
|
||||||
|
elements count the marks and nodes they map to. The fixpoint alone passes a parser returning the
|
||||||
|
empty document, the text alone one dropping every emphasis. An exception is the maintainer's to
|
||||||
|
add, and valid CommonMark parsing to a document `adfToMarkdown` refuses where a spelling could exist
|
||||||
|
is a bug to fix, never an exception.
|
||||||
|
|
||||||
## The flavour spec is read as a source
|
## The flavour spec is read as a source
|
||||||
|
|
||||||
2026-09-01, the maintainer. Goal 1. Valid while `spec/flavour.md` restates the node tables in
|
2026-09-01, the maintainer. Goal 1. Valid while `spec/flavour.md` restates the node tables in
|
||||||
@@ -465,6 +501,17 @@ rebases; a read below re-spells, because a hit skips the depth guards the walk i
|
|||||||
an ordered list past the marker cap gives way, spending two emitter levels where the parser spent
|
an ordered list past the marker cap gives way, spending two emitter levels where the parser spent
|
||||||
one. Only what succeeded is kept, so no path minted at another position is ever read.
|
one. Only what succeeded is kept, so no path minted at another position is ever read.
|
||||||
|
|
||||||
|
## Cost fixes are measured, never timed
|
||||||
|
|
||||||
|
2026-09-18, the maintainer and the stability-reviewer. Goal 9. Valid while Goal 9 promises growth
|
||||||
|
rather than a figure.
|
||||||
|
|
||||||
|
A cost fix that changes no behaviour lands on the suite staying green with no fixture output
|
||||||
|
changed, and a before-and-after figure in its PR; the gate times nothing. Measured and kept:
|
||||||
|
`adfDocumentFault`'s shape and depth walks stay two — the parting gives depth its own code — at
|
||||||
|
52 ms for a 9 MB document the emit takes 314 ms over; and `continuesContainer`'s re-scan per item
|
||||||
|
level stays, linear in the lines and bounded in depth by the 500-level guard.
|
||||||
|
|
||||||
## Only the hard break holds a raw newline
|
## Only the hard break holds a raw newline
|
||||||
|
|
||||||
2026-08-26, the maintainer. Goal 1. Valid while the whitespace carry finds a line edge by its raw
|
2026-08-26, the maintainer. Goal 1. Valid while the whitespace carry finds a line edge by its raw
|
||||||
|
|||||||
-1172
File diff suppressed because it is too large
Load Diff
@@ -2,17 +2,11 @@
|
|||||||
|
|
||||||
## 0.2.0
|
## 0.2.0
|
||||||
|
|
||||||
- **36 — Move every decision into `docs/decisions.md`, indexed from `AGENTS.md`.** Each entry states
|
|
||||||
the decision, its date, who made it, the README goal it serves and the premise it is valid while;
|
|
||||||
one no goal serves is proposed as a goal and asked. Sources: `AGENTS.md`'s body, the settled text
|
|
||||||
in this file's items, and `todo-history.md`, deleted with the bare `(28)` citations into it once
|
|
||||||
nothing cites it. Split by `AGENTS.md` section where one chunk is too big.
|
|
||||||
- **36e — Move `todo-history.md`'s decisions, re-point its citations and delete it.**
|
|
||||||
- **35 — Read and write plain markdown as a flavour of the markdown grammar.** Per Goal 2 and
|
- **35 — Read and write plain markdown as a flavour of the markdown grammar.** Per Goal 2 and
|
||||||
`docs/decisions.md` §Plain markdown is a flavour of the grammar, 10's rows are read by
|
`docs/decisions.md` §Plain markdown is a flavour of the grammar, README §Plain markdown's rows are
|
||||||
`markdownToAdf`'s parser and written by `adfToMarkdown`'s writer, and the lift goes. The exports,
|
read by `markdownToAdf`'s parser and written by `adfToMarkdown`'s writer, and the lift goes. The
|
||||||
their refusals and 10's rows stay as they are.
|
exports, their refusals and those rows stay as they are.
|
||||||
- **35a — Read the plain flavour in the parser and delete the lift.** 10's rows are read while
|
- **35a — Read the plain flavour in the parser and delete the lift.** The rows are read while
|
||||||
parsing, and `plain-lift.ts` is deleted, its tests reading through `plainMarkdownToAdf`. `>
|
parsing, and `plain-lift.ts` is deleted, its tests reading through `plainMarkdownToAdf`. `>
|
||||||
[!faq]- Why?` with the body on the next `>` line reads to an expand titled `Why?` whose body
|
[!faq]- Why?` with the body on the next `>` line reads to an expand titled `Why?` whose body
|
||||||
keeps the next lines' link targets and marks, and `> [!tip] Title` then `> body` to a panel
|
keeps the next lines' link targets and marks, and `> [!tip] Title` then `> body` to a panel
|
||||||
@@ -24,14 +18,15 @@
|
|||||||
`plainMarkdownToAdf(adfToPlainMarkdown(doc))` keeps a literal `==x==`, a quote opening `[!NOTE]`
|
`plainMarkdownToAdf(adfToPlainMarkdown(doc))` keeps a literal `==x==`, a quote opening `[!NOTE]`
|
||||||
and a list whose items all open `[x] ` as text. A highlighted `=` (today `=====`) and `a==b`
|
and a list whose items all open `[x] ` as text. A highlighted `=` (today `=====`) and `a==b`
|
||||||
(today `==a==b==`, highlighting `a` alone) come back highlighted whole, or lose the highlight
|
(today `==a==b==`, highlighting `a` alone) come back highlighted whole, or lose the highlight
|
||||||
where no spelling holds them; 10c's byte-for-byte property misses both, since the wrong document
|
where no spelling holds them; the plain pair's byte-for-byte property misses both, since the
|
||||||
re-spells to the same bytes. The reduction keeps only degrading what the flavour cannot spell.
|
wrong document re-spells to the same bytes. The reduction keeps only degrading what the flavour
|
||||||
|
cannot spell.
|
||||||
- **10f — Give task nodes read from plain markdown position ids.** Per `docs/decisions.md` §Plain
|
- **10f — Give task nodes read from plain markdown position ids.** Per `docs/decisions.md` §Plain
|
||||||
task ids come from position, README §Plain markdown's `localId` bullet saying so. The id spelling
|
task ids come from position, README §Plain markdown's `localId` bullet saying so. The id spelling
|
||||||
is part of the chunk.
|
is part of the chunk.
|
||||||
- **6 — Specify the HTML dialect.** Element-by-element mapping, the `data-*` fidelity scheme, the
|
- **6 — Specify the HTML dialect.** Element-by-element mapping, the `data-*` fidelity scheme, the
|
||||||
opaque-carry form, and the documented foreign-element set `htmlToAdf` accepts — the set
|
opaque-carry form, and the documented foreign-element set `htmlToAdf` accepts — the set
|
||||||
`markdownToAdf` shares (`spec/flavour.md` §Raw HTML in input; 29).
|
`markdownToAdf` shares (`spec/flavour.md` §Raw HTML in input).
|
||||||
The set sorts per `docs/decisions.md` §Foreign HTML sorts three ways.
|
The set sorts per `docs/decisions.md` §Foreign HTML sorts three ways.
|
||||||
- **7 — Ship HTML: `adfToHtml`, `htmlToAdf`, and `markdownToHtml` / `htmlToMarkdown` composed
|
- **7 — Ship HTML: `adfToHtml`, `htmlToAdf`, and `markdownToHtml` / `htmlToMarkdown` composed
|
||||||
through ADF.** CommonMark spec suite runs against `markdownToHtml` from here. The README's
|
through ADF.** CommonMark spec suite runs against `markdownToHtml` from here. The README's
|
||||||
@@ -53,6 +48,9 @@
|
|||||||
`line-escaping.ts`'s `charAt` and the parser's flanking read one UTF-16 unit beside an astral
|
`line-escaping.ts`'s `charAt` and the parser's flanking read one UTF-16 unit beside an astral
|
||||||
symbol — a lone surrogate is neither punctuation nor symbol, where CommonMark reads `😀` as
|
symbol — a lone surrogate is neither punctuation nor symbol, where CommonMark reads `😀` as
|
||||||
punctuation — and, where they do, read the code point, with a fixture per direction.
|
punctuation — and, where they do, read the code point, with a fixture per direction.
|
||||||
|
- **38 — Spell a lone surrogate in a text node so it survives a UTF-8 encode.** `adfToMarkdown`
|
||||||
|
emits it verbatim, so markdown stored as UTF-8 reads back U+FFFD; attribute values already escape
|
||||||
|
it.
|
||||||
- **5f — Publish the bundle size, after 7 changes it.** Measure the shipped artifact and put the
|
- **5f — Publish the bundle size, after 7 changes it.** Measure the shipped artifact and put the
|
||||||
number in the README, kept honest by the release pipeline rather than by a human re-reading it.
|
number in the README, kept honest by the release pipeline rather than by a human re-reading it.
|
||||||
The quantity is what a consumer downloads and loads: the tarball `npm pack` produces, its unpacked
|
The quantity is what a consumer downloads and loads: the tarball `npm pack` produces, its unpacked
|
||||||
|
|||||||
Reference in New Issue
Block a user