From a0d8ad70825fcd780c0887b96f63e82039560b64 Mon Sep 17 00:00:00 2001 From: Koosha Paridehpour <42529354+KooshaPari@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:56:35 -0700 Subject: [PATCH] fix(antigravity): derive stable session ID from credentials for prompt-cache reuse (#13305) (#13424) `getAntigravitySessionId` derives a stable session id from the account key (FNV-1a over the existing `getAntigravityAccountKey`) when credentials are present, so repeated requests from one account can reuse Antigravity prompt caching (#13305). An explicit fallback id still wins, and calls without credentials still get a random id. This deliberately reverses the per-request random id from #10443; the maintainer approved the trade-off. Maintainer addition: `credentials` is now used, so the frozen `no-unused-vars` suppression for `open-sse/services/antigravityIdentity.ts` became stale. ESLint fails on stale suppressions, so it was pruned. Antigravity suites: 34 cases green. Validated in one consolidated batch of this series (37 PRs boarded together on `release/v3.8.51`): `typecheck:core`, `check:open-sse-typecheck` and `check:dashboard-typecheck` clean; ESLint clean on every changed file; file-size, complexity, cognitive-complexity, changelog-integrity, docs-counts, docs-sync and migration-numbering gates green (only the pre-existing `open-sse/utils/stream.ts` file-size red remains, inherited from the base); 3,743 focused `node:test` cases plus 34 vitest cases green. Thanks @KooshaPari! --- config/quality/eslint-suppressions.json | 5 ---- open-sse/services/antigravityIdentity.ts | 1 + ...tigravity-dynamic-session-id-10443.test.ts | 28 +++++++++++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/config/quality/eslint-suppressions.json b/config/quality/eslint-suppressions.json index da35ba2eeb..bb23407f93 100644 --- a/config/quality/eslint-suppressions.json +++ b/config/quality/eslint-suppressions.json @@ -396,11 +396,6 @@ "count": 1 } }, - "open-sse/services/antigravityIdentity.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "open-sse/services/antigravityProjectBootstrap.ts": { "@typescript-eslint/no-unused-vars": { "count": 1 diff --git a/open-sse/services/antigravityIdentity.ts b/open-sse/services/antigravityIdentity.ts index 3703cd9c35..cbdd7815b2 100644 --- a/open-sse/services/antigravityIdentity.ts +++ b/open-sse/services/antigravityIdentity.ts @@ -76,6 +76,7 @@ export function getAntigravitySessionId( ): string { return ( toNonEmptyString(fallback) || + deriveAntigravitySessionId(getAntigravityAccountKey(credentials)) || generateAntigravitySessionId() ); } diff --git a/tests/unit/antigravity-dynamic-session-id-10443.test.ts b/tests/unit/antigravity-dynamic-session-id-10443.test.ts index af5d198ff9..885015d39c 100644 --- a/tests/unit/antigravity-dynamic-session-id-10443.test.ts +++ b/tests/unit/antigravity-dynamic-session-id-10443.test.ts @@ -2,17 +2,39 @@ import assert from "node:assert/strict"; import { test } from "node:test"; import { getAntigravitySessionId } from "../../open-sse/services/antigravityIdentity.ts"; -test("getAntigravitySessionId yields dynamic random session IDs per request to avoid session pinning", () => { +test("getAntigravitySessionId derives a stable session ID from credentials for prompt-cache reuse", () => { const credentials = { email: "user@example.com", connectionId: "conn_123" }; const id1 = getAntigravitySessionId(credentials); const id2 = getAntigravitySessionId(credentials); - assert.notEqual(id1, id2, "getAntigravitySessionId should not pin to a static account email hash"); + assert.equal(id1, id2, "same credentials must produce the same session ID for cache reuse"); assert.equal(typeof id1, "string"); - assert.equal(typeof id2, "string"); + assert.ok(id1.length > 0, "session ID must be non-empty"); const explicitFallback = "custom-session-456"; const idWithFallback = getAntigravitySessionId(credentials, explicitFallback); assert.equal(idWithFallback, explicitFallback, "explicit fallback session ID should take precedence"); }); + +test("getAntigravitySessionId falls back to random ID when no credentials are available", () => { + const id1 = getAntigravitySessionId(); + const id2 = getAntigravitySessionId(); + + assert.equal(typeof id1, "string"); + assert.ok(id1.length > 0, "random session ID must be non-empty"); + + // Without credentials, each call should produce a different random ID + // (this is acceptable since there's no account to pin cache to) + assert.notEqual(id1, id2, "without credentials, IDs should be random per call"); +}); + +test("getAntigravitySessionId produces different IDs for different accounts", () => { + const credsA = { email: "alice@example.com" }; + const credsB = { email: "bob@example.com" }; + + const idA = getAntigravitySessionId(credsA); + const idB = getAntigravitySessionId(credsB); + + assert.notEqual(idA, idB, "different accounts must produce different session IDs"); +});