Skip to content

fix(daemon): start open publication bound at claim - #1807

Merged
ScriptedAlchemy merged 6 commits into
masterfrom
cursor/reset-required-connection-bound-82db
Sep 19, 2026
Merged

ScriptedAlchemy merged 6 commits into
masterfrom
cursor/reset-required-connection-bound-82db

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • The foreground project-open publication bound now starts when the open is claimed, not when the connection arrives.
  • A recorded reset_required refusal is read before the cache probe an elapsed deadline can cancel, so a restart's first HTTP observation is the refusal instead of retryable unavailable.

Motivation

Master tip 3f71bccb2dba still has the connection-bound race that failed reset_required_survives_http_mcp_and_rust_sdk_across_restart on run 35411306897: the first HTTP observation after restart was application.surface.unavailable / after_delay for a store whose shape is reset_required.

The shared premise of the later test polls (e2c8b592cd, #1794) is that the client must ride out warming. That premise is wrong for this refusal. The 500 ms bound answered how long the connection had been here, so route enrollment spent it before the request joined the open. The wait then returned immediately and never read the refusal already on the watch. CLI clients retried; a one-shot HTTP or SDK call reported warming for a terminal reset.

#1794's test poll and #1797's unrelated live-daemon fixes are not absorbed. .github/workflows/ci.yml pull_request triggers are unchanged.

HEAD: bf0eeb460405e5c1a63db4bab5aeae0b61f4a145

Changes

  • project_open_publication_deadline measures the bound from the claim. Both the Unix and portable request loops use it.
  • The publication loop reads Failed before the cache-probe await.
  • enrollment_delay_does_not_hide_a_quick_reset_required fails if enrollment time is charged to the bound: the publication future is pending on its first poll, which is when an already-elapsed bound used to win.

Test plan

  • daemon::tests::bootstrap::enrollment_delay_does_not_hide_a_quick_reset_required — 1 passed
  • foreground_project_open_wait_is_bounded_and_accepts_quick_publication and a_recorded_open_failure_replaces_only_the_warming_hint — 2 passed
  • explicit_init_retries_after_joining_an_ordinary_missing_database_open — 1 passed
  • reset_required_survives_http_mcp_and_rust_sdk_across_restart — 1 passed in 3.57s, then 5/5 reruns in 2.72–2.81s
  • Full workspace nextest remains the push CI lane

Checklist

  • No secrets, credentials, or .env files included
  • CHANGELOG.md updated (daemon admission timing; no user-facing contract change)
  • Breaking changes documented (none)
Open in Web Open in Cursor 

The 500 ms wait answered how long the connection had been here, so
route enrollment could spend the budget before the request joined the
open. A restart then reported warming for a store the open had already
refused with reset_required. The bound now starts at the claim, and the
waiter reads a recorded refusal before the cache probe a deadline can
cancel.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 49ad17d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

The paused enrollment-delay check needs an explicit output type so
the publication wait can see the reset_required refusal.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review September 19, 2026 07:26
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Complements #1794 (reset_required_survives_http_mcp_and_rust_sdk_across_restart fence). This PR fixes the production bound that the test was riding around.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-19T07:29:56.761617Z bf0eeb4 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf0eeb4604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tracedecay/src/daemon/engine.rs Outdated
Comment on lines +700 to +703
if let ProjectOpenTaskState::Failed(failure) =
state.borrow().clone()
{
return Err(failure.to_error());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check for a published owner before returning a stale failure

When this waiter is descheduled after its claimed task fails, ProjectOpenTaskRegistry::prune can remove the completed failure (or discard a stale reset refusal), allowing another request to open and publish the same route before this waiter resumes. This new pre-cache return then reports the old receiver's failure even though a valid owner is available, contradicting the existing a_recorded_open_failure_replaces_only_the_warming_hint invariant that a published owner outranks a recorded failure; probe the cache before returning the failure, as the previous ordering did. The portable loop contains the same regression.

Useful? React with 👍 / 👎.

ScriptedAlchemy and others added 4 commits September 19, 2026 19:14
The pre-cache `Failed` read made a waiter answer with its own claim's
recorded failure even when another open had since published a server for
the same route, contradicting the invariant
`a_recorded_open_failure_replaces_only_the_warming_hint` states.

The read was also redundant. With the bound measured from the claim, the
publication wait always starts with a full budget, so an elapsed deadline
can only preempt a later iteration, and `prefer_recorded_open_failure`
already substitutes the recorded failure for that warming hint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`enrollment_delay_does_not_hide_a_quick_reset_required` computed its own
deadline with `project_open_publication_deadline(now)`, so it never
observed where the request loop arms the bound. Reverting the production
change to master's connection-arrival placement left the test passing,
which is the detection it claimed to provide.

`reset_required_survives_http_mcp_and_rust_sdk_across_restart` remains the
detector for this defect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Review from the merge sweep. The fix is right and nothing on master subsumes it. Master's ad95bff640 only relabels the warming refusal, and no commit since bf0eeb4604 touches engine.rs, daemon.rs, project_open_orchestration.rs or project_routing.rs.

Two changes pushed on top of the author's commits, plus a merge of origin/master with no conflicts.

e3860bf9c1 removes the pre-cache Failed read from both publication loops. This is the Codex P2 finding and it holds. With the bound measured from the claim, the wait always starts with a full 500 ms, so an elapsed deadline can only cancel a later iteration, and prefer_recorded_open_failure already substitutes the recorded failure for the warming hint. The read added nothing and reordered the loop so a waiter reported its own claim's failure ahead of a server another open had published, which the last assertion of a_recorded_open_failure_replaces_only_the_warming_hint forbids.

6bee62a76a drops enrollment_delay_does_not_hide_a_quick_reset_required. With engine.rs mutated back to the connection-arrival placement, the test still passed, because it computes its own deadline by calling project_open_publication_deadline(now) and never observes where the request loop arms the bound. reset_required_survives_http_mcp_and_rust_sdk_across_restart remains the detector.

Verified in a clean lane: cargo fmt --all -- --check, cargo clippy --workspace --all-targets --locked -- -D warnings, the four bootstrap tests under -p tracedecay --lib --features tracedecay/test-helpers, and the commit range lint. The root-transport partition runs in CI at 49ad17d9c4.

@ScriptedAlchemy
ScriptedAlchemy merged commit a3c37a4 into master Sep 19, 2026
47 of 49 checks passed
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