A reset refused by a bounded execution answers 409, not a bare 422 - #2008
Merged
Merged
Conversation
…are 422 `:execution_fenced` reached API callers through the unmapped-atom safety net: a 422 carrying no body at all, plus a warning log on every refusal. It is the third reason `reset_sandbox/2` refuses (ADR 0046) and it needs to read like the other two. It answers `409 execution_fenced` now, beside `sandbox_mid_turn` and `sandbox_reset_pending`. The message says the thing that distinguishes it from both: a running turn ends by itself and a pending reset wants an operator, but an unconfirmed remote stop clears on its own once the deadline coordinator ages the obligation out, so the caller waits rather than fetching anyone. The regression builds a journal that genuinely owes a stop — claim the spawn, bind an identity, then fail the turn, which lands the row on `ready`. Without those two steps `complete/3` takes the `no spawn was ever submitted` path straight to `stopped`, nothing is owed, and the reset succeeds; that first draft passed against the unfixed code. Reverting the clause turns the 409 back into a 422, which is what the test is for. ADR 0046 also gets two corrections: - Sprites #33 merged on 2026-09-08. It was still written as an outstanding external dependency for provider identity notifications. - The activation blocker is now stated. `FOUNTAIN_EXECUTION_LIMITS` is a single host-wide ceiling with no per-provider scope, and `_unsafe_register_bounded/3` rolls back `:provider_not_supported` inside the admission transaction, so setting it on a deployment that also runs E2B, Daytona or self-hosted runners stops those conversations opening a turn at all. runtime.exs validates the JSON shape and nothing warns the operator. Per-provider granularity is follow-up under #1864; until it lands the host ceiling is unsettable in production and the per-account one is Sprites-only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9reKpmXUUJf4eUMULogie
7 tasks
…ty map
`inference_stamp_only?/1` is `Map.keys(usage) -- ~w(inference model) == []`,
so `%{}` satisfies it. The docstring carved out the "accounting"-only case
and said nothing about this one, which left a reader to discover it from the
implementation.
Recorded as a widening rather than a decision, with the two reasons it is
harmless: no runtime produces an empty usage map, and a row holding one
debited nothing, so a later figure over it debits exactly once.
Found in review of the #1732 stack; the predicate itself is unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R9reKpmXUUJf4eUMULogie
BinaryBourbon
approved these changes
Sep 12, 2026
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.
:execution_fencedreached API callers through the unmapped-atom safety net: a 422 with no body at all, plus a warning log on every refusal. It is the third reasonreset_sandbox/2refuses (ADR 0046), and it should read like the other two.It now answers
409 execution_fencedwith a message, besidesandbox_mid_turnandsandbox_reset_pending. The message carries what separates it from both: a running turn ends by itself and a pending reset wants an operator, but an unconfirmed remote stop clears on its own once the deadline coordinator ages the obligation out — so the caller waits rather than fetching anyone.Both defects are live on
maintoday, after #1744 and #1745 landed. This does not touch the held #1746–#1752.The regression is the interesting part
It builds a journal that genuinely owes a stop: claim the spawn, bind an identity, then fail the turn, which lands the row on
ready. Without those two stepscomplete/3takes the "no spawn was ever submitted" path straight tostopped, nothing is owed, and the reset succeeds — my first draft passed against the unfixed code. Reverting the clause turns the 409 back into a 422, which is what the test exists to catch.ADR 0046 corrections
FOUNTAIN_EXECUTION_LIMITSis a single host-wide ceiling with no per-provider scope, and_unsafe_register_bounded/3rolls back:provider_not_supportedinside the admission transaction. So setting it on a deployment that also runs E2B, Daytona or self-hosted runners stops those conversations opening a turn at all;runtime.exsvalidates only the JSON shape and nothing warns the operator. The per-account ceiling is usable only for an account that never touches another provider, unchecked. Per-provider granularity is follow-up under Track remaining lifecycle extractions from #1754 #1864 — until it lands, the host ceiling is unsettable in production and the per-account one is Sprites-only.Validation
sandbox_reset_controller_test: 7 tests, 0 failures; the new one fails (422) with the clause reverted.mix format --check-formattedandmix compile --warnings-as-errorsclean;okf validate decisionsreportsvalid: true; the index needs no refresh (frontmatter unchanged).🤖 Generated with Claude Code
https://claude.ai/code/session_01R9reKpmXUUJf4eUMULogie