Skip to content

fix(runtime): doctor fails Node 22.13.0 to 22.22.0, whose TextDecoder loses windows-1252 - #284

Merged
StepenkoAnatoli merged 2 commits into
mainfrom
claude/node-windows-1252-floor-20261011
Oct 11, 2026
Merged

StepenkoAnatoli merged 2 commits into
mainfrom
claude/node-windows-1252-floor-20261011

Conversation

@StepenkoAnatoli

Copy link
Copy Markdown
Owner

Fixes #282. Records ADR-0159.

What changed

lib/runtime.mjs gains nodeDecodesWindows1252(version), a version rule beside nodeHonoursEnvProxy: false for Node 22.13.0 through 22.22.0, true elsewhere. nodeLine returns a second fail for those builds, naming the defect (nodejs/node#60888) and the first good build (22.22.1 on the 22 line, or 24), so doctor's node finding carries it. Both READMEs now require "Node 22.22.1+ or 24+" with the reason. Six rows in the doctor Node-line test; the support-policy test that pins the requirement's presence accepts a patch-spelled floor. ADR-0159 with its index row, the runtime.mjs map row, and a CHANGELOG bullet are in the same commit. Inventory unchanged (1787).

Why

The kit decodes a page by its declared charset, and that reading is Node's TextDecoder. On 22.13.0 through 22.22.0 it reads windows-1252 as Latin-1, so a capture taken on such a build silently lost its euro signs, curly quotes and dashes and was hashed into the ledger as fetched, while doctor said the Node line passed. CI never met it because setup-node resolves '22' to the newest 22.x.

Measured boundary (byte 0x80 under the windows-1252 label, each Node installed here):

Node result
22.12.0 right
22.13.0, 22.21.0, 22.22.0 wrong
22.22.1, 22.22.3, 22.23.0, 22.23.3, 24.21.0 right

The hard floor every command refuses below stays at 22: it would refuse doctor, the command that explains the finding. Rejected alternatives (a table decoder behind a runtime probe, refusing in checkNode, documenting only) are in the ADR.

Verified

  • Red first: selftest.mjs doctor 65 passed, 1 failed with only the test rows in place.
  • After the fix: selftest.mjs doctor runtime support-policy 98 passed, 0 failed.
  • doctor on this container's Node 22.22.0 prints the failing node line and exits 1; on 24.21.0 it passes.
  • Full offline suite on Node 24.21.0 linux: 1787 passed, 0 failed, 202.2 s.
  • git diff --check clean; nine files LF-only.

Got wrong and fixed

The new README wording no longer matched the support-policy test's /Node 22\+/ check (one red in the focused run before commit). The regex now accepts a patch-spelled 22 floor, with the reason in a comment; the group and the full suite pass.

Untested

This PR's all-seven CI.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Gg4isLfN2Ng16zr5DwTnH9


Generated by Claude Code

StepenkoAnatoli and others added 2 commits October 11, 2026 10:13
… loses windows-1252

What changed: lib/runtime.mjs gains nodeDecodesWindows1252(version), a version rule beside nodeHonoursEnvProxy: false for 22.13.0 up to and including 22.22.0, true elsewhere; nodeParts now reads the patch number. nodeLine returns a second `fail` for those builds, after the major floor and before the odd-line warn, naming the defect (nodejs/node#60888: a page's euro signs, curly quotes and dashes captured as control characters, with no warning) and the fix (22.22.1 or newer on the 22 line, or 24). doctor's `node` finding carries it unchanged. The doctor test's Node-line case gains six rows (22.13.0, 22.21.0, 22.22.0 fail naming windows-1252 and 22.22.1; 22.12.0, 22.22.1, 22.23.3 pass). The README requirement reads "Node 22.22.1+ or 24+" in both READMEs, with the reason; the support-policy test that pins the requirement's presence accepts a patch-spelled floor. ADR-0159 records the decision and its index row; the runtime.mjs map row gains the clause; CHANGELOG Unreleased. The inventory is unchanged (rows in existing registrations, README stays 1787).

Why: the kit decodes a page by its declared charset (G7), and that reading is Node's TextDecoder. On 22.13.0 through 22.22.0 it reads windows-1252 as Latin-1 (nodejs/node#60888, a regression after the line went LTS, fixed by nodejs/node#60893 and backported), so a capture taken on such a build silently lost 0x80-0x9F and was hashed into the ledger as fetched, while doctor reported the Node line as pass and the suite's two G7 tests went red (#282, found 2026-10-11 running the suite on a container's 22.22.0: 1785 passed, 2 failed, the same on an untouched main). CI never met it: setup-node resolves '22' to the newest 22.x, 22.23.3 that day. Alternatives set aside, recorded in ADR-0159: a table decoder for 0x80-0x9F behind a runtime probe (a second decoder beside the one the kit trusts; a feature under the freeze), refusing those builds in checkNode (would refuse doctor, the command that explains it), documenting only (doctor would still say READY on a machine whose captures are wrong). A Node release update, which the freeze admits (ADR-0117).

What it touched: research-kit/lib/runtime.mjs (nodeParts, nodeDecodesWindows1252, nodeLine); research-kit/test/doctor.test.mjs (six rows in the Node-line test); research-kit/test/support-policy.test.mjs (the requirement regex); research-kit/README.md and README.md (the Node requirement, three places); docs/adr/0159-...md and docs/adr/README.md (the decision and its row); docs/ARCHITECTURE.md (the runtime.mjs row); CHANGELOG.md (Unreleased). No new command, flag, key, format or check: the `node` finding existed, it gains a second reason to fail.

What you verified:
- verified: the boundary, by hand on 2026-10-11 with `new TextDecoder('windows-1252').decode(Uint8Array.of(0x80, 0x93))` - 22.12.0 U+20AC U+201C (right); 22.13.0, 22.21.0, 22.22.0 U+0080 U+0093 (wrong); 22.22.1, 22.22.3, 22.23.0, 22.23.3, 24.21.0 right; 20.20.0 wrong. Each installed through nvm in this container.
- verified: red first - with only the doctor test rows in place, `selftest.mjs doctor`: 65 passed, 1 failed, "22.13.0 decodes windows-1252 as Latin-1 and was reported as pass". Node 24.21.0 linux.
- verified: after the fix, `selftest.mjs doctor runtime support-policy`: 98 passed, 0 failed; nodeLine by hand: 22.12.0 pass, 22.13.0 fail, 22.21.1 fail, 22.22.0 fail, 22.22.1 pass, 22.23.3 pass, 24.21.0 pass, 20.20.0 fail (the major floor).
- verified: `doctor` on this container's 22.22.0 prints "fail node node 22.22.0 decodes windows-1252 pages as Latin-1 (nodejs/node#60888): ..." and exits 1; on 24.21.0 "pass node node 24.21.0".
- verified: the full offline suite from the repository root on Node 24.21.0 linux: 1787 passed, 0 failed, 0 unsupported, 202.2 s, exit 0.
- verified: git diff --check clean; the nine files LF-only.
- untested when written: this commit's all-seven CI, and the installed commit gate (not installed in this container; the suite was run by hand instead).

What you got wrong and fixed: mistake - the README's new requirement "Node 22.22.1+ or 24+" no longer matched the support-policy test's /Node 22\+/ check; where - research-kit/test/support-policy.test.mjs, "the prerequisites named in the policy are the ones the suite actually needs"; impact - one red test in the focused support-policy run before commit, nothing delivered affected; cause - the check pinned the spelling, not the fact; fix - the regex accepts a patch-spelled 22 floor, /Node 22(\.\d+)*\+/, with the reason in a comment; verified - `selftest.mjs support-policy` 20 passed, 0 failed, and the full suite below.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gg4isLfN2Ng16zr5DwTnH9
…252-floor-20261011

# Conflicts:
#	CHANGELOG.md
@StepenkoAnatoli
StepenkoAnatoli marked this pull request as ready for review October 11, 2026 10:27
@StepenkoAnatoli
StepenkoAnatoli merged commit 080faef into main Oct 11, 2026
7 checks passed
@StepenkoAnatoli
StepenkoAnatoli deleted the claude/node-windows-1252-floor-20261011 branch October 11, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime: Node 22.13.0–22.22.0 decode windows-1252 as Latin-1 (nodejs/node#60888); the kit admits those builds and doctor says pass

1 participant