Programmable History
Recording All the Things
Logs, metrics, and traces preserve answers you chose to collect before the program ran. If the question changes later, the evidence may simply not be there.
Wax preserves something different: enough of the program, its state, and the outside values it observed to reconstruct what happened and ask new questions afterward.
Wax does not record every instruction executed by an arbitrary native process. It records the smaller world that Wax controls: its own state, the code that produced it, and the inputs from the host that were visible to that code.
Because Wax owns that world, it does not have to reverse engineer execution after the fact. The compiler already knows the program, the runtime owns its state, and interaction with the host is explicit. A completed execution can become a portable artifact that can be reconstructed long after the original process is gone.
A frame is the span between a begin and an end the host defines. The host opens a frame, calls into Wax as many times as it wants, then closes it. A game closes one per rendered image, a request handler one per request, an agent one per step. Wax keys off that boundary, not off a clock.
Wax records execution at completed frames. At the end of a frame, Wax has returned to the host, the application stack is empty, and any surviving state lives in the Wax heap. That gives the runtime a clean place to save the application's state without saving CPU registers or native stack frames.
From there, a recording is two things: recording keyframes that hold that state and a typed input tape of the outside observations that happened between them. Those observations include calls into Wax, results from host functions, time, channel data, and other host observations needed to reproduce the next state.
A .wxs recording packages the keyframes and input tape together with the source and metadata needed to replay them against the program that actually ran. What Wax remembers covers what each part holds, what it leaves out, and what keeping history costs.
Rebuilding the Past
To reconstruct a particular frame, Wax starts from the newest keyframe before it and restores the heap and runtime state saved there. It then moves forward frame by frame, consuming the input tape in its original order.
Calls into Wax are made again with their recorded arguments. Calls from Wax into the host are not: replay returns the result or error that the host produced during the original run. Recorded time, channel data, and garbage collection decisions are supplied the same way.
By the time replay reaches the requested frame, Wax has arrived there by executing the program rather than loading a precomputed picture of that moment.
The typed recording also gives replay a way to catch disagreement early. If the program asks for a different kind of value, makes calls in a different order, or produces a different heap result, replay can stop at the frame where the two executions first diverge.
History on Demand
Replaying an old execution is useful on its own, but the more interesting part is that Wax can compile new code against the program that produced the recording.
You can inspect a reconstructed frame, search for every frame where a condition became true, follow one object through time, or compute new values across the recording. None of those questions had to exist when the original program ran.
The recording includes the source that produced it, so queries are compiled against that version of the program rather than whatever happens to be in your working tree later. Query execution is kept separate from the retained history, so a query can allocate or mutate state without changing the next frame you inspect.
Wax can also add instrumentation during replay. If you decide later that you need to know which statement changed a particular field, the program can be recompiled with that instrumentation and replayed against the same recording. Production did not have to record every possible detail in advance. Replay can also add profiling markers or new logging.
That is the point of making the past programmable: the execution happened once, but the questions do not have to be decided beforehand.