Skip to content

fix(antigravity): keep exact-model routing leases scoped - #10011

Closed
Ardem2025 wants to merge 5 commits into
diegosouzapw:release/v3.8.51from
Ardem2025:fix/antigravity-exact-model-routing-leases
Closed

Ardem2025 wants to merge 5 commits into
diegosouzapw:release/v3.8.51from
Ardem2025:fix/antigravity-exact-model-routing-leases

Conversation

@Ardem2025

Copy link
Copy Markdown
Contributor

Summary

  • keep Antigravity quota/cooldown state scoped to the exact requested model instead of poisoning sibling models in the same family
  • reserve the selected account for a request and keep that lease until the streaming lifecycle finishes
  • ensure retries and credential handoff do not let concurrent requests select the same account prematurely

This is the routing/lease part of the production-tested patch stack. Image-generation account rotation is intentionally separate in #9908.

Related Issues

Validation

  • Change type: provider / routing
  • Focused tests and category gates from the golden path
  • npm run lint (CI; focused files were exercised locally)
  • Reconciled with the current active release base; focused checks rerun afterward
  • Production-code changes include new or updated automated tests in this PR
  • SonarQube PR analysis is green or any remaining issues are explicitly documented below

Focused test result: 14/14 passed on Node 22.22.3 against the active release/v3.8.50 tree.

Tests Added Or Updated

  • tests/unit/antigravity-quota-routing-exact-model.test.ts
  • tests/unit/antigravity-routing-state.test.ts
  • tests/unit/antigravity-lease-lifecycle.test.ts
  • tests/unit/antigravity-pool-busy.test.ts
  • tests/unit/auth-antigravity-account-retry-v2.test.ts
  • tests/unit/repro-antigravity-404-family-cooldown-hijack.test.ts

Coverage Notes

The focused tests cover exact-model quota keys, routing reservations, pool-busy behavior, lease release after stream completion, credential handoff, and 404/429 sibling-model isolation.

Reviewer Notes

  • No database migration, new dependency, credential, production configuration, or infrastructure-specific path is included.
  • The lease is request-local in process memory and is released through the existing stream finalization lifecycle.
  • The conflict with the active release base in auth.ts was reconciled by retaining the release branch's exact-lock behavior while removing the obsolete family-only cooldown guard.

