EvalRender
The value/output join and the mojmap reverse-mapping of throwables. Pure functions over their arguments — no REPL state. Game loader, so the lane can render without reaching across the masking seam.
Properties
A frame of the script's own code, keyed on the source name we hand the compiler. A loader/module test would also catch the game, whose loader is unnamed on a plugin host; a class-name test would guess at the compiler's mangling. Types the script declares itself compile from the same file, so they match too.
Longest repeating block foldRepeats looks for: recursion cycles are short (1 direct, 2 mutual, a handful for a delegation loop), and the scan is bounded anyway by the JVM's 1024-frame trace ceiling.
Frame lines kept per stack, post-fold: above any real stack, below the JVM's 1024-frame recursion ceiling. Every stack, not just the timeout report — a throwable's own trace overflows the same way.
Functions
A ScriptTimeoutError is an immutable singleton and carries no stack, so its frames come from the watchdog's side channel instead: where the lane thread stood when the budget elapsed. Present only on the thread that was caught (TimeoutGuard.caughtHere), so an off-lane render omits them.
Collapse consecutive repeats of a block of lines into one copy plus a count.
Collapse each maximal run the predicate accepts. A run too short for the marker to pay for itself is left whole — the same bar foldRepeats holds itself to.
The frame block of one stack, ready to print: demapped, repeat-folded, then capped at MAX_FRAME_LINES. Shared by stack's walk and appendWatchdogTrace, which would otherwise hold the demap rules twice.
One rendered frame: net.minecraft.* demapped to mojmap when m is non-null (a non-mojmap runtime), with the source file derived from the demapped class so it stays consistent with it.
Render a throwable's stack trace, reverse-mapping runtime (intermediary/srg) names back to mojmap when a non-mojmap runtime is active — so a script that threw inside MC shows the class/method names the LLM actually wrote (ResourceLocation, not class_2960). On a mojmap runtime (dev / NeoForge production) Mappings.current is null and every name passes through untouched. Line numbers are unchanged by remap, so they still point at the true source lines.