Skip to content

Developer playground: compare Lambda before and after optimization - #8636

Merged
fhammerschmidt merged 6 commits into
masterfrom
playground-lambda-diff
Oct 20, 2026
Merged

fhammerschmidt merged 6 commits into
masterfrom
playground-lambda-diff

Conversation

@fhammerschmidt

@fhammerschmidt fhammerschmidt commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

Add Before, After, and Diff views to the developer playground's Lambda tab. Playground API v9 exposes lambda_optimized from compileWithDebug after the whole-term Lambda passes and before export grouping and JavaScript lowering. Regular compilation does not capture debug output; older compiler bundles retain an availability notice.

Keep the Lambda view mounted and cache the latest rendered comparison by its printed inputs, including line alignment, inline highlights, and context sections. Switching tabs or recompiling identical dumps reuses the diff DOM. Collapsed context renders only when expanded, and unchanged regions retain their expansion state across edits. Hidden Lambda panels keep their dump snapshot in a signal that is updated only while visible. Repeated compile errors leave that snapshot untouched, including with the locked rescript-signals 3.1.1. While Diff is open, changed output is debounced for 200 ms; opening Diff is immediate, and leaving it or unmounting cancels pending work.

Strip shared edges before the line comparison, count those edges once in the output budget, and omit empty visible sections. Token alignment prioritizes shared atoms over punctuation. Preflight all candidate work in a changed block and skip the whole block when it cannot fit the remaining global budget, preserving capacity for later small changes. Actual work on unchosen candidates remains counted so the overall bound still holds.

Validation:

  • Fresh ARM Linux validation passes yarn workspace dev-playground test and yarn workspace dev-playground build with Node 22 and the immutable lockfile dependencies.
  • Native compiler, runtime, Belt, and browser compiler builds pass.
  • The compiler runner (node scripts/test.js -ounit -mocha -build -docstrings) passes: 336 unit cases (one skipped), 622 runtime/Belt tests, all 42 build fixtures, and 744 documentation examples.
  • All 37 developer playground tests pass, including 26 Lambda algorithm/rendering tests. New cases cover hidden panels catching up, debounced consecutive edits, cancellation on tab switches, expansion surviving delayed updates, and cached panels surviving repeated compile errors without rebuilding.
  • Playground bundle tests cover API v9 optimized output, regular compilation, and master's diagnostic-color regressions.
  • Production Vite build, OCaml/ReScript/JavaScript format checks, and changelog validation pass.
  • Browser layout and scrolling remain unverified locally; Chromium cannot launch in this macOS environment because system appearance resources are unavailable.

required

let compile (output_prefix : string) export_idents hoisted (lam : Lambda.t) =
let compile ?on_optimized_lambda (output_prefix : string) export_idents hoisted

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems I cannot extract optimized lambda for the playground without this addition

@codecov

codecov Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.13%. Comparing base (b7c67d2) to head (8bbffec).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
compiler/core/lam_compile_main.ml 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8636      +/-   ##
==========================================
+ Coverage   81.11%   81.13%   +0.01%     
==========================================
  Files         455      456       +1     
  Lines       63672    63724      +52     
==========================================
+ Hits        51650    51700      +50     
- Misses      12022    12024       +2     
Files with missing lines Coverage Δ
compiler/core/lam_compile_main.ml 89.41% <0.00%> (-0.32%) ⬇️

... and 5 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.

@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@8636

@rescript/belt

npm i https://pkg.pr.new/@rescript/belt@8636

@rescript/darwin-arm64

npm i https://pkg.pr.new/@rescript/darwin-arm64@8636

@rescript/linux-arm64

npm i https://pkg.pr.new/@rescript/linux-arm64@8636

@rescript/linux-x64

npm i https://pkg.pr.new/@rescript/linux-x64@8636

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@8636

@rescript/win32-x64

npm i https://pkg.pr.new/@rescript/win32-x64@8636

commit: 8bbffec

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

@fhammerschmidt
fhammerschmidt marked this pull request as ready for review September 9, 2026 21:57
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T13:26:25.416528Z 1be49a8 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@fhammerschmidt

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 1be49a87d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cknitt

cknitt commented Oct 13, 2026

Copy link
Copy Markdown
Member

Review notes (no wrong-diff bugs found; mostly performance):

Performance

  1. LambdaView.res:78: the diff is recomputed on every compile. LambdaView is rebuilt per compile result, so the Lazy cache only lives for one render, and LambdaInlineDiff.highlight / LambdaDiff.sections aren't cached at all. With the Diff subtab open, each keystroke reruns the line diff (up to 1M cells) and the token diff (up to 250k cells) and rebuilds the diff DOM. Switching Before → Diff → Before → Diff redoes the work too.
  2. LambdaView.res:67: collapsed sections still render every hidden line. renderLines runs eagerly inside each closed <details>, so a 10k-line dump with a one-line change still creates ~10k line spans (×4 children). Rendering on toggle would avoid that.
  3. LambdaDiff.res:49: the maxLines check uses the untrimmed n + m. Two 10,001-line dumps that differ in one line trim to a 1×1 middle but still show "exceeds the diff work limit", which contradicts the comment and the test.
  4. LambdaInlineDiff.res:172: the shared token budget is charged for every candidate pair in a block, including pairs that are never chosen. One early large block (e.g. 16×16 lines of ~100 tokens) can drain the 250k budget, and every later block falls back to whole-line highlighting based on position, not similarity.