@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks for sticking with this — the exact-model routing lease design here (dedicated
antigravityLeaseLifecycle/antigravityRoutingState modules instead of piling more into
auth.ts) is a real improvement over your earlier attempts in #6064/#6281/#6680, and the
exact-model-vs-family-cooldown distinction fixes a genuine bug (confirmed: no antigravity-
scoped cooldown function exists on the current tip at all). Probe run: all 6 of your test
files pass (14/14) at your PR head. Before this can land: please retarget to
release/v3.8.51, add a changelog.d/fixes/ fragment, and let's sequence this with #9908
(which you've already scoped as the companion image-layer PR) — planning to close
#6064/#6281/#6680 in favor of this one since they're your own earlier iterations of the same
fix, credited to you either way.

@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.50 to release/v3.8.51 September 15, 2026 11:31
@Ardem2025
Ardem2025 force-pushed the fix/antigravity-exact-model-routing-leases branch from 9cc0579 to de9c762 Compare September 16, 2026 06:24
OpenClaw Auto and others added 5 commits September 17, 2026 00:24
…ng lease scoping

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…coping

quotaCache.ts kept three private helpers (resolveAntigravityExactQuota,
isUsableQuota, isAntigravityQuotaKeyForFamily) plus their normalizer and two
imports that no code path reaches since the lease/routing modules took over,
and getQuotaScopeLabelForProvider's parameters became unused once it started
answering "model" unconditionally. Removed the dead code, marked the kept
signature's parameters and pruned the now-stale eslint suppression entry,
clearing the five no-unused-vars errors this PR introduced.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@Ardem2025
Ardem2025 force-pushed the fix/antigravity-exact-model-routing-leases branch from ccd1e92 to bceb341 Compare September 16, 2026 21:24
@diegosouzapw

Copy link
Copy Markdown
Owner

Closing this one — not because the diagnosis was wrong, but because both halves of it were settled on the release branch while this PR waited.

Exact-model scoping already shipped. Your repro file tests/unit/repro-antigravity-404-family-cooldown-hijack.test.ts is on the tip since 53f435da (2026-07-22), from #8050 by @AndrianBalanescu — "scope 404 model-not-found lockout to exact model + bare-model autopick". Your copy differs from what is already there by 4 lines. This PR was opened 2026-08-10, 19 days after that merged.

The quota axis went the other way. The tip solves family-vs-model quota through selectAntigravityQuotaWindowNames in open-sse/services/antigravityQuotaFamily.ts / quotaPreflight.ts / quotaCache.ts — an aggregate-family design, not exact-model-only. When we tried to merge the release into this branch, the conflicts landed in exactly those files. Reconciling two competing designs for one subsystem is a rewrite, not a merge.

There is also a live signal that the branch is mid-redesign: after your rebase, tests/unit/antigravity-routing-state.test.ts → "release is fenced and explicit release restores availability" fails deterministically on the branch itself — it asserts family semantics for a sibling model while the lease is now exact-model.

What we are keeping. antigravityLeaseLifecycle.ts and antigravityRoutingState.ts do not exist on the tip in any form, and the problem they solve is real: without a lease, concurrent retries and credential handoff can re-pick an account that is already committed to an in-flight stream. We are reopening that as a fresh PR against the current release branch, credited to you. It is the one piece of this stack worth rescuing rather than reconciling.

Thanks for four iterations on this, @Ardem2025. The lease idea is the part nobody else had.

diegosouzapw added a commit that referenced this pull request Sep 18, 2026
…ifecycle (re-land of #10011) (#13929)

* feat(sse): reserve the Antigravity account for the request's stream lifecycle

Re-land of the account-lease half of #10011 on the current release branch.
Its exact-model-scoping half had already shipped in #8050 and its quota half
lost to the tip's aggregate-family design (selectAntigravityQuotaWindowNames /
antigravityQuotaFamily.ts); none of that is reintroduced here. The lease is a
concurrency reservation only and never reads or writes quota state.

The Antigravity account selected for a request is reserved for the whole
streaming lifecycle of that request, so a concurrent retry — or the credential
handoff inside getProviderCredentialsWithQuotaPreflight — cannot re-pick an
account already committed to an in-flight upstream stream. The reservation is
scoped to (connection, callable upstream model) rather than the whole account,
so one account can still serve two different models at once; catalog ids that
resolve to the same upstream id (the gemini-3.7-flash tiers, all
gemini-3.7-flash-tiered) share one lease. When every eligible account is leased
for that model the request returns a structured 503 antigravity_pool_busy with
a bounded Retry-After instead of piling onto a busy account.

Opt-in behind ANTIGRAVITY_ACCOUNT_LEASE_ENABLED (runtime, default false). With
the flag off no reservation is taken, credentials carry no routing descriptor,
every release/hold is a no-op on an undefined lease id, and account selection
and dispatch behave exactly as before.

#10011's original test suite asserted family semantics for a lease that was
exact-model scoped and failed deterministically on its own head; the model ids
it used (gemini-3.5-flash / gemini-3-flash-agent) no longer exist in the
catalog. The contradiction is resolved in favour of one coherent semantic —
exact callable upstream model — and the tests assert it against the alias
tables as they are on this branch.

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>

* fix(sse): widen the Antigravity lease reservation result so auth.ts narrows it

The discriminated-union form of reserveAntigravityLeaseForSelection's return type
did not narrow under tsconfig.typecheck-api.json, so reading `reserved.lease`
after the `reserved.busy` early return raised TS2339 in the API Route Typecheck
gate. A single optional-property shape carries the same information and type-checks
everywhere.

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>

---------

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ifecycle (re-land of diegosouzapw#10011) (diegosouzapw#13929)

* feat(sse): reserve the Antigravity account for the request's stream lifecycle

Re-land of the account-lease half of diegosouzapw#10011 on the current release branch.
Its exact-model-scoping half had already shipped in diegosouzapw#8050 and its quota half
lost to the tip's aggregate-family design (selectAntigravityQuotaWindowNames /
antigravityQuotaFamily.ts); none of that is reintroduced here. The lease is a
concurrency reservation only and never reads or writes quota state.

The Antigravity account selected for a request is reserved for the whole
streaming lifecycle of that request, so a concurrent retry — or the credential
handoff inside getProviderCredentialsWithQuotaPreflight — cannot re-pick an
account already committed to an in-flight upstream stream. The reservation is
scoped to (connection, callable upstream model) rather than the whole account,
so one account can still serve two different models at once; catalog ids that
resolve to the same upstream id (the gemini-3.7-flash tiers, all
gemini-3.7-flash-tiered) share one lease. When every eligible account is leased
for that model the request returns a structured 503 antigravity_pool_busy with
a bounded Retry-After instead of piling onto a busy account.

Opt-in behind ANTIGRAVITY_ACCOUNT_LEASE_ENABLED (runtime, default false). With
the flag off no reservation is taken, credentials carry no routing descriptor,
every release/hold is a no-op on an undefined lease id, and account selection
and dispatch behave exactly as before.

diegosouzapw#10011's original test suite asserted family semantics for a lease that was
exact-model scoped and failed deterministically on its own head; the model ids
it used (gemini-3.5-flash / gemini-3-flash-agent) no longer exist in the
catalog. The contradiction is resolved in favour of one coherent semantic —
exact callable upstream model — and the tests assert it against the alias
tables as they are on this branch.

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>

* fix(sse): widen the Antigravity lease reservation result so auth.ts narrows it

The discriminated-union form of reserveAntigravityLeaseForSelection's return type
did not narrow under tsconfig.typecheck-api.json, so reading `reserved.lease`
after the `reserved.busy` early return raised TS2339 in the API Route Typecheck
gate. A single optional-property shape carries the same information and type-checks
everywhere.

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>

---------

Co-authored-by: Ardem2025 <openclaw-auto@example.invalid>
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