Skip to content

feat(test): add tabular-storage contract invariant suite across all backends#510

Merged
sroussey merged 6 commits into
mainfrom
claude/add-storage-contract-invariants-dRSp6
May 15, 2026
Merged

feat(test): add tabular-storage contract invariant suite across all backends#510
sroussey merged 6 commits into
mainfrom
claude/add-storage-contract-invariants-dRSp6

Conversation

@sroussey
Copy link
Copy Markdown
Collaborator

Summary

  • Contract suite (runTabularStorageContract): four invariant blocks — subscribeToChanges, vectorColumnFormat, withTransactionRollback, countMatchesQuery — each gated by a capability flag (supportsSubscriptions, supportsVectorColumns, supportsTransactions, supportsQuery)
  • All backends wired: InMemory, Sqlite, Postgres (PGlite), FsFolder, SharedInMemory, IndexedDb, Cached, Telemetry, Supabase (mock)
  • TypedArray round-trip bug fixed in SqliteTabularStorage and PostgresTabularStorage: both were serializing Float32Array as integer-keyed JSON objects ({"0":0.1,...}) instead of arrays, then deserializing back as plain objects; now properly serializes to [0.1,...] arrays and reconstructs typed arrays on read using the schema's format: "TypedArray:*" annotation
  • supportsQuery: false capability gate added for FsFolder (its query() throws StorageUnsupportedError)
  • ScopedTabularStorage excluded: its kb_id scope column in the PK can't conform to the CompoundSchema contract type without a purpose-built scoped schema
  • HuggingFace excluded: read-only (put/delete throw)

Test plan

  • npx vitest run packages/test/src/test/storage-tabular/InMemoryTabularStorage.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/SqliteTabularStorage.integration.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/PostgresTabularStorage.integration.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/FsFolderTabularStorage.integration.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/SharedInMemoryTabularStorage.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/IndexedDbTabularStorage.integration.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/CachedTabularStorage.integration.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/TelemetryTabularStorage.test.ts — all pass
  • npx vitest run packages/test/src/test/storage-tabular/SupabaseTabularStorage.integration.test.ts — all pass

https://claude.ai/code/session_01KJmJwgy4qsAK2iXXrC2yM4


Generated by Claude Code

sroussey and others added 5 commits May 15, 2026 12:12
…riant

Adds a new contract suite under packages/test/src/contract/tabular-storage/
with a single assertion: subscribeToChanges fires exactly once per write
in commit order (three sequential puts → three events, v1→v2→v3).

- types.ts: TabularStorageContractOpts / TabularStorageContractAssertion
- runTabularStorageContract.ts: describe.skipIf wrapper + block dispatch
- assertions/subscribeToChanges.ts: the invariant with polling timing logic
- InMemoryTabularStorage.test.ts: wired up with supportsSubscriptions: true
Extends the contract suite with a round-trip assertion: a Float32Array
written via put() must come back as a Float32Array (not a plain Array or
Buffer) via get(). Wires InMemoryTabularStorage with supportsVectorColumns.

- types.ts: adds VectorItemSchema, VectorItemPrimaryKeyNames,
  createVectorStorage factory, capabilities.supportsVectorColumns,
  and "vectorColumnFormat" to TabularStorageContractAssertion
- assertions/vectorColumnFormat.ts: new assertion block
- runTabularStorageContract.ts: dispatches vectorColumnFormatBlock
- InMemoryTabularStorage.test.ts: wired with supportsVectorColumns: true
…contract

Asserts that when a withTransaction callback throws, none of its writes
are visible afterward and any pre-transaction writes are untouched.

- types.ts: adds capabilities.supportsTransactions and
  "withTransactionRollback" to TabularStorageContractAssertion
- assertions/withTransactionRollback.ts: new assertion block
- runTabularStorageContract.ts: dispatches withTransactionRollbackBlock
- InMemoryTabularStorage.test.ts: wired with supportsTransactions: false
  (InMemory transactions are a no-op wrapper; skip rather than expect-fail)
Asserts that for any predicate, count() and query().length agree.
Catches the common bug where count takes an optimizer fast path that
disagrees with the row-returning query path (null handling, partial
index usage, stale planner stats).

- types.ts: adds "countMatchesQuery" to TabularStorageContractAssertion
- assertions/countMatchesQuery.ts: new assertion block (no capability gate)
- runTabularStorageContract.ts: dispatches countMatchesQueryBlock
…uite

- Add runTabularStorageContract to: InMemory, Sqlite, Postgres, FsFolder,
  SharedInMemory, IndexedDb, Cached, Telemetry, and Supabase backends
- Fix SqliteTabularStorage and PostgresTabularStorage to properly
  serialize TypedArrays as JSON arrays and reconstruct them on read;
  previously Float32Array round-tripped as plain integer-keyed objects
- Add supportsQuery capability gate to skip countMatchesQuery on FsFolder
  (which throws StorageUnsupportedError on query())
- Add TYPED_ARRAY_CTORS lookup tables to Sqlite and Postgres providers
  for format-aware TypedArray reconstruction in sqlToJsValue

https://claude.ai/code/session_01KJmJwgy4qsAK2iXXrC2yM4
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 15, 2026

Open in StackBlitz

@workglow/cli

npm i https://pkg.pr.new/@workglow/cli@510

@workglow/ai

npm i https://pkg.pr.new/@workglow/ai@510

@workglow/browser-control

