Repository navigation
fix(runner): refuse unmetered sessions, guard reload during save (DEV-3147) - #394
Merged
Merged
Conversation
…-3147) A /api/session/:id/* call that arrived after the session's 600 s tombstone expired booted a container the cost guardrails never metered. The gate now also refuses an id with no meter (written at create, deleted at teardown): 410 for everything, 204 for a file delete. The decision lives in session-lifecycle.ts so it is testable. The edit page now arms a beforeunload guard while edits are unsaved or a save is in flight, so a reload during the 8-14 s rebuild no longer drops the edit silently. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…147) Run the meter check after the budget guard so an unknown id at anon_blocked/new_blocked keeps its 401/503, retry the meter write once because the gate now depends on it, keep edits typed during a save dirty (and the reload guard armed), and refresh the stale meter comments. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Context
Two of the three items in DEV-3147. The third (return from
PATCH /api/demos/:idbefore the build finishes) is deliberately not in this PR: it needs an editor-side polling protocol and should be decided after profiling thesnapshot.buildduration_mspoint.Unmetered resurrected containers. The
/api/session/:id/*gate only refused tombstoned sessions, and a tombstone lives 600 s. After that a stale/statuscall booted a container that no meter books, so the cost guardrails could not see it. The gate now also refuses an id with no meter (written at create, deleted at teardown): 410 for everything, 204 for a file delete. The check runs after the budget guard, so an unknown id atanon_blocked/new_blockedkeeps its 401/503. The decision is a pure function (sessionGateVerdict) so it is unit-testable.startSessionMeterretries its KV write once, because a lost write would now make a live session look dead.Reload during a save loses the edit. The edit page arms a
beforeunloadguard while edits are unsaved or a save is in flight. Edits typed during the 8-14 s rebuild are no longer marked clean when the PATCH resolves, since they are not in the request.Known trade-off: the gate reads a KV key another location may not have replicated yet. The meter is written before the create returns, so a client's first poll normally hits the same location; a stale
nullwould show as "The session was closed."Types of changes
runner/) changeHow was this verified?
pipeline/session-unmetered-gate.test.mjsdrives the real worker router (status and file write refused, file delete 204, tombstone wins over a meter, KV failure fails open, budget 401/503 preserved). Reverting the gate to master makes the three refusal tests fail.edit page guards a reload while edits are unsaved or a save is in flight(clean, unsaved, save in flight, typed mid-save, saved). It fails with the guard removed.pipeline/*.test.mjs2561/2561,pnpm typecheckclean, full Playwright suite 247 passed (182 live-gated skips) against a build served on its own port./code-reviewpass and fixed its findings.Checklist
runner/config/frameworks.json(see CONTRIBUTING.md); otherwise it won't appear on demos.handsontable.compnpm build(andpnpm dev) in the affected example/server-example locallyNot applicable: no example added or renamed. The runner app and worker were built, type-checked and tested instead.
Related issue(s):
Note
Medium Risk
Changes central session routing and metering gates that can block or allow container boots; edit-page save/dirty logic affects data-loss UX but is localized to authoring.
Overview
DEV-3147 tightens two places where edits or spend could slip through: the edit page and session subroutes on the API worker.
On
/edit/:id, abeforeunloadhandler runs while the workspace is dirty or a save is in flight (8–14 s rebuild), so reload/close can trigger the browser’s leave confirmation.onSaveonly callsclearDirty()whenfilesRef.currentstill matches the snapshot sent in the PATCH, so keystrokes during an in-flight save keep Save • and stay protected.On the API, the
/api/session/:id/*resurrection gate now refuses IDs with no session meter (not only tombstones), via testablesessionGateVerdict: 410 for most calls, 204 for file delete. Order stays tombstone → budget guard → meter check.startSessionMeterretries its KV write once so a lost meter write does not brick a live session. Pipeline and e2e tests cover the gate and the edit-page guard.Reviewed by Cursor Bugbot for commit 573068f. Bugbot is set up for automated code reviews on this repo. Configure here.