Skip to content

feat: supabase-js SDK evals (auth flow, relational report, key migration) - #129

Merged
mandarini merged 10 commits into
mainfrom
feat/supabase-js-sdk-evals
Aug 6, 2026
Merged

feat: supabase-js SDK evals (auth flow, relational report, key migration)#129
mandarini merged 10 commits into
mainfrom
feat/supabase-js-sdk-evals

Conversation

@mandarini

@mandarini mandarini commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Adds four evals for supabase-js: dedicated coverage for the SDK's two most-used surfaces (auth and the PostgREST query builder), a regression canary for the API key migration, and a second Data API scenario probing an SDK-adoption gap the first one turned up.

  • build-auth-001-email-password-flow (benchmark): signup/sign-in/profile flow against stubbed app code. Gates on agents reaching for @supabase/supabase-js unprompted (the build-functions-005 pattern); the profile display name only survives if sent as signup user metadata.
  • build-dataapi-001-relational-report (benchmark): backend reporting script over a seeded relational schema (embedded relations, aggregation). Gates on using the SDK query builder via the Data API rather than psql or a raw Postgres driver.
  • build-dataapi-002-restock-alert-report (benchmark): same shape as build-dataapi-001 — bare prompt, empty package.json, no SDK named — but a different schema/domain (inventory restock alerts vs. a sales report). Added after refreshed results on build-dataapi-001 showed every claude-code variant (4/4) reaching for @supabase/supabase-js unprompted while every codex variant (0/4) hand-rolled raw HTTP instead, despite otherwise-correct, RLS-safe implementations. One scenario isn't enough to tell a real model tendency from an artifact of that specific prompt, so this companion checks whether the split generalizes.
  • resolve-sdk-001-legacy-key-migration (regression): seeds a working app on the legacy demo JWTs; agents must migrate it to sb_publishable_/sb_secret_ keys without breaking behavior or leaking the secret key into client code.

All four were sanity-checked locally against a real stack on the pinned CLI (2.109.1): migrations apply, reference solutions pass every scorer check, and the checks discriminate (missing signup metadata, publishable-key impersonation, leftover legacy keys, and SDK vs. raw-HTTP implementations all fail as intended). A scoped .gitignore exception ships the key-migration eval's seeded .env, which holds only the well-known local demo keys.

Fix along the way: build-dataapi-001-relational-report and resolve-sdk-001-legacy-key-migration initially failed 100% of agents identically — a harness bug, not an agent gap. Both had omitted gotrue from their services: frontmatter, so the local stack's auth service never started and supabase status couldn't emit PUBLISHABLE_KEY/SECRET_KEY. Fixed by adding gotrue to services: (matching resolve-dataapi-002-secure-default-grants's pattern); results refreshed and now produce real signal.

build-dataapi-002-restock-alert-report still needs a live run (no API keys in this pass) to confirm whether the adoption split holds.

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
evals Ready Ready Preview Aug 5, 2026 2:33pm

Request Review

@mandarini mandarini self-assigned this Jul 27, 2026
@mandarini
mandarini force-pushed the feat/supabase-js-sdk-evals branch from f1b1b25 to 216ca87 Compare July 27, 2026 15:44
@mandarini
mandarini marked this pull request as ready for review July 27, 2026 15:46
@mandarini
mandarini requested a review from a team July 27, 2026 15:46
@mandarini mandarini added run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes and removed run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes labels Jul 27, 2026
@mandarini mandarini added the run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes label Jul 28, 2026
@mandarini mandarini removed the run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes label Jul 28, 2026
@mandarini mandarini added run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes and removed run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes labels Jul 28, 2026

@barryroodt barryroodt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These four are in good shape, and pulling the expected numbers out of the seeded migrations instead of hardcoding them is the right call. The auth driver holding one session across signup and both signin attempts is nice too.

One thing to sort before merge: implementation uses @supabase/supabase-js is the only failed check in all 13 benchmark failures, and the grep behind it doesn't prove SDK use. The pattern requires a quote before the package name but nothing after it (EVAL.ts:198), so @supabase/supabase-js-not-real matches, and an unused import passes just as well as a real one. So those three evals currently score whether a string appears somewhere under app/, which makes the codex/claude split hard to read.

My call is to fix the detection rather than name the SDK in the prompt, since unprompted reach is the thing you're measuring and that only means something if the gate is real. Resolving the import from the scored entry, or instrumenting module load, would both do it.

Rest is inline. The resolve-sdk-001 one is worth a look, a hardcoded stub currently passes it 4/4.

Comment thread evals/build-auth-001-email-password-flow/EVAL.ts Outdated
Comment thread evals/resolve-sdk-001-legacy-key-migration/EVAL.ts
Comment thread evals/build-auth-001-email-password-flow/EVAL.ts
Comment thread evals/build-dataapi-001-relational-report/EVAL.ts Outdated
Comment thread evals/build-dataapi-002-restock-alert-report/PROMPT.md
Comment thread .gitignore Outdated
Comment thread evals/build-dataapi-001-relational-report/local/supabase/.temp/cli-latest Outdated
Comment thread evals/build-dataapi-001-relational-report/EVAL.ts
@mandarini
mandarini force-pushed the feat/supabase-js-sdk-evals branch from a3024b3 to 1a06c3d Compare August 5, 2026 10:26
@mandarini
mandarini requested a review from barryroodt August 5, 2026 10:55
@mandarini mandarini added the run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes label Aug 5, 2026
@mandarini

Copy link
Copy Markdown
Contributor Author

@barryroodt thanks for the review! addressed your comments. Can you please take a look?

@mandarini mandarini removed the run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes label Aug 5, 2026

@barryroodt barryroodt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice, this is a lot tighter. Two things before merge.

The new key-dependency checks on resolve-sdk-001 only ask whether the corrupted run still prints parseable JSON, so a valid migration that handles the API error and prints [] fails with a misleading "hardcoded" result. Comparing against the expected titles and draft count you already compute fixes it.

build-dataapi-002-restock-alert-report has no result rows at this head, down from 8 (2 passing) at a3024b3, so I think the rebase dropped them. The rows that remain predate 488a985, so one refresh after that fix covers both.

Everything else from the first review is addressed. Nits are inline.

@barryroodt

Copy link
Copy Markdown
Contributor

Your refresh landed while I was writing that, so scratch my second point. build-dataapi-002 has its 10 rows back, and resolve-sdk-001 now shows 6 checks. dataapi-002 came out 4/4 claude-code, 0/4 codex, 0/2 opencode, so the split does generalize.

It confirms the first point though, both resolve-sdk rows now fail on the two new checks. More on that thread.

@mandarini mandarini added run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes and removed run-evals-changed Add to a PR to refresh only the benchmark evals that have had changes labels Aug 5, 2026
@mandarini

Copy link
Copy Markdown
Contributor Author

@barryroodt pushed one more commit!

@mandarini
mandarini requested a review from barryroodt August 5, 2026 14:58

@barryroodt barryroodt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice, that's all of it. Corrupting the URL instead of the key is a better call than what I suggested.

resolve-sdk-001 is 2/2 on the refreshed rows, both new checks reporting broke as expected against an unreachable project URL.

@mandarini
mandarini merged commit 9bd7320 into main Aug 6, 2026
7 checks passed
mattrossman pushed a commit that referenced this pull request Aug 6, 2026
<!-- ccr-slack-attribution -->
_Requested by **Matt Rossman** · [Slack
thread](https://supabase.slack.com/archives/C051L8U2EJF/p1786039678828039?thread_ts=1786039678.828039&cid=C051L8U2EJF)_

## Before

The public evals site's Benchmark table shows a **Claude Code / Opus 4.8
(high)** row that only has Build data. Deploy, Investigate, and Resolve
render as em-dashes (no data), yet the row still reports a **100%
TOTAL**. It's backed by just two Build-stage records, so the total is
misleading to anyone reading the public table.

## After

That row is gone and the Benchmark table matches the exported results as
of `4e50650`.

## How

Restores `apps/web/src/data/eval-results.json` byte-for-byte to its
state at commit
[`4e50650`](4e50650)
(`chore: refresh eval results (#174)`, 2026-08-06 07:18 UTC). Scope is
deliberately limited to that one file — regression-suite results live
separately in `apps/web/src/data/regression-eval-results.json` and are
**not** touched by this PR. Diffstat: `1 file changed, 620
insertions(+), 3224 deletions(-)`.

`#129` (`9bd7320`, 2026-08-06 12:51 UTC) is the only commit to touch
`eval-results.json` since `4e50650`, which matches Matt's diagnosis.

## Structural diff

Record count goes 220 → 190. All records in both versions are `suite:
"benchmark"`. Of the 182 records present in both, **zero** differ — no
pass/fail flips, no field changes. The entire delta is the rows below.

**Removed — the incomplete Opus 4.8 row (4 records).**
`claude-code-opus-4.8` and `claude-code-opus-4.8-no-skills`, each
holding only `build-cli-001-bootstrap-app` and
`build-database-001-migrate-postgres-to-supabase` (both `stage: build`,
both passing) — exactly the shape that produces Build 100% / em-dashes /
100% TOTAL. Supporting evidence that this data was accidental: there is
no `experiments/claude-code-opus-4.8*.ts` definition in the repo, so no
refresh run could have generated it. The only other mention of
`claude-opus-4-8` anywhere is a label formatting assertion in
`apps/web/src/lib/format.test.ts`.

**Removed — results for three new supabase-js SDK evals across the other
14 benchmark rows (34 records).** ⚠️ This is the part that goes beyond
the reported bug and is worth a second opinion:

- `build-auth-001-email-password-flow`
- `build-dataapi-001-relational-report`
- `build-dataapi-002-restock-alert-report`

Affected rows: `claude-code-opus-5`, `claude-code-sonnet-5`,
`codex-gpt-5.4-mini`, `codex-gpt-5.6`, `opencode-kimi-k3`, and each of
their `-no-skills` counterparts. Their eval *definitions* stay in
`evals/` (this PR touches only the JSON), so the next benchmark refresh
should repopulate them — they'll just be absent from the site until it
runs.

**Restored — metadata re-attributions that `#129` introduced (8
records).** Not new data; the same two Build evals moving back to their
pre-`#129` identity:

| Eval | Currently on `main` | After this PR |
|---|---|---|
| `build-cli-001-bootstrap-app`,
`build-database-001-migrate-postgres-to-supabase` |
`claude-code-opus-4.8` / `claude-opus-4-8` | `claude-code-opus-5` /
`claude-opus-5` |
| same two, `-no-skills` | `claude-code-opus-4.8-no-skills` |
`claude-code-opus-5-no-skills` |
| same two, codex | `codex-gpt-5.6` @ effort **low** | `codex-gpt-5.6` @
effort **medium** |
| same two, codex `-no-skills` | `codex-gpt-5.6-no-skills` @ **low** |
`codex-gpt-5.6-no-skills` @ **medium** |

## In-flight refresh — possible conflict

The benchmark refresh run started around 16:54 UTC today ([run
31121347612](https://github.com/supabase/evals/actions/runs/31121347612))
had not landed on `main` as of `85c4f6a`. Per
`.github/workflows/eval-refresh.yml`, scheduled/manual runs open their
own PR on `chore/refresh-eval-results-*` rather than pushing to `main`.
If that run produces a refresh PR touching `eval-results.json`, it will
conflict with this branch and whichever merges second wins — so it's
worth checking for that PR before merging. A refresh should regenerate
the three SDK evals and should not reintroduce the Opus 4.8 row.

## Test plan

- [ ] Confirm the Benchmark table on a preview build no longer shows a
Claude Code / Opus 4.8 row
- [ ] Confirm remaining rows' Build/Deploy/Investigate/Resolve/TOTAL
figures match pre-`#129` values
- [ ] Decide whether losing the three SDK evals' results until the next
refresh is acceptable, or whether a forward fix (drop just the Opus 4.8
records and repair the re-attributions) is preferred

---
_Generated by [Claude
Code](https://claude.ai/code/session_01TXk7jJgnnwPuancUutKkAg)_

Co-authored-by: Claude <noreply@anthropic.com>
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.

2 participants