Skip to content

Keep the typed answer deadline when an answer wait starts after recovery's budget - #22

Merged
ryanduguid merged 2 commits into
mainfrom
ryan/remaining-deadline-flakes
Oct 30, 2026
Merged

ryanduguid merged 2 commits into
mainfrom
ryan/remaining-deadline-flakes

Conversation

@ryanduguid

Copy link
Copy Markdown
Collaborator

Summary

An answer wait reached just after the bounded original-target observation ended gave an untyped error, whereas just before the same limit it gave Failure::AnswerDeadline. switch_failure only accepts typed failures, so a user with Grok fallback consent lost the fallback over a few milliseconds. The wait now returns the typed deadline without polling once the budget has expired.

  wait_original_answer
-   budget.within(wait_answer(...))        untyped once expired; can still poll after expiry
+   budget.answer_within(wait_answer(...))
+     already expired  -> Failure::AnswerDeadline, zero polls
+     expires mid-wait -> stays untyped and ineligible
  acknowledgement
    budget.within(...)                     unchanged: a lost acknowledgement stays untyped

Evidence

  • Before: holding the session write lock for the 3 s budget gave Original-target observation budget expired; recovery retained, 3 of 3. An expired budget with a pending future gave did not settle before its deadline, also untyped.
    After: both regression tests pass, 5 rounds plus 1, with zero polls of the expired wait.
  • Target disposition deadline reached on a5ff8be: with an injected 150 ms slow write it failed 3 of 3 on a5ff8be and passed 3 of 3 on 6c58009, so Record a decided tab retirement even when the write outlasts its budget #20 already fixed its likely cause. No change here.
  • Checks: cargo fmt --check, cargo build --locked and cargo clippy --all-targets --locked -- -D warnings pass. cargo test --lib, one thread: 671 passed, 0 failed, 14 ignored. bounded_provider_read tests pass 3 of 3 rounds.

Merge danger

Door: two-way. Blast radius: answer fallback

A wait reached after expiry can now be fallback eligible. It runs only after the send succeeded and the acknowledgement landed, and observe rechecks identity, receipt, dispatch and authority before the typed error leaves. That is from reading the code, not running the Grok switch end to end.

Unverified

  • The CI log can't show which call site produced the original Windows failure. If it was the acknowledgement, that test can still flake: it needs a stall of about 2.5 s in the first 250 ms or so of the 3 s window.
  • Linux wasn't run locally, and this branch hasn't had CI.
  • Integration tests weren't rerun after the last commit. Before it, bridge_doctor_accepts_and_ignores_verbose_like_commander and local_browser_cli_and_mcp_admit_foreground_and_detached_rust_workers failed locally, and both also fail on main.
  • Overlaps Keep waiting for the answer when a page read stalls after the send #17 in CHANGELOG.md, src/browser_runner.rs and src/browser_runner_tests.rs.

…ery's budget

An answer wait reached just before the recovery episode ended reported the
typed answer deadline. Reached just after it, the shared budget guard returned
an untyped error without polling the wait. Provider eligibility depends on the
type, so the same expiry withheld the Grok fallback on one side of that instant.

The answer wait now always runs. Its limit is zero once the episode has ended,
so it mints its own typed deadline. The acknowledgement keeps the guard: an
acknowledgement that does not land stays ineligible.
Tokio polls a timeout's future before its deadline, so the wait could still run
after expiry. A wait whose limit predated the expiry then went Pending and
returned the untyped timeout instead of the answer deadline.

Return the typed deadline without polling the wait. A wait still unsettled when
the deadline passes stays ineligible, as a hung read says nothing of the provider.
@sonarqubecloud

sonarqubecloud Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

@ryanduguid
ryanduguid enabled auto-merge (squash) October 30, 2026 22:27
@ryanduguid
ryanduguid merged commit 6228b59 into main Oct 30, 2026
11 checks passed
@ryanduguid
ryanduguid deleted the ryan/remaining-deadline-flakes branch October 30, 2026 22:38
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.

1 participant