Skip to content

sandbox Phase 1 — charge script CPU time, not wall clock #3295

Description

@os-zhuang

Part 1 of #3275 — see its Phase 1 section for the full implementation-ready spec. Can start now (no dependency).

Change (packages/runtime/src/sandbox/quickjs-runner.ts): make the resolveTimeout() budget a VM-active-time (CPU) budget, and add a separate wall-clock ceiling (wallCeilingMs, default 30s) as the stuck-host backstop. Slice-stopwatch every VM entry (evalCode / evalCodeAsync / executePendingJobs); idle host waits + nested-hook execution stay uncharged. Interrupt handler: (cpuMs + currentSlice) > cpuBudget || now > wallDeadline. Distinct errors — exceeded CPU budget of Xms vs exceeded wall-clock ceiling of Yms while awaiting host calls — and map the mid-slice interrupt error to the clean budget message.

Why: the wall-clock budget conflated "tolerate a slow host" with "kill a runaway script", and billed nested hooks to the parent — the #3259 flake. See #3275 §Why.

Acceptance criteria

Decide first (§1.5): wall ceiling as constructor option only, or also OS_SANDBOX_WALL_CEILING_MS.

Separate small PR after soak: drop OS_SANDBOX_HOOK_TIMEOUT_MS=10000 from .github/workflows/ci.yml.

Refs: #3275 (parent) · #3259 (flake) · #3270 (mitigation).

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions