Skip to content

fix(runtime): stop the cooperate checkpoint clobbering the last-error slot#2669

Open
slepp wants to merge 3 commits into
mainfrom
fix/2506-cooperate-error-preservation
Open

fix(runtime): stop the cooperate checkpoint clobbering the last-error slot#2669
slepp wants to merge 3 commits into
mainfrom
fix/2506-cooperate-error-preservation

Conversation

@slepp

@slepp slepp commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Why

The actor scheduler's cooperate checkpoint used require_current_context(), whose null-context path has a side effect: it writes the EXECUTION_CONTEXT_NOT_INSTALLED sentinel into LAST_ERROR. That write clobbered genuine diagnostics — for example a real process launch failure — before stdlib callers could read them, so try_run_argv callers saw the context sentinel instead of the actual OS error text.

What

  • hew-runtime (native + WASM): hew_actor_cooperate in scheduler.rs and scheduler_wasm.rs now uses the non-clobbering current_context() probe. The null check is semantically identical; only the spurious LAST_ERROR write is gone. Cooperate's contract is its return code — it is deliberately not a typed-error emitter, and the checkpoint never fabricates an error into the slot.
  • Test contract fix: two tests had encoded the clobber as a contract. task_scope.rs's test is rewritten to assert the intended behaviour (a clear slot stays clear across a no-context cooperate, and a real diagnostic set before the checkpoint survives it); the execution-context catalogue case now documents cooperate as leaving the slot untouched.

Test

  • New compiled regression test_try_run_argv_missing_command_preserves_real_error in tests/hew/process_test.hew: asserts the surviving error contains the real "failed to execute" text and not the sentinel. Verified red against the pre-fix runtime, green with the fix.
  • cooperate_without_execution_context_preserves_last_error (task_scope.rs): covers both negative-space conditions — no fabricated error on a clear slot, and a pre-set diagnostic surviving the checkpoint.
  • Full workspace nextest, the compiled-suite ratchet, and clippy/fmt are clean; the .hew regression was run three times to rule out order sensitivity.

Quality Checklist

  • PR title, body, and commit messages avoid internal-only orchestration/model vocabulary
  • No new .ok()? or unwrap_or_default() in codegen without // JUSTIFIED comment
  • New allocations have cleanup paths for sync, async, and actor shutdown contexts
  • Serialization changes include round-trip encode/decode tests
  • New runtime features have WASM implementation or // WASM-TODO(#NNN): marker (with issue ref, e.g. #1451), and new hew_* exports are classified in scripts/jit-symbol-classification.toml
  • No duplicated logic — checked for existing helpers before adding new ones

Out of scope

  • The workspace-wide audit of other last-error readers (fs/stream/channel/net) — this fix is confined to the cooperate checkpoint.
  • The Unix-only printf/kill fixture portability cleanup in the process tests.
  • The 8 remaining require_current_context() diagnostic callers are correct as-is (their readers want the sentinel) and are unchanged.

Fixes #2506

slepp added 3 commits July 15, 2026 12:35
hew_actor_cooperate is a fail-open reduction-budget probe: with no
installed execution context it returns 0 and keeps running. It used
require_current_context(), which sets the "execution context not
installed" sentinel into the thread-local last-error slot as a side
effect. In straight-line main() the compiler-injected cooperate call at
last_process_error's function entry fired after process launch had set
the real failure text and before the stdlib read it back, so try_run_argv
callers saw the sentinel instead of the genuine OS launch error.

Switch both the native and WASM cooperate checkpoints to the silent
current_context() probe — identical null-check semantics, no error
write — and document that the no-context path leaves the last-error
slot untouched. require_current_context() and its other callers are
unchanged; they legitimately want the diagnostic.
… callers

The existing missing-command test only matches the LaunchFailed variant
and discards the message, so it stayed green while the cooperate
checkpoint replaced the real OS launch error with the execution-context
sentinel. Assert the message content: it must carry the runtime's
'failed to execute' text and must not carry the sentinel. The fixture
command is a nonexistent binary, so the launch fails identically on
every platform with no Unix-only tools.
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: preserve process errors across fail-open scheduler checkpoints

1 participant