Skip to content

fix(daemon): release antigravity model lock on pre-spawn early exit - #5467

Open
tomsen02 wants to merge 1 commit into
nexu-io:mainfrom
tomsen02:fix/antigravity-model-lock-early-exit-release
Open

fix(daemon): release antigravity model lock on pre-spawn early exit#5467
tomsen02 wants to merge 1 commit into
nexu-io:mainfrom
tomsen02:fix/antigravity-model-lock-early-exit-release

Conversation

@tomsen02

Copy link
Copy Markdown
Contributor

Fixes #5466

Why

Following up on the lock-ownership gap I reported in #5466. Maintainer confirmed the bug and prescribed the fix shape in the issue thread ("an idempotent early-exit release around the acquire→spawn region, guarded so it stops firing once ownership has been transferred to the child/watch path"); this PR implements exactly that.

The pain: for an Antigravity concrete-model run, startChatRun acquires the process-global model lock before buildArgs/spawn, but only hands the release off to the child-exit/watcher path after a successful spawn. Every early exit in between returns without releasing:

  • the pre-spawn cancel / already-terminal check,
  • the two Windows command-line budget guards,
  • a buildArgs throw,
  • the missing-binary AGENT_UNAVAILABLE path,
  • a spawn failure.

A run cancelled while it is still waiting on the lock resumes once the prior holder releases, becomes the holder, hits the cancel check, and returns without releasing. The chain is then poisoned: every later concrete-model Antigravity run blocks forever on await acquireAntigravityModelLock(), and only a daemon restart recovers it.

What users will see

No visible change on the happy path. The fix removes a hang: if you cancel an Antigravity run (with a concrete model like Gemini 3.1 Pro (High)) while a previous Antigravity run is still holding the model lock, your next Antigravity run no longer hangs indefinitely with no output.

Surface area

  • None — internal daemon run-lifecycle fix + regression test only

Bug fix verification

  • Test path: apps/daemon/tests/antigravity-model-lock-cancel-release.test.ts
  • Red on main, green on this branch? yes. The spec drives three real runs over the production HTTP API (POST /api/runs, POST /api/runs/:id/cancel) against a PATH-injected fake agy: A holds the lock (its agy stalls until a go file appears), B waits on the lock and is cancelled while waiting, A exits so B resumes and (pre-fix) poisons the lock, then C can never acquire it. Assertion: C reaches a terminal status.
    • Without the fix: expected false to be true — C never terminal (lock poisoned).
    • With the fix: green, 3/3 deterministic. No orphan agy/test processes left behind.

Validation

  • pnpm --filter @open-design/daemon typecheck (both tsconfig.json and tsconfig.tests.json) — clean
  • pnpm guard — 78/78 pass
  • pnpm --filter @open-design/daemon exec vitest run tests/antigravity-model-lock-cancel-release.test.ts — green, 3/3
  • Neighboring lifecycle suites run-retry-runtime + run-retry-policy — 22/22 pass

Notes

  • The release is idempotent and handoff-guarded (antigravityModelLockHandedOff): once ownership transfers to the watcher + child-exit fallback it becomes a no-op, so it never double-releases nor reopens the settings.json cross-talk race (263fd2f) by releasing while a slow-cold-start agy still holds the file.
  • No-op for non-Antigravity runs (antigravityModelLockRelease is null), so other agents are unaffected.
  • refactor(daemon): extract startChatRun from server.ts into an explicit-deps chat-run module #5128 moves this code but does not change the ownership gap, as noted in the issue.

The global antigravity model lock is acquired before buildArgs/spawn but
its release is only handed off to the child-exit/watcher path after a
successful spawn. Every early exit in between — the pre-spawn cancel
check, the Windows command-line budget guards, a buildArgs throw, the
missing-binary AGENT_UNAVAILABLE path, and a spawn failure — returned
without releasing. A run cancelled while awaiting the lock therefore
resumed once the prior holder released, became the holder, hit the cancel
check, and returned without releasing — poisoning the chain so every
later concrete-model antigravity run blocked forever.

Add an idempotent, handoff-guarded release across the acquire->spawn
region: each early exit calls it, and it becomes a no-op once ownership
transfers to the child/watch path. This preserves the invariant that the
lock is only handed off when the child lifecycle owns it, so it never
reopens the settings.json cross-talk race (263fd2f) by releasing while
a slow-cold-start agy still holds the file.

Fixes nexu-io#5466
@lefarcen

Copy link
Copy Markdown
Contributor

Thanks @tomsen02 — the reproduction and red→green test seam are very clear here. I’ve queued this up for review and will follow along from here.

@lefarcen
lefarcen requested a review from nettee July 11, 2026 05:51
@lefarcen lefarcen added size/M PR changes 100-300 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/bugfix Bug fix needs-validation Runtime change detected; needs human or /explore agent validation. labels Jul 11, 2026
@lefarcen

Copy link
Copy Markdown
Contributor

🧪 Queued for QA validation — this PR changes a live run/cancel path, so it’ll get a manual QA pass before merge. Nothing needed from you right now; we’ll update here once that validation happens. Thanks again for the thorough reproduction. 🙏

@lefarcen

Copy link
Copy Markdown
Contributor

@nettee This PR's current head 10ce2a7 is waiting on your review.

@tomsen02

Copy link
Copy Markdown
Contributor Author

Gentle follow-up — this has been waiting on review since Jul 11 (@nettee was pinged on head 10ce2a7). CI is green and it's mergeable, no changes outstanding on my side. Could someone grab a review slot when there's a chance? Happy to rebase if needed.

@lefarcen

Copy link
Copy Markdown
Contributor

Thanks for the follow-up, @tomsen02. I’ve refreshed the review request on the current head and flagged this again for a human review pass. From what I can see, you do not need to rebase right now.

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

Labels

needs-validation Runtime change detected; needs human or /explore agent validation. risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/M PR changes 100-300 lines type/bugfix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: cancelling an Antigravity run while it waits on the model lock permanently poisons the lock

2 participants