From 1b7f66546ed728a7b3bd63500896d521a51b878d Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 16:44:32 +0200 Subject: [PATCH 1/6] Hold the shipped source to ECMAScript alone, and run the suite on Deno and Bun --- AGENTS.md | 10 ++++++++++ README.md | 3 ++- ci.sh | 15 ++++++++++----- package.json | 2 +- renovate.json | 18 ++++++++++++++++++ todo.md | 6 +++++- tsconfig.build.json | 9 +++++++++ 7 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tsconfig.build.json diff --git a/AGENTS.md b/AGENTS.md index b1716bc..f1be552 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,6 +60,12 @@ they never reach a consumer. ## 6. The package contract +- Runs on every runtime, not only Node — a browser as readily as a server. The shipped source is + ECMAScript and nothing else, at an ES2022 baseline: no host import, no host global, no DOM. + `tsconfig.build.json` is that gate, typechecking the shipped files alone with `types: []` and + `lib: ES2022`, so `node:fs`, `process` and an ES2024 method are compile errors here rather than a + consumer's crash there. Node's test runner, the corpus reads and the build are the repo's own, + never the library's. - ESM only — no CommonJS build, no dual-package hazard. - One entrypoint: built JavaScript, `.d.ts` beside it. Do not add a TypeScript-source entrypoint — Node refuses to type-strip under `node_modules` (`ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`), @@ -113,6 +119,10 @@ Test for the behaviour wanted first, then implement until green. `node --test`, Node, tsc and npm never run on the host — only via the pinned images (§9). Tests are independent, coverage does not decline, containers are torn down after a run. +The gate runs that same suite under Deno and Bun as well as Node, the three images pinned alike: +§6's compile gate proves no host API is named, and only running proves those engines execute what +is written. Both refuse a run that matches no test, so Node's is the only vacuous-green guard. + The floors live in the `test` script, so `npm test` and the gate are one path: 100% of lines and functions, and a branch floor that only ever moves upward. It sits below 100 because the guards `noUncheckedIndexedAccess` and ADF's optional keys force — `?? []`, `?? {}`, `?.`, an index diff --git a/README.md b/README.md index aa3c5d2..d7beca0 100644 --- a/README.md +++ b/README.md @@ -64,4 +64,5 @@ Personas, never named consumers (AGENTS.md §7): ## The package ESM only, no runtime dependencies, public npmjs. Built JavaScript with `.d.ts` beside it. -Contract: `AGENTS.md` §5–6. +Pure ECMAScript at an ES2022 baseline, reaching for no host API, so a browser runs it as readily +as a server; the test suite runs under Node, Deno and Bun. Contract: `AGENTS.md` §5–6. diff --git a/ci.sh b/ci.sh index ceb3dbb..7b729e9 100755 --- a/ci.sh +++ b/ci.sh @@ -2,13 +2,15 @@ set -euo pipefail cd "$(dirname "$0")" -image=node:24.19.0-alpine3.24 -in_node() { docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/app" -w /app "$image" "$@"; } +bun_image=oven/bun:1.4.0-alpine +deno_image=denoland/deno:2.9.6 +node_image=node:24.19.0-alpine3.24 +in_image() { docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/app" -w /app --entrypoint "$2" "$1" "${@:3}"; } -in_node npm ci -in_node npm run typecheck +in_image "$node_image" npm ci +in_image "$node_image" npm run typecheck -if ! test_output=$(in_node npm test 2>&1); then +if ! test_output=$(in_image "$node_image" npm test 2>&1); then printf '%s\n' "$test_output" exit 1 fi @@ -17,3 +19,6 @@ if printf '%s' "$test_output" | grep -q 'ℹ tests 0'; then echo 'the gate ran zero tests — failing instead of a vacuous green' exit 1 fi + +in_image "$deno_image" deno test --allow-read --no-check src/ +in_image "$bun_image" bun test diff --git a/package.json b/package.json index 895c904..b3aab5f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "scripts": { "test": "node --test --experimental-test-coverage --test-coverage-exclude=\"src/**/*.test.ts\" --test-coverage-branches=97 --test-coverage-functions=100 --test-coverage-lines=100 \"src/**/*.test.ts\"", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.build.json" }, "devDependencies": { "@types/node": "24.13.3", diff --git a/renovate.json b/renovate.json index 1c7b4c6..10c4b43 100644 --- a/renovate.json +++ b/renovate.json @@ -2,6 +2,15 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "automerge": true, "customManagers": [ + { + "customType": "regex", + "datasourceTemplate": "docker", + "depNameTemplate": "denoland/deno", + "description": "Pin the Deno image ci.sh runs", + "managerFilePatterns": ["ci.sh"], + "matchStrings": ["denoland/deno:(?[0-9][^\\s\"']*)"], + "versioningTemplate": "docker" + }, { "customType": "regex", "datasourceTemplate": "docker", @@ -11,6 +20,15 @@ "matchStrings": ["node:(?[0-9][^\\s\"']*)"], "versioningTemplate": "docker" }, + { + "customType": "regex", + "datasourceTemplate": "docker", + "depNameTemplate": "oven/bun", + "description": "Pin the Bun image ci.sh runs", + "managerFilePatterns": ["ci.sh"], + "matchStrings": ["oven/bun:(?[0-9][^\\s\"']*)"], + "versioningTemplate": "docker" + }, { "customType": "regex", "datasourceTemplate": "docker", diff --git a/todo.md b/todo.md index c0080f0..c7a0428 100644 --- a/todo.md +++ b/todo.md @@ -139,10 +139,14 @@ numbering is the order the work was planned in, not the order it ships. additions are read here as one list before that freeze — nine sessions mint them independently, and one cause wearing two codes is breaking to undo after `0.1.0`. `0.1.0` is the markdown round-trip: both markdown directions, the types, `isAdfDocument`. The build - lands here: a build tsconfig emitting JS and `.d.ts` to `dist/` (the dev config's + lands here: `tsconfig.build.json` gains emit of JS and `.d.ts` to `dist/` (the dev config's `allowImportingTsExtensions` forces `noEmit`, so the build config needs `rewriteRelativeImportExtensions`), plus `exports`/`files` in `package.json`. The maintainer's bump PR also removes `private: true`, the guard against any earlier publish. + §6's browser half is first checkable here, on the emitted `dist/index.js` a browser can + load — the compile gate names no host API, and a real page converting a document is the + other half. `engines` is settled here too: `>=24` is the toolchain's floor, not the ES2022 + one the shipped JavaScript needs, and it reads to a consumer as the latter. **Settled** (the maintainer, 2026-09-01): the round-trip proved over the checked-in corpus is what `0.1.0` ships on, and the open-ended proof work follows it rather than gating it — 3k's spec suite and 4's generators and maintainer-supplied payloads are `0.2.0`, 4b's retry diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..de207e6 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["ES2022"], + "target": "ES2022", + "types": [] + }, + "exclude": ["src/**/*.test.ts"] +} From 082dabb261eec420000f72382bb3e32d0f8a861e Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 16:51:15 +0200 Subject: [PATCH 2/6] State the shipped ECMAScript floor in engines, not the toolchain's --- AGENTS.md | 3 ++- package.json | 2 +- todo.md | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f1be552..286d46e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -65,7 +65,8 @@ they never reach a consumer. `tsconfig.build.json` is that gate, typechecking the shipped files alone with `types: []` and `lib: ES2022`, so `node:fs`, `process` and an ES2024 method are compile errors here rather than a consumer's crash there. Node's test runner, the corpus reads and the build are the repo's own, - never the library's. + never the library's, and `engines.node` states the floor the shipped JavaScript needs — `>=18`, + the lowest line carrying ES2022 — never the higher one those repo-only tools want. - ESM only — no CommonJS build, no dual-package hazard. - One entrypoint: built JavaScript, `.d.ts` beside it. Do not add a TypeScript-source entrypoint — Node refuses to type-strip under `node_modules` (`ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`), diff --git a/package.json b/package.json index b3aab5f..cacfab5 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "type": "module", "engines": { - "node": ">=24" + "node": ">=18" }, "scripts": { "test": "node --test --experimental-test-coverage --test-coverage-exclude=\"src/**/*.test.ts\" --test-coverage-branches=97 --test-coverage-functions=100 --test-coverage-lines=100 \"src/**/*.test.ts\"", diff --git a/todo.md b/todo.md index c7a0428..b262f10 100644 --- a/todo.md +++ b/todo.md @@ -145,8 +145,7 @@ numbering is the order the work was planned in, not the order it ships. maintainer's bump PR also removes `private: true`, the guard against any earlier publish. §6's browser half is first checkable here, on the emitted `dist/index.js` a browser can load — the compile gate names no host API, and a real page converting a document is the - other half. `engines` is settled here too: `>=24` is the toolchain's floor, not the ES2022 - one the shipped JavaScript needs, and it reads to a consumer as the latter. + other half. **Settled** (the maintainer, 2026-09-01): the round-trip proved over the checked-in corpus is what `0.1.0` ships on, and the open-ended proof work follows it rather than gating it — 3k's spec suite and 4's generators and maintainer-supplied payloads are `0.2.0`, 4b's retry From de9f23581e2023e7749bf184cbff0e3852614423 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 16:59:00 +0200 Subject: [PATCH 3/6] Answer the architecture pass: the config that owns the contract, and what each runtime leg buys --- AGENTS.md | 13 ++++++++----- ci.sh | 8 ++++++-- todo.md | 11 +++++++---- tsconfig.build.json | 26 +++++++++++++++++++++++--- tsconfig.json | 25 +++---------------------- 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 286d46e..08e79a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -65,8 +65,8 @@ they never reach a consumer. `tsconfig.build.json` is that gate, typechecking the shipped files alone with `types: []` and `lib: ES2022`, so `node:fs`, `process` and an ES2024 method are compile errors here rather than a consumer's crash there. Node's test runner, the corpus reads and the build are the repo's own, - never the library's, and `engines.node` states the floor the shipped JavaScript needs — `>=18`, - the lowest line carrying ES2022 — never the higher one those repo-only tools want. + never the library's, and `engines.node` states the floor the shipped JavaScript needs — `>=18` — + never the higher one those repo-only tools want. - ESM only — no CommonJS build, no dual-package hazard. - One entrypoint: built JavaScript, `.d.ts` beside it. Do not add a TypeScript-source entrypoint — Node refuses to type-strip under `node_modules` (`ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`), @@ -120,9 +120,12 @@ Test for the behaviour wanted first, then implement until green. `node --test`, Node, tsc and npm never run on the host — only via the pinned images (§9). Tests are independent, coverage does not decline, containers are torn down after a run. -The gate runs that same suite under Deno and Bun as well as Node, the three images pinned alike: -§6's compile gate proves no host API is named, and only running proves those engines execute what -is written. Both refuse a run that matches no test, so Node's is the only vacuous-green guard. +The gate runs that same suite under Deno and Bun as well as Node, the three images pinned alike, +and neither extra leg is Node's proof twice. Deno refuses an extensionless or directory specifier, +so it holds the module graph to the fully-spelled form a browser can load; Bun runs +JavaScriptCore, the one engine of the three that is not V8, where the Unicode property escapes +emphasis matching leans on can disagree. Both refuse a run matching no test, so Node's is the only +vacuous-green guard. The floors live in the `test` script, so `npm test` and the gate are one path: 100% of lines and functions, and a branch floor that only ever moves upward. It sits below 100 because the guards diff --git a/ci.sh b/ci.sh index 7b729e9..07cbae9 100755 --- a/ci.sh +++ b/ci.sh @@ -5,7 +5,11 @@ cd "$(dirname "$0")" bun_image=oven/bun:1.4.0-alpine deno_image=denoland/deno:2.9.6 node_image=node:24.19.0-alpine3.24 -in_image() { docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/app" -w /app --entrypoint "$2" "$1" "${@:3}"; } +in_image() { + local image=$1 entrypoint=$2 + shift 2 + docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/app" -w /app --entrypoint "$entrypoint" "$image" "$@" +} in_image "$node_image" npm ci in_image "$node_image" npm run typecheck @@ -21,4 +25,4 @@ if printf '%s' "$test_output" | grep -q 'ℹ tests 0'; then fi in_image "$deno_image" deno test --allow-read --no-check src/ -in_image "$bun_image" bun test +in_image "$bun_image" bun test src/ diff --git a/todo.md b/todo.md index b262f10..1224155 100644 --- a/todo.md +++ b/todo.md @@ -139,13 +139,16 @@ numbering is the order the work was planned in, not the order it ships. additions are read here as one list before that freeze — nine sessions mint them independently, and one cause wearing two codes is breaking to undo after `0.1.0`. `0.1.0` is the markdown round-trip: both markdown directions, the types, `isAdfDocument`. The build - lands here: `tsconfig.build.json` gains emit of JS and `.d.ts` to `dist/` (the dev config's - `allowImportingTsExtensions` forces `noEmit`, so the build config needs - `rewriteRelativeImportExtensions`), plus `exports`/`files` in `package.json`. The + lands here: `tsconfig.build.json` gains emit of JS and `.d.ts` to `dist/` (its own + `allowImportingTsExtensions` forces `noEmit`, so `rewriteRelativeImportExtensions` lands + beside it), plus `exports`/`files` in `package.json`. The maintainer's bump PR also removes `private: true`, the guard against any earlier publish. §6's browser half is first checkable here, on the emitted `dist/index.js` a browser can load — the compile gate names no host API, and a real page converting a document is the - other half. + other half; name the engines that page covers, since Bun's JavaScriptCore is not Safari's + and none of the three legs is SpiderMonkey. `engines.node` gets its one-line proof here + too — `import('./dist/index.js')` under a pinned `node:18` image, which cannot run the + suite that type stripping wants 22+ for, but proves exactly what the field claims. **Settled** (the maintainer, 2026-09-01): the round-trip proved over the checked-in corpus is what `0.1.0` ships on, and the open-ended proof work follows it rather than gating it — 3k's spec suite and 4's generators and maintainer-supplied payloads are `0.2.0`, 4b's retry diff --git a/tsconfig.build.json b/tsconfig.build.json index de207e6..40534a9 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,9 +1,29 @@ { - "extends": "./tsconfig.json", "compilerOptions": { "lib": ["ES2022"], + "module": "NodeNext", + "moduleResolution": "NodeNext", "target": "ES2022", - "types": [] + "types": [], + + "allowImportingTsExtensions": true, + "erasableSyntaxOnly": true, + "isolatedModules": true, + "noEmit": true, + "verbatimModuleSyntax": true, + + "strict": true, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true }, - "exclude": ["src/**/*.test.ts"] + "exclude": ["src/**/*.test.ts"], + "include": ["src"] } diff --git a/tsconfig.json b/tsconfig.json index 56b43c1..2a9b579 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,9 @@ { + "extends": "./tsconfig.build.json", "compilerOptions": { "lib": ["ESNext"], - "module": "NodeNext", - "moduleResolution": "NodeNext", "target": "ESNext", - "types": ["node"], - - "allowImportingTsExtensions": true, - "erasableSyntaxOnly": true, - "isolatedModules": true, - "noEmit": true, - "verbatimModuleSyntax": true, - - "strict": true, - "exactOptionalPropertyTypes": true, - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true + "types": ["node"] }, - "include": ["src"] + "exclude": [] } From 9ed4bf5c8b9340808074815270f2c31f02d39adf Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 17:00:21 +0200 Subject: [PATCH 4/6] Record the three-shim constraint the cross-runtime gate buys its proof with --- AGENTS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 08e79a7..f1c6b82 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -125,7 +125,8 @@ and neither extra leg is Node's proof twice. Deno refuses an extensionless or di so it holds the module graph to the fully-spelled form a browser can load; Bun runs JavaScriptCore, the one engine of the three that is not V8, where the Unicode property escapes emphasis matching leans on can disagree. Both refuse a run matching no test, so Node's is the only -vacuous-green guard. +vacuous-green guard, and a test may reach only for what all three `node:` shims carry — the price +of proving those engines over the corpus rather than over a smoke import. The floors live in the `test` script, so `npm test` and the gate are one path: 100% of lines and functions, and a branch floor that only ever moves upward. It sits below 100 because the guards From 5d437b9fbc63ba392a4f3164cd396e5515f95331 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 17:07:00 +0200 Subject: [PATCH 5/6] Hold the promise to the standard, and put Firefox where the build makes it checkable --- AGENTS.md | 12 +++++++----- todo.md | 7 ++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f1c6b82..f50845b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,11 +60,13 @@ they never reach a consumer. ## 6. The package contract -- Runs on every runtime, not only Node — a browser as readily as a server. The shipped source is - ECMAScript and nothing else, at an ES2022 baseline: no host import, no host global, no DOM. - `tsconfig.build.json` is that gate, typechecking the shipped files alone with `types: []` and - `lib: ES2022`, so `node:fs`, `process` and an ES2024 method are compile errors here rather than a - consumer's crash there. Node's test runner, the corpus reads and the build are the repo's own, +- Runs on any ES2022 engine, not only Node — a browser as readily as a server. The shipped source + is ECMAScript and nothing else: no host import, no host global, no DOM. `tsconfig.build.json` is + that gate, typechecking the shipped files alone with `types: []` and `lib: ES2022`, so `node:fs`, + `process` and an ES2024 method are compile errors here rather than a consumer's crash there. The + standard is the line, never an engine list: one implementing it in part — Hermes is the live + doubt, on the Unicode property escapes and the lookbehind the markdown grammar spells — is out of + scope rather than a bug. Node's test runner, the corpus reads and the build are the repo's own, never the library's, and `engines.node` states the floor the shipped JavaScript needs — `>=18` — never the higher one those repo-only tools want. - ESM only — no CommonJS build, no dual-package hazard. diff --git a/todo.md b/todo.md index 1224155..0ed3e30 100644 --- a/todo.md +++ b/todo.md @@ -144,9 +144,10 @@ numbering is the order the work was planned in, not the order it ships. beside it), plus `exports`/`files` in `package.json`. The maintainer's bump PR also removes `private: true`, the guard against any earlier publish. §6's browser half is first checkable here, on the emitted `dist/index.js` a browser can - load — the compile gate names no host API, and a real page converting a document is the - other half; name the engines that page covers, since Bun's JavaScriptCore is not Safari's - and none of the three legs is SpiderMonkey. `engines.node` gets its one-line proof here + load — the compile gate names no host API, and a real page converting the corpus is the + other half. Headless Firefox is that page, settling both at once: the browser proof, and the + only SpiderMonkey there is, `ci.sh`'s three legs being two V8s and a JavaScriptCore that is + not Safari's. `engines.node` gets its one-line proof here too — `import('./dist/index.js')` under a pinned `node:18` image, which cannot run the suite that type stripping wants 22+ for, but proves exactly what the field claims. **Settled** (the maintainer, 2026-09-01): the round-trip proved over the checked-in corpus From f8c50d5e8187698ddddbaf1f4fe6a9a9719224b2 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 1 Sep 2026 17:17:33 +0200 Subject: [PATCH 6/6] Answer the stability pass: the claim no proof stands behind, and the facts stated twice --- AGENTS.md | 15 ++++++++------- README.md | 4 ++-- todo.md | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f50845b..eddfd07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,11 +62,11 @@ they never reach a consumer. - Runs on any ES2022 engine, not only Node — a browser as readily as a server. The shipped source is ECMAScript and nothing else: no host import, no host global, no DOM. `tsconfig.build.json` is - that gate, typechecking the shipped files alone with `types: []` and `lib: ES2022`, so `node:fs`, - `process` and an ES2024 method are compile errors here rather than a consumer's crash there. The - standard is the line, never an engine list: one implementing it in part — Hermes is the live - doubt, on the Unicode property escapes and the lookbehind the markdown grammar spells — is out of - scope rather than a bug. Node's test runner, the corpus reads and the build are the repo's own, + that gate, typechecking the shipped files alone, so `node:fs`, `process` and an ES2024 method are + compile errors here rather than a consumer's crash there. The standard is the line, never an + engine list: one implementing it in part — Hermes is the live doubt, on §10's property escapes + and on lookbehind — is out of scope rather than a bug. Node's test runner, the corpus reads and + the build are the repo's own, never the library's, and `engines.node` states the floor the shipped JavaScript needs — `>=18` — never the higher one those repo-only tools want. - ESM only — no CommonJS build, no dual-package hazard. @@ -113,8 +113,9 @@ descends, so a document reports its first error in document order. differs from npm → publish and tag `vX.Y.Z`. No bump, no deploy; the bump is each shipping PR's deliberate semver judgment. - Renovate watches devDependencies, Docker pins and action tags; automerges everything on green CI. -- Docker images pin the full patch version (`node:24.19.0-alpine3.24`, never `node:24`); actions - pin semver tags. +- Docker images pin the full patch version (`node:24.19.0-alpine3.24`, never `node:24`), as + specific as the publisher tags: `oven/bun:1.4.0-alpine` pins Bun's patch and leaves the base + floating because Bun publishes nothing narrower. Actions pin semver tags. ## 10. Tests first, in Docker diff --git a/README.md b/README.md index d7beca0..52cdc73 100644 --- a/README.md +++ b/README.md @@ -64,5 +64,5 @@ Personas, never named consumers (AGENTS.md §7): ## The package ESM only, no runtime dependencies, public npmjs. Built JavaScript with `.d.ts` beside it. -Pure ECMAScript at an ES2022 baseline, reaching for no host API, so a browser runs it as readily -as a server; the test suite runs under Node, Deno and Bun. Contract: `AGENTS.md` §5–6. +Pure ECMAScript at an ES2022 baseline, reaching for no host API; the test suite runs under Node, +Deno and Bun. Contract: `AGENTS.md` §5–6. diff --git a/todo.md b/todo.md index 0ed3e30..751786a 100644 --- a/todo.md +++ b/todo.md @@ -148,7 +148,7 @@ numbering is the order the work was planned in, not the order it ships. other half. Headless Firefox is that page, settling both at once: the browser proof, and the only SpiderMonkey there is, `ci.sh`'s three legs being two V8s and a JavaScriptCore that is not Safari's. `engines.node` gets its one-line proof here - too — `import('./dist/index.js')` under a pinned `node:18` image, which cannot run the + too — `import('./dist/index.js')` under a pinned Node 18 image, which cannot run the suite that type stripping wants 22+ for, but proves exactly what the field claims. **Settled** (the maintainer, 2026-09-01): the round-trip proved over the checked-in corpus is what `0.1.0` ships on, and the open-ended proof work follows it rather than gating it —