npm i https://pkg.pr.new/@workglow/browser-control@510

@workglow/indexeddb

npm i https://pkg.pr.new/@workglow/indexeddb@510

@workglow/javascript

npm i https://pkg.pr.new/@workglow/javascript@510

@workglow/job-queue

npm i https://pkg.pr.new/@workglow/job-queue@510

@workglow/knowledge-base

npm i https://pkg.pr.new/@workglow/knowledge-base@510

@workglow/mcp

npm i https://pkg.pr.new/@workglow/mcp@510

@workglow/storage

npm i https://pkg.pr.new/@workglow/storage@510

@workglow/task-graph

npm i https://pkg.pr.new/@workglow/task-graph@510

@workglow/tasks

npm i https://pkg.pr.new/@workglow/tasks@510

@workglow/util

npm i https://pkg.pr.new/@workglow/util@510

workglow

npm i https://pkg.pr.new/workglow@510

@workglow/anthropic

npm i https://pkg.pr.new/@workglow/anthropic@510

@workglow/bun-webview

npm i https://pkg.pr.new/@workglow/bun-webview@510

@workglow/chrome-ai

npm i https://pkg.pr.new/@workglow/chrome-ai@510

@workglow/electron

npm i https://pkg.pr.new/@workglow/electron@510

@workglow/google-gemini

npm i https://pkg.pr.new/@workglow/google-gemini@510

@workglow/huggingface-inference

npm i https://pkg.pr.new/@workglow/huggingface-inference@510

@workglow/huggingface-transformers

npm i https://pkg.pr.new/@workglow/huggingface-transformers@510

@workglow/node-llama-cpp

npm i https://pkg.pr.new/@workglow/node-llama-cpp@510

@workglow/ollama

npm i https://pkg.pr.new/@workglow/ollama@510

@workglow/openai

npm i https://pkg.pr.new/@workglow/openai@510

@workglow/playwright

npm i https://pkg.pr.new/@workglow/playwright@510

@workglow/postgres

npm i https://pkg.pr.new/@workglow/postgres@510

@workglow/sqlite

npm i https://pkg.pr.new/@workglow/sqlite@510

@workglow/supabase

npm i https://pkg.pr.new/@workglow/supabase@510

@workglow/tf-mediapipe

npm i https://pkg.pr.new/@workglow/tf-mediapipe@510

commit: ae4e126

Polling-based subscriptions (FsFolder, IndexedDb) detect all writes
that happen between two polls in a single snapshot diff, so the order
in which they emit the resulting events is unspecified. Check that all
three expected values are present (sorted) for polling implementations,
and keep the strict write-order check only for event-driven backends.

https://claude.ai/code/session_01KJmJwgy4qsAK2iXXrC2yM4
@github-actions
Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 62.38% 22164 / 35529
🔵 Statements 62.23% 22940 / 36858
🔵 Functions 64.4% 4218 / 6549
🔵 Branches 50.91% 10605 / 20830
File CoverageNo changed files found.
Generated in workflow #2284 for commit ae4e126 by the Vitest Coverage Report Action

@sroussey sroussey self-assigned this May 15, 2026
@sroussey sroussey requested a review from Copilot May 15, 2026 21:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a reusable runTabularStorageContract invariant suite (subscribe, vector round-trip, transaction rollback, count==query) and wires it into all tabular storage backends. Also fixes a TypedArray serialization bug in SqliteTabularStorage and PostgresTabularStorage where Float32Array was being JSON-stringified as an integer-keyed object instead of an array, and was not reconstructed as a typed array on read.

Changes:

  • New contract suite (packages/test/src/contract/tabular-storage/) with capability-gated assertion blocks and shared VectorItemSchema.
  • Backend test files (InMemory, Sqlite, Postgres, FsFolder, SharedInMemory, IndexedDb, Cached, Telemetry, Supabase) all invoke runTabularStorageContract with their capabilities.
  • SqliteTabularStorage / PostgresTabularStorage now serialize TypedArrays as JSON arrays and reconstruct them on read using the schema format: "TypedArray:*" annotation.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
providers/sqlite/src/storage/SqliteTabularStorage.ts TypedArray JSON serialize/parse fix; reorders imports; minor formatting
providers/postgres/src/storage/PostgresTabularStorage.ts TypedArray JSON serialize/parse fix using schema format; import reorder; minor formatting
packages/test/src/contract/tabular-storage/runTabularStorageContract.ts New contract entry point composing four assertion blocks
packages/test/src/contract/tabular-storage/types.ts Contract option/capability types and shared VectorItem schema
packages/test/src/contract/tabular-storage/assertions/subscribeToChanges.ts Asserts subscription fires once per write, in commit order (event-driven)
packages/test/src/contract/tabular-storage/assertions/vectorColumnFormat.ts Asserts Float32Array round-trip preserves type/values
packages/test/src/contract/tabular-storage/assertions/withTransactionRollback.ts Asserts thrown callback rolls back writes
packages/test/src/contract/tabular-storage/assertions/countMatchesQuery.ts Asserts count(p) == query(p).length across predicates
packages/test/src/test/storage-tabular/{InMemory,Sqlite,Postgres,FsFolder,SharedInMemory,IndexedDb,Cached,Telemetry,Supabase}TabularStorage.test.ts Wire the new contract into each backend with appropriate capability flags

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@sroussey sroussey merged commit 097b4af into main May 15, 2026
19 of 20 checks passed
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.

3 participants