Skip to content

fix: refuse saved limits before active prompt handoff - #1778

Closed
jhgaylor wants to merge 1 commit into
fix/saved-allowance-wake-guardfrom
fix/saved-allowance-active-prompt
Closed

jhgaylor wants to merge 1 commit into
fix/saved-allowance-wake-guardfrom
fix/saved-allowance-active-prompt

Conversation

@jhgaylor

@jhgaylor jhgaylor commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

When a prompt reaches an existing server, an unsupported saved allowance previously returned HTTP 200 queued after turn admission refused it. It could also complete autonomous work and close the connection. Check saved policy before superseding that work, returning HTTP 422 with the current state intact. Billing and capacity preflights also precede supersession; user-busy precedence and cancellation remain unchanged.

Stacked on #1777 (fix/saved-allowance-wake-guard). Reuses its saved-policy check and HTTP mapping. Focused replacement for #1745/#1754; tracked in #1732.

Validation: six new real-server regressions, including idle/autonomous HTTP refusals for unsupported/malformed policy, unchanged turns/usage/connection, cancellation, empty-policy handoff and busy-user behavior. Four reproduce 200 queued on the parent. All 159 related tests pass. Full precommit passes 4,748 tests plus six doctests, zero failures; diff secret scan passes.

This is preflight: #1776 still rechecks inside turn admission if policy changes concurrently. It does not add an atomic prompt receipt, enforce running-turn limits or enable saved-policy writes. Initial prompt casts, channel reuse, direct boot recovery, ceilings and runtime enforcement remain separate; live enforcement acceptance is still required.

Signed-off-by: Jake Gaylor <jhgaylor@gmail.com>

@BinaryBourbon BinaryBourbon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving.

Promoting the helper to _unsafe_check_saved_execution_allowance/1 with a docstring is the correct move under the naming rule — it is now called from ConversationServer and the rehydrator, and the prefix is what tells a reader at those call sites that ownership had to be established upstream.

The substantive change is moving close_autonomous_turn(state, "superseded_by_prompt") from before the gates to inside the success branch. That is broader than execution limits — a prompt refused by TurnMachine.gate/2 (billing) or capacity_gate/2 no longer kills the background narration either — and I think it is right: refusing a prompt should not have the side effect of ending work the user did not ask to end. #817's semantics for the accepted case are unchanged, which is what that issue was actually about. The description calls this out, so it is a deliberate widening rather than an accident.

Checked the else branch returns the pre-close state, so the refusal path really is inert.

The active × malformed matrix asserting :sys.get_state(pid) == before alongside unchanged turns, unchanged conversation row and unchanged usage count is a strong shape for this — it catches a partial mutation that a return-value assertion would miss.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants