Skip to content

Viewer: time-travel debugger for script runs (Script Lab) - #209

Open
satran004 wants to merge 1 commit into
viewer/script-runsfrom
viewer/debugger
Open

satran004 wants to merge 1 commit into
viewer/script-runsfrom
viewer/debugger

Conversation

@satran004

Copy link
Copy Markdown
Member

Stacked on #208. Part of #207: PR 3 of the Script Lab series, the time-travel debugger.

What users get

/transactions/{hash}/debug/{purpose}/{index} replays one script run of any transaction in julc's VM, on Mainnet or a devnet. It uses exactly the context the Scripts tab showed, including the julc#244 corrections, so the run you debug is the run you saw.

  • Controls: step, step over, step out, continue, step back, start and end.
  • Timeline: click or drag to any step, with markers for traces and the failure.
  • Keyboard:
    • → step, ← back, ↓ over, ↑ out
    • C continue, F failure, Home/End
  • Breakpoints:
    • on UPLC lines (click a line number)
    • on builtins (click a builtin)
    • on traces and on failure
  • Code: the current term is highlighted in the UPLC and kept in view, vertically and horizontally, since UPLC is deeply indented.
  • State:
    • Now: phase, term kind, value, why it stopped, stack depth
    • Budget: CPU and memory at this step against the whole run and the declared ex-units, plus the cost of this step
    • Environment: bindings in scope, nearest first
    • Frames
    • Traces so far
  • Step links: ?step=N opens an exact machine state, and "Link to this step" copies it. ?at=failure opens at the failing step.
  • Entry points: every re-run on the Scripts tab gets Debug, or Debug the failure when it failed.
  • Notes: the run's notes (what the viewer corrected, known gaps) sit at the top of the debugger.

Stepping is fast: on a 430M-CPU Mainnet withdraw-zero validator (23,605 machine steps), every action, jumps included, takes 1–4 ms. Opening the debugger, which rebuilds the transaction, starts the engine and replays, takes about 3.5 s on the playground store.

How

  • replay/run.ts: the re-run pipeline (rebuild → evaluate → context fixes → re-evaluate) moved out of the Scripts tab, so the tab and the debugger share it. Each result keeps the VM arguments it ran with.
  • debug/Debugger.svelte:
    • opens a vm.debug session with those arguments;
    • gets the timeline with the session's timeline action;
    • steps 0…totalSteps (the last step is the finished state: result and full budget);
    • lets only the latest timeline request queue while one is running, so dragging stays live;
    • keeps the URL in sync with replaceState.
  • debug/Timeline.svelte: the scrubber. CodeView gained active (span highlight and follow) and line-number breakpoints.
  • $lib/tx/load.server.ts: the transaction loader, shared by the transaction and debugger pages.
  • A Svelte 5 gotcha: reactive state is a proxy, which can't be posted to a worker, so engine requests use the plain result objects.

Not included

Tests

  • npm run check: 0 errors, 0 warnings.
  • vitest: 51 passing (new: VM arguments and requests per Plutus version).
  • Playwright script-lab.spec.ts: all 3 tests pass against a production build in Chrome. The new one covers stepping, URL sync, End, a builtin breakpoint, and a ?step=5 link.
  • 19 devnet smoke tests pass.
  • Checked by hand:
    • a successful V2 run, dark mode
    • a deep link, light mode
    • a failing 2023 V1 run opened at the failure: highlights (delay (error))
    • phone width: no horizontal overflow

🤖 Generated with Claude Code

/transactions/{hash}/debug/{purpose}/{index} replays one script run in julc's VM with exactly the
context the Scripts tab used, and lets you move through it:

- step, step over, step out, continue, step back, start/end; a timeline to click or drag, with
  trace and failure markers; keyboard shortcuts
- breakpoints on UPLC lines (click a line number), builtins, traces and failures
- the current term highlighted in the UPLC and followed vertically and horizontally
- now (phase, term, value, why it stopped), budget at the step against the run and the declared
  ex-units, environment, frames and traces so far
- ?step=N links to an exact machine state; ?at=failure opens at the failing step
- "Debug" / "Debug the failure" links on every re-run in the Scripts tab

The re-run pipeline moved to replay/run.ts so the tab and the debugger share it, and every result
keeps the VM arguments it was run with. The transaction loader moved to $lib/tx/load.server.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown

Initial automated review · Aster

Hi @satran004, thanks for the PR! 🙏 This is an automatic first check by an AI reviewer. It does not replace maintainer review and may be wrong.

Reviewed commit: 0f69f6fc38496ee8fefc10ef4fafdd1e4e0db30a

Issues found:

  • applications/viewer/src/lib/julc/debug/Debugger.svelte:300 — A V3 script returning a non-unit value has accepted=false but VM status="success", so the debugger displays a rejected run as successful and cannot locate it with ?at=failure. Please preserve the acceptance error and seek the final step in this case.
  • applications/viewer/src/lib/julc/debug/Debugger.svelte:65 — Leaving during open() can leak a session created after teardown, and the uncancelled URL timer can write the old step onto the next page. Please guard async completions, close late sessions and cancel the timer.
  • applications/viewer/src/lib/julc/debug/Debugger.svelte:129 — Session-action timeouts bypass julc.run’s client reset, so “Reopen” reuses a disposed worker and fails for a single-script transaction. Please route these actions through the recovery wrapper.

Not tested: Static review only; build, unit and browser tests were not run, and no CI checks were reported for this commit.

This branch has not been deployed

No deployments
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