diff --git a/conformance/vectors/INDEX_all_formats.json b/conformance/vectors/INDEX_all_formats.json index bd4ddfc0e7..028de58a82 100644 --- a/conformance/vectors/INDEX_all_formats.json +++ b/conformance/vectors/INDEX_all_formats.json @@ -360,7 +360,7 @@ "file": "gf16_conformance_v0.json", "kind": "bitexact", "source": "hand-curated (pre-existing)", - "sha256": "d1c0eb5bd66247b3c5db9a00a95e29cf4359653aec56f2f9e6827f96898d1509", + "sha256": "0db7411bc9274600a81160f096fb3e83ab02ac66e92361349af2eae31f47ef14", "witnesses": 0 }, { diff --git a/conformance/vectors/README.md b/conformance/vectors/README.md index 0124e7ae8a..545a797dd5 100644 --- a/conformance/vectors/README.md +++ b/conformance/vectors/README.md @@ -251,7 +251,7 @@ af62499491faf340d7940b0b10ab0208745e57faa97bbe19588fe1d879db485b gf10_conforman cda05a8e608038f3ebb53757ecbe0f78a650f959cf34a54b0cf26d80730e54d3 gf128_conformance_v0.json ea00efde4825931a421ec9feb5910f3ad9ab7ab5d38a77d2c364ea9fa49a7f96 gf12_conformance_v0.json e2364f36a4cb5812b81d2f8f4253688b4d269201463c8481e18568438114a718 gf14_conformance_v0.json -d1c0eb5bd66247b3c5db9a00a95e29cf4359653aec56f2f9e6827f96898d1509 gf16_conformance_v0.json +0db7411bc9274600a81160f096fb3e83ab02ac66e92361349af2eae31f47ef14 gf16_conformance_v0.json 76c7814558901d5633cb16ffead7468583de5577c4ccf0378c296c73ae08acc5 gf20_conformance_v0.json 983642c7aea54b7e6c5b6e41edcf20828bfc3a1f2707307eaa713ca5a45e612c gf24_conformance_v0.json f504258daa4c537ff11a9863814470dd0731ab8cca988093d72e83c221c425f1 gf256_conformance_v0.json diff --git a/conformance/vectors/gf16_conformance_v0.json b/conformance/vectors/gf16_conformance_v0.json index 2eeb0f82bb..01916c61ee 100644 --- a/conformance/vectors/gf16_conformance_v0.json +++ b/conformance/vectors/gf16_conformance_v0.json @@ -195,29 +195,29 @@ "input_f64_hex": "0x483D6329F1C35CA5", "gf16_bits_hex": "0x7E00", "gf16_bits_int": 32256, - "decoded_f64": Infinity, + "decoded_f64": "inf", "decoded_f64_hex": "0x7FF0000000000000", - "abs_error": Infinity, + "abs_error": "inf", "category": "normal" }, { "name": "pos_inf", - "input_f64": Infinity, + "input_f64": "inf", "input_f64_hex": "0x7FF0000000000000", "gf16_bits_hex": "0x7E00", "gf16_bits_int": 32256, - "decoded_f64": Infinity, + "decoded_f64": "inf", "decoded_f64_hex": "0x7FF0000000000000", "abs_error": 0.0, "category": "inf" }, { "name": "neg_inf", - "input_f64": -Infinity, + "input_f64": "-inf", "input_f64_hex": "0xFFF0000000000000", "gf16_bits_hex": "0xFE00", "gf16_bits_int": 65024, - "decoded_f64": -Infinity, + "decoded_f64": "-inf", "decoded_f64_hex": "0xFFF0000000000000", "abs_error": 0.0, "category": "inf" diff --git a/docs/now/2026-09-07-the-json-gate-is-strict-and-the-one-file-is-legal.md b/docs/now/2026-09-07-the-json-gate-is-strict-and-the-one-file-is-legal.md new file mode 100644 index 0000000000..25699d97f9 --- /dev/null +++ b/docs/now/2026-09-07-the-json-gate-is-strict-and-the-one-file-is-legal.md @@ -0,0 +1,22 @@ +# NOW -- The JSON gate is strict, and the one file it refused is legal now (2026-09-07) + +## The JSON gate is strict (Refs #3388) + +- `validate` accepted bare `Infinity`, which CPython documents as "an extension to the JSON + specification" and RFC 8259 has no literal for. The independent check was another + language: `node -e JSON.parse(...)` refused the file this gate passed. +- Exactly one tracked file carried it in value position -- 19 others have the word inside + strings and always parsed. +- **The encoding was not chosen, it was read off the corpus.** 23 conformance files already + write these values as JSON strings and one did not, and `tools/wp18_selftest_gate.py` + uses `"inf"` / `"nan"` in its own fixtures. `"inf"` outnumbers `"Infinity"` 37 to 2. +- Nothing is lost: every affected row already carried the same value as `..._hex` + (`0x7FF0000000000000` IS +infinity), so the authoritative bits were in the file in a + legal form and the bare literal was redundant. +- The file's sha256 is pinned in `INDEX_all_formats.json` and in `README.md`. Both updated; + the old hash appears nowhere afterwards, checked. +- The consumer is unchanged in behaviour: `wp18_selftest_gate.py` exits 0 with the **same + 30 PASS** before and after. +- **This pull request is not on auto-merge.** It re-stamps a hash on a conformance artifact + for the one format that has an FPGA oracle behind it. The encoding question was settled + by evidence; whether a measurement record may be re-stamped is not mine to settle. diff --git a/tools/check_json_parses.py b/tools/check_json_parses.py index f35b32a56e..2e66f6cc5d 100755 --- a/tools/check_json_parses.py +++ b/tools/check_json_parses.py @@ -74,21 +74,24 @@ def scan(root=ROOT): # back clean. Measured before the change: 0 of 2086 tracked files are # non-UTF-8, so this costs nothing today and closes the hole anyway. # - # NOT DONE HERE, and the reason is the point: `parse_constant` would - # also refuse bare `Infinity`, which CPython accepts and documents as - # "an extension to the JSON specification" while RFC 8259 has no such - # literal. `node -e JSON.parse(...)` rejects it, so this gate passes - # what another consumer refuses -- a real defect, confirmed. + # `parse_constant` refuses bare `Infinity`, `-Infinity` and `NaN`. + # CPython accepts them and documents them as "an extension to the JSON + # specification"; RFC 8259 has no such literal, and the independent + # check is another language -- `node -e JSON.parse(...)` rejected the + # one tracked file that carried them while this gate passed it. # - # It is not fixed here because the blast radius is one tracked file, - # `conformance/vectors/gf16_conformance_v0.json`, whose six values are - # genuine IEEE754 infinities. That file is GENERATED by - # conformance/vectors/gen_all_formats.py and READ by - # tools/wp18_selftest_gate.py, so an encoding both sides agree on is a - # decision about conformance data, not about this reader. Shipping the - # stricter parse without it would leave a REQUIRED context red and - # block every merge in the repository. - json.loads(raw.decode("utf-8")) + # The encoding was not chosen here, it was read off the corpus: 23 + # conformance files already write these values as JSON strings and one + # did not, and `tools/wp18_selftest_gate.py` uses `"inf"` / `"nan"` in + # its own fixtures. Every affected row also carried the same value as + # `..._hex`, so the bits were already in the file in a legal form and + # the bare literal was redundant. + json.loads( + raw.decode("utf-8"), + parse_constant=lambda name: (_ for _ in ()).throw( + ValueError(f"bare {name} is not JSON (RFC 8259 has no such literal)") + ), + ) except Exception as e: bad.append((rel, str(e)[:90])) return empty, bad