Gate resume continuations behind the execution limits - #1873
Draft
ux-xd wants to merge 1 commit into
Draft
Conversation
One execution can pause many times, and every resume continues the sandbox with fresh code and tool calls. Both pre-execution guards passed resume through untouched, so a single billable executeWithPause that paused in a loop drove an unbounded chain of continuations past the balance gate and the rate limiter: one quota slot, zero further checks. Gate resume in withPreExecutionGate like the other execution paths: a blocked decision answers with the same descriptive error a blocked execute returns and leaves the paused execution intact — nothing runs un-gated, and approved work completes once the org is back under its limit. Each resume now also counts against the hourly rate-limit backstop. The regression test fails on the previous tree (a blocked-balance and an over-cap resume both ran to completion) and pins the fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
withPreExecutionGate(shared by the balance gate and the rate-limit backstop) now gatesresumein addition toexecute/executeWithPause, and each resume counts against the hourly rate-limit counter.The bypass
One execution can pause many times — every elicitation is a pause point, and each pause mints a new execution id. Both pre-execution guards passed
resumethrough untouched:execution-gate.ts— "resumeis never gated: a paused execution already consumed its quota slot when it started"execution-rate-limit.ts— the counter only increments onexecutecallsexecution-usage.ts— "resume doesn't count as usage"The quota-slot assumption only covers the first pause. A single billable
executeWithPausewhose code loops over an approval-gated tool drives an unbounded chain of pauses and resumes, and every continuation between the pauses is fresh sandbox work and tool calls with no balance check and no rate-limit increment after the first execution. The only bounds are the per-pause approval TTL and session idle eviction, so one free-tier quota slot could carry arbitrary amounts of continued computation.The fix
A blocked decision on
resumeanswers with the same descriptive error a blocked execute returns and never invokes the inner engine, so:Usage tracking is left as-is (a resume is still not billed as a new execution) — this PR is about enforcement, not billing semantics.
Verification
The new
execution-resume-gate.node.test.tsfails on the previous tree — a spent-balance resume and an over-cap resume both ran to completion — and passes with the fix:vitest run src/engine/execution-resume-gate.node.test.ts src/engine/execution-rate-limit.node.test.ts— 17 passed.turbo run typecheck --filter=@executor-js/cloud— 20/20 tasks green.Not run: e2e (narrow scenario still to be picked per the repo contract if reviewers want one; the changed seam is covered at the decorator level here).