% --- Python execution sandbox: isolation boundary + IPC --- \begin{figure}[htbp] \centering \begin{tikzpicture}[vqfont] % ---- Server side ---- \node[vqblue, text width=2.6cm, minimum height=2.0cm] (srv) at (0,0) {\textbf{Server}\\\vqsmall \texttt{spawn} child\\ write stdin\\ read stdout}; % ---- Child inner stages ---- \node[vqgreen, text width=4.5cm] (ns) at (8.0,2.05) {\textbf{Build namespace}\\\vqsmall 17 libs $\cdot$ \texttt{save\_excel}/\texttt{save\_word} $\cdot$ \texttt{fmp} client $\cdot$ context vars}; \node[vqorange, text width=4.5cm] (ex) at (8.0,0.35) {\textbf{\texttt{exec(code, ns)}}\\\vqsmall \texttt{stdout}/\texttt{stderr} $\to$ string buffers $\cdot$ optional \texttt{main()}}; \node[vqpurple, text width=4.5cm] (cap) at (8.0,-1.35) {\textbf{Figure capture}\\\vqsmall \texttt{get\_fignums} $\to$ PNG @150\,dpi $\to$ base64}; \draw[vqarr] (ns) -- (ex); \draw[vqarr] (ex) -- (cap); % Child container \begin{scope}[on background layer] \node[vqband, fill=VQInk!4, draw=VQInk!35, line width=0.5pt, dashed, fit=(ns)(ex)(cap), inner sep=10pt] (child) {}; \end{scope} \node[vqsmall, anchor=north west, text=VQInk!70] at (child.north west) {\textbf{Child Python process}~~\vqtiny(\texttt{PYTHONUNBUFFERED}, 90\,s timeout, Agg backend)}; % ---- IPC arrows across the boundary ---- \draw[vqflow] (srv.east) to[out=25,in=180] node[vqtag, pos=0.5, above]{stdin: \texttt{\{code, context, key\}}} (ns.west); \draw[vqflow, draw=VQTeal!80!black] (cap.west) to[out=180,in=-25] node[vqtag, pos=0.5, below]{stdout: \texttt{\{output, figures[], files[]\}}} (srv.east); % Isolation boundary marker \draw[VQRed!70!black, line width=0.7pt, dash pattern=on 3pt off 2pt] (3.0,2.8) -- (3.0,-2.3); \node[vqtag, text=VQRed!70!black, fill=white] at (3.0,-2.6) {process isolation}; \end{tikzpicture} \caption{\textbf{The Python execution sandbox.} The server runs model-authored code in a separate interpreter, not in process. It serializes one JSON request to the child's standard input; the child builds an execution namespace (scientific libraries, artifact helpers, a market-data client, and any context variables), runs the code with output redirected into string buffers, then sweeps all live matplotlib figures into base64-encoded PNGs and returns a single JSON response. A non-zero exit or empty output is surfaced as an error so the model can revise. The dashed boundary is the process-isolation line; the red marker emphasizes that a crash or timeout cannot reach the server.} \label{fig:sandbox} \end{figure}