From 9f23c89719a04c2397a36b5492ab48e6a6ab011a Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 4 Oct 2026 19:21:11 +0200 Subject: [PATCH] Answer stability round 4: the decision's title backs the loop guarantee alone, item 66 filed --- AGENTS.md | 2 +- README.md | 4 ++-- docs/decisions.md | 13 ++++++------- todo.md | 10 +++++++++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 504edfd..b0d3f6f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,7 @@ In `docs/decisions.md`: - The flavour spec is read as a source - The node tables answer to Atlassian's schema - Nothing recurses unbounded -- The guards take what `JSON.parse` or `structuredClone` builds +- No value `JSON.parse` or `structuredClone` builds loops a call - Nothing spreads an unbounded array - A retry loop checks its own termination - Readers scan by index diff --git a/README.md b/README.md index 3137576..2b2c6d2 100644 --- a/README.md +++ b/README.md @@ -238,8 +238,8 @@ Serves Goals 1, 3 and 4. input. - Past that and `~~`, no GFM: an autolink literal and a `- [ ]` marker stay text, and a checklist is the `taskList` directive — `plainMarkdownToAdf` turns the marker into a `taskList`. -- A document nested deeper than 500 levels is an error result, not a stack overflow, and no value - `JSON.parse` or `structuredClone` builds makes a call loop forever. +- A document nested deeper than 500 levels is an error result, not a stack overflow, and no call + loops forever on a string, or on a value `JSON.parse` or `structuredClone` builds. - The emitted formats are semver surface ([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#the-formats-are-api)). - **`0.2.0`** — `htmlToAdf(adfToHtml(doc))` deep-equals `doc`; fidelity HTML cannot express rides diff --git a/docs/decisions.md b/docs/decisions.md index 5ca97cd..c5c18a2 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -563,15 +563,14 @@ format, as its parser does. A list giving way to the directive form refuses at z than walking again; counting every list twice halved the list limit, counting the directive form once doubled the parser's frames per level. -## The guards take what `JSON.parse` or `structuredClone` builds +## No value `JSON.parse` or `structuredClone` builds loops a call -2026-10-04, the maintainer. Goal 1. Valid while every persona hands in a value `JSON.parse`, -`structuredClone` or an object literal builds. +2026-10-04, the maintainer. Goals 1 and 8. Valid while every persona hands in plain data, as +`JSON.parse` or `structuredClone` builds it. -The guarantees speak of plain data: own enumerable keys and plain arrays, cycles and shared objects -included. The guards walk it by `Object.values` and refuse a cycle. An inherited or non-enumerable -key, a getter, a Proxy or a custom iterator is the caller's to rule out: no persona builds one, and -each guarded shape asked for another. +The guards walk a value by `Object.values` and refuse a cycle in it. An inherited or non-enumerable +key, a getter, a Proxy or a custom iterator is the caller's to rule out: no persona builds one. +Goal 8's size counts ADF as JSON, so a shared object costs once per place it is held. ## Nothing spreads an unbounded array diff --git a/todo.md b/todo.md index a367e4f..8b0ced3 100644 --- a/todo.md +++ b/todo.md @@ -6,7 +6,7 @@ `Bar = 9` -`Next ID = 66` +`Next ID = 67` | Goal | W | |---|---| @@ -29,6 +29,7 @@ | 45 | 0.2.0 | | **Replace `isAdfDocument` with a reader returning `Result`.** | 2 | 3 | 6 | 8 | 1 | 25.2 | | 6 | 0.2.0 | decision | **Specify the HTML dialect.** | 2 | 6 | 7 | 8 | 2, 3 | 24.7 | | 64 | 0.2.0 | defect | **Read back unchanged on V8 every JSON key the emitter writes, with a fixture whose key holds `\`, `"` or a control character.** | 4 | 4 | 6 | 8 | 1, 7 | 23.0 | +| 66 | 0.2.0 | | **Refuse an attribute value that is not a plain object, array or JSON primitive.** | 3 | 2 | 5 | 8 | 1 | 22.5 | | 43 | 0.2.0 | decision | **Give each markdown input its own reader, strict to its own standard.** | 6 | 7 | 8 | 9 | 3, 4 | 22.3 | | 65 | 0.2.0 | defect | **Read an image not alone in its paragraph as its alt text linked to its URL, and a titled image alone in its paragraph as the image captioned with its title.** | 5 | 5 | 7 | 7 | 3, 4, 6 | 18.7 | | 49 | 0.2.0 | | **Read a list whose bullet or ordered delimiter changes as two lists, in both readers, and retire `!adf:listBreak`.** | 4 | 5 | 5 | 8 | 3, 4 | 17.2 | @@ -101,6 +102,13 @@ Deno and Chrome the round-trip would refuse its own output or read back a differ tells which. Confirm with a fixture first; then read JSON with our own parser or record the gap with an ending item. Found by the README-goals audit, 2026-10-03. +### 66. Refuse an attribute value that is not a plain object, array or JSON primitive. + +`isJsonValue` (`json-value.ts`) walks any object by `Object.values`, so a `Date`, `Map`, `Set` or +typed array in `attrs`, as `structuredClone` keeps it, passes the guard and is written as `{}` or a +key per element: `ok: true` with content lost. Accept an object whose prototype is +`Object.prototype` or `null`, and an array. Found by the stability review of item 63, 2026-10-04. + ### 43. Give each markdown input its own reader, strict to its own standard. Today `markdownToAdf` reads CommonMark and the lossless flavour as one input: text shaped like a