Behaviour
5. LambdaInlineDiff.res:711: the token LCS maximizes all matched tokens, punctuation included, but pairing uses the count of shared atoms. An alignment that matches (/) instead of atoms can undercount shared and reject similar pairs via shared*2 < largest.
6. Main.res:1335: because LambdaView is replaced on every compile, opened "Show N unchanged lines" sections collapse again and the scroll position jumps after each edit.
7. LambdaDiff.res:154: sections emits Visible([]) before a leading unchanged run (head === start) and after a trailing one (tail === end_), which renders empty <pre class="lambda-diff-block"> elements. The test's flatMap check doesn't catch it.

Nit
8. package.json:12: stray double space before scripts/lambda-diff.test.mjs.

Items 1, 2 and 6 share one fix: keep the view and its diff results alive across compiles, keyed on the input text, and render collapsed sections only when opened.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RrJ4XshH5etfH87fRThk2B

@fhammerschmidt fhammerschmidt changed the title Developer playground: Add lambda views before and after optimisation,… Developer playground: compare Lambda before and after optimization Oct 14, 2026
@cknitt

cknitt commented Oct 20, 2026

Copy link
Copy Markdown
Member

Thanks, e33b965 addresses all eight points from my earlier review. Two minor leftovers, neither blocking:

  1. Hidden Lambda panels update on every compile. LambdaView and its Before/After panels are now always mounted, so each compile writes both full Lambda dumps into hidden DOM even while another tab (e.g. JS) is active. Before this change the view only existed on the Lambda tab. This costs a little on large modules; skipping those panel updates while visible() is false would avoid it.
  2. The Diff tab recomputes on every edit that changes the Lambda output. With Diff open, each such keystroke reruns the full comparison with no debounce and rebuilds the diff DOM. Expanded sections stay open thanks to the per-region state, but the scroll position can still move. The work is bounded now, so this is fine as is; a short debounce would smooth typing on big modules.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RrJ4XshH5etfH87fRThk2B

… including diffs

Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
Keep the Lambda view mounted, cache its rendered comparison by input text, and render collapsed context only when expanded. Preserve expansion for unchanged regions across edits.

Count shared edges once in the line budget, prioritize atoms in token alignment, and admit whole changed blocks before charging the shared token budget. Cover the algorithm and rendering regressions, and document the API v9 capture boundary.

Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
Keep the Before and After dumps unchanged while the Lambda view is hidden.
Opening the view reads the latest compiler result. While Diff is open, wait
200 ms after the latest changed result before replacing its comparison;
opening Diff remains immediate. Leaving Diff or unmounting cancels its timer.

Review: Address cknitt's two non-blocking follow-ups. Regression tests cover
hidden panels catching up, consecutive edits, cancellation on tab switches,
and expanded context surviving the delayed update.

Validation: All 36 developer playground tests, the native compiler suites,
the browser compiler bundle tests, production Vite build, OCaml/ReScript/JS
format checks, and changelog validation pass after rebasing onto b7c67d2.

Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
@cknitt

cknitt commented Oct 20, 2026

Copy link
Copy Markdown
Member

Thanks, 8eac328 addresses both follow-ups:

  • Hidden panels: panelInput only refreshes while the view is visible. Because lambdaVisible short-circuits on activeTab, nothing in LambdaView subscribes to compileResult while another tab is open, so hidden panels do no work there.
  • Debounce: each changed result clears the previous 200 ms timer, opening Diff is immediate, and leaving Diff or unmounting cancels it. Signal.peek(diffInput) keeps the effect from triggering itself.

One tiny nit, not blocking: on the Lambda tab with a compile error, lambdaVisible does read compileResult. Computed.make in rescript-signals has no equality check by default, so panelInput still propagates its unchanged snapshot on every compile. The hidden Before signalText resets its text, and the After View.tracked rebuilds its <pre>. Passing ~equals=(a, b) => a === b to panelInput would skip that.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RrJ4XshH5etfH87fRThk2B

Give the cached panel input an identity equality check so repeated errors
on the Lambda tab do not notify the unchanged Before and After panels.

Review: Address cknitt's final non-blocking follow-up. The regression test
reproduces the After panel being rebuilt without this check, verifies reuse
across repeated errors, and checks recovery when compilation succeeds.

Validation: All 37 developer playground tests, the production Vite build,
and the changed files' ReScript/JavaScript format checks pass.

Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
Keep the visible panel snapshot in a signal updated by an owned effect.
Repeated compile errors leave the signal untouched, so neither hidden
panel is invalidated. Showing the Lambda tab publishes the latest input.

Why: The locked rescript-signals 3.1.1 still invalidates downstream
computeds despite panelInput's equality check. The local install used
3.1.4 and missed this behavior. Reproduced the CI failure with 3.1.1;
the existing panel-reuse regression now passes on the locked version.

Validation: All 37 playground tests pass with Node 22.23.3 and the locked
rescript-signals 3.1.1. The playground compiler build, production Vite
build, ReScript formatting, and diff checks pass.

Signed-off-by: Florian Hammerschmidt <florianh89@gmail.com>
@github-actions

Copy link
Copy Markdown

@fhammerschmidt
fhammerschmidt merged commit b60e855 into master Oct 20, 2026
28 checks passed
@fhammerschmidt
fhammerschmidt deleted the playground-lambda-diff branch October 20, 2026 13:18
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.

2 participants