Skip to content

Evaluator streaming - #2339

Merged
Negabinary merged 26 commits into
devfrom
eval-streaming
Jul 30, 2026
Merged

Evaluator streaming#2339
Negabinary merged 26 commits into
devfrom
eval-streaming

Conversation

@Negabinary

@Negabinary Negabinary commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

This pr adds streaming to the evaluator. This means results come through and are displayed to the user as the web worker is running.

Screen.Recording.2026-06-12.at.10.06.04.AM.mov

I've also done a lot of work cleaning up the evaluator - this may create some conflicts, but I'm hoping it'll be a lot easier to work with.

This pr commits to making evaluator state write-only (module steps), I think that's fine because we're a pure language.

We also switch the web worker to being always alive, instead of the current regime where we spin up a new web worker for each evaluation.

@Negabinary
Negabinary marked this pull request as ready for review June 12, 2026 14:11
@Negabinary

Negabinary commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Guide for reviewing this pr

Helpful Background for Reviewing

A key change we've made here is to the protocol for discussing back and forth between the webworker and the main thread. You can read these protocol specifications in the web worker server file.

The new protocol is as follows:

  1. Main thread sends over new expression + previous evaluation cache
  2. Worker performs a "reuse pass" over the whole expression to work out what files can be re-used
  3. Worker sends an acknowledgement to the main thread, with a list of ids the worker plans to re-evaluate
  4. Main thread draws these ids as shaded so the user can see what's evaluating
  5. every 5000 steps, the worker pauses and sends back any top-level ids that have completed, and the current partially complete step
  6. when the main thread receives updates, it adds it to its own previous evaluation cache.
  7. repeat upon new edits

WorkerServer.re is mostly GPT-generated but should give you an overview of how this works.

Because this changes the way the webworker works, I've tried my hardest but wouldn't be surprised if there are weird browser states you can get into here. A functional review where you try ot break it might be good.

In addition I've done some focussed human cleanup on EvaluatorState.re and Evaluator.re, these should be significantly more readable now, and I would encourage you to have a read through and see if they match your understanding of how the Evaluator should work.

I tried to keep my commits clean so reading through them should also give you a sense for what I've added.

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 51.74644% with 373 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.90%. Comparing base (61f5ff8) to head (9da202b).
⚠️ Report is 166 commits behind head on dev.

Files with missing lines Patch % Lines
src/web/util/WorkerServer.re 3.66% 105 Missing ⚠️
src/web/app/editors/result/EvalResult.re 0.00% 83 Missing ⚠️
src/web/app/editors/decoration/Highlight.re 0.00% 46 Missing ⚠️
src/language/dynamics/EvalWorklist.re 0.00% 33 Missing ⚠️
src/haz3lcore/pretty/PrettySegment.re 83.00% 17 Missing ⚠️
src/language/dynamics/EvalInfo.re 36.00% 16 Missing ⚠️
src/language/dynamics/CallStack.re 52.17% 11 Missing ⚠️
src/language/dynamics/IncrEval.re 77.55% 11 Missing ⚠️
src/language/dynamics/Sample.re 43.75% 9 Missing ⚠️
src/web/app/editors/code/CodeEditable.re 0.00% 6 Missing ⚠️
... and 13 more
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #2339      +/-   ##
==========================================
- Coverage   52.54%   50.90%   -1.65%     
==========================================
  Files         323      315       -8     
  Lines       47996    41889    -6107     
==========================================
- Hits        25219    21322    -3897     
+ Misses      22777    20567    -2210     
Files with missing lines Coverage Δ
src/haz3lcore/ProbePerform.re 13.37% <ø> (-0.26%) ⬇️
src/haz3lcore/derived/Indentation.re 97.56% <100.00%> (+0.12%) ⬆️
src/haz3lcore/tiles/Segment.re 66.22% <100.00%> (-0.58%) ⬇️
src/language/dynamics/ValueChecker.re 0.00% <ø> (ø)
src/language/dynamics/evaluation/Trampoline.re 100.00% <100.00%> (ø)
src/language/dynamics/stepper/EvaluatorStep.re 67.79% <ø> (-3.41%) ⬇️
src/language/dynamics/transition/PatternMatch.re 85.24% <ø> (ø)
src/util/Aba.re 67.16% <100.00%> (+2.64%) ⬆️
src/web/exercises/GradeExercise.re 96.66% <100.00%> (ø)
src/language/dynamics/Dynamics.re 0.00% <0.00%> (ø)
... and 22 more

... and 68 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Negabinary Negabinary mentioned this pull request Jun 30, 2026
disconcision added a commit that referenced this pull request Jul 2, 2026
fn_def_id is only observable at the Ap step; state is the channel to the
Sample minted later. Probe targets only, wiped pre-postMessage; becomes
an emitted event under evaluator streaming (#2339).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Negabinary
Negabinary force-pushed the eval-streaming branch 3 times, most recently from 4afcff9 to 8398930 Compare July 29, 2026 14:15
@Negabinary
Negabinary force-pushed the eval-streaming branch 2 times, most recently from c0b74d4 to 7b8c62e Compare July 29, 2026 16:54
… Segment fold_right/incomplete_tiles_deep)

Displaying a large result (e.g. range(1,5000): ~17k pieces) overflowed
the JS stack in stdlib fold_right/concat recursion during reassemble
(Aba.split via split_by_matching), regrout_affix, and CachedSyntax's
global_missing_shards (incomplete_tiles_deep). Rewrite them on
fold_left over reversed lists (order-preserving); recursion now only
descends into tile children, bounded by nesting depth.
yielding_step_count counts trampoline transitions (Bind/Next/Done), not
evaluator steps; 1M transitions is ~2s of sliced evaluation, so the
runaway backstop fired long before the 20s client wall-clock timer and
moderate programs (range(1,5000)) died with a spurious 'Evaluation
timed out'. Raise the backstop to 100M transitions so it is strictly a
last-resort guard beyond the client timer.
@Negabinary
Negabinary merged commit 9e95987 into dev Jul 30, 2026
3 checks passed
@Negabinary
Negabinary deleted the eval-streaming branch July 30, 2026 14:35
disconcision added a commit that referenced this pull request Jul 31, 2026
Conflict resolution notes:
- EvaluatorState: took dev's appendable-log structure (append/rebase replaces
  StateSlice capture/replay; StateSlice deleted). iv's app_args-to-app_data
  rename + stack_frame threading ported into dev's CallStack module:
  entries are now (call_stack, elided_arg, frame) and lookup_app returns
  the frame so probe samples on Aps carry the invoked fn's fn_def_id.
- CallStack.state.app_data is a shared ref (not threaded): an Ap id
  re-evaluated via cast distribution (iv's rewrap) must see recordings
  made during sub-evaluation, which dev's threaded stack discards on the
  way back up. Restores iv's global-visibility semantics; CallStack.empty
  is now a function so each run gets a fresh ref.
- Evaluator: dev's layered eval_0..5 taken wholesale; frame lookup ported
  into eval_3_record_probe_sample.
- Transition cast-Ap: dev's generated() (temp ids when no probes) combined
  with iv's rewrap on the inner Ap (id preservation through casts).
- EvalResult: dev's streaming rework taken; iv's Sample.Map.finalize
  applied in dynamics_of_state (covers streaming + final paths).
- Action.StepInto now carries CallStack.frame (iv) with dev's type names.
- Tests: ported iv-side tests to the new API (EvalInfo.of_targets and
  of_info_map, eval_incr_with_plan/has_reuse, EvaluatorState.incr_eval).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant