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