Retargetado para release/v3.8.51 (release/v3.8.50 está congelada — freeze issue #11439). Validado em lote combinado (batch-0824h2, junto de #11435/#11436/#11437) contra o tip de release/v3.8.51: typecheck:core limpo, gates estáticos OK, 127/127 testes focados passando.
Investigação sólida com repro real via container isolado, três causas independentes identificadas e corrigidas com testes de regressão dedicados para cada uma. Obrigado pela contribuição!
* fix(antigravity): heal empty-projectId accounts via retryable auto-onboarding
Accounts with an empty Cloud Code projectId get a permanent 422 "Missing
Google projectId" when loadCodeAssist returns no project. The 3.8.50
bootstrap attempts to CREATE the project via onboardUser, but a single failed
attempt (transient network/upstream error) was memoized forever in
onboardAttemptedCache: every later request in the process skipped onboarding
and 422'd, even though a retry would succeed.
Replace the permanent per-token Set with a failure-backoff map: failed onboard
attempts are retried after a 5-minute backoff (bounded, self-healing), the
in-flight lock still dedupes concurrent calls, and success clears the failure
marker and memoizes the project as before. Accounts that CAN be onboarded now
heal automatically on a later request or token refresh — no user action.
Tests: the existing "does not retry" case is now framed as the backoff window;
a new case proves the account heals (retries onboarding and recovers the
project) once the backoff expires.
* chore(changelog): fragment for #10424 antigravity project autocreate
* feat(antigravity): BYOP fast-fail + manual GCP project-id override
Port decolua/9router#2934 + VansRouter 802a859:
- tryOnboardUser now returns a three-way status; a 200 onboardUser response
WITHOUT cloudaicompanionProject means Google deprecated automatic project
creation for standard-tier (personal) accounts (BYOP). Such accounts are
cached permanently (no pointless ~18s re-onboard) and the executor fails
fast with 403 GCP_PROJECT_REQUIRED + actionable 'enter your project id'
message instead of the generic 422 or a delayed 429.
- Transient onboard failures keep the existing 5-min backoff heal.
- Manual project-id override: the EditConnectionModal now stamps
providerSpecificData.isProjectIdManual when the operator enters a project
id, and tokenRefresh skips auto-discovery for flagged accounts so the
manual value is never overwritten.
* chore(changelog): cover BYOP fast-fail + manual override in #10424 fragment
* test(antigravity): expect fast 403 GCP_PROJECT_REQUIRED when loadCodeAssist finds no project (#10424)
Google now marks accounts without an onboarded project as BYOP (automatic
project creation deprecated for standard-tier accounts, #2934). The PR's
BYOP fast-fail path returns 403 gcp_project_required instead of the old
generic 422 missing_project_id; align the #2334 executor test with that
contract so CI unit-test shard 2/4 passes.
* fix(antigravity): persist isProjectIdManual, fix BYOP citation, dodge refresh-retry
Review follow-up on #10424:
1. EditConnectionModal: isProjectIdManual was set on
updates.providerSpecificData right after the project-id field, then the
OAuth path (Antigravity is always OAuth) rebuilt providerSpecificData from
connection.providerSpecificData before the request went out, discarding the
flag — tokenRefresh.ts was guarding a field never actually persisted. The
flag now lands in the single surviving antigravity merge, with a jsdom
regression test (modeled on edit-connection-modal-openai-store-toggle).
2. The '#2934' citation for the Google BYOP claim pointed at an unrelated
closed issue. Swapped for the real tracking issue #8491 (empty Google
projectId -> 422 class) across bootstrap/executor/test comments.
3. BYOP fast-fail now returns 422 instead of 403: chatCore's generic
401/403 -> refresh-and-retry path was hitting Google's OAuth token
endpoint on every request from an affected account (pointless — refreshing
cannot create a GCP project), and 422 matches the sibling
missing_project_id error the client already maps to an action-needed
prompt.
Also: eslint-disable-next-line for the pre-existing
react-hooks/set-state-in-effect baseline noise in the modal (repo
convention, same pattern as 11 other dashboard files).
* chore(ci): drop unused eslint-disable in EditConnectionModal form hydration
The react-hooks/set-state-in-effect disable added in the previous commit is
unused under the repo's pinned eslint-plugin-react-hooks (7.0.1) — the rule
does not fire on this line at that version, so the unused directive tripped
the whole-repo 'No new ESLint warnings' gate (max-warnings 0). Verified with
the lockfile-pinned plugin: lint:json is clean (0 errors, 0 warnings).
* fix(build): bound and retry the opencode-plugin npm install in prepublish
The plugin's node_modules is gitignored, so every fresh CI checkout runs a
full npm install inside @omniroute/opencode-plugin during build:cli. npm's
unbounded fetch retries turn a stalled registry CDN connection (the recurring
onnxruntime-class ETIMEDOUT flake) into a 20-30 minute hang — the DAST
'Build CLI bundle' step has been cancelled at the 30m cap repeatedly.
- Bound npm fetch: --fetch-timeout 60s, 2 retries with capped backoff — a
stalled connection now fails fast instead of hanging the job.
- Retry the install up to 3 times with a 10s pause between attempts, so
transient CDN failures recover in-build.
Net effect: the step either completes (network OK) or fails quickly with a
clear error (network down) — it can no longer eat the whole job budget.
* ci(quality): use the npm-ci-retry action on every install step
Fast Quality Gates failed on the recurring onnxruntime-node postinstall
ETIMEDOUT (Microsoft CDN 150.171.x.x) - the same transient flake that has
hit Vitest and dast-smoke today. Only the Build job used the retry action;
the other five jobs (Docs, Fast Quality Gates, Vitest, Unit Tests,
changelog) still ran a bare install and die on any CDN hiccup. Use the
existing retry action (3 attempts, exponential backoff) on every install
step for consistency.
* Merge branch 'release/v3.8.50' into fix/antigravity-project-autocreate
* test(fix): refresh expired alibaba quota sample validity and onnxruntime pin for v3.8.50 base
- alibaba-free-tier-quota-fetcher.test.ts: sample quotaValidityPeriod
(2026-08-16 16:00 UTC) is in the past, making every quota entry classify
as expired/not_capable; bump to 2028-01-01 UTC so the text/merge
classification tests exercise the intended path again.
- optional-transformers-dependency.test.ts: onnxruntime-node pin assertion
updated from ~1.24.3 to ~1.27.0 to match package.json (bumped by #10403);
the regular-not-optional intent is unchanged.
* test(fix): widen modelsDevSync lastSync wait from 200ms default to 2000ms
The truthy-spellings loop asserted each enabled case completes its first
fetch within waitFor's 200ms default timeout, which trips under CI runner
load (observed on PR 10424 shard 2/4). Match the file's other lastSync
waits (2000ms) so the sync-completion assertion is load-tolerant.
---------
Co-authored-by: Rouzbeh <rqzbeh@users.noreply.github.com>
* fix(antigravity): per-model quota + 30min credits_exhausted reprobe
- accountFallback.ts: hasPerModelQuota() now treats antigravity/agy as
per-model quota. A single-model 429 no longer cascades to all models
in the provider.
- connectionRecovery.ts: credits_exhausted removed from terminal set;
isCreditsExhaustedReprobeCandidate() with 30min default. Loads
active+inactive rows so inactive credits_exhausted accounts can recover.
- tests/unit/quota-connection-recovery.test.ts: 6 cases covering pure
helpers + tick wiring.
* fix(antigravity): persist projectId and prefer healthy accounts
Save Cloud Code projectId after runtime discovery, skip accounts missing
projectId when alternatives exist, and mark missing_project_id on 422.
* fix(antigravity): skip quota-exhausted models during account selection
Avoid repeatedly dispatching to Antigravity models that already report
exhausted quota, reducing wasted upstream calls and combo fallback latency.
---------
Co-authored-by: hermes <hermes@nous.local>