Skip to content

feat(playground): tracer v2 records traces in the shared snapshot - #204

Merged
mnaimfaizy merged 1 commit into
mainfrom
feat/tracer-v2
Oct 11, 2026
Merged

mnaimfaizy merged 1 commit into
mainfrom
feat/tracer-v2

Conversation

@mnaimfaizy

Copy link
Copy Markdown
Owner

PR 5 of the ADR 0004 build plan. A new module at src/features/playground/tracer/, added beside the old tracer and not wired into the app; the swap comes with the stack-and-heap lens.

What it does

  • Rewrites the learner's JavaScript (acorn + astring, no new dependency), runs it on the browser's own engine and returns a trace: steps that each hold a shared snapshot (src/shared/snapshot).
  • Every object, array and closure keeps one identity for the whole run, so two variables holding one array give two slots with the same refId.
  • Every frame on the stack carries its own slots.
  • Functions are traced wherever they are written: declarations, expressions, arrows, object and class methods, callbacks run by built-ins, async functions, generators.
  • The step limit (2,000 by default) stops the run and keeps the partial trace, including while(true){}, a loop that catches everything, and a finally that returns.
  • A step's focus is derived from what the step created or changed.
  • Limits on slots per object, string length and heap objects per snapshot.

Evidence

  • story.test.ts: tracing the Stack ↔ Heap story's code gives the references its beats assert for the 9 beats a run can observe. The 10th is the garbage-collection sweep, which a trace never shows.
  • examples.test.ts: the Playground's JavaScript examples and default template trace without error and print what the untraced code prints.
  • The runtime is one self-contained typed function delivered as createTracer.toString(); tests run the serialised source standalone, and again after esbuild minification.
  • Type check, lint, 480 tests in 43 files and the build pass.

Known limits

  • A step is recorded after its statement ran, so its line and focus describe the same statement.
  • Top-level functions and classes show as values (ƒ, class); only closures become heap objects.
  • yield* resumption can miss the outer frame; the scope a class method closes over is not drawn; let/const declared directly in a switch case are not shown.
  • A function holding a var and a function declaration of the same name is refused; top-level await is a syntax error; code that declares its own __t fails with a confusing message.
  • Timers and promises stay native here; the queues come with the event loop PR.
  • examples.test.ts looks for the examples file under both its old and new name while the rename in the Playground basics PR is in flight; tidy once both are merged.

🤖 Generated with Claude Code

A new module, src/features/playground/tracer/, beside the old tracer and
not wired into the app yet (ADR 0004). It rewrites the learner's
JavaScript with acorn and astring, runs it on the browser's own engine
and returns a trace: steps that each hold a shared snapshot.

- every object, array and closure keeps one identity for the whole run
- every frame on the stack carries its own slots
- functions are traced wherever they are written
- the step limit stops the run and keeps the partial trace
- a step's focus is derived from what the step changed
- tracing the Stack and Heap story's code gives the references its
  beats assert, for the 9 beats a run can observe

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mnaimfaizy mnaimfaizy self-assigned this Oct 11, 2026
@mnaimfaizy
mnaimfaizy merged commit 4957f52 into main Oct 11, 2026
9 checks passed
@mnaimfaizy
mnaimfaizy deleted the feat/tracer-v2 branch October 11, 2026 22:40
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