Repository navigation
test(oracles): freeze canonical JSON edge cases as differential oracles - #128
Merged
Merged
Conversation
Freezes JSON inputs with the exact canonical text and digest the TypeScript implementation produces, or its refusal, where another implementation most easily diverges: key order by UTF-16 code unit, ECMAScript number formatting, string escaping, lone surrogates and non-finite numbers. The digest is also checked against an independent SHA-256 of the canonical UTF-8 bytes. Refs #84 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This was referenced Oct 27, 2026
hoklims
enabled auto-merge (squash)
October 27, 2026 20:34
hoklims
added a commit
that referenced
this pull request
Oct 27, 2026
## Summary Second slice of the R0 edge-case oracles (#84): the JavaScript scanner, module specifier discovery and the test closure, which E7 (#116) and R5a (#92) move to Rust. The first slice, canonical JSON and digests, is #128. Three fixtures in `tests/edge-oracles/` freeze each input with the exact output the TypeScript implementation produces, or its refusal code: - **`javascript-tokens.json`, 18 cases.** Each token is `[kind, start, end, text]`, plus `value` for identifier and literal kinds, the only ones consumers read. The cases cover: - UTF-16 positions; - a BOM that is skipped while a shebang after it is not; - conflict markers, whose second side is skipped too; - Unicode spaces; - regex slashes read as division, so a quote inside a regex opens a string; - the empty `#` token being skipped; - normalized numeric values (`0x1F` → `31`, `0xFFn` → `0xffn`, `017` → `15`); - decoded and invalid escapes; - nested templates. - **`module-specifiers.json`, 16 cases.** Every static and dynamic form, `require`, Bun's `mock.module`, computed specifiers, escapes, `from` across lines, a semicolon ending the search, and an import hidden behind a regex quote. - **`test-closure.json`, 12 scenarios.** Each describes an in-memory repository: - the order of resolution candidates (an exact `c.js` wins over `c.ts`); - path keys lowercased with final-sigma context (`ΑΣ/x.js` reaches `ας/x.ts`, while a per-character lowercase misses it); - the inventory spelling kept; - UTF-16 path order; - unbounded edges sorted by file, then reason; - packages, JSX runtime and runner modules; - links, both stopped and followed; - tsconfig paths with comments, a bunfig preload, package `imports`, a workspace package; - two refusals, `TEST_CLOSURE_PACKAGE_IMPORT_UNSUPPORTED` and `TEST_CLOSURE_TSCONFIG_EXTENDS_UNSUPPORTED`. `tests/scanner-closure-oracles.test.ts` replays every case and checks: - that each token text equals the source slice its UTF-16 offsets delimit; - that the required divergence traps of each fixture are still present. Kinds are recorded by name, not by the numeric value of the TypeScript enum. Refusals are recorded by their product code. ## Proof Ten negative witnesses run in a disposable worktree at `721330a`. Each one turns red on `ERR_ASSERTION` in the designated test, then green after restore: | Witness | Mutant | Red test | | --- | --- | --- | | utf8-byte-positions | token offsets in UTF-8 bytes | `utf16-astral-positions` | | numeric-value-raw | numeric value = raw text | `numeric-literal-values` | | template-not-rescanned | no template tail rescan | `template-nesting` | | any-module-call | any `x.module(...)` is an edge | `mock-module` | | concatenated-import-literal | `import("a" + x)` keeps `"a"` | `dynamic-concatenation` | | per-character-lowercase | path key lowercased per character | `path-keys-and-order` | | utf8-path-order | closure files sorted by UTF-8 bytes | `path-keys-and-order` | | ts-source-before-exact | `.ts` source tried before the exact `.js` | `resolution-candidates` | | runner-modules-resolved | runner modules resolved to packages | `packages-and-runner-modules` | | trap-case-dropped | fixture: `regex-hides-import` removed | `keep every divergence trap…` | - `pnpm check`: green at `721330a`: format, lint, schemas, conformance, typecheck, 1044/1044 tests (run alone) - Proof epoch: base `7c623ae`, candidate `721330a`, subject digest `sha256:8955fbb6…`, classifier category `test_oracles` (4 paths). ## Limits - Expected values are the current TypeScript output. Several of them freeze known limits of a context-free scanner rather than desirable behavior: regex, JSX, and HTML-like comments. A Rust scanner has to reproduce them, or a later decision has to change both implementations. - Not frozen: a specifier that is not in NFC (`./café.js`) makes `computeTestClosure` throw `TypeError: Ambiguous Unicode path segment must use NFC` instead of a `TEST_CLOSURE_*` refusal. It is left out until #130 decides the intended behavior. - The `node:` builtin list comes from the running Node version. These cases only use builtins that are stable across versions. - No independent proof auditor ran. ## Test plan - [x] `pnpm check` - [x] Ten negative witnesses red then green - [ ] CI green Refs #84, #116, #92 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First slice of the R0 edge-case oracles (#84): canonical JSON and its digest, which R3 moves to Rust first (
replayandcore <op>, byte-for-byte differential).tests/edge-oracles/canonical-json.jsonfreezes 17 JSON input texts with the exact canonical text andsha256:digest the TypeScript implementation produces, orrefused: true. The cases sit where another implementation most easily diverges:canonicalizesorts keys with JS<, so😀(surrogateD83D) sorts before。(FF61). UTF-8 byte or code point order, the default in Rust, gives the reverse;-0→0,1e21→1e+21,1e20→100000000000000000000,1e-7, rounding past 2^53, subnormal and largest finite double;\ucontrol escapes, raw/, U+2028 and U+2029, raw non-ASCII hashed as UTF-8, lone surrogates escaped (never replaced by U+FFFD);1e400and-1e400are refused.tests/edge-oracles.test.tsreplays every case and checks:node:cryptoSHA-256 of the canonical UTF-8 bytes (the core hashes with its own SHA-256);Refusals are recorded as
refused: true, without the TypeScript message, so the oracle does not depend on one language.Proof
Negative witnesses in a disposable worktree at
8959ada, each red onERR_ASSERTIONin the designated test, then green after restore:compareOrdinal→Buffer.compareof UTF-8 byteskey-order-utf16-code-units-0serialized as-0number-negative-zerotoWellFormed()string-lone-surrogatesnullnumber-overflow-refusedstring-lone-surrogatesremovedkeep every divergence trap…pnpm check: green at8959ada: typecheck, lint, build, 1013/1013 tests (run alone; an earlier run interrupted alongside the witnesses showed spawn and named-pipe errors in four unrelated suites, none of them reproduced)7c623ae, candidate8959ada, subject digestsha256:3683ae18…, classifier categorytest_oracles(2 paths).Limits
JSON.stringifyrules for the cases above, not by a second implementation.Test plan
pnpm checkRefs #84
🤖 Generated with Claude Code