Skip to content

test(plugins): reproduce Postgres plugin-storage query/count/index/order bugs (red baseline for #1) - #4

Open
vedanshujain wants to merge 1 commit into
mainfrom
test/plugin-storage-postgres-regression
Open

test(plugins): reproduce Postgres plugin-storage query/count/index/order bugs (red baseline for #1)#4
vedanshujain wants to merge 1 commit into
mainfrom
test/plugin-storage-postgres-regression

Conversation

@vedanshujain

Copy link
Copy Markdown
Owner

Why this PR is first in the stack

_plugin_storage.data is a plain text column, and plugin storage had only ever
been exercised on SQLite. On Postgres the query / count / index / order paths build
the JSON accessor as an uncast data ->> 'field', which is broken four distinct
ways. This PR adds a dialect-parametric regression suite (wired through
describeEachDialect) that pins each failure mode, so reviewers can see the bug
reproduced before the fix.

This PR is the red baseline. The Postgres dialect fails here on purpose; the
stacked fix (#1) turns it green. SQLite passes throughout, because json_extract
already returns a typed value — which is exactly why the bug went unnoticed.

Failure modes covered

  • (a) numeric RangeFilter across a multi-digit boundary — store 9 / 10 / 100,
    query { stock: { gte: 10 } }. '9' >= '10' is TRUE lexically, so 9 leaks into
    the result — an over-count / oversell. Asserts exactly {10, 100}.
  • (b) count({ stock: { gte: 10 } }) — asserts 2, not the lexical 3.
  • (c) createStorageIndexes UNIQUE expression index over data ->> 'sku' — on
    Postgres this raises operator does not exist: text ->> unknown. Asserts
    errors: [], index created, duplicate insert rejected.
  • (d) numeric orderBy — asserts [9, 10, 100], not the lexical [10, 100, 9].

Evidence (EMDASH_TEST_PG set → local urumi-pg-test on 127.0.0.1:55432)

On this branch (no fix) — RED on Postgres, GREEN on SQLite:

tests/.../storage-postgres-regression.test.ts (8 tests | 4 failed)
  × [postgres] numeric RangeFilter { gte: 10 } ...   operator does not exist: text ->> unknown
  × [postgres] count({ stock: { gte: 10 } }) ...
  × [postgres] UNIQUE expression index ...           expected [ { error: "operator does not exist: text ->> unknown", ... } ] to deeply equal []
  × [postgres] orderBy { stock: 'asc' } ...
  Tests  4 failed | 4 passed (8)   # the 4 passing are the [sqlite] variants

With #1 stacked on top — GREEN on both dialects:

  Tests  8 passed (8)   # [sqlite] ×4 + [postgres] ×4

CI note

The Tests job runs a real Postgres service with EMDASH_TEST_PG set and the
default vitest config picks up tests/integration/plugins/**, so the Postgres
job is red on this PR by design.
It goes green once #1 lands on top of it. The
Integration Tests job (no Postgres) stays green. This is a stacked, test-first PR
— it is meant to merge as part of the stack, not standalone.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TX9YciGFRZX9aF2UcQ6rUW

…der bugs

`_plugin_storage.data` is a plain `text` column and plugin storage had only
ever been exercised on SQLite. On Postgres the query/count/index/order paths
build the JSON accessor as an uncast `data ->> 'field'`, which is broken four
ways. This adds a dialect-parametric regression suite (via describeEachDialect)
pinning each failure mode:

  (a) numeric RangeFilter across a multi-digit boundary (9/10/100, gte:10) —
      `'9' >= '10'` is TRUE lexically, so 9 leaks in (over-count / oversell)
  (b) count() with the same numeric guard returns 3 instead of 2
  (c) createStorageIndexes over `data ->> 'sku'` raises
      "operator does not exist: text ->> unknown"
  (d) numeric orderBy returns [10, 100, 9] instead of [9, 10, 100]

The suite passes on SQLite (json_extract is already typed) and FAILS on the
Postgres dialect on this branch — it is the red baseline. The stacked fix
(#1, jsonb + numeric cast) turns the Postgres dialect green.

Postgres runs only when EMDASH_TEST_PG is set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX9YciGFRZX9aF2UcQ6rUW
@github-actions github-actions Bot added needs-approval review/needs-review No maintainer or bot review yet labels Jul 21, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

This PR has been inactive for 14 days. It will be closed automatically in 7 days if there is no further activity.

If you're still working on this, please push an update or leave a comment.

@github-actions github-actions Bot added stale and removed stale labels Aug 4, 2026
@github-actions github-actions Bot added stale and removed stale labels Aug 19, 2026
@github-actions github-actions Bot added stale and removed stale labels Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-approval review/needs-review No maintainer or bot review yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant