Commit graph

6 commits

Author SHA1 Message Date
ff2ef382c7
gc diagnostics: per-tier heap pressure surfaced in repl tabbar
Step 1 of the GC effort. Each tier loader now exposes heapStats():
  - asm-wasm — lumbda_heap_used / lumbda_heap_total wat exports
  - c-wasm   — emscripten linear memory size (no free path right now,
               so used = total; documented in the loader)
  - python   — pyodide module linear memory size; CPython GC cycles
               this naturally

Worker handles a "heap" message kind that round-trips the active tab's
loaded tiers; repl tabbar shows a compact "py 12M · c 32M · asm 4M"
strip next to the buttons. Polls every 2s.

Doesn't solve the leak — just makes pressure visible so the user knows
when to use "reboot tier". Real GC (Cheney over the WAT bump allocator,
Boehm-em or custom mark-sweep for c-wasm) coming next.
2026-06-14 17:32:48 -04:00
7ea65dba21
parity probe: cross-tier corpus + fix python remainder + asm modulo
New: wasm/tests/parity-cross-tier.mjs runs the parity-corpus.mjs (216
test cases tagged by whitepaper section / R7RS concept) against three
tiers — native python (reference), c-wasm, asm-wasm — and fails on any
unknown divergence. Known gaps live in KNOWN_DIVERGE so the table stays
green while the bignum / call/cc / etc. work proceeds.

Wired into `make wasm-test` so a regression against any spec claim gets
caught before merge.

Bugs caught and fixed:
  - python remainder: was `signed_a % signed_b * sign(a)`, which double-
    applied the sign of a (python's % floors) — gave -3 for (-17, 5)
    instead of the R7RS-correct -2. Now uses abs() on both sides.
  - asm-wasm modulo: was i32.rem_s (truncated, remainder semantics)
    where R7RS modulo wants sign of divisor. Added the "if rem and
    divisor disagree on sign, add divisor" branch.

Cross-tier numbers after fix:
  216 passing
    3 known diverge: expt-2-100, expt-3-50, big-arith — all asm-wasm
      (no bignums on the asm tier yet; whitepaper §2.1 claim still open)
    0 fail

REPL layout: body is now the scroll container, prompt-bar is
position:fixed at the viewport bottom so it doesn't get pushed off
screen by a long transcript. Empty space above the prompt on a fresh
session reads like a terminal.

All other tests still pass: 20 unit, 8 integration, 11 functional.
2026-06-14 15:21:19 -04:00
ef8b9b5819
wat iter-5: TCO via return_call + dotted pairs + bend gpu demo
WASM tail-call instruction wired into every tail position:
  if branches, eval_begin last expression, all special-form dispatchers
  (cond/when/unless/case/let/let*/letrec/begin/and/or), function
  application's $apply, and apply's closure-body $eval_begin.
  wat2wasm + wasm-validate now use --enable-tail-call.

Reader fixes:
  - Dotted pair syntax: (a b . rest) parses as a real dotted list.
    Without this, variadic params and other dotted-cdr forms parsed
    as 4-element proper lists.
  - Stray ) at top level advances source_ptr instead of spinning
    forever. Found via bisection of functional.lsp under TCO.
  - eval_args guards against non-pair tails so a misplaced dotted
    argument (e.g. an unexpanded macro template) can't deref garbage.

Cross-tier numbers (wasm-test-functional-cross):
  before: 93/111 reached, stack overflow on (ack 3 4)
  now:    progresses through the full TCO section, deep let, named-let
          to 100k, mutual recursion to 200k. Still climbing.

Bend gpu demo:
  6th playground option ("bend (gpu dispatch) ⚡") ships a SHAKE256
  fan-out at 1M inputs via (bend!-call ...). Run button is GUARDED:
  if no bend URL is configured, refuses with
  "set a bend URL first — this demo is GPU-only by design".
  Protects customer machines from burning minutes on a workload the
  local tiers cannot finish in reasonable time.
2026-06-14 14:18:41 -04:00
b3bcff5f08
repl: explain PBKDF2 + AES-GCM on the lock-screen modal 2026-06-14 13:12:05 -04:00
656f206c40
playground+repl: bend+vault on one line, grid-only layout, hidden fix
- bend URL and vault password now share a single config-bar row, split
  via a 2-column grid (1fr 1fr). Vault still hidden when free-form
  isn't selected; just collapses its column.
- Every flexbox removed. Every multi-child container uses CSS grid:
  .controls, .config-bar, .bend-bar, .vault-bar, .panes, .pane,
  .brand, .tabbar, .tabs, .tab, .transcript, .entry, .tier-output,
  .prompt-bar, .lock-screen, .lock-card, .lock-row.
- Added `[hidden] { display: none !important; }` so the ephemeral
  button on the REPL lock screen actually hides the modal. Without
  this, .lock-screen's `display: grid` overrode the hidden attribute's
  UA-default display: none.
2026-06-14 13:11:09 -04:00
d8ffab5ea6
repl: /repl/ page with encrypted multi-tab sessions
Interactive REPL at lumbda.com/repl with:
  - multi-tab sessions (click + to add, × to close, double-click to rename)
  - per-tab tier selector (python/c/asm/all-three race)
  - persistent transcripts encrypted in localStorage via Web Crypto
    (PBKDF2 + AES-GCM, vault id = SHA-256(password || device-salt) —
    same pattern as unsandbox's vault-encryption-design.md, native
    crypto.subtle API instead of CryptoJS)
  - ephemeral mode (skip vault, transcripts vanish on reload)
  - one worker per (tab × tier) — state persists across evals in a tab
  - reboot tier button (terminate this tab's worker, fresh state next eval)
  - cancel button (kills the running worker in active tab)

Home page now links to both /playground/ and /repl/.

Tier state itself does NOT persist across reloads — the transcript does,
but defines/set!/hash-tables vanish with the worker. Portal save/resume
in WAT (deferred) will let a tier session survive close+reopen.
2026-06-14 12:50:35 -04:00