From 5e2c75e5341c2b348f2c25dd7c32659e2c69231f Mon Sep 17 00:00:00 2001 From: timon0305 Date: Wed, 15 Jul 2026 17:13:25 +0200 Subject: [PATCH 1/2] test: SDK-shape conformance guard for SearchableIndex (#220) SearchableIndex is a hand-written interface and indexes.ts force-casts the SDK index to it with as unknown as, which erases type checking; existing tests only mock our own interface. So an SDK bump that renames or removes a method the code calls would slip past the compiler and fail at runtime. Assert the members the code relies on (describeIndexStats, namespace, searchRecords, query) exist on a real SDK index handle, constructed offline with no network. A compile-time assertion was tried but the SDK types the index too loosely to catch drift without passing vacuously, so this is a runtime check; verified a renamed member fails it. --- .../searchable-index-conformance.test.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/core/pinecone/searchable-index-conformance.test.ts diff --git a/src/core/pinecone/searchable-index-conformance.test.ts b/src/core/pinecone/searchable-index-conformance.test.ts new file mode 100644 index 0000000..00a695b --- /dev/null +++ b/src/core/pinecone/searchable-index-conformance.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from 'vitest'; +import { Pinecone } from '@pinecone-database/pinecone'; + +/** + * SDK-shape conformance guard for SearchableIndex (#220). + * + * `indexes.ts` force-casts `pc.index(...)` to `SearchableIndex` with `as unknown as`, + * which erases type checking, and the other tests only mock our own interface. So + * nothing verifies the real SDK index still provides the members the code calls. If a + * Pinecone SDK bump renames or removes one, it slips past the compiler and fails at + * runtime in production. This asserts those members exist on a real SDK index, so a + * drift fails here loudly instead. + * + * A compile-time assertion was tried but the SDK types the index too loosely to catch + * drift, so this is a runtime existence check. `pc.index()` returns a handle + * synchronously with no network call, so it needs no live Pinecone. + */ +describe('SearchableIndex SDK conformance (#220)', () => { + // Members the code calls on the index through SearchableIndex (indexes.ts / search.ts). + const REQUIRED_MEMBERS = ['describeIndexStats', 'namespace', 'searchRecords', 'query'] as const; + + const index = new Pinecone({ apiKey: 'pc-conformance-test' }).index( + 'conformance-test' + ) as unknown as Record; + + it.each(REQUIRED_MEMBERS)('the SDK index exposes %s()', (method) => { + expect(typeof index[method]).toBe('function'); + }); +}); From c7ba1744f86df31b7e51efd6e8d7ab233e55309d Mon Sep 17 00:00:00 2001 From: timon0305 Date: Wed, 15 Jul 2026 17:46:35 +0200 Subject: [PATCH 2/2] test: assert query/searchRecords on the namespace handle, not top-level (#220 review) The code calls query and searchRecords through index.namespace(ns) (indexes.ts namespace(ns).query, search.ts namespace(ns).searchRecords), so probe them on the namespace handle rather than the top-level index. describeIndexStats/namespace and the searchRecords index-fallback stay on the top-level index. Confirmed a bogus namespace-handle member fails the test. --- .../searchable-index-conformance.test.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/core/pinecone/searchable-index-conformance.test.ts b/src/core/pinecone/searchable-index-conformance.test.ts index 00a695b..a711300 100644 --- a/src/core/pinecone/searchable-index-conformance.test.ts +++ b/src/core/pinecone/searchable-index-conformance.test.ts @@ -16,14 +16,28 @@ import { Pinecone } from '@pinecone-database/pinecone'; * synchronously with no network call, so it needs no live Pinecone. */ describe('SearchableIndex SDK conformance (#220)', () => { - // Members the code calls on the index through SearchableIndex (indexes.ts / search.ts). - const REQUIRED_MEMBERS = ['describeIndexStats', 'namespace', 'searchRecords', 'query'] as const; - const index = new Pinecone({ apiKey: 'pc-conformance-test' }).index( 'conformance-test' ) as unknown as Record; - it.each(REQUIRED_MEMBERS)('the SDK index exposes %s()', (method) => { - expect(typeof index[method]).toBe('function'); - }); + // Called on the top-level index: indexes.ts uses describeIndexStats() and + // namespace(), and search.ts uses searchRecords() on the index fallback branch. + it.each(['describeIndexStats', 'namespace', 'searchRecords'] as const)( + 'the SDK index exposes %s()', + (method) => { + expect(typeof index[method]).toBe('function'); + } + ); + + // Called on the namespace handle from index.namespace(ns): indexes.ts does + // namespace(ns).query(...) and search.ts does namespace(ns).searchRecords(...). + const namespaceHandle = (index.namespace as (name: string) => Record)( + 'conformance-test' + ); + it.each(['query', 'searchRecords'] as const)( + 'the SDK namespace handle exposes %s()', + (method) => { + expect(typeof namespaceHandle[method]).toBe('function'); + } + ); });