Skip to content

test(ts): compare wasm32 aborts in the differential - #393

Merged
moq-bot[bot] merged 8 commits into
mainfrom
quest/m3/ts-abort-differential
Nov 2, 2026
Merged

moq-bot[bot] merged 8 commits into
mainfrom
quest/m3/ts-abort-differential

Conversation

@kixelated

@kixelated kixelated commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The lang differential could not compare wasm32's aborts. std's rtabort! traps without running the panic hook, so the native side saw an empty "panic" message where the runtime threw rt.Panic("rwlock locked for reading"). Fixtures avoided re-locking an RwLock while a guard held it (see #384 and #392). Completes quest/m3/ts-abort-differential.md.

Approach

  • Native: fixtures/wasm.rs keeps the hook's message as an Option, and message() returns null when no hook ran. Wasm.call returns the outcome directly: the output, { panic }, or "abort".
  • Runtime: rt.Abort, a Panic subclass named "Abort", is thrown where wasm32's std aborts. Today that is RwLock::read while written and RwLock::write while held.
  • Differential: an abort matches an abort by kind only, since wasm32-unknown-unknown has no stderr for std's fatal runtime error: ..., aborting. Panics still compare by exact message. The summary line now counts aborts.
  • Cases: locks::relock now re-locks through every guard while the guard is held, then locks once more after it drops. A mutex guard taken by lock or by try_lock panics, since wasm32's mutex uses assert_eq!. A read-write lock is read or written again through a read guard, a write guard, a mapped guard of either, or a mapped guard's own map; this aborts unless both locks are reads. caller.ts runs all 16 picks.

Lang differential: 656402 cases, 79299 panics, 9 aborts, 0 differences.

A wrong classification fails the test. I ran each mutation against the same build (node tests/differential.ts <wasm> <caller.ts> 0):

Mutation Result
Runtime throws rt.Panic for rwlock locked for reading 6 differences (native abort / ts panic "rwlock locked for reading")
Runtime throws rt.Abort for the mutex re-lock 4 differences (native panic "assertion ... cannot recursively acquire mutex ..." / ts abort)
Native side reads every trap as a panic 9 differences (native panic "" / ts abort)

Impact

  • Runtime: new export rt.Abort. An RwLock locked again while held now throws rt.Abort instead of a plain rt.Panic, with the same message. It is still instanceof rt.Panic, so callers that catch panics are unchanged, and no MIGRATE.md entry is needed. The README documents it.
  • Test and bench harness only: Wasm.call returns the Outcome, and panicMessage is gone.
  • Consumer: the lang differential, which is the m3 std coverage the quest serves.

Choices made without the maintainer

  • rt.Abort extends rt.Panic, so a caller that catches one catches both. The alternatives were a separate Error class, which callers catching only Panic would miss, or a Panic carrying std's fatal runtime error: ..., aborting text, which the differential would have to parse by prefix and could confuse with a user panic of that text.
  • Abort's message is rtabort!'s argument, as Panic's is the payload, without std's fatal runtime error: frame.
  • I extended locks::relock rather than adding a sibling case, so every re-lock lives in one function.

Alternatives

  • Classifying aborts by message prefix on the TypeScript side; rejected for the reason above.
  • A persistent mutation test in CI. It would cost a full lang differential run (about 4 minutes of CPU) per mutation for a property that the three show branches make plain. The runs above record the evidence instead.

Follow-ups

Review

🤖 Generated with Claude Code

kixelated and others added 4 commits November 1, 2026 07:58
A trap without a panic hook's message is an abort natively, and the runtime's
`RwLock` re-lock throws `rt.Abort`, so the lang differential compares the two by
kind and keeps comparing panics by message. `locks::relock` now re-locks a
mutex and a read-write lock through each guard, mapped or not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Aborts in the differential test(ts): compare wasm32 aborts in the differential Nov 1, 2026
@kixelated
kixelated marked this pull request as ready for review November 1, 2026 17:00
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4358a7b0-5c40-419d-a79e-c1b4db58d4a2
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@kixelated
kixelated enabled auto-merge (squash) November 1, 2026 18:02
@moq-bot
moq-bot Bot disabled auto-merge November 1, 2026 18:03
@moq-bot moq-bot Bot removed the quest:merge label Nov 1, 2026
@moq-bot

moq-bot Bot commented Nov 1, 2026

Copy link
Copy Markdown

quest land removed this pull request from the queue: Conflicts with the base: ts/fixtures/lang/caller.ts
.

@moq-bot

moq-bot Bot commented Nov 1, 2026

Copy link
Copy Markdown

codex / Codex land fixer: Base conflicts in ts/fixtures/lang/caller.ts; preserving relocks and capacityCases re·solves it mechanically, but from ts/ both &#96;cargo build --locked --package rust2-ts&#96; and &#96;cargo test --locked --pack. Recommendation: Provide the pinned nightly toolchain with rustc-dev; merge base preserving both case lists, then rerun the build and full package tests. PR branch left unchanged.

   Compiling vsimd v0.8.0
   Compiling oxc_sourcemap v9.0.0
   Compiling escape-simd v0.1.0
   Compiling winnow v1.0.4
   Compiling outref v0.5.2
   Compiling rustc-hash v2.1.3
   Compiling toml_writer v1.1.3+spec-1.1.0
   Compiling json-escape-simd v3.1.2
   Compiling toml_parser v1.1.5+spec-1.1.0
   Compiling base64-simd v0.8.0
   Compiling syn v3.0.9
   Compiling toml_datetime v1.1.2+spec-1.1.0
   Compiling serde_spanned v1.1.2
   Compiling toml v1.1.8+spec-1.1.0
   Compiling serde_derive v1.0.229
   Compiling rust2-driver v0.0.0 (/work/driver)
error[E0463]: can't find crate for `rustc_driver`
  --> /work/driver/src/lib.rs:10:1
   |
10 | extern crate rustc_driver;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
   |
   = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`

error[E0463]: can't find crate for `rustc_session`
  --> /work/driver/src/lib.rs:11:1
   |
11 | extern crate rustc_session;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
   |
   = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`

For more information about this error, try `rustc --explain E0463`.
error: could not compile `rust2-driver` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...

exec
/bin/bash -lc "python3 - <<'PY'
from pathlib import Path
p=Path('/work/ts/fixtures/lang/caller.ts')
s=p.read_text()
a=s.index('<<<<<<< HEAD\\n')
b=s.index('=======\\n',a)
c=s.index('>>>>>>> base\\n',b)
s=s[:a]+s[b+len('=======\\n'):c].replace('...mappedLocks, ...rwlocks','...mappedLocks, ...relocks, ...rwlocks')+s[c+len('>>>>>>> base\\n'):]
p.write_text(s)
PY
 git add ts/fixtures/lang/caller.ts
 git diff --check --cached" in /work
 succeeded in 0ms:
exec
/bin/bash -lc 'cargo test --locked --package rust2-ts' in /work/ts
 exited 101 in 6ms:
   Compiling rust2-driver v0.0.0 (/work/driver)
error[E0463]: can't find crate for `rustc_driver`
  --> /work/driver/src/lib.rs:10:1
   |
10 | extern crate rustc_driver;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
   |
   = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`

error[E0463]: can't find crate for `rustc_session`
  --> /work/driver/src/lib.rs:11:1
   |
11 | extern crate rustc_session;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
   |
   = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`

For more information about this error, try `rustc --explain E0463`.
error: could not compile `rust2-driver` (lib) due to 2 previous errors

codex
The conflict can be resolved mechanically, but both build and tests stop with `error[E0463]: can't find crate for rustc_driver`. I’ll hand back PR #393 with that validation blocker and restore its branch unchanged.

exec
/bin/bash -lc "git merge --abort
python3 - <<'PY'
import json
from pathlib import Path
result=[{'number':393,'action':'handback','diagnosis':'Base conflicts in ts/fixtures/lang/caller.ts; preserving relocks and capacityCases resolves it mechanically, but from ts/ both "'`cargo build --locked --package rust2-ts` and `cargo test --locked --package rust2-ts` fail: "error[E0463]: can'"\\'t find crate for "'`rustc_driver`" (also rustc_session).'"','recommendation':'Provide the pinned nightly toolchain with rustc-dev; merge base preserving both case lists, then rerun the build and full package tests. PR branch left unchanged.'}]
Path('quest-land-result.json').write_text(json.dumps(result,indent=2)+'\\n')
PY
 git status --short
 git rev-parse pr-393" in /work
 succeeded in 0ms:
?? quest-land-result.json
5c4cf2172096eae8add3b754775634f2d970a7b3

codex
PR #393 handed back: build and tests fail because `rustc_driver` and `rustc_session` are unavailable. The conflict is mechanically resolvable, but validation is blocked.

Branch unchanged. Result saved uncommitted in [quest-land-result.json](/work/quest-land-result.json).
tokens used
34,603
PR #393 handed back: build and tests fail because `rustc_driver` and `rustc_session` are unavailable. The conflict is mechanically resolvable, but validation is blocked.

Branch unchanged. Result saved uncommitted in [quest-land-result.json](/work/quest-land-result.json).
fixer result written

(written by codex / Codex)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated enabled auto-merge (squash) November 1, 2026 22:33
@moq-bot

moq-bot Bot commented Nov 1, 2026

Copy link
Copy Markdown

codex / Codex land fixer note:

The landing log reports this conflict on line 1:

Conflicts with the base: ts/fixtures/lang/caller.ts, ts/fixtures/lang/expected/lib.ts, ts/fixtures/lang/expected/locks.ts, ts/fixtures/lang/src/locks.rs

I temporarily merged base, combined the relock cases with the base's downgrade and leak cases, and regenerated the two conflicted TypeScript snapshots. Formatting, Clippy, runtime type-checking, eight runtime tests, and bundling the changed benchmark entries passed.

Validation then failed: cd ts && cargo test --locked -p rust2-ts --test fixtures task -- --exact --nocapture exited 101 with:

35417 cases, 3059 panics, 0 aborts, 628 differences

For input 0000180006000303060004000600, the native and translated results disagree on Waker::noop identity comparisons. The same case disagrees when the generated task uses base's unchanged rt.ts and rt/task.ts; this PR does not change the waker identity implementation. This needs behavior review outside the permitted mechanical fixes. Blame here identifies the merge conflict, not the separate waker failure.

The temporary merge was aborted and pr-393 remains at its pinned head. The full suite and language differential run were stopped after the task failure; the targeted task test reproduced it independently. Rebase and regenerate the fixtures, and resolve the waker test issue before landing.

(written by codex / Codex)

@moq-bot
moq-bot Bot disabled auto-merge November 1, 2026 23:28
@moq-bot moq-bot Bot removed the quest:merge label Nov 1, 2026
@moq-bot

moq-bot Bot commented Nov 1, 2026

Copy link
Copy Markdown

codex / Codex land fixer: The base merge conflicts in four language fixture files; after mechanically resolving them, &#96;cd ts && cargo test --locked -p rust2-ts --test fixtures task -- --exact --nocapture&#96; exits 101: "35417 cas. Recommendation: Rebase preserving the relock, downgrade, and leak cases and regenerate the language snapshots; review and re·solve the base runtime/native Waker::noop identity mismatch before requeueing.

Conflicts with the base: ts/fixtures/lang/caller.ts, ts/fixtures/lang/expected/lib.ts, ts/fixtures/lang/expected/locks.ts, ts/fixtures/lang/src/locks.rs

(written by codex / Codex)

kixelated and others added 2 commits November 1, 2026 16:06
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant