diff --git a/apps/web/src/data/eval-results.json b/apps/web/src/data/eval-results.json index 97dac8ad..5c495b9b 100644 --- a/apps/web/src/data/eval-results.json +++ b/apps/web/src/data/eval-results.json @@ -31,7 +31,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user d7fb398a-0a59-40f5-aaa8-bc0b26722470, signUp returned {\"userId\":\"d7fb398a-0a59-40f5-aaa8-bc0b26722470\"}" + "notes": "db user 395bd1d4-1bba-4d85-9249-9c1b92f698f3, signUp returned {\"userId\":\"395bd1d4-1bba-4d85-9249-9c1b92f698f3\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -46,7 +46,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"d7fb398a-0a59-40f5-aaa8-bc0b26722470\"}" + "notes": "{\"userId\":\"395bd1d4-1bba-4d85-9249-9c1b92f698f3\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -77,35 +77,39 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"signUp email password options data user metadata javascript\", limit: 4) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"signUp email password user metadata display_name javascript\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ + { + "url": "https://supabase.com/docs/reference/javascript/auth-signup" + }, { "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", "title": "Customizing Emails by Language" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signup" + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" + "url": "https://supabase.com/docs/reference/dart/auth-signup" }, { - "url": "https://supabase.com/docs/guides/auth/auth-mfa", - "title": "Multi-Factor Authentication" + "url": "https://supabase.com/docs/reference/csharp/auth-signinwithpassword", + "title": "SignIn(email, password)" } ], - "resultChars": 22309 + "resultChars": 6901 }, { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog.md | head -60", + "source": "web_fetch", + "query": "List any entries tagged breaking-change, and any entries about supabase-js v2/v3, auth signUp/signInWithPassword, publishable vs anon API keys, or session persistence. Include dates and links.", + "hasContent": true, "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 3161 + "resultChars": 2421 } ] }, @@ -148,7 +152,7 @@ { "name": "todos table exists with at least 2 seeded rows", "passed": true, - "notes": "found 2 rows" + "notes": "found 3 rows" }, { "name": "row level security is enabled on todos", @@ -166,7 +170,7 @@ { "name": "REST API returns the todos to authenticated requests", "passed": true, - "notes": "2 rows" + "notes": "3 rows" } ], "skills": { @@ -182,24 +186,26 @@ "docs": { "calls": [ { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog.md 2>&1 | grep -iE 'breaking|rls|policy|grant' | head -30", + "source": "web_fetch", + "query": "List any entries tagged breaking-change, and any entries related to: RLS policies, local development / CLI migrations, seed files / seed.sql, Data API (PostgREST) exposure or grants for anon/authenticated roles, or default privileges on new tables. Include dates and links.", + "hasContent": true, "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 5391 + "resultChars": 1525 }, { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically.md 2>&1 | head -60", + "source": "web_fetch", + "query": "What exactly changed? Does it apply to new projects only or existing ones, and from what date? Does it affect local development via the Supabase CLI? What SQL must a developer now write to expose a new table to the Data API for anon/authenticated roles? Quote any example SQL / GRANT statements.", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically.md" + "url": "https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically" } ], - "resultChars": 3976 + "resultChars": 1490 } ] }, @@ -260,14 +266,15 @@ "docs": { "calls": [ { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/docs/guides/local-development/declarative-database-schemas.md | head -120", + "source": "web_fetch", + "query": "What is the exact workflow and CLI commands for adding a column to an existing table using declarative schemas? Include the commands for stopping the db, generating the migration (db diff), and applying it. Also list any documented caveats/limitations.", + "hasContent": true, "pages": [ { "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas.md" } ], - "resultChars": 4170 + "resultChars": 1318 } ] }, @@ -314,7 +321,7 @@ { "name": "process-tasks function drains the queue", "passed": true, - "notes": "function removed the seeded message (id 83) from the queue" + "notes": "function removed the seeded message (id 3) from the queue" } ], "skills": { @@ -331,7 +338,7 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"pg_cron schedule job invoke edge function pgmq queue\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"pg_cron schedule job every minute cron.schedule queues pgmq\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -343,56 +350,45 @@ "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", - "title": "pg_cron debugging guide" + "url": "https://supabase.com/docs/guides/cron/install", + "title": "Install" }, { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" } ], - "resultChars": 62989 + "resultChars": 77877 }, { "source": "web_fetch", - "query": "How do you create a cron job that runs every minute using SQL (cron.schedule)? Show the exact SQL syntax, including how to name a job, how to run SQL vs invoke an edge function, and how to unschedule/replace an existing job. Include any notes about job names and idempotency.", + "query": "Show the exact SQL syntax for creating a pg_cron job that runs every minute, including cron.schedule signature, how to name jobs, how to unschedule, and how to inspect cron.job and cron.job_run_details. Quote SQL verbatim.", "hasContent": true, "pages": [ { "url": "https://supabase.com/docs/guides/cron/quickstart.md" } ], - "resultChars": 1310 + "resultChars": 1101 }, { "source": "web_fetch", - "query": "How do you create a pgmq queue and send/read/delete messages? Show exact SQL function signatures for pgmq.create, pgmq.send, pgmq.read, pgmq.delete, pgmq.pop. Also note anything about queue types (basic/unlogged/partitioned) and the pgmq_public wrappers for the Data API.", + "query": "Show exact SQL for creating a pgmq queue, sending a message, reading messages, and deleting/archiving them. Include pgmq.create, pgmq.send, pgmq.read, pgmq.delete, pgmq.pop signatures and the pgmq_public wrappers exposed via the Data API. Quote SQL verbatim.", "hasContent": true, "pages": [ { "url": "https://supabase.com/docs/guides/queues/quickstart.md" } ], - "resultChars": 1391 - }, - { - "source": "web_fetch", - "query": "List any entries tagged breaking-change or otherwise notable that relate to: Queues / pgmq, Cron / pg_cron, or Edge Functions (deployment, config.toml verify_jwt, serving). Include dates and links.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 3048 + "resultChars": 958 } ] }, @@ -463,31 +459,34 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"secret key service role server-side supabase-js createClient API keys\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"secret key service role server-side supabase-js createClient API keys\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", - "title": "Performing administration tasks on the server side with a secret key" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" }, { "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", "title": "Build a User Management App with RedwoodJS" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", + "title": "Performing administration tasks on the server side with a secret key" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { "url": "https://supabase.com/docs/guides/getting-started/quickstarts/sveltekit", "title": "Use Supabase with SvelteKit" + }, + { + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-createclient" } ], - "resultChars": 94242 + "resultChars": 94600 } ] }, @@ -551,12 +550,67 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "List any entries tagged breaking-change or otherwise breaking, especially anything related to: API keys (secret/publishable keys, sb_secret_ format), supabase-js client library versions, PostgREST filtering/embedded resources, or service_role behavior. Include dates and links.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 3069 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"secret key publishable key API keys service_role backend\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" + }, + { + "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", + "title": "Supabase for Platforms" + } + ], + "resultChars": 81035 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"filter compare two columns in same row PostgREST\", limit: 2) { nodes { title href } } }", + "hasContent": false, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/rls-performance-and-best-practices-Z5Jjwv", + "title": "RLS Performance and Best Practices" + } + ], + "resultChars": 322 + } + ] }, "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", @@ -666,12 +720,12 @@ { "name": "user A cannot force-read user B note", "passed": true, - "notes": "status=403" + "notes": "status=200" }, { "name": "user B cannot force-read user A note", "passed": true, - "notes": "status=403" + "notes": "status=200" } ], "skills": { @@ -687,17 +741,17 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Function auth user Authorization header RLS createClient\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Edge Function auth user Authorization header RLS createClient\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" - }, { "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", "title": "Why is my service role key client getting RLS errors or not returning data?" }, + { + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, { "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", "title": "Build a User Management App with Next.js" @@ -705,53 +759,15 @@ { "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", "title": "Which package to use" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", - "title": "Token Security and Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/functions/http-methods", - "title": "Routing" - } - ], - "resultChars": 73347 - }, - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/docs/guides/functions/auth.md | head -120", - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/auth.md" - } - ], - "resultChars": 5299 - }, - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/docs/guides/functions/auth-headers.md", - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/auth-headers.md" - } - ], - "resultChars": 3330 - }, - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/docs/guides/functions/secrets.md | head -60", - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/secrets.md" } ], - "resultChars": 2599 + "resultChars": 56091 } ] }, "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-opus-5/build-functions-004-service-role-bypass.json" }, { @@ -793,17 +809,17 @@ { "name": "user with JWT reads only their own rows", "passed": true, - "notes": "status 200: [{\"user_id\":\"07c687de-fcad-4acd-9271-a501b42d02be\",\"metric\":\"steps_a_msj188pa\",\"value\":111}]" + "notes": "status 200: {\"user_id\":\"b822071e-2e75-46f5-a945-92a381c55d26\",\"stats\":[{\"user_id\":\"b822071e-2e75-46f5-a945-92a381c55d26\",\"metric\":\"steps_a_mt946yl8\",\"value\":111}]}" }, { "name": "user cannot read another user's rows by passing user_id", "passed": true, - "notes": "status 200: [{\"user_id\":\"07c687de-fcad-4acd-9271-a501b42d02be\",\"metric\":\"steps_a_msj188pa\",\"value\":111}]" + "notes": "status 200: {\"user_id\":\"b822071e-2e75-46f5-a945-92a381c55d26\",\"stats\":[{\"user_id\":\"b822071e-2e75-46f5-a945-92a381c55d26\",\"metric\":\"steps_a_mt946yl8\",\"value\":111}]}" }, { "name": "service key bypasses RLS to read the target user's rows", "passed": true, - "notes": "status 200: [{\"user_id\":\"831c5088-6bc6-4c0e-8c1f-3fe53e8a0852\",\"metric\":\"steps_b_msj188pa\",\"value\":222}]" + "notes": "status 200: {\"user_id\":\"ceddef4b-8303-4e7e-b65d-44688c9107ae\",\"stats\":[{\"user_id\":\"ceddef4b-8303-4e7e-b65d-44688c9107ae\",\"metric\":\"steps_b_mt946yl8\",\"value\":222}]}" }, { "name": "non-service key is not granted service access", @@ -837,87 +853,85 @@ }, "docs": { "calls": [ - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog.md 2>/dev/null | head -60 || echo \"changelog fetch failed\"", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 3161 - }, - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog/45702-developer-update-may-2026.md 2>/dev/null | head -100", - "pages": [ - { - "url": "https://supabase.com/changelog/45702-developer-update-may-2026.md" - } - ], - "resultChars": 6160 - }, { "source": "search_docs", - "query": "{ searchDocs(query: \"@supabase/server SDK edge functions auth service role\", limit: 12) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function authentication verify JWT service role key user auth\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" }, { "url": "https://supabase.com/docs/guides/functions/auth", "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/auth/third-party/auth0", - "title": "Auth0" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", - "title": "Firebase Auth" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", "title": "Integrating With Supabase Auth" - }, + } + ], + "resultChars": 75098 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"new API keys publishable secret key sb_secret legacy anon service_role\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/auth/third-party/aws-cognito", - "title": "Amazon Cognito (Amplify)" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", - "title": "Resumable WebSockets with Edge Functions" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/auth/third-party/workos", - "title": "WorkOS" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" }, { - "url": "https://supabase.com/docs/guides/storage/schema/custom-roles", - "title": "Custom Roles" + "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", + "title": "Creating a Supabase client for SSR" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-functions", - "title": "Manage Supabase Edge functions" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/auth/architecture", - "title": "Auth architecture" - }, + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + } + ], + "resultChars": 128632 + }, + { + "source": "shell_fetch", + "query": "curl -s https://supabase.com/changelog.md 2>/dev/null | grep -i -E 'breaking|edge function|api key|verify_jwt|@supabase/server' | head -40", + "pages": [ { - "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", - "title": "Which package to use" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 75829 + "resultChars": 7372 } ] }, "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-opus-5/build-functions-005-dual-auth-user-secret.json" }, { @@ -1010,7 +1024,8 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { @@ -1059,7 +1074,7 @@ { "name": "user A lists only own files", "passed": true, - "notes": "saw: 019fdc90-5069-75c6-93dc-d42f28e61c92/receipt-alpha.pdf, 019fdc90-5069-75c6-93dc-d42f28e61c92/receipt-beta.pdf" + "notes": "saw: 01a03a89-40d1-7375-b613-78614f389325/receipt-alpha.pdf, 01a03a89-40d1-7375-b613-78614f389325/receipt-beta.pdf" }, { "name": "user B cannot read user A files", @@ -1080,7 +1095,7 @@ { "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "Meets all required criteria: private user-files bucket, owner-scoped SELECT and INSERT RLS policies on storage.objects for authenticated users with RLS kept enabled, and supabase-js createSignedUrl code with expiry for temporary sharing. No disqualifying public bucket, permissive policies, public URL sharing, or client service-role usage." + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT policies, RLS remains enabled, and temporary sharing uses createSignedUrl with expiry." } ], "skills": { @@ -1094,52 +1109,52 @@ }, "docs": { "calls": [ + { + "source": "web_fetch", + "query": "List any entries tagged breaking-change, or any entries related to Storage buckets, storage RLS policies, bucket types, signed URLs, or storage access control. Include dates and links.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 3606 + }, { "source": "search_docs", - "query": "{ searchDocs(query: \"storage RLS policies private bucket user folder owner uid\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"storage RLS policies restrict users to own folder auth.uid\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" }, { "url": "https://supabase.com/docs/guides/storage/security/access-control", "title": "Storage Access Control" }, + { + "url": "https://supabase.com/docs/guides/storage/security/ownership", + "title": "Ownership" + }, { "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", "title": "Configure S3 Storage" }, { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" - }, - { - "url": "https://supabase.com/docs/guides/local-development/database-migrations", - "title": "Database migrations" + "url": "https://supabase.com/docs/guides/storage/debugging/error-codes", + "title": "Error Codes" }, { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" - } - ], - "resultChars": 36724 - }, - { - "source": "web_fetch", - "query": "List any entries tagged breaking-change, and any entries related to Storage buckets, storage RLS policies, signed URLs, or the storage.objects schema (e.g. owner/owner_id columns, new bucket types). Include dates and links.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" } ], - "resultChars": 8117 + "resultChars": 44042 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"createSignedUrl expires in temporary link download share\", limit: 4) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"createSignedUrl signed URL expiring temporary share file\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -1151,12 +1166,19 @@ { "url": "https://supabase.com/docs/reference/dart/file-buckets-createsignedurl" }, + { + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" + }, { "url": "https://supabase.com/docs/reference/csharp/storage-from-createsignedurl", "title": "From().CreateSignedUrl()" + }, + { + "url": "https://supabase.com/docs/reference/python/storage-from-createsignedurl", + "title": "from_.create_signed_url()" } ], - "resultChars": 3099 + "resultChars": 4725 } ] }, @@ -1190,17 +1212,17 @@ { "name": "pgTAP test file(s) written under supabase/tests/", "passed": true, - "notes": "3 file(s): supabase/tests/002_tenant_isolation_writes.test.sql, supabase/tests/001_tenant_isolation_select.test.sql, supabase/tests/003_tenant_isolation_baseline.test.sql" + "notes": "3 file(s): supabase/tests/database/01_notes_tenant_isolation.sql, supabase/tests/database/02_posts_tenant_isolation.sql, supabase/tests/database/03_memberships_exposure.sql" }, { "name": "pgTAP isolation tests ran and pass", "passed": true, - "notes": "7 passed, 5 failed" + "notes": "3 passed, 3 failed" }, { "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as having the broken tenant isolation policy, explicitly noting authenticated users in any org can read every post because the policy is missing `m.org_id = posts.org_id`. It grounds this in pgTAP results, distinguishes `notes` as passing read isolation, and treats test results as authoritative rather than trusting migration comments." + "judgeNotes": "Correctly identifies the `posts` SELECT policy as allowing cross-organization reads and grounds this in the pgTAP failures, while noting `notes` passes its direct isolation tests." } ], "skills": { @@ -1209,8 +1231,7 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { @@ -1252,12 +1273,12 @@ { "name": "HNSW index on the embedding column", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { "name": "index operator class matches the search operator", "passed": true, - "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { "name": "user A search returns only own sections, best match first", @@ -1290,9 +1311,13 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"semantic search pgvector gte-small edge function embeddings match_document_sections RLS\", limit: 6) { nodes { title href content } } }", + "query": "{\n searchDocs(query: \"semantic search pgvector match function RLS gte-small 384 dimensions\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", "hasContent": true, "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, { "url": "https://supabase.com/docs/guides/ai/hybrid-search", "title": "Hybrid search" @@ -1301,24 +1326,55 @@ "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", "title": "RAG with Permissions" }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgvector", + "title": "pgvector: Embeddings and vector similarity" + }, + { + "url": "https://supabase.com/docs/guides/storage/vector/querying-vectors", + "title": "Querying Vectors" + } + ], + "resultChars": 68336 + }, + { + "source": "search_docs", + "query": "{\n searchDocs(query: \"pgvector hnsw index vector column embedding indexing distance operator\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/vector-indexes/hnsw-indexes", + "title": "HNSW indexes" + }, { "url": "https://supabase.com/docs/guides/ai/semantic-search", "title": "Semantic search" }, { - "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", - "title": "Semantic Search" + "url": "https://supabase.com/docs/guides/ai/vector-indexes/ivf-indexes", + "title": "IVFFlat indexes" }, { "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/ai/vector-columns", - "title": "Vector columns" + "url": "https://supabase.com/docs/guides/ai/going-to-prod", + "title": "Going to Production" + } + ], + "resultChars": 67791 + }, + { + "source": "web_fetch", + "query": "List any breaking changes or notable recent changes related to: pgvector / vector extension, the `extensions` schema vs `public` schema for extensions, Edge Functions Supabase.ai Session gte-small embeddings, RLS policies, or PostgREST RPC function calls. Quote the entries and dates.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 84107 + "resultChars": 1501 } ] }, @@ -1355,12 +1411,12 @@ { "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "judgeNotes": "Meets requirements: HTTPS Supabase Metrics API scrape for evalshostedprojectxy.supabase.co at /customer/v1/privileged/metrics, uses HTTP Basic Auth with password_file, preserves existing app scrape, and docker-compose mounts the secrets directory matching the password_file path." + "judgeNotes": "Meets all rubric requirements: HTTPS Supabase target, correct metrics path, Basic Auth with password_file, matching read-only secret volume mount, and preserved app scrape job." }, { "name": "documented live deployment and verification steps", "passed": true, - "judgeNotes": "README includes Secret API key creation, matching password_file setup, reload/Compose rollout steps, and concrete verification via curl, Prometheus targets/query API, and Grafana dashboard." + "judgeNotes": "README documents creating a Supabase Secret API key, installing the matching password file, reloading Prometheus, and verifying the target is up via the Prometheus targets API. Endpoint and basic-auth setup are consistent, with no real secret hardcoded." } ], "skills": { @@ -1376,42 +1432,73 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"Prometheus metrics endpoint project observability scrape\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Prometheus metrics endpoint project metrics scrape\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", "title": "Metrics API with Grafana Cloud" - }, - { - "url": "https://supabase.com/docs/guides/platform/read-replicas", - "title": "Read Replicas" } ], - "resultChars": 29057 + "resultChars": 20571 }, { "source": "web_fetch", - "query": "What is the exact metrics endpoint URL format, what authentication does it use (username/password), and what is the recommended Prometheus scrape config and scrape interval? Include any notes about rate limits or which key to use.", + "query": "What is the exact Prometheus metrics endpoint URL for a Supabase project? What authentication is required (username/password, which key)? Give the exact prometheus.yml scrape_config example including scheme, metrics_path, basic_auth, and any notes about scrape interval limits or plan requirements.", "hasContent": true, "pages": [ { "url": "https://supabase.com/docs/guides/telemetry/metrics.md" } ], - "resultChars": 1186 + "resultChars": 992 + }, + { + "source": "web_fetch", + "query": "List any breaking changes or recent entries related to: the Metrics API / Prometheus metrics endpoint, API keys (sb_secret / publishable / legacy anon+service_role keys, deprecation dates), or the customer/v1/privileged/metrics path. Include dates.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 824 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"legacy anon service_role JWT API keys deprecation migrate publishable secret sb_secret\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/rotating-anon-service-and-jwt-secrets-1Jq6yd", + "title": "Rotating Anon, Service, and JWT Secrets" + } + ], + "resultChars": 47558 } ] }, @@ -1453,7 +1540,7 @@ { "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get(\"WEATHER_API_KEY\")." }, { "name": "WEATHER_API_KEY value is not committed to the repo", @@ -1473,9 +1560,13 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions secrets environment variables managing\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Edge Functions environment variables secrets set deploy\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, { "url": "https://supabase.com/docs/guides/functions/secrets", "title": "Environment Variables" @@ -1484,63 +1575,39 @@ "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", "title": "Migrating to publishable and secret API keys" }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", + "title": "Transcription Telegram Bot" + }, { "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + }, + { + "url": "https://supabase.com/docs/guides/deployment/branching/configuration", + "title": "Configuration" }, { "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", "title": "Automatic embeddings" } ], - "resultChars": 71163 + "resultChars": 89502 }, { "source": "web_fetch", - "query": "List any breaking changes or notable changes related to Edge Functions, function deployment, function secrets/environment variables, or the CLI's secrets/functions commands.", + "query": "List any breaking changes or notable changes related to Edge Functions: deployment, secrets/environment variables, config.toml function settings, JWT verification defaults, or the Deno runtime version. Include dates.", "hasContent": true, "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 1947 - }, - { - "source": "web_fetch", - "query": "How do you set and access environment variables/secrets in Supabase Edge Functions? Include the exact CLI commands for setting production secrets from a .env file, local .env handling, and reserved secret names. Quote commands verbatim.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/secrets.md" - } - ], - "resultChars": 1274 - }, - { - "source": "web_fetch", - "query": "Show the current recommended boilerplate for a Supabase Edge Function index.ts (Deno.serve vs std serve import), the deploy command, and any config.toml settings for functions like verify_jwt. Quote code verbatim.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/quickstart.md" - } - ], - "resultChars": 879 - }, - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/docs/guides/functions/quickstart.md | head -120", - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/quickstart.md" - } - ], - "resultChars": 5029 + "resultChars": 1663 } ] }, @@ -1601,26 +1668,14 @@ "docs": { "calls": [ { - "source": "web_fetch", - "query": "Extract the full self-hosting with Docker guide verbatim-ish: the exact steps to get the docker setup, all the secrets/env vars that must be changed before going to production (JWT secret, anon/service keys, postgres password, dashboard user/pass, secret_key_base, vault enc key, SITE_URL, API_EXTERNAL_URL, SUPABASE_PUBLIC_URL, pooler tenant id, etc.), securing services, and any notes about restarting/regenerating keys.", - "hasContent": true, + "source": "shell_fetch", + "query": "curl -sS --max-time 30 https://supabase.com/docs/guides/self-hosting/docker.md | head -250", "pages": [ { "url": "https://supabase.com/docs/guides/self-hosting/docker.md" } ], - "resultChars": 3113 - }, - { - "source": "web_fetch", - "query": "List any entries tagged breaking-change or otherwise relevant to self-hosting, Docker, JWT signing keys / API key format (publishable/secret vs anon/service_role), Supavisor/pooler, or Studio, from 2025 and 2026. Include dates and links.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 3915 + "resultChars": 11270 } ] }, @@ -1638,49 +1693,44 @@ "modelId": "claude-opus-5", "reasoningEffort": "high" }, - "eval": "investigate-auth-001-deleted-user-access", + "eval": "investigate-realtime-001-subscribed-no-events", "stage": "investigate", "product": [ - "auth" + "realtime", + "database" ], "topic": [ - "security", "sdk" ], "suite": "benchmark", "interface": "mcp", - "passed": false, + "passed": true, "checks": [ { - "name": "victim session active before delete-account", + "name": "orders table added to supabase_realtime publication", "passed": true }, { - "name": "delete_account flow ran for the victim", + "name": "courier_locations still in supabase_realtime publication", "passed": true }, { - "name": "delete-account revokes the user's sessions", - "passed": true, - "notes": "sessions left: 0" - }, - { - "name": "deleted user's refresh token is rejected", + "name": "publication still publishes INSERT events", "passed": true }, { - "name": "deleted user cannot sign back in", - "passed": false, - "notes": "deleted account can still sign in" + "name": "RLS still enabled on orders", + "passed": true }, { - "name": "other users keep their sessions and access", - "passed": true + "name": "staff can still read orders through RLS", + "passed": true, + "notes": "authenticated sees 2 of 2 orders" }, { - "name": "diagnosed and explained session revocation", + "name": "diagnosed missing publication membership", "passed": true, - "judgeNotes": "The answer identifies the original soft-delete-only bug and lack of session/refresh-token revocation, implements real auth/session revocation via banning and deleting sessions plus RLS checks, and explains the remaining stateless JWT caveat consistently: Data API notes/profiles are closed by RLS, but purely local JWT validation remains valid until exp with mitigations. It also correctly distinguishes publishable frontend keys with RLS from server-only secret/service_role keys that bypass RLS and must not ship to clients." + "judgeNotes": "Correctly identified orders missing from supabase_realtime, added only public.orders to the existing publication, and preserved courier_locations, RLS, policies, and grants." } ], "skills": { @@ -1696,73 +1746,38 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"publishable key secret key new API keys anon service_role RLS\", limit: 6) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", - "title": "Creating a Supabase client for SSR" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" - }, - { - "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", - "title": "Build a Social Auth App with Expo React Native" - } - ], - "resultChars": 190908 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"delete user does not invalidate access token revoke sessions sign out\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"enable realtime postgres changes add table to supabase_realtime publication\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", - "title": "OAuth 2.1 Flows" + "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes", + "title": "Subscribing to Database Changes" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" + "url": "https://supabase.com/docs/guides/realtime/benchmarks", + "title": "Benchmarks" }, { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" + "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", + "title": "Backup and Restore using the CLI" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/should-i-set-a-shorter-max-age-parameter-on-the-cookies-8sbF4V", - "title": "Should I set a shorter Max-Age parameter on the cookies?" + "url": "https://supabase.com/docs/guides/realtime/architecture", + "title": "Realtime Architecture" } ], - "resultChars": 66489 + "resultChars": 102869 } ] }, - "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", - "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-opus-5/investigate-auth-001-deleted-user-access.json" + "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", + "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-opus-5/investigate-realtime-001-subscribed-no-events.json" }, { "experiment": "claude-code-opus-5", @@ -1773,98 +1788,32 @@ "modelId": "claude-opus-5", "reasoningEffort": "high" }, - "eval": "investigate-realtime-001-subscribed-no-events", + "eval": "investigate-reliability-003-edge-function-5xx-correlation", "stage": "investigate", "product": [ - "realtime", - "database" + "edge-functions" ], "topic": [ - "sdk" + "observability" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "orders table added to supabase_realtime publication", - "passed": true - }, - { - "name": "courier_locations still in supabase_realtime publication", - "passed": true - }, - { - "name": "publication still publishes INSERT events", - "passed": true - }, - { - "name": "RLS still enabled on orders", - "passed": true - }, - { - "name": "staff can still read orders through RLS", - "passed": true, - "notes": "authenticated sees 2 of 2 orders" - }, - { - "name": "diagnosed missing publication membership", - "passed": true, - "judgeNotes": "The assistant correctly identified the root cause as orders missing from the supabase_realtime publication despite SUBSCRIBED succeeding, fixed it with ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, and did not weaken RLS/policies or disrupt courier_locations. It checked RLS/grants but did not blame them or change them." - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase" - ] - }, - "docs": { - "calls": [] - }, - "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", - "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-opus-5/investigate-realtime-001-subscribed-no-events.json" - }, - { - "experiment": "claude-code-opus-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-opus-5", - "reasoningEffort": "high" - }, - "eval": "investigate-reliability-003-edge-function-5xx-correlation", - "stage": "investigate", - "product": [ - "edge-functions" - ], - "topic": [ - "observability" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "identified image-transform and the recurring 503 pattern", - "passed": true, - "judgeNotes": "Identified image-transform as affected and described the 8 HTTP 503 gateway failures recurring across the morning of 2026-04-28 from 07:00Z to 12:00Z, distinguishing them from unrelated billing-webhook 503s." + "name": "identified image-transform and the recurring 503 pattern", + "passed": true, + "judgeNotes": "Identified image-transform and the recurring pattern of eight HTTP 503 gateway failures from 07:00Z–12:00Z on 2026-04-28." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": true, - "judgeNotes": "The assistant clearly attributes the recurring image-transform 503s to the gateway/Edge platform layer, not function code, and grounds this in valid observations: gateway 503s had no matching edge-function invocations, nearby invocations succeeded, deployment/version stayed unchanged, and avatar-upload's function-level 500 is distinguished as a separate class of error." + "judgeNotes": "Attributes the 503s to the gateway/platform boundary, supported by gateway-only log entries with no matching function invocations while nearby executed invocations returned 200. It also correctly distinguishes avatar-upload’s in-function 500." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "The assistant recommended concrete next steps, including opening/support escalation to the platform with the specific time window and evidence, investigating the scheduled caller, adding jitter/retries, and separately triaging a code-path error." + "judgeNotes": "The assistant provided multiple concrete next steps, including pulling fresh logs, identifying the scheduled caller, tracing the real upload path, checking function boot logs and concurrency limits, and separately investigating the avatar-upload package." } ], "skills": { @@ -1872,9 +1821,7 @@ "supabase", "supabase-postgres-best-practices" ], - "loaded": [ - "supabase" - ] + "loaded": [] }, "docs": { "calls": [] @@ -1935,7 +1882,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "Diagnosed RLS enabled with no policies causing deny-all Data API results, kept RLS enabled, and created authenticated-only owner-scoped SELECT and INSERT policies using auth.uid() with WITH CHECK for inserts. Did not use permissive policies or disable RLS." + "judgeNotes": "Correctly identifies deny-all RLS with no policies, keeps RLS enabled, and creates authenticated owner-scoped SELECT and INSERT policies using auth.uid() with USING and WITH CHECK." } ], "skills": { @@ -1944,51 +1891,12 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{ searchDocs(query: \"row level security policy auth.uid() select insert performance index\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0003_auth_rls_initplan", - "title": "Database Advisor: Lint 0003_auth_rls_initplan" - }, - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/rls-performance-and-best-practices-Z5Jjwv", - "title": "RLS Performance and Best Practices" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", - "title": "Column Level Security" - } - ], - "resultChars": 67906 - }, - { - "source": "web_fetch", - "query": "List any entries tagged breaking-change related to RLS, row level security, policies, the Data API / PostgREST, grants, or auth.uid(). Just list titles, dates and one-line summaries.", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 1403 - } - ] + "calls": [] }, "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", @@ -2039,7 +1947,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "Avatar migration was applied through `supabase db push` in action #21, with output showing `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration was reconciled by adding the missing local migration file `supabase/migrations/20240115000000_add_profile_bio.sql` in action #18, after which `supabase migration list` showed local/remote alignment and the push proceeded. I saw read-only psql inspections and a rolled-back verification schema, but no prohibited workaround or direct application of the avatar migration outside the CLI." + "judgeNotes": "`supabase db push --yes` applied `20240220000000_add_avatar_url.sql`. History was reconciled by adding local `20240115000000_add_profile_bio.sql`, then running the successful push; migration lists confirmed alignment. No prohibited workaround was used." } ], "skills": { @@ -2230,7 +2138,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user 5a5d5991-7eae-49b4-8f13-2487fba8366c, signUp returned {\"userId\":\"5a5d5991-7eae-49b4-8f13-2487fba8366c\"}" + "notes": "db user ac0cf5d8-6ad6-4b0d-9a73-256ec6ffcbda, signUp returned {\"userId\":\"ac0cf5d8-6ad6-4b0d-9a73-256ec6ffcbda\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -2245,7 +2153,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"5a5d5991-7eae-49b4-8f13-2487fba8366c\"}" + "notes": "{\"userId\":\"ac0cf5d8-6ad6-4b0d-9a73-256ec6ffcbda\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -2309,7 +2217,7 @@ { "name": "todos table exists with at least 2 seeded rows", "passed": true, - "notes": "found 3 rows" + "notes": "found 2 rows" }, { "name": "row level security is enabled on todos", @@ -2322,12 +2230,12 @@ { "name": "REST API returns no todos to anonymous requests", "passed": true, - "notes": "0 rows" + "notes": "error 42501: permission denied for table todos" }, { "name": "REST API returns the todos to authenticated requests", "passed": true, - "notes": "3 rows" + "notes": "2 rows" } ], "skills": { @@ -2335,7 +2243,82 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "List any entries tagged breaking-change, and anything about RLS policies, local development / CLI db reset / seed files, or migrations. Include dates and links.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 3612 + }, + { + "source": "web_fetch", + "query": "What exactly changed, when does it apply, and what SQL (GRANTs) is now required to expose a new public-schema table to the Data API for anon/authenticated roles? Does it affect local CLI development?", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically" + } + ], + "resultChars": 1334 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"expose table to Data API grant anon authenticated RLS securing your API\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0023_sensitive_columns_exposed", + "title": "Database Advisor: Lint 0023_sensitive_columns_exposed" + }, + { + "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0027_pg_graphql_authenticated_table_exposed", + "title": "Database Advisor: Lint 0027_pg_graphql_authenticated_table_exposed" + }, + { + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" + } + ], + "resultChars": 65357 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"seed test auth users local development seed.sql create user\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", + "title": "Supabase for Platforms" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-react", + "title": "Build a User Management App with Ionic React" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-solidjs", + "title": "Build a User Management App with SolidJS" + } + ], + "resultChars": 96837 + } + ] }, "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", @@ -2389,7 +2372,7 @@ "calls": [ { "source": "search_docs", - "query": "{searchDocs(query:\"declarative database schemas migration workflow db diff\", limit:4){nodes{title href content}}}", + "query": "query { searchDocs(query: \"declarative database schema migrations db diff workflow\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -2397,19 +2380,23 @@ "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" + "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", + "title": "Multiple SSO Providers" }, { "url": "https://supabase.com/docs/reference/cli/supabase-db-pull", "title": "Pull schema from the remote database" }, { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations", + "title": "Database migrations" } ], - "resultChars": 62949 + "resultChars": 73628 } ] }, @@ -2451,12 +2438,12 @@ { "name": "cron command enqueues to the 'tasks' queue", "passed": true, - "notes": "queue depth 0 -> 1" + "notes": "queue depth 1 -> 2" }, { "name": "process-tasks function drains the queue", "passed": true, - "notes": "function removed the seeded message (id 13) from the queue" + "notes": "function removed the seeded message (id 7) from the queue" } ], "skills": { @@ -2467,67 +2454,71 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"pg_cron schedule job every minute queues pgmq send\", limit: 6) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"queues pgmq create queue send message cron schedule\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, { "url": "https://supabase.com/docs/guides/queues/pgmq", "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" }, { "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/cron/install", - "title": "Install" + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" } ], - "resultChars": 69432 + "resultChars": 66129 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Supabase Queues create queue read delete messages edge function\", limit: 6) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"cron job schedule edge function invoke pg_net\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/queues/quickstart", + "url": "https://supabase.com/docs/guides/cron/quickstart", "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/queues", - "title": "Supabase Queues" - }, + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" + } + ], + "resultChars": 56835 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Queues API read messages supabase-js pgmq_public schema rpc\", limit: 2) { nodes { title href } } }", + "hasContent": false, + "pages": [ { - "url": "https://supabase.com/docs/guides/database/extensions/pgmq", - "title": "pgmq: Queues" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/functions/architecture", - "title": "Edge Functions Architecture" + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" } ], - "resultChars": 55770 + "resultChars": 246 } ] }, @@ -2755,12 +2746,12 @@ { "name": "user A cannot force-read user B note", "passed": true, - "notes": "status=200" + "notes": "status=403" }, { "name": "user B cannot force-read user A note", "passed": true, - "notes": "status=200" + "notes": "status=403" } ], "skills": { @@ -2809,37 +2800,37 @@ { "name": "rejects request with no credentials", "passed": true, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "notes": "status 401: {\"error\":\"unauthorized\"}" }, { "name": "user with JWT reads only their own rows", - "passed": false, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "passed": true, + "notes": "status 200: {\"user_id\":\"019a424a-6789-4da2-8d8f-dd72db083f1e\",\"stats\":[{\"user_id\":\"019a424a-6789-4da2-8d8f-dd72db083f1e\",\"metric\":\"steps_a_mt94wcpz\",\"value\":111}]}" }, { "name": "user cannot read another user's rows by passing user_id", "passed": false, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "notes": "status 403: {\"error\":\"forbidden: cannot request another user's stats\"}" }, { "name": "service key bypasses RLS to read the target user's rows", - "passed": false, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "passed": true, + "notes": "status 200: {\"user_id\":\"c599a9fe-b0a9-4def-a9ec-0d4eee72a6cc\",\"stats\":[{\"user_id\":\"c599a9fe-b0a9-4def-a9ec-0d4eee72a6cc\",\"metric\":\"steps_b_mt94wcpz\",\"value\":222}]}" }, { "name": "non-service key is not granted service access", "passed": true, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "notes": "status 401: {\"error\":\"unauthorized\"}" }, { "name": "rejects an unverified (forged) user token", "passed": true, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "notes": "status 401: {\"error\":\"unauthorized\"}" }, { "name": "a user token in the apikey slot is not treated as the service key", "passed": true, - "notes": "status 502: { \"message\":\"An invalid response was received from the upstream server\" }" + "notes": "status 401: {\"error\":\"unauthorized\"}" }, { "name": "implementation uses @supabase/server", @@ -2855,7 +2846,7 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"edge function environment variables SUPABASE_SERVICE_ROLE_KEY SB_SECRET_KEY publishable\", limit: 5) { nodes { title href content } } }", + "query": "{searchDocs(query:\"edge function environment variables SUPABASE_SECRET_KEY SUPABASE_PUBLISHABLE_KEY api keys\", limit:10){nodes{title href content}}}", "hasContent": true, "pages": [ { @@ -2874,13 +2865,57 @@ "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", "title": "Self-Hosted Functions" }, + { + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, { "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", "title": "Build a Social Auth App with Expo React Native" - } - ], - "resultChars": 94601 - } + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", + "title": "Transcription Telegram Bot" + } + ], + "resultChars": 186781 + }, + { + "source": "search_docs", + "query": "{searchDocs(query:\"@supabase/server withSupabase createSupabaseContext edge function dual auth service role user\", limit:4){nodes{title href content}}}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, + { + "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", + "title": "Which package to use" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + } + ], + "resultChars": 31937 + } ] }, "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", @@ -3022,7 +3057,7 @@ { "name": "user A lists only own files", "passed": true, - "notes": "saw: 019fdc8e-c692-723e-917b-7953678ca0d1/receipt-alpha.pdf, 019fdc8e-c692-723e-917b-7953678ca0d1/receipt-beta.pdf" + "notes": "saw: 01a03a89-8adf-7443-90a3-4373a11200b8/receipt-alpha.pdf, 01a03a89-8adf-7443-90a3-4373a11200b8/receipt-beta.pdf" }, { "name": "user B cannot read user A files", @@ -3043,7 +3078,7 @@ { "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "Meets all requirements: private user-files bucket, authenticated owner-scoped SELECT and INSERT policies with WITH CHECK, RLS kept enabled, and supabase-js createSignedUrl/createSignedUrls with expiry for temporary sharing." + "judgeNotes": "Creates a private user-files bucket, keeps RLS enabled, adds authenticated owner-scoped SELECT and INSERT policies (plus UPDATE/DELETE), and uses createSignedUrl with an expiry for temporary sharing." } ], "skills": { @@ -3051,7 +3086,61 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"storage RLS policy user id folder owner private bucket\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" + }, + { + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" + }, + { + "url": "https://supabase.com/docs/guides/security/product-security", + "title": "Secure configuration of Supabase products" + }, + { + "url": "https://supabase.com/docs/guides/storage/schema/design", + "title": "The Storage Schema" + } + ], + "resultChars": 25024 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"createSignedUrl expiring temporary share link storage\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" + }, + { + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" + }, + { + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" + }, + { + "url": "https://supabase.com/docs/reference/dart/file-buckets-createsignedurl" + } + ], + "resultChars": 7134 + } + ] }, "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", @@ -3083,17 +3172,17 @@ { "name": "pgTAP test file(s) written under supabase/tests/", "passed": true, - "notes": "3 file(s): supabase/tests/database/02_posts_tenant_isolation.test.sql, supabase/tests/database/03_memberships_and_writes.test.sql, supabase/tests/database/01_notes_tenant_isolation.test.sql" + "notes": "1 file(s): supabase/tests/database/rls_tenant_isolation.test.sql" }, { "name": "pgTAP isolation tests ran and pass", "passed": true, - "notes": "4 passed, 2 failed" + "notes": "10 passed, 5 failed" }, { "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as the broken tenant isolation policy, explains that authenticated members can read posts from orgs they are not members of, and grounds this in pgTAP/direct test results. It also distinguishes `notes` as passing isolation." + "judgeNotes": "Correctly identifies the `posts` policy as allowing cross-tenant reads and grounds the conclusion in multiple pgTAP failures. It correctly distinguishes `notes` as isolated and treats the test results as authoritative." } ], "skills": { @@ -3105,7 +3194,7 @@ }, "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-opus-5-no-skills/build-tests-001-rls-tenant-isolation.json" }, { @@ -3139,12 +3228,12 @@ { "name": "HNSW index on the embedding column", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { "name": "index operator class matches the search operator", "passed": true, - "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { "name": "user A search returns only own sections, best match first", @@ -3168,7 +3257,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"gte-small embedding dimensions Supabase.ai Session semantic search\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", + "title": "Semantic Search" + }, + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, + { + "url": "https://supabase.com/docs/guides/ai/choosing-compute-addon", + "title": "Choosing your Compute Add-on" + }, + { + "url": "https://supabase.com/docs/guides/functions/ai-models", + "title": "Running AI Models" + }, + { + "url": "https://supabase.com/docs/guides/ai/concepts", + "title": "Concepts" + } + ], + "resultChars": 62210 + } + ] }, "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", @@ -3203,12 +3321,12 @@ { "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "judgeNotes": "Supabase scrape uses HTTPS, correct metrics path, Basic Auth with password_file, targets a supabase.co project ref, preserves the app job, and docker-compose mounts the secrets directory containing the password file path." + "judgeNotes": "HTTPS Supabase scrape uses the correct metrics path and Basic Auth password_file; the matching secrets directory is mounted, and the existing app job remains intact." }, { "name": "documented live deployment and verification steps", "passed": true, - "judgeNotes": "README includes Secret API key creation, matching secret file path, Compose restart/up and reload guidance, plus concrete verification via Prometheus targets, PromQL API, and Grafana dashboard checks." + "judgeNotes": "README provides Secret API key creation and matching file placement, Compose restart/reload steps, correct endpoint/auth setup, and concrete verification via curl and Prometheus targets." } ], "skills": { @@ -3219,33 +3337,37 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"Prometheus metrics endpoint scrape project metrics observability\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Prometheus metrics endpoint scrape project metrics\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", "title": "Metrics API with Grafana Cloud" } ], - "resultChars": 19943 + "resultChars": 20571 } ] }, "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-opus-5-no-skills/deploy-database-001-prometheus-metrics.json" }, { @@ -3281,7 +3403,7 @@ { "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." }, { "name": "WEATHER_API_KEY value is not committed to the repo", @@ -3296,7 +3418,7 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"edge functions environment variables secrets manage\", limit: 5) { nodes { title href content } } }", + "query": "{\n searchDocs(query: \"edge functions secrets environment variables manage\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", "hasContent": true, "pages": [ { @@ -3374,7 +3496,48 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"self-hosting docker environment variables secrets JWT\", limit: 8) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", + "title": "Configure Social Login (OAuth) Providers" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" + } + ], + "resultChars": 124775 + } + ] }, "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", @@ -3432,7 +3595,7 @@ { "name": "diagnosed and explained session revocation", "passed": true, - "judgeNotes": "The answer diagnoses the original flow as only soft-deleting public.profiles and not touching auth.users/sessions/refresh tokens. It implements real revocation by banning/soft-deleting the auth user and deleting refresh_tokens/sessions, plus RLS gating. It consistently explains JWT access tokens remain cryptographically valid until expiry for local validation, while its implemented RLS/session-existence check closes the Data API window. It also correctly distinguishes publishable frontend keys under anon/authenticated + RLS from secret/service_role backend-only keys that bypass RLS." + "judgeNotes": "Correctly diagnoses the unenforced soft delete, revokes sessions and refresh tokens, disables future authentication, closes stale-JWT Data API access through RLS, accurately explains residual JWT validity for local validation, and correctly distinguishes publishable frontend keys from secret server-only RLS-bypassing keys." } ], "skills": { @@ -3443,41 +3606,33 @@ "calls": [ { "source": "search_docs", - "query": "{\n banned: searchDocs(query: \"ban user banned_until revoke session delete user admin API\", limit: 4) {\n nodes { title href content }\n }\n keys: searchDocs(query: \"publishable key secret key legacy anon service_role API keys migration RLS\", limit: 6) {\n nodes { title href content }\n }\n}", + "query": "{ searchDocs(query: \"new API keys publishable key secret key legacy anon service_role RLS\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/auth/auth-anonymous", - "title": "Anonymous Sign-Ins" + "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", + "title": "Creating a Supabase client for SSR" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" }, { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", "title": "Build a User Management App with RedwoodJS" }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, { "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", "title": "Build a Social Auth App with Expo React Native" }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - }, { "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", "title": "Build a User Management App with SvelteKit" @@ -3487,458 +3642,28 @@ "title": "Build a User Management App with SolidJS" } ], - "resultChars": 245869 + "resultChars": 254082 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"publishable key secret key API keys\", limit: 3) { nodes { title href content } } }", - "hasContent": true, + "query": "{ searchDocs(query: \"delete user account revoke refresh token sign out all sessions admin deleteUser\", limit: 4) { nodes { title href } } }", + "hasContent": false, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/reference/swift/auth-admin-signout", + "title": "signOut()" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" - } - ], - "resultChars": 61983 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"sb_secret sb_publishable new API keys migration\", limit: 2) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" - } - ], - "resultChars": 29035 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"Understanding API keys publishable key anon role RLS\", limit: 1) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - } - ], - "resultChars": 13676 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"secret key bypasses Row Level Security service_role postgres role\", limit: 2) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/reference/javascript/auth-signout" } ], - "resultChars": 329 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"ban user ban_duration admin updateUserById\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-updateuserbyid" - }, - { - "url": "https://supabase.com/docs/reference/dart/auth-admin-updateuserbyid" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-updateuser" - } - ], - "resultChars": 3573 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"deleteUser soft delete admin\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" - }, - { - "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" - }, - { - "url": "https://supabase.com/docs/reference/swift/auth-admin-deleteuser", - "title": "deleteUser()" - } - ], - "resultChars": 1237 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"disable legacy anon service_role key dashboard rotate JWT secret\", limit: 2) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/rotating-anon-service-and-jwt-secrets-1Jq6yd", - "title": "Rotating Anon, Service, and JWT Secrets" - } - ], - "resultChars": 34590 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"JWT expiry access token lifetime sessions\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - }, - { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" - } - ], - "resultChars": 59617 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"auth.admin.signOut revoke sessions scope global\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/signout", - "title": "Signing out" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-signout" - } - ], - "resultChars": 5307 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"legacy API keys deprecation end of 2026 removal timeline\", limit: 2) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - } - ], - "resultChars": 45967 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"banned_until auth.users table columns\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/auth-mfa", - "title": "Multi-Factor Authentication" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-anonymous", - "title": "Anonymous Sign-Ins" - } - ], - "resultChars": 31852 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"delete account user edge function service role\", limit: 2) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", - "title": "Supabase for Platforms" - } - ], - "resultChars": 20425 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"do not modify auth schema managed by Supabase\", limit: 2) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/database/prisma/prisma-troubleshooting", - "title": "Troubleshooting prisma errors" - }, - { - "url": "https://supabase.com/docs/guides/auth/architecture", - "title": "Auth architecture" - } - ], - "resultChars": 16231 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"verifying a JWT from Supabase getClaims asymmetric local verification\", limit: 2) { nodes { title href } subsections: nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", - "title": "OAuth 2.1 Flows" - } - ], - "resultChars": 490 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"JSON Web Token JWT verifying revocation\", limit: 1) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" - } - ], - "resultChars": 14157 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"banned user cannot sign in ban\", limit: 3) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-email-passwordless", - "title": "Passwordless email logins" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-identity-linking", - "title": "Identity Linking" - } - ], - "resultChars": 392 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"cannot delete user foreign key constraint troubleshooting\", limit: 3) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0021_fkey_to_auth_unique", - "title": "Database Advisor: Lint 0021_fkey_to_auth_unique" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/cascade-deletes", - "title": "Cascade Deletes" - }, - { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" - } - ], - "resultChars": 468 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"user management managing users admin api\", limit: 3) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-refine", - "title": "Build a User Management App with Refine" - }, - { - "url": "https://supabase.com/docs/guides/auth/users", - "title": "Users" - } - ], - "resultChars": 406 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"Users guide auth users table permanent anonymous\", limit: 1) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/users", - "title": "Users" - } - ], - "resultChars": 11521 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"managing user data profiles trigger accessing user data\", limit: 1) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-angular", - "title": "Build a User Management App with Angular" - } - ], - "resultChars": 34746 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"signOut jwt scope admin server side revoke refresh tokens\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", - "title": "OAuth 2.1 Flows" - }, - { - "url": "https://supabase.com/docs/reference/javascript/oauth-server-revokegrant" - } - ], - "resultChars": 38073 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"JWT claims reference session_id is_anonymous fields\", limit: 1) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/jwt-fields", - "title": "JWT Claims Reference" - } - ], - "resultChars": 12679 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"shouldSoftDelete\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/data-deletion", - "title": "Deleting data and dropping objects safely" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/soft-deletes-with-supabase-js", - "title": "Implementing soft deletes with supabase-js" - } - ], - "resultChars": 12330 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"service role key never expose server side edge function admin client\", limit: 2) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - } - ], - "resultChars": 326 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"Data API PostgREST how requests are authorized JWT role\", limit: 2) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/roles", - "title": "Postgres Roles" - } - ], - "resultChars": 273 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"access token expiry setting jwt_exp configuration auth\", limit: 2) { nodes { title href } } }", - "hasContent": false, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/should-i-set-a-shorter-max-age-parameter-on-the-cookies-8sbF4V", - "title": "Should I set a shorter Max-Age parameter on the cookies?" - } - ], - "resultChars": 358 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"user_banned error code\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" - } - ], - "resultChars": 11900 - }, - { - "source": "search_docs", - "query": "{ error(code: \"user_banned\", service: AUTH) { code httpStatusCode message } }", - "hasContent": false, - "pages": [], - "resultChars": 280 - }, - { - "source": "search_docs", - "query": "{ a: error(code: \"session_not_found\", service: AUTH) { code message } b: error(code: \"user_not_found\", service: AUTH) { code message } c: error(code: \"refresh_token_not_found\", service: AUTH) { code message } d: error(code: \"refresh_token_already_used\", service: AUTH) { code message } e: error(code: \"session_expired\", service: AUTH) { code message } }", - "hasContent": false, - "pages": [], - "resultChars": 971 + "resultChars": 452 } ] }, @@ -3993,7 +3718,7 @@ { "name": "diagnosed missing publication membership", "passed": true, - "judgeNotes": "The answer correctly identifies that the channel can reach SUBSCRIBED while INSERT events are silent because public.orders was missing from the supabase_realtime publication. It fixes exactly that with ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, preserves courier_locations, keeps RLS/policies intact, and explicitly does not blame RLS or client code." + "judgeNotes": "Correctly identified orders missing from supabase_realtime, added only public.orders to the existing publication, and preserved RLS, policies, and courier_locations." } ], "skills": { @@ -4001,7 +3726,40 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"postgres_changes realtime publication table not receiving events\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/realtime/protocol", + "title": "Realtime Protocol" + }, + { + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" + }, + { + "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes", + "title": "Subscribing to Database Changes" + }, + { + "url": "https://supabase.com/docs/guides/realtime/benchmarks", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/replication/pipelines-faq", + "title": "Pipelines FAQ" + }, + { + "url": "https://supabase.com/docs/guides/database/replication/pipelines", + "title": "Set up Pipelines" + } + ], + "resultChars": 135761 + } + ] }, "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", @@ -4032,17 +3790,17 @@ { "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "judgeNotes": "The assistant clearly identified `image-transform` as the affected function and described the recurring pattern of eight HTTP 503 gateway failures spread through the morning of 2026-04-28, while distinguishing them from older billing-webhook 503s." + "judgeNotes": "Identified `image-transform` and documented all eight recurring HTTP 503 gateway failures from 07:00Z through 12:00Z on 2026-04-28, including the 90-minute repeating pattern." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": true, - "judgeNotes": "Attributes the recurring image-transform 503s to the gateway/platform layer, not function code, and grounds this in valid observations: 503s only in gateway logs with no runtime invocations, nearby successful invocations, unchanged deployment/version, and distinction from avatar-upload's function-level 500." + "judgeNotes": "Attributes the 503s to the upstream gateway/platform layer, supported by absent invocation logs, successful nearby invocations, unchanged deployment/version, and distinction from avatar-upload’s function-level 500." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "The assistant recommended multiple concrete next steps: investigate half-hour scheduled jobs/concurrency, query function_edge_logs for status>=500, check Edge Function limits/metrics, open a support ticket with timestamps, and examine avatar-upload error output." + "judgeNotes": "The assistant provided multiple concrete next steps, including opening a Supabase support ticket with specific gateway request IDs and timestamps, auditing 90-minute scheduled workloads, adding retry/backoff, and separately investigating the avatar-upload error." } ], "skills": { @@ -4108,7 +3866,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "Diagnosed RLS enabled with zero policies as the cause of empty Data API results, kept RLS enabled, and created authenticated-only owner-scoped SELECT and INSERT policies using auth.uid() with WITH CHECK for inserts." + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and created authenticated-only SELECT and INSERT policies scoped by user_id = auth.uid() using USING and WITH CHECK." } ], "skills": { @@ -4167,7 +3925,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "Avatar migration was applied through the Supabase CLI with `supabase db push` in action #19, showing `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration was reconciled by adding the local file `20240115000000_add_profile_bio.sql` in action #16, after which Supabase CLI migration list showed it matched remote (#17) and the subsequent `db push` succeeded. No disallowed direct-SQL mutation or prepared-statement workaround was used." + "judgeNotes": "`supabase db push` (#20) applied `20240220000000_add_avatar_url.sql` and finished successfully. The orphan bio migration was reconciled by adding `20240115000000_add_profile_bio.sql` locally (#18), then running the successful CLI push; the final migration list matched. Only read-only `psql` inspection was used; no workaround or direct SQL mutation occurred." } ], "skills": { @@ -4175,7 +3933,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Remote migration versions not found in local migrations directory db pull migration repair reverted\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/deployment/branching/troubleshooting", + "title": "Troubleshooting" + }, + { + "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", + "title": "Multiple SSO Providers" + }, + { + "url": "https://supabase.com/docs/reference/cli/supabase-migration-repair", + "title": "Repair the migration history table" + }, + { + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" + }, + { + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + } + ], + "resultChars": 69700 + } + ] }, "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", @@ -4342,7 +4129,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user 0ac704f8-596e-4f98-84c9-00595301873d, signUp returned {\"userId\":\"0ac704f8-596e-4f98-84c9-00595301873d\"}" + "notes": "db user 44e223c2-f7d3-4332-acac-ad83fe2c1a60, signUp returned {\"userId\":\"44e223c2-f7d3-4332-acac-ad83fe2c1a60\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -4357,7 +4144,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"0ac704f8-596e-4f98-84c9-00595301873d\"}" + "notes": "{\"userId\":\"44e223c2-f7d3-4332-acac-ad83fe2c1a60\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -4458,7 +4245,18 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "shell_fetch", + "query": "curl -s https://supabase.com/changelog.md | head -100", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 5440 + } + ] }, "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", @@ -4510,7 +4308,8 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { @@ -4554,12 +4353,12 @@ { "name": "cron command enqueues to the 'tasks' queue", "passed": true, - "notes": "queue depth 0 -> 1" + "notes": "queue depth 1 -> 2" }, { "name": "process-tasks function drains the queue", "passed": true, - "notes": "function removed the seeded message (id 3) from the queue" + "notes": "function removed the seeded message (id 4) from the queue" } ], "skills": { @@ -4568,102 +4367,99 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"cron.schedule pgmq send queue example\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"pgmq queue send cron schedule enqueue\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, { "url": "https://supabase.com/docs/guides/queues/pgmq", "title": "PGMQ Extension" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" } ], "resultChars": 35564 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions read from queue pgmq delete message worker\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"pg_cron schedule cron.schedule syntax local development\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" + "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", + "title": "Building an MCP Server with mcp-lite" }, { - "url": "https://supabase.com/docs/guides/functions/recursive-functions", - "title": "Recursive / Nested Function Calls" + "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", + "title": "pg_cron debugging guide" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/cron/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", - "title": "Backup and Restore using the CLI" + "url": "https://supabase.com/docs/guides/cron/install", + "title": "Install" } ], - "resultChars": 93380 + "resultChars": 40484 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions default environment variables SUPABASE_SERVICE_ROLE_KEY SUPABASE_URL automatically available\", limit: 3) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"schedule edge function with cron vault secrets project_url service_role_key local development kong\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" } ], - "resultChars": 28165 + "resultChars": 16116 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Queues schedule cron job to process messages Edge Function example\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function deno serve supabase-js create client service role example queues pgmq\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" + "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", + "title": "Serverless Drivers" }, { - "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook", - "title": "Send Email Hook" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", + "title": "Integrating with Supabase Database (Postgres)" }, { - "url": "https://supabase.com/docs/guides/functions/examples/slack-bot-mention", - "title": "Slack Bot Mention Edge Function" + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" } ], - "resultChars": 81933 + "resultChars": 33382 } ] }, @@ -4726,16 +4522,14 @@ "supabase", "supabase-postgres-best-practices" ], - "loaded": [ - "supabase" - ] + "loaded": [] }, "docs": { "calls": [] }, "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-sonnet-5/build-dataapi-001-relational-report.json" }, { @@ -4801,7 +4595,7 @@ }, "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "claude-code-sonnet-5/build-dataapi-002-restock-alert-report.json" }, { @@ -4970,17 +4764,17 @@ { "name": "user with JWT reads only their own rows", "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"9dfb45f7-a584-480f-9567-31a82085a4db\",\"metric\":\"steps_a_msj1bz52\",\"value\":111}]}" + "notes": "status 200: {\"data\":[{\"user_id\":\"9d7043c0-60db-4949-a5a5-db85d75b966a\",\"metric\":\"steps_a_mt93otku\",\"value\":111}]}" }, { "name": "user cannot read another user's rows by passing user_id", "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"9dfb45f7-a584-480f-9567-31a82085a4db\",\"metric\":\"steps_a_msj1bz52\",\"value\":111}]}" + "notes": "status 200: {\"data\":[{\"user_id\":\"9d7043c0-60db-4949-a5a5-db85d75b966a\",\"metric\":\"steps_a_mt93otku\",\"value\":111}]}" }, { "name": "service key bypasses RLS to read the target user's rows", "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"7ef32f13-71a0-4757-84bc-00f9632c3443\",\"metric\":\"steps_b_msj1bz52\",\"value\":222}]}" + "notes": "status 200: {\"data\":[{\"user_id\":\"e1030fdc-33bc-4692-aea2-9b3fe67f2d9b\",\"metric\":\"steps_b_mt93otku\",\"value\":222}]}" }, { "name": "non-service key is not granted service access", @@ -5014,9 +4808,29 @@ }, "docs": { "calls": [ + { + "source": "shell_fetch", + "query": "curl -s https://supabase.com/changelog.md | head -200", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 11519 + }, + { + "source": "shell_fetch", + "query": "curl -s https://supabase.com/changelog/45702-developer-update-may-2026.md", + "pages": [ + { + "url": "https://supabase.com/changelog/45702-developer-update-may-2026.md" + } + ], + "resultChars": 6160 + }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions environment variables SUPABASE_URL SUPABASE_SERVICE_ROLE_KEY SUPABASE_ANON_KEY secret key\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Edge Functions environment variables SUPABASE_URL SUPABASE_ANON_KEY SUPABASE_SERVICE_ROLE_KEY\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -5038,13 +4852,21 @@ { "url": "https://supabase.com/docs/guides/functions/storage-caching", "title": "Integrating with Supabase Storage" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" } ], - "resultChars": 36932 + "resultChars": 53817 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"new API keys publishable secret key edge functions verify_jwt\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"new API keys publishable secret key sb_publishable sb_secret\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -5052,411 +4874,269 @@ "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", + "title": "Build a Social Auth App with Expo React Native" }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", + "title": "Build a User Management App with SvelteKit" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-solidjs", + "title": "Build a User Management App with SolidJS" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" }, { "url": "https://supabase.com/docs/guides/auth/signing-keys", "title": "JWT Signing Keys" } ], - "resultChars": 70715 + "resultChars": 258482 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Securing Edge Functions auth modes user secret publishable multiple auth withSupabase array\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"verify_jwt config.toml edge functions apikey header\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/functions/deploy", + "title": "Deploy to Production" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" + }, + { + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { "url": "https://supabase.com/docs/guides/getting-started/api-keys", "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" } ], - "resultChars": 45970 + "resultChars": 64415 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Authorization headers edge functions apikey header verify_jwt disable\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"@supabase/server package\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ + { + "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", + "title": "Which package to use" + }, + { + "url": "https://supabase.com/docs/guides/auth/server-side", + "title": "Server-Side Rendering" + }, { "url": "https://supabase.com/docs/guides/functions/auth", "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" + "url": "https://supabase.com/docs/guides/api/rest/client-libs", + "title": "Client Libraries" }, { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" }, { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", + "title": "Serverless Drivers" }, { - "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook", - "title": "Send Email Hook" + "url": "https://supabase.com/docs/guides/api/rest/generating-types", + "title": "Generating TypeScript Types" } ], - "resultChars": 95133 + "resultChars": 76008 }, { - "source": "search_docs", - "query": "{ searchDocs(query: \"combining auth modes user secret verify_jwt false config.toml example\", limit: 3) { nodes { title href content } } }", + "source": "web_fetch", + "query": "List any entries related to: new API keys system (publishable/secret keys), @supabase/server package, Edge Functions environment variables changes, verify_jwt changes. Include dates.", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/development-tips", - "title": "Development tips" - }, - { - "url": "https://supabase.com/docs/guides/functions/deploy", - "title": "Deploy to Production" - }, - { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 24076 + "resultChars": 1206 }, { - "source": "search_docs", - "query": "{ searchDocs(query: \"@supabase/server package version pin npm install deno.json import map\", limit: 3) { nodes { title href content } } }", - "hasContent": true, + "source": "shell_fetch", + "query": "curl -s https://supabase.com/docs/guides/functions/secrets.md", "pages": [ { - "url": "https://supabase.com/docs/guides/security/npm-security", - "title": "Securing npm installs" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", - "title": "Building an MCP Server with mcp-lite" - }, - { - "url": "https://supabase.com/docs/guides/functions/dependencies", - "title": "Managing dependencies" + "url": "https://supabase.com/docs/guides/functions/secrets.md" } ], - "resultChars": 34326 + "resultChars": 5105 }, { - "source": "web_search", - "query": "\"failed to determine entrypoint\" supabase edge-runtime worker boot error", - "pages": [], - "resultChars": 2031 + "source": "shell_fetch", + "query": "curl -s https://supabase.com/docs/guides/api/api-keys.md", + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/api-keys.md" + } + ], + "resultChars": 14 }, { - "source": "web_search", - "query": "supabase cli issue 4190 podman edge functions serve entrypoint bind mount", - "hasContent": false, + "source": "shell_fetch", + "query": "curl -s https://supabase.com/docs/guides/functions/secrets.md | grep -i -A5 -B5 \"jwt\\|verify_jwt\\|apikey\"", "pages": [ { - "url": "https://supabase.com/docs/guides/functions/troubleshooting", - "title": "Supabase Docs | Edge Functions Troubleshooting" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/issues-serving-edge-functions-locally", - "title": "Supabase Docs | Troubleshooting | Issues serving Edge Functions locally" - }, + "url": "https://supabase.com/docs/guides/functions/secrets.md" + } + ], + "resultChars": 1042 + }, + { + "source": "shell_fetch", + "query": "curl -sL https://supabase.com/docs/guides/api/api-keys.md | head -c 6000", + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration | Supabase Docs" - }, + "url": "https://supabase.com/docs/guides/api/api-keys.md" + } + ], + "resultChars": 5996 + }, + { + "source": "shell_fetch", + "query": "curl -s \"https://supabase.com/docs/guides/functions/config.md\" | head -c 8000", + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/development-tips", - "title": "Development tips | Supabase Docs" + "url": "https://supabase.com/docs/guides/functions/config.md" } ], - "resultChars": 2355 + "resultChars": 8000 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"Issues serving Edge Functions locally troubleshooting entrypoint bind mount docker context\", limit: 3) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"verify_jwt Edge Functions config.toml functions section disable JWT verification apikey\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/issues-serving-edge-functions-locally", - "title": "Issues serving Edge Functions locally" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" + "url": "https://supabase.com/docs/guides/functions/deploy", + "title": "Deploy to Production" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" - } - ], - "resultChars": 45231 - } - ] - }, - "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", - "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-sonnet-5/build-functions-005-dual-auth-user-secret.json" - }, - { - "experiment": "claude-code-sonnet-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "build-rls-003-org-roles-permissions", - "stage": "build", - "product": [ - "database", - "auth" - ], - "topic": [ - "rls", - "security" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "RLS enabled on documents", - "passed": true - }, - { - "name": "viewer sees only documents in their org", - "passed": true - }, - { - "name": "viewer cannot insert", - "passed": true - }, - { - "name": "editor can insert own org document", - "passed": true - }, - { - "name": "editor can update own document", - "passed": true - }, - { - "name": "editor cannot update another user's document", - "passed": true - }, - { - "name": "editor cannot delete another user's document", - "passed": true - }, - { - "name": "admin can update any document in their org", - "passed": true - }, - { - "name": "admin can delete any document in their org", - "passed": true - }, - { - "name": "admin cannot affect another org", - "passed": true - }, - { - "name": "WITH CHECK blocks editor from moving document to another org", - "passed": true - }, - { - "name": "editor can still see their own org's roster", - "passed": true - }, - { - "name": "cannot see another org's membership roster", - "passed": true - }, - { - "name": "a viewer role in one org doesn't grant admin power in another org", - "passed": true - }, - { - "name": "multi-org user can act as admin in the org where they hold that role", - "passed": true - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [] - }, - "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", - "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5/build-rls-003-org-roles-permissions.json" - }, - { - "experiment": "claude-code-sonnet-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "build-storage-001-private-bucket-access", - "stage": "build", - "product": [ - "storage", - "database" - ], - "topic": [ - "rls", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "bucket user-files exists", - "passed": true - }, - { - "name": "bucket user-files is private", - "passed": true - }, - { - "name": "RLS still enabled on storage.objects", - "passed": true - }, - { - "name": "user A lists only own files", - "passed": true, - "notes": "saw: 019fdc8d-2b1c-70b8-a74d-7a4097cf4fa6/receipt-alpha.pdf, 019fdc8d-2b1c-70b8-a74d-7a4097cf4fa6/receipt-beta.pdf" - }, - { - "name": "user B cannot read user A files", - "passed": true - }, - { - "name": "anon reads no files", - "passed": true - }, - { - "name": "user A can upload into own folder", - "passed": true - }, - { - "name": "user B cannot upload into user A folder", - "passed": true - }, - { - "name": "configured private per-user storage access", - "passed": true, - "judgeNotes": "The answer creates a private user-files bucket, defines authenticated SELECT and INSERT policies on storage.objects scoped to bucket_id and the user's UID folder with WITH CHECK for uploads, keeps RLS enabled, avoids public/anon/service-role pitfalls, and provides supabase-js createSignedUrl with an expiry for temporary sharing." - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase" - ] - }, - "docs": { - "calls": [ + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + } + ], + "resultChars": 28146 + }, { "source": "search_docs", - "query": "{ searchDocs(query: \"storage RLS policy owner folder path user id\", limit: 5) { nodes { ... on Guide { title href content } } } }", + "query": "{ searchDocs(query: \"Securing Edge Functions user JWT RLS service role @supabase/server createClient scoped user\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/storage/security/ownership", - "title": "Ownership" + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { "url": "https://supabase.com/docs/guides/auth/third-party/clerk", "title": "Clerk" }, { - "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", - "title": "Column Level Security" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" } ], - "resultChars": 61599 + "resultChars": 66262 }, { - "source": "search_docs", - "query": "{ searchDocs(query: \"createSignedUrl expiring share link\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", - "hasContent": true, + "source": "shell_fetch", + "query": "curl -s https://supabase.com/docs/guides/functions/auth.md", "pages": [ { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" - }, - { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" - }, - { - "url": "https://supabase.com/docs/reference/dart/file-buckets-createsignedurl" - }, + "url": "https://supabase.com/docs/guides/functions/auth.md" + } + ], + "resultChars": 7274 + }, + { + "source": "shell_fetch", + "query": "echo \"=== auth.md ===\"; curl -s https://supabase.com/docs/guides/functions/auth.md; echo; echo \"=== END auth.md ===\"", + "pages": [ { - "url": "https://supabase.com/docs/guides/storage/serving/downloads", - "title": "Serving assets from Storage" - }, + "url": "https://supabase.com/docs/guides/functions/auth.md" + } + ], + "resultChars": 7311 + }, + { + "source": "shell_fetch", + "query": "echo \"=== auth-headers.md ===\"; curl -s https://supabase.com/docs/guides/functions/auth-headers.md; echo; echo \"=== END ===\"", + "pages": [ { - "url": "https://supabase.com/docs/reference/csharp/storage-from-createsignedurl", - "title": "From().CreateSignedUrl()" + "url": "https://supabase.com/docs/guides/functions/auth-headers.md" } ], - "resultChars": 7873 + "resultChars": 3367 } ] }, - "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", - "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", + "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/build-storage-001-private-bucket-access.json" + "sourcePath": "claude-code-sonnet-5/build-functions-005-dual-auth-user-secret.json" }, { "experiment": "claude-code-sonnet-5", @@ -5467,248 +5147,95 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-tests-001-rls-tenant-isolation", + "eval": "build-rls-003-org-roles-permissions", "stage": "build", "product": [ - "database" + "database", + "auth" ], "topic": [ - "tests", - "rls" + "rls", + "security" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "pgTAP test file(s) written under supabase/tests/", - "passed": true, - "notes": "1 file(s): supabase/tests/tenant_isolation_test.sql" + "name": "RLS enabled on documents", + "passed": true }, { - "name": "pgTAP isolation tests ran and pass", - "passed": true, - "notes": "6 passed, 4 failed" + "name": "viewer sees only documents in their org", + "passed": true }, { - "name": "agent correctly identifies the posts isolation bug from test results", - "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as having a broken tenant isolation SELECT policy, specifically that members of any org can read posts from other orgs, and grounds this in pgTAP test 5 failing. It treats test results as authoritative and contrasts `posts` with `notes`, which passed isolation tests. It also notes additional membership-table issues, but does not blame `notes` instead of `posts`." - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [] - }, - "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", - "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5/build-tests-001-rls-tenant-isolation.json" - }, - { - "experiment": "claude-code-sonnet-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "build-vectors-001-rag-with-permissions", - "stage": "build", - "product": [ - "database", - "vectors" - ], - "topic": [ - "sql", - "rls" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ + "name": "viewer cannot insert", + "passed": true + }, { - "name": "document_sections.embedding is vector(384)", - "passed": true, - "notes": "vector(384)" + "name": "editor can insert own org document", + "passed": true }, { - "name": "HNSW index on the embedding column", - "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "name": "editor can update own document", + "passed": true }, { - "name": "index operator class matches the search operator", - "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "name": "editor cannot update another user's document", + "passed": true }, { - "name": "user A search returns only own sections, best match first", + "name": "editor cannot delete another user's document", "passed": true }, { - "name": "user B search returns only own sections, best match first", + "name": "admin can update any document in their org", "passed": true }, { - "name": "user A reads only own sections through the API", + "name": "admin can delete any document in their org", "passed": true }, { - "name": "user A reads only own documents through the API", + "name": "admin cannot affect another org", "passed": true - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{ searchDocs(query: \"semantic search edge functions pgvector gte-small match_document_sections\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", - "title": "Semantic Search" - }, - { - "url": "https://supabase.com/docs/guides/database/full-text-search", - "title": "Full Text Search" - }, - { - "url": "https://supabase.com/docs/guides/ai/hybrid-search", - "title": "Hybrid search" - } - ], - "resultChars": 61699 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"vector extension schema best practice extensions schema\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" - }, - { - "url": "https://supabase.com/docs/guides/realtime/getting_started", - "title": "Getting Started with Realtime" - }, - { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" - } - ], - "resultChars": 46198 - } - ] - }, - "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", - "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5/build-vectors-001-rag-with-permissions.json" - }, - { - "experiment": "claude-code-sonnet-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "deploy-database-001-prometheus-metrics", - "stage": "deploy", - "product": [ - "database" - ], - "topic": [ - "observability" - ], - "suite": "benchmark", - "interface": "cli", - "passed": true, - "checks": [ + }, { - "name": "preserved existing app scrape job", + "name": "WITH CHECK blocks editor from moving document to another org", "passed": true }, { - "name": "configured the Supabase Metrics API scrape correctly", - "passed": true, - "judgeNotes": "Meets requirements: HTTPS Supabase Metrics API scrape at the correct path with project target, basic_auth using password_file, app scrape preserved, and docker-compose mounts the secrets directory containing the password file." + "name": "editor can still see their own org's roster", + "passed": true }, { - "name": "documented live deployment and verification steps", - "passed": true, - "judgeNotes": "README includes steps to create/use a Supabase Secret API key, place it in the mounted secret file matching password_file, reload/restart Prometheus via Compose or lifecycle reload, and verify via Prometheus targets showing the supabase job UP." + "name": "cannot see another org's membership roster", + "passed": true + }, + { + "name": "a viewer role in one org doesn't grant admin power in another org", + "passed": true + }, + { + "name": "multi-org user can act as admin in the org where they hold that role", + "passed": true } ], "skills": { "available": [ "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase" - ] + "supabase-postgres-best-practices" + ], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{ searchDocs(query: \"project metrics prometheus endpoint observability\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" - }, - { - "url": "https://supabase.com/docs/guides/platform/read-replicas", - "title": "Read Replicas" - } - ], - "resultChars": 29057 - } - ] + "calls": [] }, - "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", - "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", + "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/deploy-database-001-prometheus-metrics.json" + "sourcePath": "claude-code-sonnet-5/build-rls-003-org-roles-permissions.json" }, { "experiment": "claude-code-sonnet-5", @@ -5719,35 +5246,57 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "deploy-functions-001-edge-function-secrets", - "stage": "deploy", + "eval": "build-storage-001-private-bucket-access", + "stage": "build", "product": [ - "edge-functions" + "storage", + "database" ], "topic": [ - "security" + "rls", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "WEATHER_API_KEY is set as a Function secret on the project", + "name": "bucket user-files exists", "passed": true }, { - "name": "the weather function is deployed to the project", - "passed": true, - "notes": "status ACTIVE" + "name": "bucket user-files is private", + "passed": true }, { - "name": "the weather function reads WEATHER_API_KEY from the environment", + "name": "RLS still enabled on storage.objects", + "passed": true + }, + { + "name": "user A lists only own files", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "notes": "saw: 01a03a85-d1d2-735a-8843-dbd30323f57e/receipt-alpha.pdf, 01a03a85-d1d2-735a-8843-dbd30323f57e/receipt-beta.pdf" }, { - "name": "WEATHER_API_KEY value is not committed to the repo", + "name": "user B cannot read user A files", + "passed": true + }, + { + "name": "anon reads no files", + "passed": true + }, + { + "name": "user A can upload into own folder", + "passed": true + }, + { + "name": "user B cannot upload into user A folder", "passed": true + }, + { + "name": "configured private per-user storage access", + "passed": true, + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT policies, RLS retained, and short-lived createSignedUrl sharing code are all provided." } ], "skills": { @@ -5763,66 +5312,106 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions environment variables secrets Deno.env deploy\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"storage access control RLS policies user folder\", limit: 5) { nodes { ... on Guide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", - "title": "Inspecting edge function environment variables" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" }, { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/storage/production/scaling", + "title": "Storage Optimizations" }, { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", - "title": "Testing and linting" + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" } ], - "resultChars": 38791 + "resultChars": 62447 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"management API invoke edge function endpoint\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"createSignedUrl storage share temporary link\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/architecture", - "title": "Edge Functions Architecture" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" }, { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-functions", - "title": "Manage Supabase Edge functions" + "url": "https://supabase.com/docs/reference/dart/file-buckets-createsignedurl" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" + } + ], + "resultChars": 7891 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"storage.foldername helper function policy user access own folder example\", limit: 5) { nodes { ... on Guide { title href content } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" } ], - "resultChars": 66572 + "resultChars": 8659 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"create bucket SQL insert into storage.buckets migration\", limit: 5) { nodes { ... on Guide { title href content } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/copy-from-platform-s3", + "title": "Copy Storage Objects from Platform" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", + "title": "Backup and Restore using the CLI" + }, + { + "url": "https://supabase.com/docs/guides/storage/quickstart", + "title": "Storage Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-react", + "title": "Build a User Management App with Ionic React" + }, + { + "url": "https://supabase.com/docs/guides/storage/buckets/creating-buckets", + "title": "Creating Buckets" + } + ], + "resultChars": 81714 } ] }, - "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", - "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", + "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/deploy-functions-001-edge-function-secrets.json" + "sourcePath": "claude-code-sonnet-5/build-storage-001-private-bucket-access.json" }, { "experiment": "claude-code-sonnet-5", @@ -5833,106 +5422,33 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "deploy-self-hosting-001-docker-compose", - "stage": "deploy", + "eval": "build-tests-001-rls-tenant-isolation", + "stage": "build", "product": [ - "database", - "auth", - "storage" + "database" ], "topic": [ - "self-hosting" + "tests", + "rls" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", - "passed": true - }, - { - "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", - "passed": true - }, - { - "name": "secrets rotated off the shipped defaults", - "passed": true - }, - { - "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", - "passed": true - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase" - ] - }, - "docs": { - "calls": [] - }, - "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", - "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5/deploy-self-hosting-001-docker-compose.json" - }, - { - "experiment": "claude-code-sonnet-5", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "investigate-auth-001-deleted-user-access", - "stage": "investigate", - "product": [ - "auth" - ], - "topic": [ - "security", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": false, - "checks": [ - { - "name": "victim session active before delete-account", - "passed": true - }, - { - "name": "delete_account flow ran for the victim", - "passed": true - }, - { - "name": "delete-account revokes the user's sessions", + "name": "pgTAP test file(s) written under supabase/tests/", "passed": true, - "notes": "sessions left: 0" - }, - { - "name": "deleted user's refresh token is rejected", - "passed": true - }, - { - "name": "deleted user cannot sign back in", - "passed": false, - "notes": "deleted account can still sign in" + "notes": "1 file(s): supabase/tests/database/tenant_isolation.sql" }, { - "name": "other users keep their sessions and access", - "passed": true + "name": "pgTAP isolation tests ran and pass", + "passed": true, + "notes": "6 passed, 4 failed" }, { - "name": "diagnosed and explained session revocation", + "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The answer identifies the soft-delete-only bug, implements real revocation by deleting auth.sessions and banning the auth user, adds RLS checks to close the data-access stale-JWT window, and consistently explains that stateless JWTs remain locally valid until expiry. It also correctly distinguishes frontend publishable/anon keys from server-only secret/service_role keys and notes secret bypasses RLS." + "judgeNotes": "Correctly identifies `posts` as having the tenant-isolation flaw, explains the missing org_id correlation, and grounds the conclusion in the pgTAP failures while recognizing `notes` isolation passes." } ], "skills": { @@ -5941,16 +5457,16 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase-postgres-best-practices" ] }, "docs": { - "calls": [] - }, - "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", - "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-sonnet-5/investigate-auth-001-deleted-user-access.json" + "calls": [] + }, + "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", + "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5/build-tests-001-rls-tenant-isolation.json" }, { "experiment": "claude-code-sonnet-5", @@ -5961,44 +5477,50 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "investigate-realtime-001-subscribed-no-events", - "stage": "investigate", + "eval": "build-vectors-001-rag-with-permissions", + "stage": "build", "product": [ - "realtime", - "database" + "database", + "vectors" ], "topic": [ - "sdk" + "sql", + "rls" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "orders table added to supabase_realtime publication", - "passed": true + "name": "document_sections.embedding is vector(384)", + "passed": true, + "notes": "vector(384)" }, { - "name": "courier_locations still in supabase_realtime publication", - "passed": true + "name": "HNSW index on the embedding column", + "passed": true, + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { - "name": "publication still publishes INSERT events", + "name": "index operator class matches the search operator", + "passed": true, + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + }, + { + "name": "user A search returns only own sections, best match first", "passed": true }, { - "name": "RLS still enabled on orders", + "name": "user B search returns only own sections, best match first", "passed": true }, { - "name": "staff can still read orders through RLS", - "passed": true, - "notes": "authenticated sees 2 of 2 orders" + "name": "user A reads only own sections through the API", + "passed": true }, { - "name": "diagnosed missing publication membership", - "passed": true, - "judgeNotes": "The assistant correctly identified the root cause as orders missing from the supabase_realtime publication despite SUBSCRIBED status, added only public.orders to the existing publication, preserved courier_locations/RLS/policies, and did not blame or alter client code, RLS, grants, or networking." + "name": "user A reads only own documents through the API", + "passed": true } ], "skills": { @@ -6007,16 +5529,38 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"match_documents function pgvector search_path empty vector similarity\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, + { + "url": "https://supabase.com/docs/guides/ai/vector-columns", + "title": "Vector columns" + }, + { + "url": "https://supabase.com/docs/guides/storage/vector/querying-vectors", + "title": "Querying Vectors" + } + ], + "resultChars": 44654 + } + ] }, - "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", - "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", + "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", + "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/investigate-realtime-001-subscribed-no-events.json" + "sourcePath": "claude-code-sonnet-5/build-vectors-001-rag-with-permissions.json" }, { "experiment": "claude-code-sonnet-5", @@ -6027,32 +5571,31 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "investigate-reliability-003-edge-function-5xx-correlation", - "stage": "investigate", + "eval": "deploy-database-001-prometheus-metrics", + "stage": "deploy", "product": [ - "edge-functions" + "database" ], "topic": [ "observability" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "identified image-transform and the recurring 503 pattern", - "passed": true, - "judgeNotes": "Identified image-transform as the main affected function and described the recurring HTTP 503 pattern across the 2026-04-28 morning window, including the eight gateway failures from about 07:00Z to 12:00Z. Also correctly distinguished older billing-webhook 503s as unrelated." + "name": "preserved existing app scrape job", + "passed": true }, { - "name": "attributed recurring 503s to gateway/platform layer, not function code", + "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "judgeNotes": "Attributes image-transform 503s to upstream gateway/platform rejection rather than handler code, grounded in missing edge-function runtime logs for 503s while 200s appear, and distinguishes avatar-upload's runtime 500 as a separate function-level error." + "judgeNotes": "Meets all requirements: HTTPS Supabase target and path, Basic Auth via password_file, matching read-only secret mount, and preserved app scrape." }, { - "name": "recommended a concrete next step", + "name": "documented live deployment and verification steps", "passed": true, - "judgeNotes": "The assistant provided multiple concrete actionable next steps, including instrumenting memory/input sizes, checking for a recurring scheduler/batch job, adding retry/backoff, investigating the separate avatar-upload stack trace, and considering architectural changes for heavy image processing." + "judgeNotes": "README provides correct hosted Metrics API endpoint/auth, Secret API key creation and matching secret file placement, project-ref replacement, Prometheus reload, and concrete verification via Targets or direct authenticated curl." } ], "skills": { @@ -6065,12 +5608,41 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"Prometheus metrics endpoint project observability\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" + }, + { + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" + } + ], + "resultChars": 20571 + } + ] }, - "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", - "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", + "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/investigate-reliability-003-edge-function-5xx-correlation.json" + "sourcePath": "claude-code-sonnet-5/deploy-database-001-prometheus-metrics.json" }, { "experiment": "claude-code-sonnet-5", @@ -6081,49 +5653,35 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-dataapi-001-empty-results", - "stage": "resolve", + "eval": "deploy-functions-001-edge-function-secrets", + "stage": "deploy", "product": [ - "data-api", - "database", - "auth" + "edge-functions" ], "topic": [ - "rls", - "sdk" + "security" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "RLS still enabled on bookmarks", - "passed": true - }, - { - "name": "user A reads own bookmarks", - "passed": true - }, - { - "name": "user B cannot read user A bookmarks", + "name": "WEATHER_API_KEY is set as a Function secret on the project", "passed": true }, { - "name": "anon reads no bookmarks", - "passed": true + "name": "the weather function is deployed to the project", + "passed": true, + "notes": "status ACTIVE" }, { - "name": "user A can save a new bookmark", - "passed": true + "name": "the weather function reads WEATHER_API_KEY from the environment", + "passed": true, + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." }, { - "name": "user B cannot insert a bookmark as user A", + "name": "WEATHER_API_KEY value is not committed to the repo", "passed": true - }, - { - "name": "diagnosed RLS and added owner-scoped policies", - "passed": true, - "judgeNotes": "The assistant correctly diagnosed RLS enabled with no policies causing deny-all Data API results, kept RLS enabled, created authenticated SELECT and INSERT policies scoped to user_id = auth.uid() with WITH CHECK for insert, and verified behavior." } ], "skills": { @@ -6136,12 +5694,37 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"edge function environment variables secrets Deno.env\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/functions/unit-test", + "title": "Testing your Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + } + ], + "resultChars": 27596 + } + ] }, - "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", - "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", + "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", + "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/resolve-dataapi-001-empty-results.json" + "sourcePath": "claude-code-sonnet-5/deploy-functions-001-edge-function-secrets.json" }, { "experiment": "claude-code-sonnet-5", @@ -6152,42 +5735,35 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-database-001-migration-history-mismatch", - "stage": "resolve", + "eval": "deploy-self-hosting-001-docker-compose", + "stage": "deploy", "product": [ - "database" + "database", + "auth", + "storage" ], "topic": [ - "migrations" + "self-hosting" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "the avatar_url column is applied on the hosted profiles table", - "passed": true - }, - { - "name": "migration 20240220000000 is recorded in the remote history", + "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", "passed": true }, { - "name": "remote migration history matches local migration files", + "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", "passed": true }, { - "name": "local migrations are a valid reconciled sequence", + "name": "secrets rotated off the shipped defaults", "passed": true }, { - "name": "production profile data is intact (not reset)", + "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", "passed": true - }, - { - "name": "the avatar migration and history reconciliation were done via the Supabase CLI", - "passed": true, - "judgeNotes": "Applied avatar_url via `supabase db push` in #11, which showed `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` Reconciled the orphan bio migration by adding local file `20240115000000_add_profile_bio.sql` in #9, after which `supabase migration list` matched local/remote and `db push` proceeded. No disallowed workaround or direct mutation observed; psql usage was read-only inspection." } ], "skills": { @@ -6200,12 +5776,24 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "Give me the full instructions for setting up self-hosted Supabase with Docker: which files to clone/create (docker-compose.yml, .env, volumes/ layout), how to generate JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, POSTGRES_PASSWORD, dashboard credentials, and any other secrets. Include the exact repo path within supabase/supabase that contains the docker setup.", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/docker.md" + } + ], + "resultChars": 2490 + } + ] }, - "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", - "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", + "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/resolve-database-001-migration-history-mismatch.json" + "sourcePath": "claude-code-sonnet-5/deploy-self-hosting-001-docker-compose.json" }, { "experiment": "claude-code-sonnet-5", @@ -6216,39 +5804,48 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-performance-001-slow-query-cpu-spike", - "stage": "resolve", + "eval": "investigate-auth-001-deleted-user-access", + "stage": "investigate", "product": [ - "database" + "auth" ], "topic": [ - "observability", - "sql" + "security", + "sdk" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "inspected pg_stat_statements for query performance", + "name": "victim session active before delete-account", + "passed": true + }, + { + "name": "delete_account flow ran for the victim", + "passed": true + }, + { + "name": "delete-account revokes the user's sessions", + "passed": true, + "notes": "sessions left: 0" + }, + { + "name": "deleted user's refresh token is rejected", "passed": true }, { - "name": "ran EXPLAIN on the expensive query", + "name": "deleted user cannot sign back in", "passed": true }, { - "name": "created index covering user_id and created_at", + "name": "other users keep their sessions and access", "passed": true }, { - "name": "query plan uses an index and avoids sequential scan", + "name": "diagnosed and explained session revocation", "passed": true, - "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" - }, - { - "name": "inserts still work", - "passed": true + "judgeNotes": "Correctly diagnoses the ineffective soft delete, implements auth-user/session removal, handles stale JWTs consistently with live RLS checks, and accurately distinguishes frontend publishable keys from server-only RLS-bypassing secret keys." } ], "skills": { @@ -6257,17 +5854,45 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"publishable key secret key migrate from anon and service_role API keys\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", + "title": "Supabase for Platforms" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", + "title": "Build a User Management App with RedwoodJS" + } + ], + "resultChars": 107177 + } + ] }, - "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", - "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5/resolve-performance-001-slow-query-cpu-spike.json" + "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", + "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5/investigate-auth-001-deleted-user-access.json" }, { "experiment": "claude-code-sonnet-5", @@ -6278,55 +5903,44 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-security-002-rls-cross-tenant-leak", - "stage": "resolve", + "eval": "investigate-realtime-001-subscribed-no-events", + "stage": "investigate", "product": [ - "database", - "auth" + "realtime", + "database" ], "topic": [ - "rls", - "security" + "sdk" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "RLS enabled on notes", - "passed": true - }, - { - "name": "tenant A sees only org A notes", - "passed": true - }, - { - "name": "tenant B cannot read org A notes", - "passed": true - }, - { - "name": "tenant A author can update own note", + "name": "orders table added to supabase_realtime publication", "passed": true }, { - "name": "tenant B cannot update org A note", + "name": "courier_locations still in supabase_realtime publication", "passed": true }, { - "name": "tenant B author can delete own note", + "name": "publication still publishes INSERT events", "passed": true }, { - "name": "tenant B cannot delete org A note", + "name": "RLS still enabled on orders", "passed": true }, { - "name": "tenant A can insert note in own org", - "passed": true + "name": "staff can still read orders through RLS", + "passed": true, + "notes": "authenticated sees 2 of 2 orders" }, { - "name": "tenant B cannot insert into org A", - "passed": true + "name": "diagnosed missing publication membership", + "passed": true, + "judgeNotes": "Correctly identified missing publication membership as the root cause and added public.orders to the existing supabase_realtime publication without altering RLS, policies, or courier_locations." } ], "skills": { @@ -6341,171 +5955,149 @@ "docs": { "calls": [] }, - "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", - "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", + "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5/resolve-security-002-rls-cross-tenant-leak.json" + "sourcePath": "claude-code-sonnet-5/investigate-realtime-001-subscribed-no-events.json" }, { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", + "experiment": "claude-code-sonnet-5", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "claude-code", "modelProvider": "anthropic", "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-auth-001-email-password-flow", - "stage": "build", + "eval": "investigate-reliability-003-edge-function-5xx-correlation", + "stage": "investigate", "product": [ - "auth", - "database" + "edge-functions" ], "topic": [ - "sdk", - "rls" + "observability" ], "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", - "passed": true, + "interface": "mcp", + "passed": false, "checks": [ { - "name": "auth module loads and the driver completes", - "passed": true, - "notes": "driver produced a result" - }, - { - "name": "signUp creates the account and returns its user id", - "passed": true, - "notes": "db user 863566c0-fe1b-4264-9906-53f26c545be8, signUp returned {\"userId\":\"863566c0-fe1b-4264-9906-53f26c545be8\"}" - }, - { - "name": "signup metadata reaches the profile (display name)", - "passed": true, - "notes": "profiles.display_name = \"Alex Doe\"" - }, - { - "name": "wrong password is rejected gracefully (no throw, no session)", - "passed": true, - "notes": "{\"error\":\"Invalid login credentials\"}" - }, - { - "name": "signIn with the right password returns the user id", - "passed": true, - "notes": "{\"userId\":\"863566c0-fe1b-4264-9906-53f26c545be8\"}" - }, - { - "name": "getMyProfile returns the signed-in user's profile", + "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + "judgeNotes": "Identified `image-transform` and the recurring pattern of eight intermittent HTTP 503s from 07:00Z through 12:00Z on 2026-04-28." }, { - "name": "app code does not use the secret / service-role key", - "passed": true, - "notes": "no secret-key references found" + "name": "attributed recurring 503s to gateway/platform layer, not function code", + "passed": false, + "judgeNotes": "It blames Edge Function runtime/resource-limit kills and recommends changing/redeploying function behavior. It does not identify the gateway/platform layer or cite the key absence of corresponding invocation/runtime rows; it also conflates the gateway 503 with avatar-upload’s function-level 500." }, { - "name": "implementation uses @supabase/supabase-js", + "name": "recommended a concrete next step", "passed": true, - "notes": "imports found in: app/src/auth.mjs" + "judgeNotes": "The assistant provided multiple concrete actions, including checking Edge Function CPU/memory metrics, adding diagnostic logging and validation, moving transforms to a queue, implementing retries, and configuring a log drain." } ], "skills": { - "available": [], + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], "loaded": [] }, "docs": { "calls": [] }, - "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", - "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-auth-001-email-password-flow.json" + "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", + "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5/investigate-reliability-003-edge-function-5xx-correlation.json" }, { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", + "experiment": "claude-code-sonnet-5", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "claude-code", "modelProvider": "anthropic", "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-cli-001-bootstrap-app", - "stage": "build", + "eval": "resolve-dataapi-001-empty-results", + "stage": "resolve", "product": [ + "data-api", "database", - "data-api" + "auth" ], "topic": [ - "migrations", - "rls" + "rls", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase project initialised (supabase/config.toml exists)", + "name": "RLS still enabled on bookmarks", "passed": true }, { - "name": "todos table is created by a migration file", + "name": "user A reads own bookmarks", "passed": true }, { - "name": "todos table exists with at least 2 seeded rows", - "passed": true, - "notes": "found 2 rows" + "name": "user B cannot read user A bookmarks", + "passed": true }, { - "name": "row level security is enabled on todos", + "name": "anon reads no bookmarks", "passed": true }, { - "name": "a SELECT policy targets the authenticated role", + "name": "user A can save a new bookmark", "passed": true }, { - "name": "REST API returns no todos to anonymous requests", - "passed": true, - "notes": "0 rows" + "name": "user B cannot insert a bookmark as user A", + "passed": true }, { - "name": "REST API returns the todos to authenticated requests", + "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "notes": "2 rows" + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and created authenticated owner-scoped SELECT and INSERT policies using auth.uid(), including WITH CHECK for inserts. Verification also confirmed isolation and spoofing prevention." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase" + ] }, "docs": { "calls": [] }, - "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", - "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", + "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", + "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-001-bootstrap-app.json" + "sourcePath": "claude-code-sonnet-5/resolve-dataapi-001-empty-results.json" }, { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", + "experiment": "claude-code-sonnet-5", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "claude-code", "modelProvider": "anthropic", "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-cli-002-declarative-schema", - "stage": "build", + "eval": "resolve-database-001-migration-history-mismatch", + "stage": "resolve", "product": [ "database" ], "topic": [ - "declarative-schema", "migrations" ], "suite": "benchmark", @@ -6513,147 +6105,185 @@ "passed": true, "checks": [ { - "name": "supabase db diff used to generate the migration", + "name": "the avatar_url column is applied on the hosted profiles table", "passed": true }, { - "name": "schema file updated to include description column", + "name": "migration 20240220000000 is recorded in the remote history", "passed": true }, { - "name": "a new migration was generated for the change", + "name": "remote migration history matches local migration files", "passed": true }, { - "name": "description column exists in the live database", + "name": "local migrations are a valid reconciled sequence", + "passed": true + }, + { + "name": "production profile data is intact (not reset)", "passed": true + }, + { + "name": "the avatar migration and history reconciliation were done via the Supabase CLI", + "passed": true, + "judgeNotes": "Avatar migration was applied by `supabase db push` (#12), showing both “Applying migration” and “Finished supabase db push.” History was reconciled by adding `20240115000000_add_profile_bio.sql` locally (#10), confirmed aligned by `supabase migration list` (#11), then pushing via the CLI. No prohibited workaround occurred; `psql` was read-only." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase" + ] }, "docs": { "calls": [] }, - "prompt": "Add a description text column to the `products` table in my local Supabase stack", - "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", + "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-002-declarative-schema.json" + "sourcePath": "claude-code-sonnet-5/resolve-database-001-migration-history-mismatch.json" }, { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", + "experiment": "claude-code-sonnet-5", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "claude-code", "modelProvider": "anthropic", "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-cli-003-pg-cron-queue-workflow", - "stage": "build", + "eval": "resolve-performance-001-slow-query-cpu-spike", + "stage": "resolve", "product": [ - "database", - "edge-functions", - "cron", - "queues" + "database" ], "topic": [ - "sql", - "sdk" + "observability", + "sql" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", - "passed": true, - "notes": "schedule='* * * * *', active=true" + "name": "inspected pg_stat_statements for query performance", + "passed": true }, { - "name": "cron command enqueues to the 'tasks' queue", - "passed": true, - "notes": "queue depth 0 -> 1" + "name": "ran EXPLAIN on the expensive query", + "passed": true }, { - "name": "process-tasks function drains the queue", + "name": "created index covering user_id and created_at", + "passed": true + }, + { + "name": "query plan uses an index and avoids sequential scan", "passed": true, - "notes": "function removed the seeded message (id 4) from the queue" + "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + }, + { + "name": "inserts still work", + "passed": true } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [] }, - "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", - "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", + "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", + "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-003-pg-cron-queue-workflow.json" + "sourcePath": "claude-code-sonnet-5/resolve-performance-001-slow-query-cpu-spike.json" }, { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", + "experiment": "claude-code-sonnet-5", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "claude-code", "modelProvider": "anthropic", "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-dataapi-001-relational-report", - "stage": "build", + "eval": "resolve-security-002-rls-cross-tenant-leak", + "stage": "resolve", "product": [ - "data-api", - "database" + "database", + "auth" ], "topic": [ - "sdk" + "rls", + "security" ], "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", + "interface": "mcp", "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" + "name": "RLS enabled on notes", + "passed": true }, { - "name": "report numbers match the database (per customer, sorted)", - "passed": true, - "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" + "name": "tenant A sees only org A notes", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", - "passed": true, - "notes": "publishable read errored: permission denied for table customers" + "name": "tenant B cannot read org A notes", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": true, - "notes": "imports found in: app/report.mjs" + "name": "tenant A author can update own note", + "passed": true }, { - "name": "report queries via the Data API, not raw SQL", - "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "name": "tenant B cannot update org A note", + "passed": true + }, + { + "name": "tenant B author can delete own note", + "passed": true + }, + { + "name": "tenant B cannot delete org A note", + "passed": true + }, + { + "name": "tenant A can insert note in own org", + "passed": true + }, + { + "name": "tenant B cannot insert into org A", + "passed": true } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase" + ] }, "docs": { "calls": [] }, - "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", - "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-sonnet-5-no-skills/build-dataapi-001-relational-report.json" + "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", + "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5/resolve-security-002-rls-cross-tenant-leak.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -6664,44 +6294,60 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-dataapi-002-restock-alert-report", + "eval": "build-auth-001-email-password-flow", "stage": "build", "product": [ - "data-api", + "auth", "database" ], "topic": [ - "sdk" + "sdk", + "rls" ], "suite": "benchmark", "interface": "cli", "cliVersion": "2.109.1", - "passed": false, + "passed": true, "checks": [ { - "name": "report runs and prints JSON", + "name": "auth module loads and the driver completes", "passed": true, - "notes": "exit 0" + "notes": "driver produced a result" }, { - "name": "alerts match the database (below threshold, sorted)", + "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" + "notes": "db user 16bf0f94-05e5-49ce-bb89-e66780928e7a, signUp returned {\"userId\":\"16bf0f94-05e5-49ce-bb89-e66780928e7a\"}" }, { - "name": "tables stay locked down (publishable key reads nothing)", + "name": "signup metadata reaches the profile (display name)", "passed": true, - "notes": "publishable read errored: permission denied for table inventory" + "notes": "profiles.display_name = \"Alex Doe\"" }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "wrong password is rejected gracefully (no throw, no session)", + "passed": true, + "notes": "{\"error\":\"Invalid login credentials\"}" }, { - "name": "report queries via the Data API, not raw SQL", + "name": "signIn with the right password returns the user id", "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "notes": "{\"userId\":\"16bf0f94-05e5-49ce-bb89-e66780928e7a\"}" + }, + { + "name": "getMyProfile returns the signed-in user's profile", + "passed": true, + "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + }, + { + "name": "app code does not use the secret / service-role key", + "passed": true, + "notes": "no secret-key references found" + }, + { + "name": "implementation uses @supabase/supabase-js", + "passed": true, + "notes": "imports found in: app/src/auth.mjs" } ], "skills": { @@ -6711,10 +6357,10 @@ "docs": { "calls": [] }, - "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", - "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-sonnet-5-no-skills/build-dataapi-002-restock-alert-report.json" + "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", + "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5-no-skills/build-auth-001-email-password-flow.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -6725,37 +6371,50 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-database-001-migrate-postgres-to-supabase", + "eval": "build-cli-001-bootstrap-app", "stage": "build", "product": [ - "database" + "database", + "data-api" ], "topic": [ - "migrations" + "migrations", + "rls" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "all 3 tables exist (teams, members, tasks)", + "name": "supabase project initialised (supabase/config.toml exists)", "passed": true }, { - "name": "row counts match (teams=5, members=10, tasks=13)", + "name": "todos table is created by a migration file", "passed": true }, { - "name": "foreign key constraints survived the restore", - "passed": true + "name": "todos table exists with at least 2 seeded rows", + "passed": true, + "notes": "found 2 rows" }, { - "name": "tasks_team_status_idx index survived the restore", + "name": "row level security is enabled on todos", "passed": true }, { - "name": "sequences synced (next insert won't conflict with existing IDs)", + "name": "a SELECT policy targets the authenticated role", "passed": true + }, + { + "name": "REST API returns no todos to anonymous requests", + "passed": true, + "notes": "0 rows" + }, + { + "name": "REST API returns the todos to authenticated requests", + "passed": true, + "notes": "2 rows" } ], "skills": { @@ -6765,10 +6424,10 @@ "docs": { "calls": [] }, - "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", - "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", + "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", + "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-database-001-migrate-postgres-to-supabase.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-001-bootstrap-app.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -6779,46 +6438,34 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-functions-004-service-role-bypass", + "eval": "build-cli-002-declarative-schema", "stage": "build", "product": [ - "edge-functions", - "auth", "database" ], "topic": [ - "rls", - "security", - "sdk" + "declarative-schema", + "migrations" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "rejects missing auth", - "passed": true, - "notes": "status=401" - }, - { - "name": "user A reads own note", - "passed": true, - "notes": "status=200" + "name": "supabase db diff used to generate the migration", + "passed": true }, { - "name": "reads only with the caller's JWT", - "passed": true, - "notes": "bearer_tokens=2, all_match=true" + "name": "schema file updated to include description column", + "passed": true }, { - "name": "user A cannot force-read user B note", - "passed": true, - "notes": "status=200" + "name": "a new migration was generated for the change", + "passed": true }, { - "name": "user B cannot force-read user A note", - "passed": true, - "notes": "status=200" + "name": "description column exists in the live database", + "passed": true } ], "skills": { @@ -6828,10 +6475,10 @@ "docs": { "calls": [] }, - "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", - "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", - "attempts": 2, - "sourcePath": "claude-code-sonnet-5-no-skills/build-functions-004-service-role-bypass.json" + "prompt": "Add a description text column to the `products` table in my local Supabase stack", + "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-002-declarative-schema.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -6842,67 +6489,36 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-functions-005-dual-auth-user-secret", + "eval": "build-cli-003-pg-cron-queue-workflow", "stage": "build", "product": [ + "database", "edge-functions", - "auth", - "database" + "cron", + "queues" ], "topic": [ - "sdk", - "rls", - "security" + "sql", + "sdk" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "seed rows present", - "passed": true, - "notes": "found 2/2 seeded rows" - }, - { - "name": "rejects request with no credentials", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "user with JWT reads only their own rows", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"6f5b2171-8fac-4f4d-a612-8f5898da836f\",\"metric\":\"steps_a_msj0y6nu\",\"value\":111}]}" - }, - { - "name": "user cannot read another user's rows by passing user_id", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"6f5b2171-8fac-4f4d-a612-8f5898da836f\",\"metric\":\"steps_a_msj0y6nu\",\"value\":111}]}" - }, - { - "name": "service key bypasses RLS to read the target user's rows", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"36482d33-6a70-43e3-bd27-459a7428cf03\",\"metric\":\"steps_b_msj0y6nu\",\"value\":222}]}" - }, - { - "name": "non-service key is not granted service access", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "rejects an unverified (forged) user token", + "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "schedule='* * * * *', active=true" }, { - "name": "a user token in the apikey slot is not treated as the service key", + "name": "cron command enqueues to the 'tasks' queue", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "queue depth 0 -> 1" }, { - "name": "implementation uses @supabase/server", + "name": "process-tasks function drains the queue", "passed": true, - "notes": "imports @supabase/server / withSupabase" + "notes": "function removed the seeded message (id 36) from the queue" } ], "skills": { @@ -6911,94 +6527,40 @@ }, "docs": { "calls": [ - { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog.md 2>&1 | head -100", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 5516 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"Edge Functions environment variables SUPABASE_SERVICE_ROLE_KEY SUPABASE_URL default secrets\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - } - ], - "resultChars": 41771 - }, { "source": "search_docs", - "query": "{ searchDocs(query: \"new API keys publishable secret key edge functions env var migration from anon service_role\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function process queue messages pgmq read delete\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", - "title": "Backup and Restore using the CLI" - } - ], - "resultChars": 95976 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"Authorization headers verify_jwt combining auth modes user secret apikey Edge Functions\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" } ], - "resultChars": 24799 + "resultChars": 76390 } ] }, - "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", - "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", + "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", + "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-functions-005-dual-auth-user-secret.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-cli-003-pg-cron-queue-workflow.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7009,79 +6571,105 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-rls-003-org-roles-permissions", + "eval": "build-dataapi-001-relational-report", "stage": "build", "product": [ - "database", - "auth" + "data-api", + "database" ], "topic": [ - "rls", - "security" + "sdk" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "RLS enabled on documents", - "passed": true - }, - { - "name": "viewer sees only documents in their org", - "passed": true - }, - { - "name": "viewer cannot insert", - "passed": true - }, - { - "name": "editor can insert own org document", - "passed": true - }, - { - "name": "editor can update own document", - "passed": true - }, - { - "name": "editor cannot update another user's document", - "passed": true + "name": "report runs and prints JSON", + "passed": true, + "notes": "exit 0" }, { - "name": "editor cannot delete another user's document", - "passed": true + "name": "report numbers match the database (per customer, sorted)", + "passed": true, + "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" }, { - "name": "admin can update any document in their org", - "passed": true + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table customers" }, { - "name": "admin can delete any document in their org", - "passed": true + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "admin cannot affect another org", - "passed": true - }, + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [] + }, + "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", + "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5-no-skills/build-dataapi-001-relational-report.json" + }, + { + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" + }, + "eval": "build-dataapi-002-restock-alert-report", + "stage": "build", + "product": [ + "data-api", + "database" + ], + "topic": [ + "sdk" + ], + "suite": "benchmark", + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, + "checks": [ { - "name": "WITH CHECK blocks editor from moving document to another org", - "passed": true + "name": "report runs and prints JSON", + "passed": true, + "notes": "exit 0" }, { - "name": "editor can still see their own org's roster", - "passed": true + "name": "alerts match the database (below threshold, sorted)", + "passed": true, + "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" }, { - "name": "cannot see another org's membership roster", - "passed": true + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table inventory" }, - { - "name": "a viewer role in one org doesn't grant admin power in another org", - "passed": true + { + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "multi-org user can act as admin in the org where they hold that role", - "passed": true + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -7091,10 +6679,10 @@ "docs": { "calls": [] }, - "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", - "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", + "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", + "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", "attempts": 2, - "sourcePath": "claude-code-sonnet-5-no-skills/build-rls-003-org-roles-permissions.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-dataapi-002-restock-alert-report.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7105,57 +6693,37 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-storage-001-private-bucket-access", + "eval": "build-database-001-migrate-postgres-to-supabase", "stage": "build", "product": [ - "storage", "database" ], "topic": [ - "rls", - "sdk" + "migrations" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "bucket user-files exists", - "passed": true - }, - { - "name": "bucket user-files is private", - "passed": true - }, - { - "name": "RLS still enabled on storage.objects", + "name": "all 3 tables exist (teams, members, tasks)", "passed": true }, { - "name": "user A lists only own files", - "passed": true, - "notes": "saw: 019fdc8c-98ed-736c-a6e0-4477d1da6052/receipt-alpha.pdf, 019fdc8c-98ed-736c-a6e0-4477d1da6052/receipt-beta.pdf" - }, - { - "name": "user B cannot read user A files", + "name": "row counts match (teams=5, members=10, tasks=13)", "passed": true }, { - "name": "anon reads no files", + "name": "foreign key constraints survived the restore", "passed": true }, { - "name": "user A can upload into own folder", + "name": "tasks_team_status_idx index survived the restore", "passed": true }, { - "name": "user B cannot upload into user A folder", + "name": "sequences synced (next insert won't conflict with existing IDs)", "passed": true - }, - { - "name": "configured private per-user storage access", - "passed": true, - "judgeNotes": "Meets requirements: private user-files bucket, authenticated owner-scoped SELECT and INSERT policies on storage.objects with WITH CHECK for uploads, no RLS disabling or public access, and supabase-js createSignedUrl with expiry for temporary sharing." } ], "skills": { @@ -7165,10 +6733,10 @@ "docs": { "calls": [] }, - "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", - "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", + "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-storage-001-private-bucket-access.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-database-001-migrate-postgres-to-supabase.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7179,33 +6747,46 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-tests-001-rls-tenant-isolation", + "eval": "build-functions-004-service-role-bypass", "stage": "build", "product": [ + "edge-functions", + "auth", "database" ], "topic": [ - "tests", - "rls" + "rls", + "security", + "sdk" ], "suite": "benchmark", - "interface": "cli", - "passed": true, + "interface": "mcp", + "passed": false, "checks": [ { - "name": "pgTAP test file(s) written under supabase/tests/", + "name": "rejects missing auth", "passed": true, - "notes": "1 file(s): supabase/tests/database/tenant_isolation_test.sql" + "notes": "status=401" }, { - "name": "pgTAP isolation tests ran and pass", + "name": "user A reads own note", "passed": true, - "notes": "10 passed, 5 failed" + "notes": "status=200" }, { - "name": "agent correctly identifies the posts isolation bug from test results", + "name": "reads only with the caller's JWT", + "passed": false, + "notes": "bearer_tokens=2, all_match=false" + }, + { + "name": "user A cannot force-read user B note", + "passed": true, + "notes": "status=200" + }, + { + "name": "user B cannot force-read user A note", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as having the tenant isolation flaw, explains the missing `org_id` predicate, and grounds the conclusion in the pgTAP failures showing cross-org post visibility. It does not blame `notes` and treats the test results as authoritative." + "notes": "status=200" } ], "skills": { @@ -7215,10 +6796,10 @@ "docs": { "calls": [] }, - "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", - "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-tests-001-rls-tenant-isolation.json" + "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", + "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5-no-skills/build-functions-004-service-role-bypass.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7229,98 +6810,67 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "build-vectors-001-rag-with-permissions", + "eval": "build-functions-005-dual-auth-user-secret", "stage": "build", "product": [ - "database", - "vectors" + "edge-functions", + "auth", + "database" ], "topic": [ - "sql", - "rls" + "sdk", + "rls", + "security" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", + "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "document_sections.embedding is vector(384)", + "name": "seed rows present", "passed": true, - "notes": "vector(384)" + "notes": "found 2/2 seeded rows" }, { - "name": "HNSW index on the embedding column", + "name": "rejects request with no credentials", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "index operator class matches the search operator", + "name": "user with JWT reads only their own rows", "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "status 200: {\"user_id\":\"3751d136-3c4e-45cf-8103-c2849b937959\",\"stats\":[{\"metric\":\"steps_a_mt93my8x\",\"value\":111}]}" }, { - "name": "user A search returns only own sections, best match first", - "passed": true + "name": "user cannot read another user's rows by passing user_id", + "passed": true, + "notes": "status 200: {\"user_id\":\"3751d136-3c4e-45cf-8103-c2849b937959\",\"stats\":[{\"metric\":\"steps_a_mt93my8x\",\"value\":111}]}" }, { - "name": "user B search returns only own sections, best match first", - "passed": true + "name": "service key bypasses RLS to read the target user's rows", + "passed": true, + "notes": "status 200: {\"user_id\":\"4dcb5627-2a9d-4184-ab01-236bd29828f2\",\"stats\":[{\"metric\":\"steps_b_mt93my8x\",\"value\":222}]}" }, { - "name": "user A reads only own sections through the API", - "passed": true + "name": "non-service key is not granted service access", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "user A reads only own documents through the API", - "passed": true - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", - "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/build-vectors-001-rag-with-permissions.json" - }, - { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "deploy-database-001-prometheus-metrics", - "stage": "deploy", - "product": [ - "database" - ], - "topic": [ - "observability" - ], - "suite": "benchmark", - "interface": "cli", - "passed": true, - "checks": [ - { - "name": "preserved existing app scrape job", - "passed": true + "name": "rejects an unverified (forged) user token", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "configured the Supabase Metrics API scrape correctly", + "name": "a user token in the apikey slot is not treated as the service key", "passed": true, - "judgeNotes": "Meets all requirements: Supabase Metrics API scrape uses HTTPS, correct metrics path, Basic Auth with password_file, valid supabase.co project target, app scrape is preserved, and docker-compose mounts the secrets directory containing the password file." + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "documented live deployment and verification steps", + "name": "implementation uses @supabase/server", "passed": true, - "judgeNotes": "README includes Secret API key creation, matching secret file placement, Compose start/reload, and concrete verification via Prometheus targets." + "notes": "imports @supabase/server / withSupabase" } ], "skills": { @@ -7331,38 +6881,134 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"project metrics endpoint prometheus\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function verify JWT service role key user_id manual auth\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" + } + ], + "resultChars": 54757 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"Securing Edge Functions user JWT or service key dual pattern manual verification\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" + } + ], + "resultChars": 60884 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"verify_jwt false combining user and secret auth modes config.toml\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/deploy", + "title": "Deploy to Production" + }, + { + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" + }, + { + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/auth/passkeys", + "title": "Passkey authentication" + } + ], + "resultChars": 30569 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"@supabase/server package ctx supabase supabaseAdmin userClaims reference createSupabaseContext options\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + } + ], + "resultChars": 7837 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"failed to determine entrypoint edge runtime local serve error\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" + "url": "https://supabase.com/docs/guides/functions/status-codes", + "title": "Status codes" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" + "url": "https://supabase.com/docs/guides/troubleshooting/issues-serving-edge-functions-locally", + "title": "Issues serving Edge Functions locally" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" + "url": "https://supabase.com/docs/reference/cli/supabase-functions-serve", + "title": "Serve all Functions locally" }, { - "url": "https://supabase.com/docs/guides/database/replication/manual-replication-monitoring", - "title": "Manual replication monitoring" + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-fails-deploy", + "title": "Edge Function deploy failed due to an internal error" } ], - "resultChars": 23548 + "resultChars": 21510 } ] }, - "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", - "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", + "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/deploy-database-001-prometheus-metrics.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-functions-005-dual-auth-user-secret.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7373,153 +7019,79 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "deploy-functions-001-edge-function-secrets", - "stage": "deploy", + "eval": "build-rls-003-org-roles-permissions", + "stage": "build", "product": [ - "edge-functions" + "database", + "auth" ], "topic": [ + "rls", "security" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "WEATHER_API_KEY is set as a Function secret on the project", + "name": "RLS enabled on documents", "passed": true }, { - "name": "the weather function is deployed to the project", - "passed": true, - "notes": "status ACTIVE" + "name": "viewer sees only documents in their org", + "passed": true }, { - "name": "the weather function reads WEATHER_API_KEY from the environment", - "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "name": "viewer cannot insert", + "passed": true }, { - "name": "WEATHER_API_KEY value is not committed to the repo", + "name": "editor can insert own org document", "passed": true - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", - "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/deploy-functions-001-edge-function-secrets.json" - }, - { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "deploy-self-hosting-001-docker-compose", - "stage": "deploy", - "product": [ - "database", - "auth", - "storage" - ], - "topic": [ - "self-hosting" - ], - "suite": "benchmark", - "interface": "cli", - "passed": true, - "checks": [ + }, { - "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", + "name": "editor can update own document", "passed": true }, { - "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", + "name": "editor cannot update another user's document", "passed": true }, { - "name": "secrets rotated off the shipped defaults", + "name": "editor cannot delete another user's document", "passed": true }, { - "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", + "name": "admin can update any document in their org", "passed": true - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", - "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", - "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/deploy-self-hosting-001-docker-compose.json" - }, - { - "experiment": "claude-code-sonnet-5-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "claude-code", - "modelProvider": "anthropic", - "modelId": "claude-sonnet-5", - "reasoningEffort": "high" - }, - "eval": "investigate-auth-001-deleted-user-access", - "stage": "investigate", - "product": [ - "auth" - ], - "topic": [ - "security", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": false, - "checks": [ + }, { - "name": "victim session active before delete-account", + "name": "admin can delete any document in their org", "passed": true }, { - "name": "delete_account flow ran for the victim", + "name": "admin cannot affect another org", "passed": true }, { - "name": "delete-account revokes the user's sessions", - "passed": true, - "notes": "sessions left: 0" + "name": "WITH CHECK blocks editor from moving document to another org", + "passed": true }, { - "name": "deleted user's refresh token is rejected", + "name": "editor can still see their own org's roster", "passed": true }, { - "name": "deleted user cannot sign back in", - "passed": false, - "notes": "deleted account can still sign in" + "name": "cannot see another org's membership roster", + "passed": true }, { - "name": "other users keep their sessions and access", + "name": "a viewer role in one org doesn't grant admin power in another org", "passed": true }, { - "name": "diagnosed and explained session revocation", - "passed": true, - "judgeNotes": "Meets all rubric requirements: identifies soft-delete/no auth revocation root cause, implements session/refresh-token revocation plus sign-in blocking and RLS enforcement, explains remaining stateless JWT/local-validation window consistently with the RLS fix, and correctly distinguishes publishable vs secret keys and RLS behavior." + "name": "multi-org user can act as admin in the org where they hold that role", + "passed": true } ], "skills": { @@ -7529,10 +7101,10 @@ "docs": { "calls": [] }, - "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", - "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", + "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", + "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", "attempts": 2, - "sourcePath": "claude-code-sonnet-5-no-skills/investigate-auth-001-deleted-user-access.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-rls-003-org-roles-permissions.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7543,13 +7115,14 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "investigate-realtime-001-subscribed-no-events", - "stage": "investigate", + "eval": "build-storage-001-private-bucket-access", + "stage": "build", "product": [ - "realtime", + "storage", "database" ], "topic": [ + "rls", "sdk" ], "suite": "benchmark", @@ -7557,30 +7130,42 @@ "passed": true, "checks": [ { - "name": "orders table added to supabase_realtime publication", + "name": "bucket user-files exists", "passed": true }, { - "name": "courier_locations still in supabase_realtime publication", + "name": "bucket user-files is private", "passed": true }, { - "name": "publication still publishes INSERT events", + "name": "RLS still enabled on storage.objects", "passed": true }, { - "name": "RLS still enabled on orders", + "name": "user A lists only own files", + "passed": true, + "notes": "saw: 01a03a86-1162-70fa-958a-7bdfb850c3ad/receipt-alpha.pdf, 01a03a86-1162-70fa-958a-7bdfb850c3ad/receipt-beta.pdf" + }, + { + "name": "user B cannot read user A files", "passed": true }, { - "name": "staff can still read orders through RLS", - "passed": true, - "notes": "authenticated sees 2 of 2 orders" + "name": "anon reads no files", + "passed": true }, { - "name": "diagnosed missing publication membership", + "name": "user A can upload into own folder", + "passed": true + }, + { + "name": "user B cannot upload into user A folder", + "passed": true + }, + { + "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "The assistant correctly identified that the channel can reach SUBSCRIBED while INSERT events do not fire because public.orders was missing from the supabase_realtime publication. It fixed exactly that with ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, verified courier_locations remained included, and did not disable RLS or weaken policies." + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT policies, RLS retained, and short-lived createSignedUrl sharing code are all provided." } ], "skills": { @@ -7590,10 +7175,10 @@ "docs": { "calls": [] }, - "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", - "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", + "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", + "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/investigate-realtime-001-subscribed-no-events.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-storage-001-private-bucket-access.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7604,74 +7189,46 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "investigate-reliability-003-edge-function-5xx-correlation", - "stage": "investigate", + "eval": "build-tests-001-rls-tenant-isolation", + "stage": "build", "product": [ - "edge-functions" + "database" ], "topic": [ - "observability" + "tests", + "rls" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "identified image-transform and the recurring 503 pattern", + "name": "pgTAP test file(s) written under supabase/tests/", "passed": true, - "judgeNotes": "The assistant correctly identified `image-transform` as the affected function and described the recurring HTTP 503 pattern across the morning of 2026-04-28, including all 8 failures from 07:00Z through 12:00Z. It also avoided misattributing the main issue to the older `billing-webhook` 503s." + "notes": "1 file(s): supabase/tests/database/tenant_isolation.test.sql" }, { - "name": "attributed recurring 503s to gateway/platform layer, not function code", + "name": "pgTAP isolation tests ran and pass", "passed": true, - "judgeNotes": "Attributes the recurring 503s to gateway/platform/boot-level failure rather than application code, grounded in valid observations: no corresponding execution logs for failed requests, nearby successful invocations, unchanged deployment/version, and distinction from avatar-upload's function-level 500." + "notes": "9 passed, 3 failed" }, { - "name": "recommended a concrete next step", + "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The assistant recommended multiple concrete next steps: checking Edge Function dashboard logs for BOOT_ERROR/WORKER_RESOURCE_LIMIT in a specific time window, reviewing recent deployment img-deploy-42 and considering rollback, investigating resource limits/input size/concurrency, and adding alerting." + "judgeNotes": "Correctly identifies `posts` as having the broken SELECT tenant-isolation policy and grounds the conclusion in pgTAP test 4 showing an org A member could read org B's post. It correctly contrasts `notes` as isolated." } ], "skills": { "available": [], "loaded": [] }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{ searchDocs(query: \"edge function 503 error worker boot\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", - "title": "Edge Function 503 error response" - }, - { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" - }, - { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", - "title": "Edge Function 504 error response" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-546-error-response", - "title": "546 - WORKER_RESOURCE_LIMIT Exceeded / WORKER_LIMIT Exceeded" - } - ], - "resultChars": 43344 - } - ] - }, - "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", - "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "docs": { + "calls": [] + }, + "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", + "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/investigate-reliability-003-edge-function-5xx-correlation.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-tests-001-rls-tenant-isolation.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7682,49 +7239,50 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-dataapi-001-empty-results", - "stage": "resolve", + "eval": "build-vectors-001-rag-with-permissions", + "stage": "build", "product": [ - "data-api", "database", - "auth" + "vectors" ], "topic": [ - "rls", - "sdk" + "sql", + "rls" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "RLS still enabled on bookmarks", - "passed": true + "name": "document_sections.embedding is vector(384)", + "passed": true, + "notes": "vector(384)" }, { - "name": "user A reads own bookmarks", - "passed": true + "name": "HNSW index on the embedding column", + "passed": true, + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { - "name": "user B cannot read user A bookmarks", - "passed": true + "name": "index operator class matches the search operator", + "passed": true, + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" }, { - "name": "anon reads no bookmarks", + "name": "user A search returns only own sections, best match first", "passed": true }, { - "name": "user A can save a new bookmark", + "name": "user B search returns only own sections, best match first", "passed": true }, { - "name": "user B cannot insert a bookmark as user A", + "name": "user A reads only own sections through the API", "passed": true }, { - "name": "diagnosed RLS and added owner-scoped policies", - "passed": true, - "judgeNotes": "Diagnosed RLS deny-all due to no policies, kept RLS enabled, and added authenticated-only SELECT and INSERT policies scoped to user_id = auth.uid() with WITH CHECK for inserts." + "name": "user A reads only own documents through the API", + "passed": true } ], "skills": { @@ -7734,10 +7292,10 @@ "docs": { "calls": [] }, - "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", - "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", + "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", + "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/resolve-dataapi-001-empty-results.json" + "sourcePath": "claude-code-sonnet-5-no-skills/build-vectors-001-rag-with-permissions.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7748,42 +7306,108 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-database-001-migration-history-mismatch", - "stage": "resolve", + "eval": "deploy-database-001-prometheus-metrics", + "stage": "deploy", "product": [ "database" ], "topic": [ - "migrations" + "observability" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "the avatar_url column is applied on the hosted profiles table", + "name": "preserved existing app scrape job", "passed": true }, { - "name": "migration 20240220000000 is recorded in the remote history", - "passed": true + "name": "configured the Supabase Metrics API scrape correctly", + "passed": true, + "judgeNotes": "HTTPS Supabase metrics scrape is correctly configured with the required path, Basic Auth password_file, project target, preserved app job, and matching mounted secrets directory." }, { - "name": "remote migration history matches local migration files", - "passed": true - }, + "name": "documented live deployment and verification steps", + "passed": true, + "judgeNotes": "README provides correct Secret API key creation, matching secret file placement, Compose start/reload steps, and concrete verification through Prometheus Targets and direct endpoint testing." + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"prometheus metrics endpoint self-hosted\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" + } + ], + "resultChars": 19943 + } + ] + }, + "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", + "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5-no-skills/deploy-database-001-prometheus-metrics.json" + }, + { + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" + }, + "eval": "deploy-functions-001-edge-function-secrets", + "stage": "deploy", + "product": [ + "edge-functions" + ], + "topic": [ + "security" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ { - "name": "local migrations are a valid reconciled sequence", + "name": "WEATHER_API_KEY is set as a Function secret on the project", "passed": true }, { - "name": "production profile data is intact (not reset)", - "passed": true + "name": "the weather function is deployed to the project", + "passed": true, + "notes": "status ACTIVE" }, { - "name": "the avatar migration and history reconciliation were done via the Supabase CLI", + "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "PASS: avatar_url was applied through `supabase db push` in #14, with output `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration was reconciled by adding the missing local migration file in #12 (`20240115000000_add_profile_bio.sql`), after which `supabase migration list` in #13 showed local and remote histories aligned. psql usage was read-only inspection only; no disallowed workaround seen." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get(\"WEATHER_API_KEY\")." + }, + { + "name": "WEATHER_API_KEY value is not committed to the repo", + "passed": true } ], "skills": { @@ -7791,12 +7415,33 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"invoke edge function curl apikey authorization header\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + } + ], + "resultChars": 37835 + } + ] }, - "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", - "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", + "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/resolve-database-001-migration-history-mismatch.json" + "sourcePath": "claude-code-sonnet-5-no-skills/deploy-functions-001-edge-function-secrets.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7807,38 +7452,34 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-performance-001-slow-query-cpu-spike", - "stage": "resolve", + "eval": "deploy-self-hosting-001-docker-compose", + "stage": "deploy", "product": [ - "database" + "database", + "auth", + "storage" ], "topic": [ - "observability", - "sql" + "self-hosting" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "inspected pg_stat_statements for query performance", + "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", "passed": true }, { - "name": "ran EXPLAIN on the expensive query", + "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", "passed": true }, { - "name": "created index covering user_id and created_at", + "name": "secrets rotated off the shipped defaults", "passed": true }, { - "name": "query plan uses an index and avoids sequential scan", - "passed": true, - "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" - }, - { - "name": "inserts still work", + "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", "passed": true } ], @@ -7849,10 +7490,10 @@ "docs": { "calls": [] }, - "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", - "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", + "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", + "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/resolve-performance-001-slow-query-cpu-spike.json" + "sourcePath": "claude-code-sonnet-5-no-skills/deploy-self-hosting-001-docker-compose.json" }, { "experiment": "claude-code-sonnet-5-no-skills", @@ -7863,55 +7504,48 @@ "modelId": "claude-sonnet-5", "reasoningEffort": "high" }, - "eval": "resolve-security-002-rls-cross-tenant-leak", - "stage": "resolve", + "eval": "investigate-auth-001-deleted-user-access", + "stage": "investigate", "product": [ - "database", "auth" ], "topic": [ - "rls", - "security" + "security", + "sdk" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "RLS enabled on notes", - "passed": true - }, - { - "name": "tenant A sees only org A notes", - "passed": true - }, - { - "name": "tenant B cannot read org A notes", + "name": "victim session active before delete-account", "passed": true }, { - "name": "tenant A author can update own note", + "name": "delete_account flow ran for the victim", "passed": true }, { - "name": "tenant B cannot update org A note", - "passed": true + "name": "delete-account revokes the user's sessions", + "passed": true, + "notes": "sessions left: 0" }, { - "name": "tenant B author can delete own note", + "name": "deleted user's refresh token is rejected", "passed": true }, { - "name": "tenant B cannot delete org A note", + "name": "deleted user cannot sign back in", "passed": true }, { - "name": "tenant A can insert note in own org", + "name": "other users keep their sessions and access", "passed": true }, { - "name": "tenant B cannot insert into org A", - "passed": true + "name": "diagnosed and explained session revocation", + "passed": true, + "judgeNotes": "Correctly diagnoses the soft-delete issue, hard-deletes the auth user to revoke sessions/refresh tokens, consistently explains stale JWT behavior and RLS mitigation, and accurately distinguishes publishable client keys from secret server-only RLS-bypassing keys." } ], "skills": { @@ -7921,614 +7555,373 @@ "docs": { "calls": [] }, - "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", - "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", + "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", "attempts": 1, - "sourcePath": "claude-code-sonnet-5-no-skills/resolve-security-002-rls-cross-tenant-leak.json" + "sourcePath": "claude-code-sonnet-5-no-skills/investigate-auth-001-deleted-user-access.json" }, { - "experiment": "codex-gpt-5.4-mini", - "experimentSuite": "benchmark", + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" - }, - "eval": "build-auth-001-email-password-flow", - "stage": "build", + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" + }, + "eval": "investigate-realtime-001-subscribed-no-events", + "stage": "investigate", "product": [ - "auth", + "realtime", "database" ], "topic": [ - "sdk", - "rls" + "sdk" ], "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", + "interface": "mcp", "passed": true, "checks": [ { - "name": "auth module loads and the driver completes", - "passed": true, - "notes": "driver produced a result" - }, - { - "name": "signUp creates the account and returns its user id", - "passed": true, - "notes": "db user 3d73a23b-4cc8-4789-9fd3-9abe325e1baa, signUp returned {\"userId\":\"3d73a23b-4cc8-4789-9fd3-9abe325e1baa\"}" - }, - { - "name": "signup metadata reaches the profile (display name)", - "passed": true, - "notes": "profiles.display_name = \"Alex Doe\"" + "name": "orders table added to supabase_realtime publication", + "passed": true }, { - "name": "wrong password is rejected gracefully (no throw, no session)", - "passed": true, - "notes": "{\"error\":\"Invalid login credentials\"}" + "name": "courier_locations still in supabase_realtime publication", + "passed": true }, { - "name": "signIn with the right password returns the user id", - "passed": true, - "notes": "{\"userId\":\"3d73a23b-4cc8-4789-9fd3-9abe325e1baa\"}" + "name": "publication still publishes INSERT events", + "passed": true }, { - "name": "getMyProfile returns the signed-in user's profile", - "passed": true, - "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + "name": "RLS still enabled on orders", + "passed": true }, { - "name": "app code does not use the secret / service-role key", + "name": "staff can still read orders through RLS", "passed": true, - "notes": "no secret-key references found" + "notes": "authenticated sees 2 of 2 orders" }, { - "name": "implementation uses @supabase/supabase-js", + "name": "diagnosed missing publication membership", "passed": true, - "notes": "imports found in: app/src/auth.mjs" + "judgeNotes": "Correctly identified the missing orders table in supabase_realtime, added only public.orders to the existing publication, and preserved courier_locations, RLS, and policies." } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"supabase-js signUp signInWithPassword getUser getSession auth admin createUser user_metadata display_name profiles\", limit: 5) {\n nodes {\n title\n href\n content\n ... on ClientLibraryFunctionReference {\n language\n methodName\n }\n }\n totalCount\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", - "title": "Migrate from Auth0 to Supabase Auth" - }, - { - "url": "https://supabase.com/docs/guides/auth", - "title": "Auth" - }, - { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", - "title": "Customizing Emails by Language" - }, - { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-apple", - "title": "Login with Apple" - } - ], - "resultChars": 79187 - }, - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"signInWithPassword supabase-js reference signUp options data getUser getSession auth.currentUser\", limit: 10) {\n nodes {\n title\n href\n content\n ... on ClientLibraryFunctionReference {\n language\n methodName\n }\n }\n totalCount\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/javascript/auth-getuser" - }, - { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" - }, - { - "url": "https://supabase.com/docs/guides/auth/passwords", - "title": "Password-based Auth" - }, - { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-google", - "title": "Login with Google" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", - "title": "Configure SAML SSO" - }, - { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-azure", - "title": "Login with Azure (Microsoft)" - }, - { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", - "title": "Migrate from Auth0 to Supabase Auth" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" - }, - { - "url": "https://supabase.com/docs/reference/dart/auth-signinwithpassword" - }, - { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-figma", - "title": "Login with Figma" - } - ], - "resultChars": 193019 - } - ] + "calls": [] }, - "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", - "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-auth-001-email-password-flow.json" + "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", + "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5-no-skills/investigate-realtime-001-subscribed-no-events.json" }, { - "experiment": "codex-gpt-5.4-mini", - "experimentSuite": "benchmark", + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" }, - "eval": "build-cli-001-bootstrap-app", - "stage": "build", + "eval": "investigate-reliability-003-edge-function-5xx-correlation", + "stage": "investigate", "product": [ - "database", - "data-api" + "edge-functions" ], "topic": [ - "migrations", - "rls" + "observability" ], "suite": "benchmark", - "interface": "cli", - "passed": true, + "interface": "mcp", + "passed": false, "checks": [ { - "name": "supabase project initialised (supabase/config.toml exists)", - "passed": true - }, - { - "name": "todos table is created by a migration file", - "passed": true - }, - { - "name": "todos table exists with at least 2 seeded rows", + "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "notes": "found 2 rows" - }, - { - "name": "row level security is enabled on todos", - "passed": true - }, - { - "name": "a SELECT policy targets the authenticated role", - "passed": true + "judgeNotes": "Identified image-transform as the affected function and explicitly listed all eight recurring HTTP 503 failures from 07:00Z through 12:00Z on 2026-04-28, while correctly distinguishing the older billing-webhook incident." }, { - "name": "REST API returns no todos to anonymous requests", - "passed": true, - "notes": "0 rows" + "name": "attributed recurring 503s to gateway/platform layer, not function code", + "passed": false, + "judgeNotes": "Although it correctly notes the failures appear only in gateway logs with no runtime invocation rows, it then attributes them to function cold starts/heavy dependencies and recommends modifying function initialization or keeping functions warm. This treats the function/runtime as the underlying cause and remediation target, contrary to the required gateway/platform-layer attribution." }, { - "name": "REST API returns the todos to authenticated requests", + "name": "recommended a concrete next step", "passed": true, - "notes": "2 rows" + "judgeNotes": "The assistant provided multiple concrete next steps: instrumenting function boot time, checking cold-start metrics, configuring keep-warm pings or minimum instances, adding client retries, and reducing initialization cost." } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 6745 - }, - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"local development migrations RLS select authenticated anon expose table data api\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" - }, - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-flutter", - "title": "Build a User Management App with Flutter" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" - } - ], - "resultChars": 152845 - }, - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"Securing your API grants authenticated anon RLS select policy\", limit: 3) {\n nodes { title href content }\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-anonymous", - "title": "Anonymous Sign-Ins" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - } - ], - "resultChars": 63887 - } - ] - }, - "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", - "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-cli-001-bootstrap-app.json" + "calls": [] + }, + "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", + "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "attempts": 2, + "sourcePath": "claude-code-sonnet-5-no-skills/investigate-reliability-003-edge-function-5xx-correlation.json" }, { - "experiment": "codex-gpt-5.4-mini", - "experimentSuite": "benchmark", + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" }, - "eval": "build-cli-002-declarative-schema", - "stage": "build", + "eval": "resolve-dataapi-001-empty-results", + "stage": "resolve", "product": [ - "database" + "data-api", + "database", + "auth" ], "topic": [ - "declarative-schema", - "migrations" + "rls", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase db diff used to generate the migration", + "name": "RLS still enabled on bookmarks", "passed": true }, { - "name": "schema file updated to include description column", + "name": "user A reads own bookmarks", "passed": true }, { - "name": "a new migration was generated for the change", + "name": "user B cannot read user A bookmarks", "passed": true }, { - "name": "description column exists in the live database", + "name": "anon reads no bookmarks", + "passed": true + }, + { + "name": "user A can save a new bookmark", + "passed": true + }, + { + "name": "user B cannot insert a bookmark as user A", "passed": true + }, + { + "name": "diagnosed RLS and added owner-scoped policies", + "passed": true, + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies and added authenticated, owner-scoped SELECT and INSERT policies using auth.uid(), while keeping RLS enabled." } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query SearchDocs {\n searchDocs(query: \"declarative database schemas local development migration generate supabase schema_paths\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", - "title": "Declarative database schemas" - }, - { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" - }, - { - "url": "https://supabase.com/docs/guides/deployment/branching/working-with-branches", - "title": "Working with branches" - }, - { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" - } - ], - "resultChars": 65847 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 6745 - } - ] + "calls": [] }, - "prompt": "Add a description text column to the `products` table in my local Supabase stack", - "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", + "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-cli-002-declarative-schema.json" + "sourcePath": "claude-code-sonnet-5-no-skills/resolve-dataapi-001-empty-results.json" }, { - "experiment": "codex-gpt-5.4-mini", - "experimentSuite": "benchmark", + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" }, - "eval": "build-cli-003-pg-cron-queue-workflow", - "stage": "build", + "eval": "resolve-database-001-migration-history-mismatch", + "stage": "resolve", "product": [ - "database", - "edge-functions", - "cron", - "queues" + "database" ], "topic": [ - "sql", - "sdk" + "migrations" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", - "passed": true, - "notes": "schedule='* * * * *', active=true" + "name": "the avatar_url column is applied on the hosted profiles table", + "passed": true }, { - "name": "cron command enqueues to the 'tasks' queue", - "passed": true, - "notes": "queue depth 0 -> 1" + "name": "migration 20240220000000 is recorded in the remote history", + "passed": true }, { - "name": "process-tasks function drains the queue", + "name": "remote migration history matches local migration files", + "passed": true + }, + { + "name": "local migrations are a valid reconciled sequence", + "passed": true + }, + { + "name": "production profile data is intact (not reset)", + "passed": true + }, + { + "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "notes": "function removed the seeded message (id 36) from the queue" + "judgeNotes": "`supabase db push` (#15) applied `20240220000000_add_avatar_url.sql` and finished successfully. History was reconciled by adding local `20240115000000_add_profile_bio.sql` (#13), then pushing via the CLI. The `psql` usage was read-only; no prohibited workaround occurred." } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"pg_cron create cron job every minute run function Supabase local queue pgmq pop delete\", limit: 5) {\n nodes {\n title\n href\n ... on Guide { content }\n ... on Subsection { content }\n ... on CLICommandReference { content }\n ... on ClientLibraryFunctionReference { content }\n ... on TroubleshootingGuide { content }\n ... on ManagementApiReference { content }\n }\n }\n}", - "hasContent": true, - "pages": [] - }, - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"pg_cron create cron job every minute Supabase queue pgmq pop delete\", limit: 10) {\n nodes {\n title\n href\n content\n }\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, - { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" - }, - { - "url": "https://supabase.com/docs/guides/cron/install", - "title": "Install" - }, - { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", - "title": "pg_cron debugging guide" - }, - { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" - }, - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_cron", - "title": "pg_cron: Schedule Recurring Jobs with Cron Syntax in Postgres" - }, - { - "url": "https://supabase.com/docs/guides/queues", - "title": "Supabase Queues" - }, - { - "url": "https://supabase.com/docs/guides/queues/quickstart", - "title": "Quickstart" - }, - { - "url": "https://supabase.com/docs/guides/queues/pgmq", - "title": "PGMQ Extension" - } - ], - "resultChars": 69751 - }, - { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"pg_cron unschedule jobname cron.schedule same name idempotent\", limit: 5) {\n nodes { title href content }\n }\n}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/pg_cron-launcher-crashes-with-duplicate-key-value-violates-unique-constraint-cc6472", - "title": "`pg_cron launcher crashes with 'duplicate key value violates unique constraint'`" - }, - { - "url": "https://supabase.com/docs/guides/platform/upgrading", - "title": "Upgrading" - }, - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", - "title": "pg_cron debugging guide" - } - ], - "resultChars": 42853 - } - ] + "calls": [] + }, + "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", + "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5-no-skills/resolve-database-001-migration-history-mismatch.json" + }, + { + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" + }, + "eval": "resolve-performance-001-slow-query-cpu-spike", + "stage": "resolve", + "product": [ + "database" + ], + "topic": [ + "observability", + "sql" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": true, + "checks": [ + { + "name": "inspected pg_stat_statements for query performance", + "passed": true + }, + { + "name": "ran EXPLAIN on the expensive query", + "passed": true + }, + { + "name": "created index covering user_id and created_at", + "passed": true + }, + { + "name": "query plan uses an index and avoids sequential scan", + "passed": true, + "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + }, + { + "name": "inserts still work", + "passed": true + } + ], + "skills": { + "available": [], + "loaded": [] }, - "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", - "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", + "docs": { + "calls": [] + }, + "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", + "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-cli-003-pg-cron-queue-workflow.json" + "sourcePath": "claude-code-sonnet-5-no-skills/resolve-performance-001-slow-query-cpu-spike.json" }, { - "experiment": "codex-gpt-5.4-mini", - "experimentSuite": "benchmark", + "experiment": "claude-code-sonnet-5-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" + "agent": "claude-code", + "modelProvider": "anthropic", + "modelId": "claude-sonnet-5", + "reasoningEffort": "high" }, - "eval": "build-dataapi-001-relational-report", - "stage": "build", + "eval": "resolve-security-002-rls-cross-tenant-leak", + "stage": "resolve", "product": [ - "data-api", - "database" + "database", + "auth" ], "topic": [ - "sdk" + "rls", + "security" ], "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", - "passed": false, + "interface": "mcp", + "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" + "name": "RLS enabled on notes", + "passed": true }, { - "name": "report numbers match the database (per customer, sorted)", - "passed": true, - "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" + "name": "tenant A sees only org A notes", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", - "passed": true, - "notes": "publishable read errored: permission denied for table customers" + "name": "tenant B cannot read org A notes", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "tenant A author can update own note", + "passed": true }, { - "name": "report queries via the Data API, not raw SQL", - "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "name": "tenant B cannot update org A note", + "passed": true + }, + { + "name": "tenant B author can delete own note", + "passed": true + }, + { + "name": "tenant B cannot delete org A note", + "passed": true + }, + { + "name": "tenant A can insert note in own org", + "passed": true + }, + { + "name": "tenant B cannot insert into org A", + "passed": true } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 6745 - } - ] + "calls": [] }, - "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", - "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini/build-dataapi-001-relational-report.json" + "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", + "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "attempts": 1, + "sourcePath": "claude-code-sonnet-5-no-skills/resolve-security-002-rls-cross-tenant-leak.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -8539,14 +7932,15 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-dataapi-002-restock-alert-report", + "eval": "build-auth-001-email-password-flow", "stage": "build", "product": [ - "data-api", + "auth", "database" ], "topic": [ - "sdk" + "sdk", + "rls" ], "suite": "benchmark", "interface": "cli", @@ -8554,29 +7948,44 @@ "passed": false, "checks": [ { - "name": "report runs and prints JSON", + "name": "auth module loads and the driver completes", "passed": true, - "notes": "exit 0" + "notes": "driver produced a result" }, { - "name": "alerts match the database (below threshold, sorted)", + "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" + "notes": "db user 78d06d57-98dc-4a0c-81d8-2378fd164549, signUp returned {\"userId\":\"78d06d57-98dc-4a0c-81d8-2378fd164549\"}" }, { - "name": "tables stay locked down (publishable key reads nothing)", + "name": "signup metadata reaches the profile (display name)", "passed": true, - "notes": "publishable read errored: permission denied for table inventory" + "notes": "profiles.display_name = \"Alex Doe\"" }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "wrong password is rejected gracefully (no throw, no session)", + "passed": true, + "notes": "{\"error\":\"Invalid login credentials\"}" }, { - "name": "report queries via the Data API, not raw SQL", + "name": "signIn with the right password returns the user id", "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "notes": "{\"userId\":\"78d06d57-98dc-4a0c-81d8-2378fd164549\"}" + }, + { + "name": "getMyProfile returns the signed-in user's profile", + "passed": true, + "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + }, + { + "name": "app code does not use the secret / service-role key", + "passed": true, + "notes": "no secret-key references found" + }, + { + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" } ], "skills": { @@ -8584,47 +7993,43 @@ "supabase", "supabase-postgres-best-practices" ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "loaded": [] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase local psql database query cli worker node supabase-js examples\", limit: 5) { edges { node { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on CLICommandReference { title href content } ... on TroubleshootingGuide { title href content } } } } }", + "query": "query {\n searchDocs(query: \"supabase-js signUp signInWithPassword getUser getSession auth metadata user_metadata display_name\", limit: 5) {\n nodes {\n ... on ClientLibraryFunctionReference {\n title\n href\n content\n language\n methodName\n }\n ... on Guide {\n title\n href\n content\n }\n ... on TroubleshootingGuide {\n title\n href\n content\n }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", - "title": "Testing and linting" + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" }, { - "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", - "title": "Serverless Drivers" + "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", + "title": "Customizing Emails by Language" }, { - "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", - "title": "Integrating with Supabase Database (Postgres)" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", + "title": "Migrate from Auth0 to Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/local-development", - "title": "Local Development & CLI" + "url": "https://supabase.com/docs/reference/javascript/auth-getuser" }, { - "url": "https://supabase.com/docs/guides/database/inspect", - "title": "Debugging and monitoring" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-google", + "title": "Login with Google" } ], - "resultChars": 36819 + "resultChars": 75886 } ] }, - "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", - "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", + "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", + "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini/build-dataapi-002-restock-alert-report.json" + "sourcePath": "codex-gpt-5.4-mini/build-auth-001-email-password-flow.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -8635,37 +8040,50 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-database-001-migrate-postgres-to-supabase", + "eval": "build-cli-001-bootstrap-app", "stage": "build", "product": [ - "database" + "database", + "data-api" ], "topic": [ - "migrations" + "migrations", + "rls" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "all 3 tables exist (teams, members, tasks)", + "name": "supabase project initialised (supabase/config.toml exists)", "passed": true }, { - "name": "row counts match (teams=5, members=10, tasks=13)", + "name": "todos table is created by a migration file", "passed": true }, { - "name": "foreign key constraints survived the restore", - "passed": true + "name": "todos table exists with at least 2 seeded rows", + "passed": true, + "notes": "found 2 rows" }, { - "name": "tasks_team_status_idx index survived the restore", + "name": "row level security is enabled on todos", "passed": true }, { - "name": "sequences synced (next insert won't conflict with existing IDs)", + "name": "a SELECT policy targets the authenticated role", "passed": true + }, + { + "name": "REST API returns no todos to anonymous requests", + "passed": true, + "notes": "0 rows" + }, + { + "name": "REST API returns the todos to authenticated requests", + "passed": true, + "notes": "2 rows" } ], "skills": { @@ -8682,49 +8100,93 @@ "calls": [ { "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,140p'\"", + "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 6693 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"local development migrations seed RLS data API authenticated anon policies\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" + }, + { + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" } ], - "resultChars": 7789 + "resultChars": 82379 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase db start --from-backup logical backup pg_restore dump\", limit: 5) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"supabase local development workflow seed sql config.toml migrations new db reset\", limit: 10) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/download-logical-backups", - "title": "How to download logical backups in Supabase with physical backups enabled?" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/guides/local-development/seeding-your-database", + "title": "Seeding your database" }, { - "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", - "title": "Restore a Platform Project to Self-Hosted" + "url": "https://supabase.com/docs/reference/cli/supabase-db-reset", + "title": "Resets the local database to current migrations" }, { - "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", - "title": "Restoring a downloaded backup locally" + "url": "https://supabase.com/docs/guides/deployment/branching/troubleshooting", + "title": "Troubleshooting" + }, + { + "url": "https://supabase.com/docs/guides/deployment/branching/working-with-branches", + "title": "Working with branches" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations", + "title": "Database migrations" + }, + { + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/transferring-from-cloud-to-self-host-in-supabase-2oWNvW", - "title": "Transferring from platform to self-hosted Supabase" + "url": "https://supabase.com/docs/guides/deployment/branching/github-integration", + "title": "GitHub integration" }, { - "url": "https://supabase.com/docs/guides/platform/backups", - "title": "Database Backups" + "url": "https://supabase.com/docs/guides/deployment/managing-environments", + "title": "Managing Environments" } ], - "resultChars": 24731 + "resultChars": 102399 } ] }, - "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", - "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", + "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", + "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-database-001-migrate-postgres-to-supabase.json" + "sourcePath": "codex-gpt-5.4-mini/build-cli-001-bootstrap-app.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -8735,46 +8197,34 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-functions-004-service-role-bypass", + "eval": "build-cli-002-declarative-schema", "stage": "build", "product": [ - "edge-functions", - "auth", "database" ], "topic": [ - "rls", - "security", - "sdk" + "declarative-schema", + "migrations" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "rejects missing auth", - "passed": true, - "notes": "status=401" - }, - { - "name": "user A reads own note", - "passed": true, - "notes": "status=200" + "name": "supabase db diff used to generate the migration", + "passed": true }, { - "name": "reads only with the caller's JWT", - "passed": true, - "notes": "bearer_tokens=2, all_match=true" + "name": "schema file updated to include description column", + "passed": true }, { - "name": "user A cannot force-read user B note", - "passed": true, - "notes": "status=403" + "name": "a new migration was generated for the change", + "passed": true }, { - "name": "user B cannot force-read user A note", - "passed": true, - "notes": "status=403" + "name": "description column exists in the live database", + "passed": true } ], "skills": { @@ -8783,56 +8233,46 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions verify_jwt auth.getUser Bearer token\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", + "query": "query {\n searchDocs(query: \"declarative database schemas migrations supabase schema_paths\", limit: 5) {\n nodes {\n title\n href\n ... on Guide {\n content\n }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", + "title": "Declarative database schemas" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase", + "title": "Migrating to Supabase" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/api/rest/generating-types", + "title": "Generating TypeScript Types" }, { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" - } - ], - "resultChars": 32605 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/api/rest/generating-python-types", + "title": "Generating Python Types" } ], - "resultChars": 6745 + "resultChars": 55971 } ] }, - "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", - "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", + "prompt": "Add a description text column to the `products` table in my local Supabase stack", + "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-functions-004-service-role-bypass.json" + "sourcePath": "codex-gpt-5.4-mini/build-cli-002-declarative-schema.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -8843,279 +8283,132 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-functions-005-dual-auth-user-secret", + "eval": "build-cli-003-pg-cron-queue-workflow", "stage": "build", "product": [ + "database", "edge-functions", - "auth", - "database" + "cron", + "queues" ], "topic": [ - "sdk", - "rls", - "security" + "sql", + "sdk" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "seed rows present", - "passed": true, - "notes": "found 2/2 seeded rows" - }, - { - "name": "rejects request with no credentials", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "user with JWT reads only their own rows", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"9c85b93d-750c-4545-ad08-2e86b35ad9a6\",\"metric\":\"steps_a_msj0xq5b\",\"value\":111}]}" - }, - { - "name": "user cannot read another user's rows by passing user_id", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"9c85b93d-750c-4545-ad08-2e86b35ad9a6\",\"metric\":\"steps_a_msj0xq5b\",\"value\":111}]}" - }, - { - "name": "service key bypasses RLS to read the target user's rows", - "passed": true, - "notes": "status 200: {\"data\":[{\"user_id\":\"af4aed6d-bffa-426b-98f4-2f78b0fb1835\",\"metric\":\"steps_b_msj0xq5b\",\"value\":222}]}" - }, - { - "name": "non-service key is not granted service access", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "rejects an unverified (forged) user token", + "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "schedule='* * * * *', active=true" }, { - "name": "a user token in the apikey slot is not treated as the service key", + "name": "cron command enqueues to the 'tasks' queue", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "queue depth 1 -> 2" }, { - "name": "implementation uses @supabase/server", + "name": "process-tasks function drains the queue", "passed": true, - "notes": "imports @supabase/server / withSupabase" + "notes": "function removed the seeded message (id 3) from the queue" } ], "skills": { "available": [ "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions auth service_role key verify supabase access token request header user_id body\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#row-level-security", - "title": "Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#example", - "title": "Example" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#setting-up-auth-context", - "title": "Setting up auth context" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#fetching-the-user", - "title": "Fetching the user" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#security-considerations", - "title": "Security considerations" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#what-secret-keys-allow-access-to", - "title": "What secret keys allow access to" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#known-limitations-and-compatibility-differences", - "title": "Known limitations and compatibility differences" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#best-practices-for-handling-secret-keys", - "title": "Best practices for handling secret keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#what-to-do-if-a-secret-key-or-service_role-has-been-leaked-or-compromised", - "title": "What to do if a secret key or service_role has been leaked or compromised?" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#overview", - "title": "Overview" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#publishable-keys", - "title": "Publishable keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys#interaction-with-supabase-auth", - "title": "Interaction with Supabase Auth" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#public-functions", - "title": "Public functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#external-webhooks", - "title": "External webhooks" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#combining-modes", - "title": "Combining modes" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#custom-error-responses", - "title": "Custom error responses" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#environment-variables", - "title": "Environment variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#authenticated-user-calls", - "title": "Authenticated user calls" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth#service-to-service-calls", - "title": "Service-to-service calls" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-headers#understanding-authorization-headers", - "title": "Understanding authorization headers" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-headers#the-verify_jwt-platform-check", - "title": "The verify_jwt platform check" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", - "title": "Resumable WebSockets with Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#next-steps", - "title": "Next steps" - }, + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"pgmq queue enqueue dequeue cron scheduled job edge function local development\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#why-this-pattern-works", - "title": "Why this pattern works" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#browser-client", - "title": "Browser client" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#edge-function-websocket-proxy", - "title": "Edge Function (WebSocket proxy)" + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#database-schema", - "title": "Database schema" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#architecture", - "title": "Architecture" + "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", + "title": "Building an MCP Server with mcp-lite" } ], - "resultChars": 91747 + "resultChars": 78621 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase functions serve verify_jwt false config.toml edge function\", limit: 5) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"pgmq read delete message_record queue_name vt qty delete queue job message\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" - }, - { - "url": "https://supabase.com/docs/guides/functions/development-tips", - "title": "Development tips" - }, - { - "url": "https://supabase.com/docs/guides/functions/deploy", - "title": "Deploy to Production" + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", - "title": "Building an MCP Server with mcp-lite" + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" } ], - "resultChars": 32331 + "resultChars": 35174 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions service role key env var SUPABASE_SERVICE_ROLE_KEY secret key Deno.env\", limit: 5) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"pg_cron schedule every minute cron.schedule net.http_post edge function\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" + "url": "https://supabase.com/docs/guides/cron/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", - "title": "Inspecting edge function environment variables" + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" } ], - "resultChars": 44193 + "resultChars": 58557 } ] }, - "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", - "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-functions-005-dual-auth-user-secret.json" + "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", + "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini/build-cli-003-pg-cron-queue-workflow.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9126,79 +8419,44 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-rls-003-org-roles-permissions", + "eval": "build-dataapi-001-relational-report", "stage": "build", "product": [ - "database", - "auth" + "data-api", + "database" ], "topic": [ - "rls", - "security" + "sdk" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "RLS enabled on documents", - "passed": true - }, - { - "name": "viewer sees only documents in their org", - "passed": true - }, - { - "name": "viewer cannot insert", - "passed": true - }, - { - "name": "editor can insert own org document", - "passed": true - }, - { - "name": "editor can update own document", - "passed": true - }, - { - "name": "editor cannot update another user's document", - "passed": true - }, - { - "name": "editor cannot delete another user's document", - "passed": true - }, - { - "name": "admin can update any document in their org", - "passed": true - }, - { - "name": "admin can delete any document in their org", - "passed": true - }, - { - "name": "admin cannot affect another org", - "passed": true - }, - { - "name": "WITH CHECK blocks editor from moving document to another org", - "passed": true + "name": "report runs and prints JSON", + "passed": true, + "notes": "exit 0" }, { - "name": "editor can still see their own org's roster", - "passed": true + "name": "report numbers match the database (per customer, sorted)", + "passed": true, + "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" }, { - "name": "cannot see another org's membership roster", - "passed": true + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table customers" }, { - "name": "a viewer role in one org doesn't grant admin power in another org", - "passed": true + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "multi-org user can act as admin in the org where they hold that role", - "passed": true + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -9207,46 +8465,44 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"row level security organization members docs auth.uid policy security invoker\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "query": "query { searchDocs(query: \"supabase local project worker node report query table schema select\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/database/tables", - "title": "Tables and Data" + "url": "https://supabase.com/docs/reference/javascript/schema" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/api/sql-to-api", + "title": "Converting SQL to JavaScript API" }, { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/local-development/database-migrations", + "title": "Database migrations" }, { - "url": "https://supabase.com/docs/guides/database/postgres/roles", - "title": "Postgres Roles" + "url": "https://supabase.com/docs/guides/database/joins-and-nesting", + "title": "Querying Joins and Nested tables" } ], - "resultChars": 83587 + "resultChars": 46387 } ] }, - "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", - "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-rls-003-org-roles-permissions.json" + "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", + "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini/build-dataapi-001-relational-report.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9257,57 +8513,104 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-storage-001-private-bucket-access", + "eval": "build-dataapi-002-restock-alert-report", "stage": "build", "product": [ - "storage", + "data-api", "database" ], "topic": [ - "rls", "sdk" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "bucket user-files exists", - "passed": true + "name": "report runs and prints JSON", + "passed": true, + "notes": "exit 0" }, { - "name": "bucket user-files is private", - "passed": true + "name": "alerts match the database (below threshold, sorted)", + "passed": true, + "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" }, { - "name": "RLS still enabled on storage.objects", - "passed": true + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table inventory" }, { - "name": "user A lists only own files", - "passed": true, - "notes": "saw: 019fdc8d-2d5c-7238-bdd6-e937eefa55fb/receipt-alpha.pdf, 019fdc8d-2d5c-7238-bdd6-e937eefa55fb/receipt-beta.pdf" + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "user B cannot read user A files", + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" + } + ], + "skills": { + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] + }, + "docs": { + "calls": [] + }, + "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", + "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini/build-dataapi-002-restock-alert-report.json" + }, + { + "experiment": "codex-gpt-5.4-mini", + "experimentSuite": "benchmark", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.4-mini", + "reasoningEffort": "medium" + }, + "eval": "build-database-001-migrate-postgres-to-supabase", + "stage": "build", + "product": [ + "database" + ], + "topic": [ + "migrations" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "all 3 tables exist (teams, members, tasks)", "passed": true }, { - "name": "anon reads no files", + "name": "row counts match (teams=5, members=10, tasks=13)", "passed": true }, { - "name": "user A can upload into own folder", + "name": "foreign key constraints survived the restore", "passed": true }, { - "name": "user B cannot upload into user A folder", + "name": "tasks_team_status_idx index survived the restore", "passed": true }, { - "name": "configured private per-user storage access", - "passed": true, - "judgeNotes": "Creates private user-files bucket, owner-scoped SELECT and INSERT policies for authenticated role using first folder segment = auth.uid(), keeps RLS intact (no disabling), and provides createSignedUrl with a 15-minute expiry. Extra UPDATE/DELETE policies are acceptable." + "name": "sequences synced (next insert won't conflict with existing IDs)", + "passed": true } ], "skills": { @@ -9323,191 +8626,56 @@ "docs": { "calls": [ { - "source": "search_docs", - "query": "query { searchDocs(query: \"storage bucket policies objects path owner user id signed URL supabase\", limit: 5) { nodes { __typename title href ... on Guide { content } ... on TroubleshootingGuide { content } ... on ClientLibraryFunctionReference { content language methodName } } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" - }, - { - "url": "https://supabase.com/docs/guides/storage/serving/downloads", - "title": "Serving assets from Storage" - }, - { - "url": "https://supabase.com/docs/guides/storage", - "title": "Storage" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", - "title": "Build a User Management App with SvelteKit" - } - ], - "resultChars": 119861 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"storage.objects policy owner path prefix foldername user id signed URL createSignedUrl\", limit: 10) { nodes { __typename title href ... on Guide { content } ... on TroubleshootingGuide { content } ... on ClientLibraryFunctionReference { content language methodName } } } }", + "source": "shell_fetch", + "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,120p'\"", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" - }, - { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" - }, - { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" - }, - { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" - }, - { - "url": "https://supabase.com/docs/guides/storage/cdn/smart-cdn", - "title": "Smart CDN" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt", - "title": "Why can't I upload/list/etc my public bucket?" - }, - { - "url": "https://supabase.com/docs/reference/swift/storage-from-createsigneduploadurl", - "title": "from.createSignedUploadURL()" - }, - { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" - }, - { - "url": "https://supabase.com/docs/guides/storage/serving/downloads", - "title": "Serving assets from Storage" - }, - { - "url": "https://supabase.com/docs/reference/swift/storage-from-createsignedurls", - "title": "from.createSignedUrls()" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 17609 + "resultChars": 6693 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"storage access control policy examples foldername auth uid owner\", limit: 10) { nodes { __typename title href ... on Guide { content } ... on TroubleshootingGuide { content } } } }", + "query": "query { searchDocs(query: \"local development restore pg_restore binary dump supabase start init\", limit: 5) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content methodName language } ... on TroubleshootingGuide { title href content } } totalCount } }", "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" - }, - { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" - }, - { - "url": "https://supabase.com/docs/guides/storage/security/ownership", - "title": "Ownership" - }, - { - "url": "https://supabase.com/docs/guides/storage/quickstart", - "title": "Storage Quickstart" - }, - { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" - }, - { - "url": "https://supabase.com/docs/guides/storage/management/copy-move-objects", - "title": "Copy Objects" - }, - { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" - }, - { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/supabase-storage-inefficient-folder-operations-and-hierarchical-rls-challenges-b05a4d", - "title": "Supabase Storage: Inefficient folder operations and hierarchical RLS challenges" - } - ], - "resultChars": 60503 + "pages": [] }, { "source": "search_docs", - "query": "query { searchDocs(query: \"storage object ownership owner column path prefix foldername access control\", limit: 10) { nodes { __typename title href ... on Guide { content } ... on TroubleshootingGuide { content } } } }", + "query": "query { searchDocs(query: \"supabase init local development start containers restore dump pg_restore\", limit: 5) { nodes { title href content } totalCount } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/security/ownership", - "title": "Ownership" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/supabase-storage-inefficient-folder-operations-and-hierarchical-rls-challenges-b05a4d", - "title": "Supabase Storage: Inefficient folder operations and hierarchical RLS challenges" - }, - { - "url": "https://supabase.com/docs/guides/storage/management/copy-move-objects", - "title": "Copy Objects" - }, - { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" - }, - { - "url": "https://supabase.com/docs/guides/storage/schema/design", - "title": "The Storage Schema" - }, - { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" + "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", + "title": "Restoring a downloaded backup locally" }, { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" + "url": "https://supabase.com/docs/guides/ai/vecs-python-client", + "title": "Python client" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" - } - ], - "resultChars": 32342 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"supabase-js createSignedUrl storage from bucket expiresIn share file temporary link\", limit: 3) { nodes { __typename title href ... on ClientLibraryFunctionReference { content language methodName } } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/storage/serving/downloads", - "title": "Serving assets from Storage" + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" }, { - "url": "https://supabase.com/docs/guides/platform/manage-your-usage/storage-image-transformations", - "title": "Manage Storage Image Transformations usage" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", + "title": "Migrate from Postgres to Supabase" }, { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" } ], - "resultChars": 1476 + "resultChars": 60080 } ] }, - "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", - "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", + "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-storage-001-private-bucket-access.json" + "sourcePath": "codex-gpt-5.4-mini/build-database-001-migrate-postgres-to-supabase.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9518,33 +8686,46 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-tests-001-rls-tenant-isolation", + "eval": "build-functions-004-service-role-bypass", "stage": "build", "product": [ + "edge-functions", + "auth", "database" ], "topic": [ - "tests", - "rls" + "rls", + "security", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "pgTAP test file(s) written under supabase/tests/", + "name": "rejects missing auth", "passed": true, - "notes": "1 file(s): supabase/tests/tenant_isolation_test.sql" + "notes": "status=401" }, { - "name": "pgTAP isolation tests ran and pass", + "name": "user A reads own note", "passed": true, - "notes": "4 passed, 0 failed" + "notes": "status=200" }, { - "name": "agent correctly identifies the posts isolation bug from test results", + "name": "reads only with the caller's JWT", "passed": true, - "judgeNotes": "The agent correctly identified `posts` as the broken tenant isolation policy, grounded it in the pgTAP result (`cross-org posts` check failed), and did not blame `notes` or dismiss the tests. It also noted `notes` passed and treated the test results as authoritative." + "notes": "bearer_tokens=2, all_match=true" + }, + { + "name": "user A cannot force-read user B note", + "passed": true, + "notes": "status=403" + }, + { + "name": "user B cannot force-read user A note", + "passed": true, + "notes": "status=403" } ], "skills": { @@ -9560,78 +8741,98 @@ "docs": { "calls": [ { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,160p'\"", + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase Edge Functions auth getUser verify_jwt Authorization header\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/auth", + "title": "Auth" } ], - "resultChars": 1140 + "resultChars": 33865 }, { "source": "search_docs", - "query": "query {\n searchDocs(query: \"pgTAP tests RLS Supabase local database tests\", limit: 5) {\n nodes {\n ... on Guide {\n title\n href\n content\n }\n ... on TroubleshootingGuide {\n title\n href\n content\n }\n ... on CLICommandReference {\n title\n href\n content\n }\n }\n totalCount\n }\n}", + "query": "query { searchDocs(query: \"Edge Functions authorization verify_jwt auth.getUser service role private notes\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/local-development/testing/overview", - "title": "Testing Overview" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/database/testing", - "title": "Testing Your Database" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", - "title": "Testing and linting" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, { - "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", - "title": "Advanced pgTAP Testing" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" } ], - "resultChars": 68853 + "resultChars": 50091 }, { - "source": "search_docs", - "query": "query {\n searchDocs(query: \"request.jwt.claims auth.uid set local pgtap Supabase\", limit: 5) {\n nodes {\n ... on Guide {\n title\n href\n content\n }\n }\n totalCount\n }\n}", + "source": "shell_fetch", + "query": "/bin/bash -lc 'curl -fsSL https://supabase.com/changelog.md | rg -n \"breaking-change|Edge Functions|verify_jwt|auth\"'", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/local-development/testing/overview", - "title": "Testing Overview" - }, - { - "url": "https://supabase.com/docs/guides/realtime/authorization", - "title": "Realtime Authorization" - }, + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 22279 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Edge Functions verify_jwt default Authorization header auth.getUser RLS\", limit: 3) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", - "title": "Firebase Auth" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" } ], - "resultChars": 66662 + "resultChars": 19054 } ] }, - "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", - "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", + "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", + "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/build-tests-001-rls-tenant-isolation.json" + "sourcePath": "codex-gpt-5.4-mini/build-functions-004-service-role-bypass.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9642,24 +8843,27 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-vectors-001-rag-with-permissions", + "eval": "build-functions-005-dual-auth-user-secret", "stage": "build", "product": [ - "database", - "vectors" + "edge-functions", + "auth", + "database" ], "topic": [ - "sql", - "rls" + "sdk", + "rls", + "security" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", + "cliVersion": "2.109.1", "passed": false, "checks": [ { - "name": "created auth sessions", + "name": "scorer completed without errors", "passed": false, - "notes": "Internal server error" + "notes": "could not read `supabase status`: WARN: config section [inbucket] is deprecated. Please use [local_smtp] instead.\nsupabase_db_sandbox-dual-auth container is not running: exited\nTry rerunning the command with --debug to troubleshoot the error.\n" } ], "skills": { @@ -9668,74 +8872,141 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"semantic search pgvector row level security documents ownership\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href methodName language } ... on TroubleshootingGuide { title href content } } } }", + "query": "query {\n searchDocs(query: \"Edge Functions verify JWT service_role apikey header supabase function supabase-js createClient user-stats\", limit: 5) {\n edges {\n node {\n title\n href\n content\n }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/ai/hybrid-search", - "title": "Hybrid search" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/storage/vector/querying-vectors", - "title": "Querying Vectors" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgvector", - "title": "pgvector: Embeddings and vector similarity" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" } ], - "resultChars": 68480 + "resultChars": 36762 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"pgvector extension vector schema extensions match_documents function RLS authenticated ownership\", limit: 10) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href methodName language } } } }", + "query": "query {\n searchDocs(query: \"Edge Functions verify_jwt false secret key apikey user JWT withSupabase auth array config.toml functions.user-stats\", limit: 10) {\n edges { node { title href content } }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgvector", - "title": "pgvector: Embeddings and vector similarity" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/storage/vector/introduction", - "title": "Vector Buckets" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/ai/hybrid-search", - "title": "Hybrid search" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/reports", + "title": "Reports" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + } + ], + "resultChars": 115133 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"authorization headers secret key service_role apikey Edge Functions auth secret legacy service_role\", limit: 10) {\n edges { node { title href content } }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/roles", + "title": "Postgres Roles" } ], - "resultChars": 49023 + "resultChars": 126017 } ] }, - "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", - "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", + "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", + "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini/build-vectors-001-rag-with-permissions.json" + "sourcePath": "codex-gpt-5.4-mini/build-functions-005-dual-auth-user-secret.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9746,31 +9017,79 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "deploy-database-001-prometheus-metrics", - "stage": "deploy", + "eval": "build-rls-003-org-roles-permissions", + "stage": "build", "product": [ - "database" + "database", + "auth" ], "topic": [ - "observability" + "rls", + "security" ], "suite": "benchmark", - "interface": "cli", - "passed": false, + "interface": "mcp", + "passed": true, "checks": [ { - "name": "preserved existing app scrape job", + "name": "RLS enabled on documents", "passed": true }, { - "name": "configured the Supabase Metrics API scrape correctly", - "passed": false, - "judgeNotes": "prometheus.yml does not add a deployable Supabase scrape job. It relies on an entrypoint/env injection not shown, uses SUPABASE_SECRET_API_KEY instead of an HTTP Basic Auth password_file, and docker-compose.yml does not mount that password_file via a volume or Compose secret. The existing app job is preserved, but required Supabase scrape wiring is missing." + "name": "viewer sees only documents in their org", + "passed": true }, { - "name": "documented live deployment and verification steps", - "passed": false, - "judgeNotes": "README explains env-based setup and restart, but it does not require placing a matching secret file, and it lacks concrete verification steps via Prometheus targets, PromQL/Grafana, or equivalent." + "name": "viewer cannot insert", + "passed": true + }, + { + "name": "editor can insert own org document", + "passed": true + }, + { + "name": "editor can update own document", + "passed": true + }, + { + "name": "editor cannot update another user's document", + "passed": true + }, + { + "name": "editor cannot delete another user's document", + "passed": true + }, + { + "name": "admin can update any document in their org", + "passed": true + }, + { + "name": "admin can delete any document in their org", + "passed": true + }, + { + "name": "admin cannot affect another org", + "passed": true + }, + { + "name": "WITH CHECK blocks editor from moving document to another org", + "passed": true + }, + { + "name": "editor can still see their own org's roster", + "passed": true + }, + { + "name": "cannot see another org's membership roster", + "passed": true + }, + { + "name": "a viewer role in one org doesn't grant admin power in another org", + "passed": true + }, + { + "name": "multi-org user can act as admin in the org where they hold that role", + "passed": true } ], "skills": { @@ -9786,45 +9105,44 @@ "docs": { "calls": [ { - "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase metrics Prometheus project metrics\", limit: 5) { nodes { __typename title href content ... on Guide { subsections { nodes { title href content } } } ... on TroubleshootingGuide { } } totalCount } }", - "hasContent": true, + "source": "web_search", + "query": "site:supabase.com changelog.md breaking-change row level security supabase", "pages": [] }, { "source": "search_docs", - "query": "query { searchDocs(query: \"metrics prometheus\", limit: 5) { nodes { title href content } totalCount } }", + "query": "query { searchDocs(query: \"row level security policies authenticated TO owner membership org admin editor viewer\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" + "url": "https://supabase.com/docs/guides/realtime/getting_started", + "title": "Getting Started with Realtime" }, { - "url": "https://supabase.com/docs/guides/database/replication/manual-replication-monitoring", - "title": "Manual replication monitoring" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" } ], - "resultChars": 23603 + "resultChars": 75044 } ] }, - "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", - "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini/deploy-database-001-prometheus-metrics.json" + "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", + "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.4-mini/build-rls-003-org-roles-permissions.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -9835,35 +9153,57 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "deploy-functions-001-edge-function-secrets", - "stage": "deploy", + "eval": "build-storage-001-private-bucket-access", + "stage": "build", "product": [ - "edge-functions" + "storage", + "database" ], "topic": [ - "security" + "rls", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "WEATHER_API_KEY is set as a Function secret on the project", + "name": "bucket user-files exists", "passed": true }, { - "name": "the weather function is deployed to the project", - "passed": true, - "notes": "status ACTIVE" + "name": "bucket user-files is private", + "passed": true }, { - "name": "the weather function reads WEATHER_API_KEY from the environment", + "name": "RLS still enabled on storage.objects", + "passed": true + }, + { + "name": "user A lists only own files", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "notes": "saw: 01a03a86-86ea-7788-86c2-2199d0e1bcc4/receipt-alpha.pdf, 01a03a86-86ea-7788-86c2-2199d0e1bcc4/receipt-beta.pdf" }, { - "name": "WEATHER_API_KEY value is not committed to the repo", + "name": "user B cannot read user A files", + "passed": true + }, + { + "name": "anon reads no files", + "passed": true + }, + { + "name": "user A can upload into own folder", + "passed": true + }, + { + "name": "user B cannot upload into user A folder", "passed": true + }, + { + "name": "configured private per-user storage access", + "passed": true, + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT policies, enabled RLS, and expiring createSignedUrl sharing are all present." } ], "skills": { @@ -9872,341 +9212,193 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions environment variables secrets deploy supabase secrets set function env var runtime\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "query": "query {\n searchDocs(query: \"storage signed url policy bucket private files path owner user id\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n ... on ManagementApiReference { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", - "title": "Envoy API Gateway" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#x-forwarded-headers", - "title": "X-Forwarded headers" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#forwarded-headers-and-cors", - "title": "Forwarded headers and CORS" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#opaque-key-translation", - "title": "Opaque key translation" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#api-key-enforcement-on-protected-routes", - "title": "API key enforcement on protected routes" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#dashboard-basic-auth", - "title": "Dashboard basic auth" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#authentication", - "title": "Authentication" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#routes", - "title": "Routes" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#how-the-configuration-is-rendered-at-startup", - "title": "How the configuration is rendered at startup" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#configuration-file-structure", - "title": "Configuration file structure" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#architecture", - "title": "Architecture" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#verify", - "title": "Verify" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#enabling-the-envoy-gateway", - "title": "Enabling the Envoy gateway" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#before-you-begin", - "title": "Before you begin" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#see-also", - "title": "See also" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#common-issues", - "title": "Common issues" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#logs", - "title": "Logs" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#troubleshooting", - "title": "Troubleshooting" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#admin-interface", - "title": "Admin interface" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#customizing-the-configuration", - "title": "Customizing the configuration" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#security-hardening", - "title": "Security hardening" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#cors", - "title": "CORS" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-2-adopt-the-supabaseserver-sdk", - "title": "Option 2: Adopt the @supabase/server SDK" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-5-verify-nothing-uses-the-legacy-keys", - "title": "Step 5: Verify nothing uses the legacy keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-6-deactivate-the-legacy-keys", - "title": "Step 6: Deactivate the legacy keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#known-limitations", - "title": "Known limitations" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#next-steps", - "title": "Next steps" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-1-read-the-new-keys-from-the-environment", - "title": "Option 1: Read the new keys from the environment" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#before-you-start", - "title": "Before you start" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-1-create-the-new-api-keys", - "title": "Step 1: Create the new API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-2-swap-the-publishable-key-in-client-code", - "title": "Step 2: Swap the publishable key in client code" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-3-swap-the-secret-key-in-backend-code", - "title": "Step 3: Swap the secret key in backend code" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#database-webhooks-and-pg_net", - "title": "Database Webhooks and pg_net" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-4-update-edge-functions", - "title": "Step 4: Update Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", - "title": "Streaming Speech with ElevenLabs" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#run-locally", - "title": "Run locally" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#code-the-supabase-edge-function", - "title": "Code the Supabase Edge Function" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#dependencies", - "title": "Dependencies" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#set-up-the-environment-variables", - "title": "Set up the environment variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#create-a-supabase-edge-function-for-speech-generation", - "title": "Create a Supabase Edge Function for speech generation" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#configure-background-tasks-for-supabase-edge-functions", - "title": "Configure background tasks for Supabase Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#configure-the-storage-bucket", - "title": "Configure the storage bucket" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#create-a-supabase-project-locally", - "title": "Create a Supabase project locally" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#setup", - "title": "Setup" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#requirements", - "title": "Requirements" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#introduction", - "title": "Introduction" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#test-the-function", - "title": "Test the function" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#set-the-function-secrets", - "title": "Set the function secrets" + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#deploy-to-supabase", - "title": "Deploy to Supabase" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-angular", + "title": "Build a User Management App with Angular" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#try-it-out", - "title": "Try it out" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-angular", + "title": "Build a User Management App with Ionic Angular" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", - "title": "Transcription Telegram Bot" + "url": "https://supabase.com/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt", + "title": "Why can't I upload/list/etc my public bucket?" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#dependencies", - "title": "Dependencies" - }, + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native", + "title": "Build a User Management App with Expo React Native" + } + ], + "resultChars": 103275 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"supabase-js createSignedUrl storage from bucket download private bucket\", limit: 10) {\n nodes {\n ... on Guide { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n }\n }\n}", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#test-the-bot", - "title": "Test the bot" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-the-function-secrets", - "title": "Set the function secrets" + "url": "https://supabase.com/docs/guides/platform/manage-your-usage/storage-image-transformations", + "title": "Manage Storage Image Transformations usage" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-up-the-webhook", - "title": "Set up the webhook" + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#apply-the-database-migrations", - "title": "Apply the database migrations" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-download" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#deploy-to-supabase", - "title": "Deploy to Supabase" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/firebase-storage", + "title": "Migrated from Firebase Storage to Supabase" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#code-the-telegram-bot", - "title": "Code the Telegram bot" + "url": "https://supabase.com/docs/guides/functions/examples/amazon-bedrock-image-generator", + "title": "Generate Images with Amazon Bedrock" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-up-the-environment-variables", - "title": "Set up the environment variables" + "url": "https://supabase.com/docs/guides/storage/serving/image-transformations", + "title": "Storage Image Transformations" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-supabase-edge-function-to-handle-telegram-webhook-requests", - "title": "Create a Supabase Edge Function to handle Telegram webhook requests" + "url": "https://supabase.com/docs/guides/storage/uploads/resumable-uploads", + "title": "Resumable Uploads" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-database-table-to-log-the-transcription-results", - "title": "Create a database table to log the transcription results" + "url": "https://supabase.com/docs/guides/storage/management/copy-move-objects", + "title": "Copy Objects" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-supabase-project-locally", - "title": "Create a Supabase project locally" - }, + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" + } + ], + "resultChars": 63682 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"storage access control bucket policy storage.objects owner path prefix createSignedUrl\", limit: 10) {\n nodes {\n ... on Guide { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n }\n }\n}", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#register-a-telegram-bot", - "title": "Register a Telegram bot" + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#setup", - "title": "Setup" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#requirements", - "title": "Requirements" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#introduction", - "title": "Introduction" + "url": "https://supabase.com/docs/guides/storage/cdn/smart-cdn", + "title": "Smart CDN" }, { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/security/product-security", + "title": "Secure configuration of Supabase products" }, { - "url": "https://supabase.com/docs/guides/functions/secrets#default-secrets", - "title": "Default secrets" + "url": "https://supabase.com/docs/reference/dart/file-buckets-createsigneduploadurl" }, { - "url": "https://supabase.com/docs/guides/functions/secrets#production-secrets", - "title": "Production secrets" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" }, { - "url": "https://supabase.com/docs/guides/functions/secrets#local-secrets", - "title": "Local secrets" + "url": "https://supabase.com/docs/reference/swift/storage-from-createsigneduploadurl", + "title": "from.createSignedUploadURL()" }, { - "url": "https://supabase.com/docs/guides/functions/secrets#accessing-environment-variables", - "title": "Accessing environment variables" + "url": "https://supabase.com/docs/guides/storage/cdn/fundamentals", + "title": "Storage CDN" } ], - "resultChars": 149695 + "resultChars": 22924 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "web_search", + "query": "site:supabase.com changelog md Supabase breaking-change storage signed url", + "pages": [] }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Edge Functions JWT verification no-verify-jwt public browser invoke\", limit: 5) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"storage.foldername helper function storage objects folder prefix\", limit: 5) {\n nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/firebase-storage", + "title": "Migrated from Firebase Storage to Supabase" + } + ], + "resultChars": 7872 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"storage object ownership owner_id owner select insert foldername\", limit: 5) {\n nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/storage/management/copy-move-objects", + "title": "Copy Objects" }, { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" + "url": "https://supabase.com/docs/guides/storage/security/ownership", + "title": "Ownership" }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/security/product-security", + "title": "Secure configuration of Supabase products" }, { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" } ], - "resultChars": 47787 + "resultChars": 17780 + }, + { + "source": "web_search", + "query": "site:supabase.com/docs/guides/storage/security/access-control Supabase Storage access control private buckets signed URL", + "pages": [] } ] }, - "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", - "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", + "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/deploy-functions-001-edge-function-secrets.json" + "sourcePath": "codex-gpt-5.4-mini/build-storage-001-private-bucket-access.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -10217,35 +9409,33 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "deploy-self-hosting-001-docker-compose", - "stage": "deploy", + "eval": "build-tests-001-rls-tenant-isolation", + "stage": "build", "product": [ - "database", - "auth", - "storage" + "database" ], "topic": [ - "self-hosting" + "tests", + "rls" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", - "passed": true - }, - { - "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", - "passed": true + "name": "pgTAP test file(s) written under supabase/tests/", + "passed": true, + "notes": "2 file(s): supabase/tests/database/tenant_isolation.test.sql, supabase/tests/tenant_isolation.test.sql" }, { - "name": "secrets rotated off the shipped defaults", - "passed": true + "name": "pgTAP isolation tests ran and pass", + "passed": true, + "notes": "8 passed, 0 failed" }, { - "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", - "passed": true + "name": "agent correctly identifies the posts isolation bug from test results", + "passed": true, + "judgeNotes": "Correctly identifies `posts` as the broken tenant-isolation policy, explains the missing organization check, and grounds the conclusion in pgTAP results showing cross-tenant reads before the fix and 4/4 passing afterward." } ], "skills": { @@ -10261,25 +9451,39 @@ "docs": { "calls": [ { - "source": "web_search", - "query": "site:supabase.com/changelog.md Supabase breaking-change self-hosting docker compose", - "pages": [] - }, - { - "source": "web_search", - "query": "https://supabase.com/docs/guides/self-hosting/docker", + "source": "search_docs", + "query": "query { searchDocs(query: \"database tests pgTAP Supabase CLI test db\", limit: 5) { nodes { title href content } } }", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker" + "url": "https://supabase.com/docs/reference/cli/supabase-test-db", + "title": "Tests local database with pgTAP" + }, + { + "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", + "title": "Testing and linting" + }, + { + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" + }, + { + "url": "https://supabase.com/docs/guides/database/testing", + "title": "Testing Your Database" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgtap", + "title": "pgTAP: Unit Testing" } - ] + ], + "resultChars": 23900 } ] }, - "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", - "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", + "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", + "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini/deploy-self-hosting-001-docker-compose.json" + "sourcePath": "codex-gpt-5.4-mini/build-tests-001-rls-tenant-isolation.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -10290,48 +9494,50 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "investigate-auth-001-deleted-user-access", - "stage": "investigate", + "eval": "build-vectors-001-rag-with-permissions", + "stage": "build", "product": [ - "auth" + "database", + "vectors" ], "topic": [ - "security", - "sdk" + "sql", + "rls" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "victim session active before delete-account", - "passed": true + "name": "document_sections.embedding is vector(384)", + "passed": true, + "notes": "vector(384)" }, { - "name": "delete_account flow ran for the victim", - "passed": true + "name": "HNSW index on the embedding column", + "passed": true, + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops) WHERE (embedding IS NOT NULL)" }, { - "name": "delete-account revokes the user's sessions", + "name": "index operator class matches the search operator", "passed": true, - "notes": "sessions left: 0" + "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops) WHERE (embedding IS NOT NULL)" }, { - "name": "deleted user's refresh token is rejected", + "name": "user A search returns only own sections, best match first", "passed": true }, { - "name": "deleted user cannot sign back in", + "name": "user B search returns only own sections, best match first", "passed": true }, { - "name": "other users keep their sessions and access", + "name": "user A reads only own sections through the API", "passed": true }, { - "name": "diagnosed and explained session revocation", - "passed": true, - "judgeNotes": "Meets the rubric: identifies soft-delete-only bug, updates flow to delete auth user and lock down RLS, explains stale JWT caveat consistently with the RLS mitigation, and correctly distinguishes publishable/anon vs secret/service_role keys." + "name": "user A reads only own documents through the API", + "passed": true } ], "skills": { @@ -10346,94 +9552,145 @@ }, "docs": { "calls": [ + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, { "source": "search_docs", - "query": "query { searchDocs(query: \"delete user revoke sessions auth admin sign out user delete account\", limit: 5) { nodes { title href ... on Guide { content } ... on TroubleshootingGuide { content } ... on ClientLibraryFunctionReference { methodName language content href } } } }", + "query": "query { searchDocs(query: \"pgvector semantic search RLS ownership documents\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } ... on ManagementApiReference { title href content } ... on CLICommandReference { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/ai/hybrid-search", + "title": "Hybrid search" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-signout" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" + "url": "https://supabase.com/docs/guides/ai/vector-indexes/ivf-indexes", + "title": "IVFFlat indexes" } ], - "resultChars": 20977 + "resultChars": 76887 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"publishable key secret key anon key service role frontend rls\", limit: 5) { nodes { title href ... on Guide { content } ... on ClientLibraryFunctionReference { methodName language content href } } } }", + "query": "query { searchDocs(query: \"semantic search pgvector documents sections RLS policy auth.uid()\", limit: 3) { nodes { ... on Guide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/auth/jwt-fields", - "title": "JWT Claims Reference" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" + "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", + "title": "Declarative database schemas" + } + ], + "resultChars": 35600 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"row level security documents owner_id auth.uid ownership policy\", limit: 3) { nodes { ... on Guide { title href content } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/storage/security/ownership", + "title": "Ownership" } ], - "resultChars": 68789 - }, - { - "source": "web_search", - "query": "site:supabase.com/changelog.md Supabase changelog markdown", - "pages": [] + "resultChars": 27934 }, { - "source": "web_search", - "query": "https://supabase.com/changelog.md", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs/guides/getting-started/api-keys Supabase publishable secret key anon service_role", - "pages": [] + "source": "search_docs", + "query": "query { searchDocs(query: \"vector column dimensions pgvector supabase vector(n)\", limit: 5) { nodes { ... on Guide { title href content } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/vector-indexes/hnsw-indexes", + "title": "HNSW indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgvector", + "title": "pgvector: Embeddings and vector similarity" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" + }, + { + "url": "https://supabase.com/docs/guides/ai/vector-columns", + "title": "Vector columns" + }, + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + } + ], + "resultChars": 65961 }, { - "source": "web_search", - "query": "https://supabase.com/docs/guides/getting-started/api-keys", + "source": "search_docs", + "query": "query { searchDocs(query: \"pgvector vector without dimensions unbounded column\", limit: 5) { nodes { ... on Guide { title href content } } } }", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/api-keys" + "url": "https://supabase.com/docs/guides/database/extensions/pgvector", + "title": "pgvector: Embeddings and vector similarity" + }, + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, + { + "url": "https://supabase.com/docs/guides/storage/vector/introduction", + "title": "Vector Buckets" + }, + { + "url": "https://supabase.com/docs/guides/ai/choosing-compute-addon", + "title": "Choosing your Compute Add-on" + }, + { + "url": "https://supabase.com/docs/guides/ai/vector-columns", + "title": "Vector columns" } - ] - }, - { - "source": "web_search", - "query": "'Deleting users' in https://supabase.com/docs/guides/auth/managing-user-data", - "pages": [] + ], + "resultChars": 50744 } ] }, - "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", - "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", + "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", + "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini/investigate-auth-001-deleted-user-access.json" + "sourcePath": "codex-gpt-5.4-mini/build-vectors-001-rag-with-permissions.json" }, { "experiment": "codex-gpt-5.4-mini", @@ -10444,44 +9701,31 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "investigate-realtime-001-subscribed-no-events", - "stage": "investigate", + "eval": "deploy-database-001-prometheus-metrics", + "stage": "deploy", "product": [ - "realtime", "database" ], "topic": [ - "sdk" + "observability" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "passed": false, "checks": [ { - "name": "orders table added to supabase_realtime publication", - "passed": true - }, - { - "name": "courier_locations still in supabase_realtime publication", - "passed": true - }, - { - "name": "publication still publishes INSERT events", - "passed": true - }, - { - "name": "RLS still enabled on orders", - "passed": true + "name": "preserved existing app scrape job", + "passed": false }, { - "name": "staff can still read orders through RLS", - "passed": true, - "notes": "authenticated sees 2 of 2 orders" + "name": "configured the Supabase Metrics API scrape correctly", + "passed": false, + "judgeNotes": "prometheus.yml is empty. No app or Supabase scrape job exists, and docker-compose.yml does not mount a Basic Auth password_file via volume or secret." }, { - "name": "diagnosed missing publication membership", - "passed": true, - "judgeNotes": "Identified the root cause as orders missing from supabase_realtime despite successful subscription, fixed by ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, and preserved courier_locations plus RLS/policies." + "name": "documented live deployment and verification steps", + "passed": false, + "judgeNotes": "README covers key setup and Compose recreation, but lacks concrete verification steps such as checking Prometheus /targets or running a PromQL/Grafana query." } ], "skills": { @@ -10489,466 +9733,720 @@ "supabase", "supabase-postgres-best-practices" ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "loaded": [] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Realtime postgres_changes publication supabase_realtime table not receiving events\", limit: 5) { nodes { __typename title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "query": "query { searchDocs(query: \"project metrics prometheus observability endpoint metrics supabase\", limit: 10) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes", - "title": "Subscribing to Database Changes" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#broadcast-authorization", - "title": "Broadcast authorization" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#streaming-updates", - "title": "Streaming updates" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#streaming-inserts", - "title": "Streaming inserts" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#enable-postgres-changes", - "title": "Enable Postgres Changes" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#using-postgres-changes", - "title": "Using Postgres Changes" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#listening-on-client-side", - "title": "Listening on client side" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#create-a-trigger", - "title": "Create a trigger" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#create-a-trigger-function", - "title": "Create a trigger function" - }, - { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes#using-broadcast", - "title": "Using Broadcast" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks", - "title": "Benchmarks" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#methodology", - "title": "Methodology" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#workloads", - "title": "Workloads" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#results", - "title": "Results" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#broadcast-using-websockets", - "title": "Broadcast: Using WebSockets" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#broadcast-using-the-database", - "title": "Broadcast: Using the database" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#broadcast-impact-of-payload-size", - "title": "Broadcast: Impact of payload size" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#1kb-payload", - "title": "1KB payload" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#10kb-payload", - "title": "10KB payload" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#50kb-payload", - "title": "50KB payload" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#broadcast-scalability-scenarios", - "title": "Broadcast: Scalability scenarios" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#realtime-auth", - "title": "Realtime Auth" - }, - { - "url": "https://supabase.com/docs/guides/realtime/benchmarks#postgres-changes", - "title": "Postgres Changes" - }, - { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes", - "title": "Postgres Changes" - }, - { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#refreshed-tokens", - "title": "Refreshed tokens" - }, - { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#custom-tokens", - "title": "Custom tokens" - }, - { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#private-schemas", - "title": "Private schemas" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#receiving-old-records", - "title": "Receiving old records" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#what-you-can-do-with-the-metrics-api", + "title": "What you can do with the Metrics API" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#quick-start", - "title": "Quick start" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#choose-your-monitoring-stack", + "title": "Choose your monitoring stack" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#usage", - "title": "Usage" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#additional-resources", + "title": "Additional resources" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-specific-schemas", - "title": "Listening to specific schemas" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-insert-events", - "title": "Listening to INSERT events" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#components", + "title": "Components" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-update-events", - "title": "Listening to UPDATE events" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#1-define-the-scrape-job", + "title": "1. Define the scrape job" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-delete-events", - "title": "Listening to DELETE events" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#collector-specific-notes", + "title": "Collector-specific notes" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-specific-tables", - "title": "Listening to specific tables" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#2-secure-the-credentials", + "title": "2. Secure the credentials" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#listening-to-multiple-changes", - "title": "Listening to multiple changes" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#3-downstream-dashboards", + "title": "3. Downstream dashboards" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#filtering-for-specific-changes", - "title": "Filtering for specific changes" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#4-alerts-and-automation", + "title": "4. Alerts and automation" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#available-filters", - "title": "Available filters" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#5-multi-project-setups", + "title": "5. Multi-project setups" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#equal-to-eq", - "title": "Equal to (eq)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#not-equal-to-neq", - "title": "Not equal to (neq)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#6-troubleshooting", + "title": "6. Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#less-than-lt", - "title": "Less than (lt)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#1-create-a-grafana-cloud-stack", + "title": "1. Create a Grafana Cloud stack" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#less-than-or-equal-to-lte", - "title": "Less than or equal to (lte)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#2-install-the-supabase-integration-for-grafana-cloud", + "title": "2. Install the Supabase integration for Grafana Cloud" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#greater-than-gt", - "title": "Greater than (gt)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#3-configure-the-supabase-integration", + "title": "3. Configure the Supabase integration" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#greater-than-or-equal-to-gte", - "title": "Greater than or equal to (gte)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#4-import-the-supabase-dashboard", + "title": "4. Import the Supabase dashboard" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#contained-in-list-in", - "title": "Contained in list (in)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#5-configure-alerts-optional", + "title": "5. Configure alerts (optional)" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#database-instance-and-realtime-performance", - "title": "Database instance and realtime performance" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#installation", + "title": "Installation" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#spaces-in-table-names", - "title": "Spaces in table names" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#manual-setup", + "title": "Manual setup" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#delete-events-are-not-filterable", - "title": "Delete events are not filterable" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#prerequisites", + "title": "Prerequisites" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes#limitations", - "title": "Limitations" + "url": "https://supabase.com/docs/guides/platform/read-replicas", + "title": "Read Replicas" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol", - "title": "Realtime Protocol" + "url": "https://supabase.com/docs/guides/platform/read-replicas#logging", + "title": "Logging" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#join-errors", - "title": "Join errors" + "url": "https://supabase.com/docs/guides/platform/read-replicas#metrics", + "title": "Metrics" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#websocket-connection-setup", - "title": "WebSocket connection setup" + "url": "https://supabase.com/docs/guides/platform/read-replicas#centralized-configuration-management", + "title": "Centralized configuration management" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#protocol-messages", - "title": "Protocol messages" + "url": "https://supabase.com/docs/guides/platform/read-replicas#pricing", + "title": "Pricing" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#100", - "title": "1.0.0" + "url": "https://supabase.com/docs/guides/platform/read-replicas#about-read-replicas", + "title": "About Read Replicas" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#200", - "title": "2.0.0" + "url": "https://supabase.com/docs/guides/platform/read-replicas#features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#text-frames", - "title": "Text frames" + "url": "https://supabase.com/docs/guides/platform/read-replicas#dedicated-endpoints", + "title": "Dedicated endpoints" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#binary-frames", - "title": "Binary frames" + "url": "https://supabase.com/docs/guides/platform/read-replicas#dedicated-connection-pool", + "title": "Dedicated connection pool" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#user-broadcast-push", - "title": "User Broadcast Push" + "url": "https://supabase.com/docs/guides/platform/read-replicas#api-load-balancer", + "title": "API load balancer" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#user-broadcast", - "title": "User Broadcast" + "url": "https://supabase.com/docs/guides/platform/read-replicas#querying-through-the-sql-editor", + "title": "Querying through the SQL editor" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#event-types", - "title": "Event types" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#client-sent-events", - "title": "Client sent events" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#architecture", + "title": "Architecture" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#phx_join", - "title": "phx_join" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#1-deploy-prometheus", + "title": "1. Deploy Prometheus" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#phx_leave", - "title": "phx_leave" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#2-deploy-grafana", + "title": "2. Deploy Grafana" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#heartbeat", - "title": "heartbeat" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#3-import-supabase-dashboards", + "title": "3. Import Supabase dashboards" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#access_token", - "title": "access_token" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#4-configure-alerting", + "title": "4. Configure alerting" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#broadcast-text-frame", - "title": "broadcast (text frame)" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#5-operating-tips", + "title": "5. Operating tips" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#broadcast-binary-frame", - "title": "broadcast (binary frame)" + "url": "https://supabase.com/docs/guides/database/connection-management", + "title": "Connection management" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#presence", - "title": "presence" + "url": "https://supabase.com/docs/guides/database/connection-management#connections", + "title": "Connections" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#server-sent-events", - "title": "Server sent events" + "url": "https://supabase.com/docs/guides/database/connection-management#configuring-supavisors-pool-size", + "title": "Configuring Supavisor's pool size" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#phx_close", - "title": "phx_close" + "url": "https://supabase.com/docs/guides/database/connection-management#monitoring-connections", + "title": "Monitoring connections" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#phx_error", - "title": "phx_error" + "url": "https://supabase.com/docs/guides/database/connection-management#capturing-historical-usage", + "title": "Capturing historical usage" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#phx_reply", - "title": "phx_reply" + "url": "https://supabase.com/docs/guides/database/connection-management#dashboard-monitoring-charts", + "title": "Dashboard monitoring charts" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#system", - "title": "system" + "url": "https://supabase.com/docs/guides/database/connection-management#grafana-dashboard", + "title": "Grafana Dashboard" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#broadcast-text-frame-1", - "title": "broadcast (text frame)" + "url": "https://supabase.com/docs/guides/database/connection-management#observing-live-connections", + "title": "Observing live connections" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#broadcast-binary-frame-1", - "title": "broadcast (binary frame)" - }, + "url": "https://supabase.com/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_", + "title": "How to View Database Metrics" + } + ], + "resultChars": 154163 + } + ] + }, + "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", + "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini/deploy-database-001-prometheus-metrics.json" + }, + { + "experiment": "codex-gpt-5.4-mini", + "experimentSuite": "benchmark", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.4-mini", + "reasoningEffort": "medium" + }, + "eval": "deploy-functions-001-edge-function-secrets", + "stage": "deploy", + "product": [ + "edge-functions" + ], + "topic": [ + "security" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "WEATHER_API_KEY is set as a Function secret on the project", + "passed": true + }, + { + "name": "the weather function is deployed to the project", + "passed": true, + "notes": "status ACTIVE" + }, + { + "name": "the weather function reads WEATHER_API_KEY from the environment", + "passed": true, + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get(\"WEATHER_API_KEY\")." + }, + { + "name": "WEATHER_API_KEY value is not committed to the repo", + "passed": true + } + ], + "skills": { + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase" + ] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"edge functions environment variables secrets deploy supabase functions deploy\", limit: 5) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/protocol#postgres_changes", - "title": "postgres_changes" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#presence_state", - "title": "presence_state" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#presence_diff", - "title": "presence_diff" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#error-handling", - "title": "Error handling" + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#channel-level-system-errors", - "title": "Channel-level system errors" - }, + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + } + ], + "resultChars": 39625 + }, + { + "source": "web_search", + "query": "\".supabase-eval-profile.yaml\" supabase profile yaml", + "pages": [] + }, + { + "source": "web_search", + "query": "site:supabase.com/docs SUPABASE_PROFILE environment variable supabase cli", + "pages": [] + }, + { + "source": "web_search", + "query": "site:github.com/supabase/cli \"~/.supabase/profile\" format", + "pages": [] + }, + { + "source": "web_search", + "query": "\"~/.supabase/profile\" \"access_token\" \"project_ref\"", + "pages": [] + }, + { + "source": "web_search", + "query": "site:github.com/supabase/cli \"api_url\" \"access_token\" profile file supabase", + "pages": [] + }, + { + "source": "web_search", + "query": "site:supabase.com/docs invoke edge function supabase cli latest", + "pages": [] + }, + { + "source": "web_search", + "query": "site:supabase.com/docs management api invoke function edge functions", + "pages": [] + }, + { + "source": "web_search", + "query": "site:github.com/supabase/cli function invoke management api supabase", + "pages": [] + } + ] + }, + "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", + "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.4-mini/deploy-functions-001-edge-function-secrets.json" + }, + { + "experiment": "codex-gpt-5.4-mini", + "experimentSuite": "benchmark", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.4-mini", + "reasoningEffort": "medium" + }, + "eval": "deploy-self-hosting-001-docker-compose", + "stage": "deploy", + "product": [ + "database", + "auth", + "storage" + ], + "topic": [ + "self-hosting" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", + "passed": true + }, + { + "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", + "passed": true + }, + { + "name": "secrets rotated off the shipped defaults", + "passed": true + }, + { + "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", + "passed": true + } + ], + "skills": { + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] + }, + "docs": { + "calls": [ + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | sed -n '1,220p'\"", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/protocol#postgres-changes-subscription-errors", - "title": "Postgres Changes subscription errors" - }, + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 12609 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"self-hosting docker compose secrets supabase.yml environment variables\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on CLICommandReference { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on ManagementApiReference { title href content } } totalCount } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/protocol#broadcast-errors", - "title": "Broadcast errors" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#presence-errors", - "title": "Presence errors" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#access-token-refresh", - "title": "Access token refresh" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" }, { - "url": "https://supabase.com/docs/guides/realtime/protocol#reconnection", - "title": "Reconnection" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started", - "title": "Getting Started with Realtime" - }, + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access", + "title": "Remove Superuser Access from Studio" + } + ], + "resultChars": 72542 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Self-hosting with Docker generate-keys.sh run.sh .env.example docker-compose.yml quick start Linux\", limit: 10) { nodes { __typename ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } totalCount } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/getting_started#when-to-use-presence", - "title": "When to use Presence" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#quick-start", - "title": "Quick start" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#framework-examples", - "title": "Framework examples" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", + "title": "Configure Social Login (OAuth) Providers" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#integration-guides", - "title": "Integration guides" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#advanced-topics", - "title": "Advanced topics" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-proxy-https", + "title": "Configure Reverse Proxy and HTTPS" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#security--configuration", - "title": "Security & configuration" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#core-features", - "title": "Core features" + "url": "https://supabase.com/docs/guides/self-hosting/updating", + "title": "Update Your Self-Hosted Deployment" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#next-steps", - "title": "Next steps" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#when-to-use-postgres-changes", - "title": "When to use Postgres Changes" - }, + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates", + "title": "Custom Email Templates" + } + ], + "resultChars": 159000 + } + ] + }, + "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", + "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.4-mini/deploy-self-hosting-001-docker-compose.json" + }, + { + "experiment": "codex-gpt-5.4-mini", + "experimentSuite": "benchmark", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.4-mini", + "reasoningEffort": "medium" + }, + "eval": "investigate-auth-001-deleted-user-access", + "stage": "investigate", + "product": [ + "auth" + ], + "topic": [ + "security", + "sdk" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": false, + "checks": [ + { + "name": "victim session active before delete-account", + "passed": true + }, + { + "name": "delete_account flow ran for the victim", + "passed": true + }, + { + "name": "delete-account revokes the user's sessions", + "passed": true, + "notes": "sessions left: 0" + }, + { + "name": "deleted user's refresh token is rejected", + "passed": true + }, + { + "name": "deleted user cannot sign back in", + "passed": true + }, + { + "name": "other users keep their sessions and access", + "passed": true + }, + { + "name": "diagnosed and explained session revocation", + "passed": false, + "judgeNotes": "The fix deletes the auth user, cascades session/refresh-token removal, and closes the Data API window via RLS. However, it incorrectly says there is no lasting window without clarifying that the stateless access JWT remains locally valid until expiry; getClaims() or signature/expiry-only middleware will still accept it." + } + ], + "skills": { + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"publishable keys secret keys anon service_role frontend RLS\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/getting_started#when-to-use-broadcast", - "title": "When to use Broadcast" + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#choose-the-right-feature", - "title": "Choose the right feature" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", + "title": "Build a User Management App with RedwoodJS" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#clean-up-subscriptions", - "title": "Clean up subscriptions" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#follow-naming-conventions", - "title": "Follow naming conventions" + "url": "https://supabase.com/docs/guides/auth/jwt-fields", + "title": "JWT Claims Reference" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#use-private-channels", - "title": "Use private channels" - }, + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" + } + ], + "resultChars": 60334 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"delete user sessions revoke auth sessions deleting a user does not invalidate access tokens\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/getting_started#essential-best-practices", - "title": "Essential best practices" + "url": "https://supabase.com/docs/guides/auth/sessions", + "title": "User sessions" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#53-using-database-triggers", - "title": "5.3 using database triggers" + "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", + "title": "OAuth 2.1 Flows" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#52-using-httprest-api", - "title": "5.2 using HTTP/REST API" + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#51-using-client-libraries", - "title": "5.1 using client libraries" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#5-send-and-receive-messages", - "title": "5. Send and receive messages" - }, + "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", + "title": "Multiple SSO Providers" + } + ], + "resultChars": 83489 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"delete user revoke sessions auth.users cascade sessions refresh_tokens delete_account\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/getting_started#4-set-up-authorization", - "title": "4. Set up authorization" + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#3-create-your-first-channel", - "title": "3. Create your first Channel" + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#get-api-details", - "title": "Get API details" + "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", + "title": "Multiple SSO Providers" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#2-initialize-the-client", - "title": "2. Initialize the client" + "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started#1-install-the-client-library", - "title": "1. Install the client library" + "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", + "title": "OAuth 2.1 Flows" } ], - "resultChars": 389763 + "resultChars": 77385 + } + ] + }, + "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", + "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini/investigate-auth-001-deleted-user-access.json" + }, + { + "experiment": "codex-gpt-5.4-mini", + "experimentSuite": "benchmark", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.4-mini", + "reasoningEffort": "medium" + }, + "eval": "investigate-realtime-001-subscribed-no-events", + "stage": "investigate", + "product": [ + "realtime", + "database" + ], + "topic": [ + "sdk" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": true, + "checks": [ + { + "name": "orders table added to supabase_realtime publication", + "passed": true + }, + { + "name": "courier_locations still in supabase_realtime publication", + "passed": true + }, + { + "name": "publication still publishes INSERT events", + "passed": true + }, + { + "name": "RLS still enabled on orders", + "passed": true + }, + { + "name": "staff can still read orders through RLS", + "passed": true, + "notes": "authenticated sees 2 of 2 orders" + }, + { + "name": "diagnosed missing publication membership", + "passed": true, + "judgeNotes": "Correctly identified orders missing from supabase_realtime, added only public.orders to the existing publication, verified both feeds remain included, and preserved RLS and policies." + } + ], + "skills": { + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] + }, + "docs": { + "calls": [ + { + "source": "web_search", + "query": "site:supabase.com/docs realtime postgres_changes orders table publication RLS Supabase", + "pages": [] + }, + { + "source": "web_search", + "query": "site:supabase.com/docs postgres changes publication table realtime publication orders replication", + "pages": [] } ] }, "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini/investigate-realtime-001-subscribed-no-events.json" }, { @@ -10970,22 +10468,22 @@ ], "suite": "benchmark", "interface": "mcp", - "passed": true, + "passed": false, "checks": [ { "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "judgeNotes": "Identified image-transform as the affected function and described repeated HTTP 503 gateway responses throughout the morning of 2026-04-28 from 07:00Z to 12:00Z, while distinguishing unrelated issues." + "judgeNotes": "Identified image-transform as the main affected function and listed all eight recurring HTTP 503 failures from 07:00Z through 12:00Z on 2026-04-28." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", - "passed": true, - "judgeNotes": "Attributes recurring image-transform 503s to the edge/API gateway/platform layer rather than function code, and grounds this in API/gateway 503s alongside successful edge-function executions, plus distinguishes the avatar-upload 500 as a separate function-level error." + "passed": false, + "judgeNotes": "Although it identifies gateway-level 503s and unchanged versions, it ultimately blames the function package/runtime or dependencies and recommends rollback/fixes. The rubric requires attribution to the gateway/platform layer in front of the function." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "The assistant recommended concrete next steps, including pulling fuller traces for failing request windows, checking Supabase edge/runtime incidents or rollouts, adding retry/backoff, and investigating a specific isolated 500 code path." + "judgeNotes": "Provides several concrete actions: inspect function packages, add structured logging, review and roll back deployments, implement retries, and investigate runtime/dependency behavior." } ], "skills": { @@ -11002,7 +10500,7 @@ }, "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini/investigate-reliability-003-edge-function-5xx-correlation.json" }, { @@ -11056,7 +10554,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "The assistant correctly diagnosed RLS enabled with no policies as deny-all for Data API, kept RLS enabled, created authenticated SELECT policy scoped to user_id = auth.uid(), and created authenticated INSERT policy with WITH CHECK enforcing user_id = auth.uid()." + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and created authenticated-only SELECT and INSERT policies scoped by user_id = auth.uid() using USING and WITH CHECK." } ], "skills": { @@ -11065,45 +10563,72 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Exposing a Table to the Data API RLS bookmarks anon authenticated GRANT\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on CLICommandReference { title href content } } } }", + "query": "query {\n searchDocs(query: \"RLS bookmarks policy authenticated select insert auth.uid() with check\", limit: 5) {\n nodes {\n __typename\n title\n href\n ... on Guide { content }\n ... on ClientLibraryFunctionReference { methodName language content href }\n ... on TroubleshootingGuide { content href }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" }, { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0017_foreign_table_in_api", - "title": "Database Advisor: Lint 0017_foreign_table_in_api" + "url": "https://supabase.com/docs/guides/realtime/authorization", + "title": "Realtime Authorization" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" + } + ], + "resultChars": 66217 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"auth.uid request.jwt.claims sub role set_config Supabase SQL test RLS\", limit: 5) {\n nodes {\n __typename\n title\n href\n ... on Guide { content }\n ... on TroubleshootingGuide { content href }\n }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" + }, + { + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" }, { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0013_rls_disabled_in_public", - "title": "Database Advisor: Lint 0013_rls_disabled_in_public" + "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", + "title": "Firebase Auth" } ], - "resultChars": 58013 + "resultChars": 61212 } ] }, "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini/resolve-dataapi-001-empty-results.json" }, { @@ -11150,7 +10675,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "Applied avatar_url via `supabase db push --db-url \"$DB_URL\"` (#42), which showed `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` Reconciled orphan bio history by adding local migration `supabase/migrations/20240115000000_add_profile_bio.sql` (#36-37), after which `supabase migration list --db-url` showed local/remote aligned (#39, #45). Only read-only psql inspection observed; no prohibited workaround." + "judgeNotes": "`supabase db push --db-url ...` (#30) applied `20240220000000_add_avatar_url.sql` and finished successfully. The orphan bio history was reconciled by adding `20240115000000_add_profile_bio.sql` locally, then letting the same CLI push align history; #31 confirms all versions match. No prohibited workaround was used; psql commands were read-only." } ], "skills": { @@ -11159,8 +10684,7 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { @@ -11208,7 +10732,7 @@ { "name": "query plan uses an index and avoids sequential scan", "passed": true, - "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + "notes": "Limit (cost=0.28..119.10 rows=50 width=58)\n -> Index Scan using events_user_id_created_at_idx on events (cost=0.28..237.92 rows=100 width=58)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" }, { "name": "inserts still work", @@ -11229,23 +10753,231 @@ "calls": [ { "source": "search_docs", - "query": "query {\n searchDocs(query: \"composite index query optimization order by desc limit user_id created_at\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n ... on ManagementApiReference { title href content }\n }\n }\n}", + "query": "query { searchDocs(query: \"Postgres missing index order by limit composite index user_id created_at\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { "url": "https://supabase.com/docs/guides/database/query-optimization", "title": "Query Optimization" }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#example-query", + "title": "Example query" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#where-clause", + "title": "where clause:" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#join-columns", + "title": "join columns" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#order-by-clause", + "title": "order by clause" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#key-concepts", + "title": "Key concepts" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#analyze-the-query-plan", + "title": "Analyze the query plan" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#use-appropriate-index-types", + "title": "Use appropriate index types" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#partial-indexes", + "title": "Partial indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#composite-indexes", + "title": "Composite indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#over-indexing", + "title": "Over-Indexing" + }, + { + "url": "https://supabase.com/docs/guides/database/query-optimization#statistics", + "title": "Statistics" + }, { "url": "https://supabase.com/docs/guides/database/orioledb", "title": "OrioleDB Overview" }, { - "url": "https://supabase.com/docs/guides/database/postgres/indexes", - "title": "Managing Indexes in Postgres" + "url": "https://supabase.com/docs/guides/database/orioledb#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#index-organized-tables", + "title": "Index-organized tables" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#no-buffer-mapping", + "title": "No buffer mapping" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#undo-log", + "title": "Undo log" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#copy-on-write-checkpoints", + "title": "Copy-on-write checkpoints" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#usage", + "title": "Usage" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#creating-orioledb-project", + "title": "Creating OrioleDB project" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#creating-tables", + "title": "Creating tables" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#creating-indexes", + "title": "Creating indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#data-manipulation", + "title": "Data manipulation" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#viewing-query-plans", + "title": "Viewing query plans" + }, + { + "url": "https://supabase.com/docs/guides/database/orioledb#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#more-resources", + "title": "More resources" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#authenticated-and-unauthenticated-roles", + "title": "Authenticated and unauthenticated roles" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#creating-policies", + "title": "Creating policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#select-policies", + "title": "SELECT policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#insert-policies", + "title": "INSERT policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#update-policies", + "title": "UPDATE policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#delete-policies", + "title": "DELETE policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#views", + "title": "Views" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions", + "title": "Helper functions" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#authuid", + "title": "auth.uid()" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#authjwt", + "title": "auth.jwt()" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#mfa", + "title": "MFA" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#bypassing-row-level-security", + "title": "Bypassing Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#rls-performance-recommendations", + "title": "RLS performance recommendations" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#add-indexes", + "title": "Add indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#benchmarks", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#call-functions-with-select", + "title": "Call functions with select" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#benchmarks-1", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#add-filters-to-every-query", + "title": "Add filters to every query" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#benchmarks-2", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#use-security-definer-functions", + "title": "Use security definer functions" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#minimize-joins", + "title": "Minimize joins" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#benchmarks-3", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#specify-roles-in-your-policies", + "title": "Specify roles in your policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#benchmarks-4", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#row-level-security-in-supabase", + "title": "Row Level Security in Supabase" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#policies", + "title": "Policies" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#enabling-row-level-security", + "title": "Enabling Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security#auto-enable-rls-for-new-tables", + "title": "Auto-enable RLS for new tables" } ], - "resultChars": 18373 + "resultChars": 92618 } ] }, @@ -11320,39 +11052,38 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"row level security policy auth.uid select using with check memberships supabase\", limit: 5) { nodes { __typename title href content } } }", + "query": "{ searchDocs(query:\"workspace notes row level security tenant ownership foreign key\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/authorization", - "title": "Realtime Authorization" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/auth/third-party/clerk", - "title": "Clerk" + "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", + "title": "Declarative database schemas" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0017_foreign_table_in_api", + "title": "Database Advisor: Lint 0017_foreign_table_in_api" }, { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", - "title": "Firebase Auth" + "url": "https://supabase.com/docs/guides/database/extensions/wrappers/overview", + "title": "Foreign Data Wrappers" } ], - "resultChars": 75855 + "resultChars": 53335 } ] }, @@ -11393,7 +11124,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user fbab494f-6a4b-4376-b26a-10e30c44a54d, signUp returned {\"userId\":\"fbab494f-6a4b-4376-b26a-10e30c44a54d\"}" + "notes": "db user 486003ad-17fe-46c0-aea3-59e6392588c7, signUp returned {\"userId\":\"486003ad-17fe-46c0-aea3-59e6392588c7\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -11408,7 +11139,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"fbab494f-6a4b-4376-b26a-10e30c44a54d\"}" + "notes": "{\"userId\":\"486003ad-17fe-46c0-aea3-59e6392588c7\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -11485,7 +11216,7 @@ { "name": "REST API returns no todos to anonymous requests", "passed": true, - "notes": "0 rows" + "notes": "error 42501: permission denied for table todos" }, { "name": "REST API returns the todos to authenticated requests", @@ -11579,89 +11310,103 @@ ], "suite": "benchmark", "interface": "cli", - "passed": true, + "passed": false, "checks": [ { "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", - "passed": true, - "notes": "schedule='* * * * *', active=true" + "passed": false, + "notes": "job not found in cron.job" }, { "name": "cron command enqueues to the 'tasks' queue", - "passed": true, - "notes": "queue depth 1 -> 2" + "passed": false, + "notes": "job not found, so its command can't run" }, { "name": "process-tasks function drains the queue", - "passed": true, - "notes": "function removed the seeded message (id 6) from the queue" + "passed": false, + "notes": "couldn't enqueue a test message. Is the 'tasks' queue created? query failed: ERROR: relation \"pgmq.q_tasks\" does not exist\nLINE 2: INSERT INTO pgmq.q_tasks (vt, message, headers)\n ^\nQUERY: \n INSERT INTO pgmq.q_tasks (vt, message, headers)\n VALUES ($2, $1, $3)\n RETURNING msg_id;\n \nCONTEXT: PL/pgSQL function pgmq.send(text,jsonb,jsonb,timestamp with time zone) line 14 at RETURN QUERY\nSQL function \"send\" statement 1\n" } ], "skills": { "available": [], - "loaded": [] - }, - "docs": { - "calls": [ - { - "source": "web_search", - "query": "Supabase pg_cron schedule cron.schedule syntax official docs", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs pgmq create queue function create queue", - "pages": [] - }, + "loaded": [] + }, + "docs": { + "calls": [ { - "source": "web_search", - "query": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase local cron schedule edge function queue enqueue dequeue background workflow\", limit: 5) { nodes { ... on Guide { title href content subsections { totalCount } } ... on CLICommandReference { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } ... on ManagementApiReference { title href content } } totalCount } }", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions" + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" + }, + { + "url": "https://supabase.com/docs/guides/functions/architecture", + "title": "Edge Functions Architecture" } - ] - }, - { - "source": "web_search", - "query": "'pop(' in https://supabase.com/docs/guides/queues/pgmq", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs cron.schedule pg_cron supabase example", - "pages": [] - }, - { - "source": "web_search", - "query": "site:github.com supabase pg_cron cron.schedule supabase migration", - "pages": [] - }, - { - "source": "web_search", - "query": "'if not exists' in https://supabase.com/docs/guides/queues/pgmq", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs pg_cron unschedule cron.schedule idempotent", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs pgmq message_record msg_id message field", - "pages": [] + ], + "resultChars": 25692 }, { - "source": "web_search", - "query": "site:supabase.com/docs edge function config.toml verify_jwt false", - "pages": [] + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase queues create queue pgmq send read delete local postgres queue name create_queue\", limit: 10) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } ... on ManagementApiReference { title href content } } totalCount } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/queues/expose-self-hosted-queues", + "title": "Expose Queues for local and self-hosted Supabase" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgmq", + "title": "pgmq: Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/42501--permission-denied-for-table-httprequestqueue-KnozmQ", + "title": "42501 : permission denied for table http_request_queue" + } + ], + "resultChars": 44420 } ] }, "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini-no-skills/build-cli-003-pg-cron-queue-workflow.json" }, { @@ -11833,7 +11578,32 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"restore binary dump local supabase db pg_restore\", limit: 5) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content } } totalCount } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" + }, + { + "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", + "title": "Restoring a downloaded backup locally" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", + "title": "Migrate from Postgres to Supabase" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", + "title": "Backup and Restore using the CLI" + } + ], + "resultChars": 70471 + } + ] }, "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", @@ -11899,7 +11669,7 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Edge Functions verify_jwt auth getUser service role private notes\", limit: 5) { nodes { __typename ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"supabase edge function getUser authorization header Deno.serve createClient service role verify_jwt\", limit: 5) { nodes { title href content ... on ClientLibraryFunctionReference { language methodName } } } }", "hasContent": true, "pages": [ { @@ -11907,29 +11677,29 @@ "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/functions/websockets", + "title": "Handling WebSockets" }, { "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", + "title": "Integrating with Supabase Database (Postgres)" } ], - "resultChars": 39139 + "resultChars": 42278 } ] }, "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini-no-skills/build-functions-004-service-role-bypass.json" }, { @@ -11966,37 +11736,37 @@ { "name": "rejects request with no credentials", "passed": true, - "notes": "status 401: {\"error\":\"Unauthorized\"}" + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "user with JWT reads only their own rows", - "passed": true, - "notes": "status 200: [{\"user_id\":\"a9708acd-ab70-4e53-8f37-66b0ed3c7434\",\"metric\":\"steps_a_msj11abm\",\"value\":111}]" + "passed": false, + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "user cannot read another user's rows by passing user_id", - "passed": true, - "notes": "status 200: [{\"user_id\":\"a9708acd-ab70-4e53-8f37-66b0ed3c7434\",\"metric\":\"steps_a_msj11abm\",\"value\":111}]" + "passed": false, + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "service key bypasses RLS to read the target user's rows", "passed": false, - "notes": "status 401: {\"error\":\"Unauthorized\"}" + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "non-service key is not granted service access", "passed": true, - "notes": "status 401: {\"error\":\"Unauthorized\"}" + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "rejects an unverified (forged) user token", "passed": true, - "notes": "status 401: {\"error\":\"Unauthorized\"}" + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "a user token in the apikey slot is not treated as the service key", "passed": true, - "notes": "status 401: {\"error\":\"Unauthorized\"}" + "notes": "status 503: {\"message\":\"name resolution failed\"}" }, { "name": "implementation uses @supabase/server", @@ -12012,7 +11782,7 @@ "calls": [ { "source": "search_docs", - "query": "query {\n searchDocs(query: \"edge function get user auth supabase service role apikey header SUPABASE_SERVICE_ROLE_KEY SUPABASE_ANON_KEY\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", + "query": "query {\n searchDocs(query: \"Edge Functions verify JWT service role apikey header Deno.serve createClient\", limit: 5) {\n edges {\n node {\n title\n href\n content\n }\n }\n totalCount\n }\n}", "hasContent": true, "pages": [ { @@ -12020,23 +11790,67 @@ "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/functions/websockets", + "title": "Handling WebSockets" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, + { + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + } + ], + "resultChars": 46624 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"Securing Edge Functions auth user secret verifyCredentials withSupabase createAdminClient\", limit: 5) {\n edges { node { title href content } }\n totalCount\n }\n}", + "hasContent": true, + "pages": [ { "url": "https://supabase.com/docs/guides/functions/auth", "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", + "title": "Performing administration tasks on the server side with a secret key" + } + ], + "resultChars": 29648 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"userClaims id sub @supabase/server Edge Function\", limit: 5) {\n edges { node { title href content } }\n totalCount\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, + { + "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", + "title": "Which package to use" } ], - "resultChars": 56285 + "resultChars": 18661 } ] }, @@ -12066,7 +11880,7 @@ ], "suite": "benchmark", "interface": "mcp", - "passed": true, + "passed": false, "checks": [ { "name": "RLS enabled on documents", @@ -12074,7 +11888,7 @@ }, { "name": "viewer sees only documents in their org", - "passed": true + "passed": false }, { "name": "viewer cannot insert", @@ -12082,11 +11896,11 @@ }, { "name": "editor can insert own org document", - "passed": true + "passed": false }, { "name": "editor can update own document", - "passed": true + "passed": false }, { "name": "editor cannot update another user's document", @@ -12098,11 +11912,11 @@ }, { "name": "admin can update any document in their org", - "passed": true + "passed": false }, { "name": "admin can delete any document in their org", - "passed": true + "passed": false }, { "name": "admin cannot affect another org", @@ -12118,7 +11932,7 @@ }, { "name": "cannot see another org's membership roster", - "passed": true + "passed": false }, { "name": "a viewer role in one org doesn't grant admin power in another org", @@ -12126,7 +11940,7 @@ }, { "name": "multi-org user can act as admin in the org where they hold that role", - "passed": true + "passed": false } ], "skills": { @@ -12138,7 +11952,7 @@ }, "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini-no-skills/build-rls-003-org-roles-permissions.json" }, { @@ -12179,7 +11993,7 @@ { "name": "user A lists only own files", "passed": true, - "notes": "saw: 019fdc8c-c70c-75ca-a770-9cd6c0d41bf9/receipt-alpha.pdf, 019fdc8c-c70c-75ca-a770-9cd6c0d41bf9/receipt-beta.pdf" + "notes": "saw: 01a03a85-da2a-7149-9c4f-dbdd02dcd0a8/receipt-alpha.pdf, 01a03a85-da2a-7149-9c4f-dbdd02dcd0a8/receipt-beta.pdf" }, { "name": "user B cannot read user A files", @@ -12200,7 +12014,7 @@ { "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "Meets rubric: private user-files bucket, RLS remains enabled, authenticated SELECT and INSERT policies scoped to bucket and auth.uid() path prefix, and supabase-js uses createSignedUrl with expiry." + "judgeNotes": "Private bucket verified; RLS remains enabled with authenticated, owner-folder-scoped SELECT and INSERT policies. Sharing uses createSignedUrl with a 900-second expiry and no service-role key." } ], "skills": { @@ -12211,31 +12025,51 @@ "calls": [ { "source": "search_docs", - "query": "query {\n searchDocs(query: \"storage.foldername policy storage.objects auth.uid bucket private files\", limit: 5) {\n nodes {\n ... on Guide { title href content }\n ... on ClientLibraryFunctionReference { title href content language methodName }\n ... on TroubleshootingGuide { title href content }\n ... on CLICommandReference { title href content }\n ... on ManagementApiReference { title href content }\n }\n }\n}", + "query": "query {\n searchDocs(query: \"storage bucket row level security object policies authenticated user own folder create_bucket signed url supabase-js createSignedUrl\", limit: 10) {\n nodes {\n title\n href\n ... on Guide {\n content\n }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt", - "title": "Why can't I upload/list/etc my public bucket?" + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" }, { - "url": "https://supabase.com/docs/guides/storage/quickstart", - "title": "Storage Quickstart" + "url": "https://supabase.com/docs/guides/storage/s3/authentication", + "title": "S3 Authentication" }, { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" + "url": "https://supabase.com/docs/guides/storage/schema/custom-roles", + "title": "Custom Roles" }, { "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", "title": "Configure S3 Storage" + }, + { + "url": "https://supabase.com/docs/guides/storage", + "title": "Storage" + }, + { + "url": "https://supabase.com/docs/guides/storage/buckets/creating-buckets", + "title": "Creating Buckets" + }, + { + "url": "https://supabase.com/docs/guides/storage/management/copy-move-objects", + "title": "Copy Objects" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/platform/manage-your-usage/storage-image-transformations", + "title": "Manage Storage Image Transformations usage" } ], - "resultChars": 25446 + "resultChars": 47387 } ] }, @@ -12279,7 +12113,7 @@ { "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as the table with the tenant isolation flaw, not `notes`, and treats pgTAP verification as the signal after adding isolation tests. It describes fixing `posts` RLS so authenticated users cannot read other organizations' posts." + "judgeNotes": "Correctly identifies `posts` as leaking cross-organization data due to an unscoped membership check, while `notes` is correctly isolated. It grounds this conclusion in the pgTAP failures showing 2 visible posts and 1 cross-tenant post before the fix." } ], "skills": { @@ -12325,12 +12159,12 @@ { "name": "HNSW index on the embedding column", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" }, { "name": "index operator class matches the search operator", "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" }, { "name": "user A search returns only own sections, best match first", @@ -12354,22 +12188,11 @@ "loaded": [] }, "docs": { - "calls": [ - { - "source": "web_search", - "query": "site:supabase.com gte-small 384 Supabase AI Session dimension", - "pages": [] - }, - { - "source": "web_search", - "query": "site:supabase.com/docs pgvector Supabase vector search match function", - "pages": [] - } - ] + "calls": [] }, "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.4-mini-no-skills/build-vectors-001-rag-with-permissions.json" }, { @@ -12400,12 +12223,12 @@ { "name": "configured the Supabase Metrics API scrape correctly", "passed": false, - "judgeNotes": "Fails because Prometheus uses basic_auth.password with an environment variable instead of basic_auth.password_file, and docker-compose.yml does not mount the password file via a volume or Compose secret. App scrape and endpoint are otherwise preserved." + "judgeNotes": "Uses basic_auth.password with an environment-expanded hardcoded secret instead of required password_file, and docker-compose.yml does not mount that password file via a volume or Compose secret." }, { "name": "documented live deployment and verification steps", "passed": false, - "judgeNotes": "README includes env setup, restart/recreate Compose, and Prometheus target verification, but it does not provide steps to create the Secret API key in Supabase or place a matching secret file. The setup uses .env rather than the required secret file, so the secret setup requirement is not met." + "judgeNotes": "README uses an environment variable instead of instructing users to place the matching secret file. Although it covers key creation, Compose recreation, and Prometheus target verification, it fails the required secret-file setup." } ], "skills": { @@ -12416,7 +12239,7 @@ "calls": [ { "source": "search_docs", - "query": "query {\n searchDocs(query: \"metrics prometheus project metrics scrape endpoint\", limit: 10) {\n nodes {\n ... on Guide {\n title\n href\n content\n }\n ... on TroubleshootingGuide {\n title\n href\n content\n }\n ... on ClientLibraryFunctionReference {\n title\n href\n content\n language\n methodName\n }\n }\n totalCount\n }\n}", + "query": "query { searchDocs(query: \"metrics prometheus project metrics\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -12425,26 +12248,22 @@ }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" + "title": "Metrics API" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", "title": "Metrics API with Grafana Cloud" }, { - "url": "https://supabase.com/docs/guides/platform/read-replicas", - "title": "Read Replicas" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_", - "title": "How to View Database Metrics" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" } ], - "resultChars": 29978 + "resultChars": 20609 } ] }, @@ -12486,7 +12305,7 @@ { "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get." }, { "name": "WEATHER_API_KEY value is not committed to the repo", @@ -12501,415 +12320,233 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query:\"Edge Function environment variable deploy secrets WEATHER_API_KEY supabase functions secrets set\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "query": "query {\n searchDocs(query: \"Edge Functions secret env deploy supabase secrets set env-file functions deploy Deno env vars\", limit: 5) {\n nodes {\n ... on Guide {\n title\n href\n content\n }\n ... on CLICommandReference {\n title\n href\n content\n }\n ... on TroubleshootingGuide {\n title\n href\n content\n }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-1-create-the-new-api-keys", - "title": "Step 1: Create the new API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#before-you-start", - "title": "Before you start" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#next-steps", - "title": "Next steps" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#known-limitations", - "title": "Known limitations" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-6-deactivate-the-legacy-keys", - "title": "Step 6: Deactivate the legacy keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-5-verify-nothing-uses-the-legacy-keys", - "title": "Step 5: Verify nothing uses the legacy keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-2-adopt-the-supabaseserver-sdk", - "title": "Option 2: Adopt the @supabase/server SDK" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-1-read-the-new-keys-from-the-environment", - "title": "Option 1: Read the new keys from the environment" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-4-update-edge-functions", - "title": "Step 4: Update Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-3-swap-the-secret-key-in-backend-code", - "title": "Step 3: Swap the secret key in backend code" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#database-webhooks-and-pg_net", - "title": "Database Webhooks and pg_net" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-2-swap-the-publishable-key-in-client-code", - "title": "Step 2: Swap the publishable key in client code" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", - "title": "Transcription Telegram Bot" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#deploy-to-supabase", - "title": "Deploy to Supabase" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#introduction", - "title": "Introduction" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#requirements", - "title": "Requirements" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#setup", - "title": "Setup" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#register-a-telegram-bot", - "title": "Register a Telegram bot" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-supabase-project-locally", - "title": "Create a Supabase project locally" + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-database-table-to-log-the-transcription-results", - "title": "Create a database table to log the transcription results" + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#create-a-supabase-edge-function-to-handle-telegram-webhook-requests", - "title": "Create a Supabase Edge Function to handle Telegram webhook requests" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-up-the-environment-variables", - "title": "Set up the environment variables" - }, + "url": "https://supabase.com/docs/guides/functions/quickstart-dashboard", + "title": "Getting Started with Edge Functions (Dashboard)" + } + ], + "resultChars": 44444 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"Supabase Edge Function config.toml verify_jwt false functions directory\", limit: 10) {\n nodes {\n ... on Guide { title href content }\n ... on CLICommandReference { title href content }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#dependencies", - "title": "Dependencies" + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#code-the-telegram-bot", - "title": "Code the Telegram bot" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#apply-the-database-migrations", - "title": "Apply the database migrations" + "url": "https://supabase.com/docs/guides/functions/deploy", + "title": "Deploy to Production" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-up-the-webhook", - "title": "Set up the webhook" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#set-the-function-secrets", - "title": "Set the function secrets" + "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", + "title": "Building an MCP Server with mcp-lite" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech#test-the-bot", - "title": "Test the bot" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", "title": "Streaming Speech with ElevenLabs" }, { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#deploy-to-supabase", - "title": "Deploy to Supabase" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#try-it-out", - "title": "Try it out" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#run-locally", - "title": "Run locally" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#code-the-supabase-edge-function", - "title": "Code the Supabase Edge Function" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#dependencies", - "title": "Dependencies" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#set-up-the-environment-variables", - "title": "Set up the environment variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#create-a-supabase-edge-function-for-speech-generation", - "title": "Create a Supabase Edge Function for speech generation" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#configure-background-tasks-for-supabase-edge-functions", - "title": "Configure background tasks for Supabase Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#configure-the-storage-bucket", - "title": "Configure the storage bucket" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#create-a-supabase-project-locally", - "title": "Create a Supabase project locally" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#setup", - "title": "Setup" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#introduction", - "title": "Introduction" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#requirements", - "title": "Requirements" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#test-the-function", - "title": "Test the function" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream#set-the-function-secrets", - "title": "Set the function secrets" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets#accessing-environment-variables", - "title": "Accessing environment variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets#local-secrets", - "title": "Local secrets" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets#production-secrets", - "title": "Production secrets" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets#default-secrets", - "title": "Default secrets" + "url": "https://supabase.com/docs/guides/functions/unit-test", + "title": "Testing your Edge Functions" }, { "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", "title": "Supabase for Platforms" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#changing-compute-sizes", - "title": "Changing compute sizes" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#recommended-api-keys", - "title": "Recommended API keys" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#nano-compute-instance", - "title": "Nano compute instance" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#launching-projects", - "title": "Launching projects" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#overview", - "title": "Overview" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#platform-kit", - "title": "Platform kit" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#claim-flow", - "title": "Claim flow" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#disaster-recovery-for-production", - "title": "Disaster recovery for production" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#security-checks-for-production", - "title": "Security checks for production" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#merge-all-changes", - "title": "Merge all changes" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#deploying-edge-functions", - "title": "Deploying Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#add-seed-data", - "title": "Add seed data" - }, + "url": "https://supabase.com/docs/guides/ai/examples/openai", + "title": "Generating OpenAI GPT3 completions" + } + ], + "resultChars": 84667 + }, + { + "source": "search_docs", + "query": "query {\n searchDocs(query: \"edge function invoke management api supabase function logs invoke endpoint\", limit: 10) {\n nodes {\n ... on Guide { title href content }\n ... on ManagementApiReference { title href content }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#reverting-changes", - "title": "Reverting changes" + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#create-a-restore-point", - "title": "Create a restore point" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#make-database-changes", - "title": "Make database changes" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#creating-a-dev-branch", - "title": "Creating a DEV branch" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#development-workflow", - "title": "Development workflow" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#configuration-changes", - "title": "Configuration changes" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/reports", + "title": "Reports" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms#debugging-projects", - "title": "Debugging projects" + "url": "https://supabase.com/docs/guides/functions/architecture", + "title": "Edge Functions Architecture" } ], - "resultChars": 164975 + "resultChars": 116204 }, { "source": "search_docs", - "query": "query { searchDocs(query:\"Edge Functions invoke URL functions/v1 project ref invoke runtime endpoint\", limit: 10) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"invoke edge function management api api endpoint\", limit: 20) {\n nodes {\n ... on ManagementApiReference { title href content }\n ... on Guide { title href content }\n ... on TroubleshootingGuide { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/recursive-functions", - "title": "Recursive / Nested Function Calls" + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" }, { "url": "https://supabase.com/docs/guides/getting-started/features", "title": "Features" }, { - "url": "https://supabase.com/docs/guides/functions/storage-caching", - "title": "Integrating with Supabase Storage" - }, - { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/functions/architecture", + "title": "Edge Functions Architecture" }, { - "url": "https://supabase.com/docs/guides/functions/ai-models", - "title": "Running AI Models" + "url": "https://supabase.com/docs/guides/ai-tools/mcp", + "title": "Supabase MCP Server" }, { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/reference/api/v1-deploy-a-function", + "title": "Deploy a function" }, { - "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", - "title": "Serverless Drivers" + "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", + "title": "Backup and Restore using the CLI" }, { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" - } - ], - "resultChars": 93047 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query:\"Management API edge functions get function by slug project ref functions/{function_slug}\", limit: 10) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/reference/api/v1-get-a-function", - "title": "Retrieve a function" + "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", + "title": "Supabase for Platforms" }, { - "url": "https://supabase.com/docs/reference/api/v1-delete-a-function", - "title": "Delete a function" + "url": "https://supabase.com/docs/reference/api/v1-create-a-function", + "title": "Create a function" }, { - "url": "https://supabase.com/docs/reference/api/v1-update-a-function", - "title": "Update a function" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" }, { - "url": "https://supabase.com/docs/reference/api/v1-list-all-functions", - "title": "List all functions" + "url": "https://supabase.com/docs/guides/functions/ai-models", + "title": "Running AI Models" }, { - "url": "https://supabase.com/docs/reference/api/v1-get-a-function-body", - "title": "Retrieve a function body" + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" }, { - "url": "https://supabase.com/docs/reference/api/v1-create-a-function", - "title": "Create a function" + "url": "https://supabase.com/docs/guides/functions/examples/send-emails", + "title": "Sending Emails" }, { - "url": "https://supabase.com/docs/reference/api/v1-deploy-a-function", - "title": "Deploy a function" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/reports", + "title": "Reports" }, { - "url": "https://supabase.com/docs/reference/api/v1-bulk-update-functions", - "title": "Bulk update functions" + "url": "https://supabase.com/docs/guides/functions/quickstart-dashboard", + "title": "Getting Started with Edge Functions (Dashboard)" }, { - "url": "https://supabase.com/docs/reference/api/v1-get-project-function-combined-stats", - "title": "Gets a project's function combined statistics" + "url": "https://supabase.com/docs/guides/functions/http-methods", + "title": "Routing" }, { - "url": "https://supabase.com/docs/guides/ai-tools/mcp", - "title": "Supabase MCP Server" + "url": "https://supabase.com/docs/guides/platform/manage-your-usage/edge-function-invocations", + "title": "Manage Edge Function Invocations usage" } ], - "resultChars": 18063 + "resultChars": 229017 + }, + { + "source": "web_search", + "query": "evalshostedprojectxy.supabase.co functions weather", + "pages": [] }, { "source": "search_docs", - "query": "query { searchDocs(query:\"get_project_url project url supabase management api\", limit: 5) { nodes { title href content } } }", + "query": "query {\n searchDocs(query: \"edge functions management api reference functions endpoint slug\", limit: 20) {\n nodes {\n ... on ManagementApiReference { title href content }\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/analytics/connecting-to-analytics-bucket", - "title": "Iceberg Catalog" + "url": "https://supabase.com/docs/reference/api/v1-get-a-function", + "title": "Retrieve a function" }, { - "url": "https://supabase.com/docs/guides/ai-tools/mcp", - "title": "Supabase MCP Server" + "url": "https://supabase.com/docs/reference/api/v1-deploy-a-function", + "title": "Deploy a function" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", - "title": "Supabase for Platforms" + "url": "https://supabase.com/docs/reference/api/v1-update-a-function", + "title": "Update a function" }, { - "url": "https://supabase.com/docs/guides/api/creating-routes", - "title": "Creating API Routes" + "url": "https://supabase.com/docs/reference/api/v1-delete-a-function", + "title": "Delete a function" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" + "url": "https://supabase.com/docs/reference/api/v1-get-a-function-body", + "title": "Retrieve a function body" + }, + { + "url": "https://supabase.com/docs/reference/api/v1-create-a-function", + "title": "Create a function" } ], - "resultChars": 69182 + "resultChars": 4313 + }, + { + "source": "web_search", + "query": "site:supabase.com/docs/guides/functions/secrets Supabase Edge Functions secrets Deno.env.get", + "pages": [] } ] }, @@ -12965,14 +12602,32 @@ "docs": { "calls": [ { - "source": "web_search", - "query": "Supabase self-hosting docker compose official secrets env file", - "pages": [] - }, - { - "source": "web_search", - "query": "site:github.com/supabase/supabase docker generate-keys.sh .env.example", - "pages": [] + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase self-hosting Docker Compose .env file JWT_SECRET POSTGRES_PASSWORD ANON_KEY SERVICE_ROLE_KEY\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on CLICommandReference { title href content } ... on ManagementApiReference { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access", + "title": "Remove Superuser Access from Studio" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", + "title": "Configure SAML SSO" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17", + "title": "Upgrade to Postgres 17" + } + ], + "resultChars": 92183 } ] }, @@ -13013,16 +12668,18 @@ }, { "name": "delete-account revokes the user's sessions", - "passed": true, - "notes": "sessions left: 0" + "passed": false, + "notes": "sessions left: 1" }, { "name": "deleted user's refresh token is rejected", - "passed": true + "passed": false, + "notes": "refresh token still produces a session" }, { "name": "deleted user cannot sign back in", - "passed": true + "passed": false, + "notes": "deleted account can still sign in" }, { "name": "other users keep their sessions and access", @@ -13031,7 +12688,7 @@ { "name": "diagnosed and explained session revocation", "passed": false, - "judgeNotes": "The answer correctly diagnoses the soft-delete bug, deletes the auth user so sessions/refresh tokens cascade, adds RLS that blocks stale JWTs on the data path, and correctly explains publishable vs secret keys. However, it does not clearly state the required caveat that access tokens are stateless JWTs not recalled by deletion/revocation and that purely local validation such as getClaims/custom JWT middleware will continue accepting them until expiry." + "judgeNotes": "It only proposes a fix and explicitly does not implement or patch the delete flow. It also does not clearly diagnose the exact issue: soft-deleting only the profile row while leaving the auth user and sessions intact. Its JWT-window and publishable-vs-secret key explanations are otherwise largely correct." } ], "skills": { @@ -13042,26 +12699,18 @@ "calls": [ { "source": "web_search", - "query": "site:supabase.com/docs publishable secret keys supabase frontend secret keys rls", + "query": "site:supabase.com docs publishable key secret key service_role anon frontend RLS Supabase", "pages": [] }, { "source": "web_search", - "query": "https://supabase.com/docs/guides/getting-started/api-keys", - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys" - } - ] + "query": "site:supabase.com docs delete user auth.admin.deleteUser revoke tokens delete account function Supabase", + "pages": [] }, { "source": "web_search", - "query": "https://supabase.com/docs/guides/auth/jwts", - "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/jwts" - } - ] + "query": "site:supabase.com docs access token valid until expiry delete user revoke refresh token Supabase deleteUser", + "pages": [] } ] }, @@ -13090,11 +12739,11 @@ ], "suite": "benchmark", "interface": "mcp", - "passed": true, + "passed": false, "checks": [ { "name": "orders table added to supabase_realtime publication", - "passed": true + "passed": false }, { "name": "courier_locations still in supabase_realtime publication", @@ -13115,182 +12764,8 @@ }, { "name": "diagnosed missing publication membership", - "passed": true, - "judgeNotes": "The assistant correctly identified that orders was missing from the supabase_realtime publication despite the channel subscribing, added only public.orders to the existing publication, and preserved courier_locations, RLS, and policies." - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", - "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini-no-skills/investigate-realtime-001-subscribed-no-events.json" - }, - { - "experiment": "codex-gpt-5.4-mini-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" - }, - "eval": "investigate-reliability-003-edge-function-5xx-correlation", - "stage": "investigate", - "product": [ - "edge-functions" - ], - "topic": [ - "observability" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": false, - "checks": [ - { - "name": "identified image-transform and the recurring 503 pattern", - "passed": true, - "judgeNotes": "Identified image-transform as the affected function and described the recurring HTTP 503 pattern across the morning of 2026-04-28, covering all 8 gateway failures from 07:00Z to 12:00Z." - }, - { - "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": false, - "judgeNotes": "Although the assistant correctly attributes the 503s to the gateway/Edge invocation path and grounds this in valid observations, it recommends redeploying the functions as a remediation, which the rubric explicitly lists as a fail condition." - }, - { - "name": "recommended a concrete next step", - "passed": true, - "judgeNotes": "The assistant recommended concrete next steps including redeploying Edge Functions, checking Supabase incidents/status, adding retry/backoff, and opening a support ticket with exact timestamps and deployment IDs." - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", - "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini-no-skills/investigate-reliability-003-edge-function-5xx-correlation.json" - }, - { - "experiment": "codex-gpt-5.4-mini-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" - }, - "eval": "resolve-dataapi-001-empty-results", - "stage": "resolve", - "product": [ - "data-api", - "database", - "auth" - ], - "topic": [ - "rls", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "RLS still enabled on bookmarks", - "passed": true - }, - { - "name": "user A reads own bookmarks", - "passed": true - }, - { - "name": "user B cannot read user A bookmarks", - "passed": true - }, - { - "name": "anon reads no bookmarks", - "passed": true - }, - { - "name": "user A can save a new bookmark", - "passed": true - }, - { - "name": "user B cannot insert a bookmark as user A", - "passed": true - }, - { - "name": "diagnosed RLS and added owner-scoped policies", - "passed": true, - "judgeNotes": "The assistant correctly diagnosed RLS enabled with no policies causing deny-all/empty Data API results, kept RLS enabled, and created authenticated SELECT and INSERT owner-scoped policies using auth.uid() = user_id, including WITH CHECK for INSERT. Extra update/delete owner policies do not violate the rubric." - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [] - }, - "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", - "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-dataapi-001-empty-results.json" - }, - { - "experiment": "codex-gpt-5.4-mini-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.4-mini", - "reasoningEffort": "medium" - }, - "eval": "resolve-database-001-migration-history-mismatch", - "stage": "resolve", - "product": [ - "database" - ], - "topic": [ - "migrations" - ], - "suite": "benchmark", - "interface": "cli", - "passed": true, - "checks": [ - { - "name": "the avatar_url column is applied on the hosted profiles table", - "passed": true - }, - { - "name": "migration 20240220000000 is recorded in the remote history", - "passed": true - }, - { - "name": "remote migration history matches local migration files", - "passed": true - }, - { - "name": "local migrations are a valid reconciled sequence", - "passed": true - }, - { - "name": "production profile data is intact (not reset)", - "passed": true - }, - { - "name": "the avatar migration and history reconciliation were done via the Supabase CLI", - "passed": true, - "judgeNotes": "Avatar migration was applied through Supabase CLI with `supabase db push --db-url 'postgresql://postgres:postgres@172.17.0.1:41925/postgres?sslmode=disable'` (#34), which output `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration history was reconciled by adding the local migration file `supabase/migrations/20240115000000_add_profile_bio.sql` (#31), after which `supabase migration list` showed local and remote matched for `20240115000000` (#32), allowing the push to proceed. Only read-only `psql` inspections were used; no prohibited direct SQL mutation or prepared-statement workaround was seen." + "judgeNotes": "It failed to identify or fix the missing `orders` table in the `supabase_realtime` publication and instead suggested a likely client-side subscription/filter issue." } ], "skills": { @@ -13300,10 +12775,10 @@ "docs": { "calls": [] }, - "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", - "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", + "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", "attempts": 2, - "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-database-001-migration-history-mismatch.json" + "sourcePath": "codex-gpt-5.4-mini-no-skills/investigate-realtime-001-subscribed-no-events.json" }, { "experiment": "codex-gpt-5.4-mini-no-skills", @@ -13314,39 +12789,32 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "resolve-performance-001-slow-query-cpu-spike", - "stage": "resolve", + "eval": "investigate-reliability-003-edge-function-5xx-correlation", + "stage": "investigate", "product": [ - "database" + "edge-functions" ], "topic": [ - "observability", - "sql" + "observability" ], "suite": "benchmark", "interface": "mcp", - "passed": true, + "passed": false, "checks": [ { - "name": "inspected pg_stat_statements for query performance", - "passed": true - }, - { - "name": "ran EXPLAIN on the expensive query", - "passed": true + "name": "identified image-transform and the recurring 503 pattern", + "passed": true, + "judgeNotes": "Identified `image-transform` and listed all eight recurring HTTP 503 gateway failures from 07:00Z through 12:00Z on 2026-04-28." }, { - "name": "created index covering user_id and created_at", - "passed": true + "name": "attributed recurring 503s to gateway/platform layer, not function code", + "passed": false, + "judgeNotes": "Although it observes runtime 200s alongside gateway 503s, it ultimately attributes failures to shared application logic or dependencies and recommends function-level debugging rather than identifying the gateway/platform layer as the cause." }, { - "name": "query plan uses an index and avoids sequential scan", + "name": "recommended a concrete next step", "passed": true, - "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_desc_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" - }, - { - "name": "inserts still work", - "passed": true + "judgeNotes": "Provides multiple specific actions: add targeted error logging, correlate timestamps with request attributes, check upstream incidents/rate limits, implement retries, and trace a failing request ID in runtime stderr." } ], "skills": { @@ -13356,10 +12824,10 @@ "docs": { "calls": [] }, - "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", - "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-performance-001-slow-query-cpu-spike.json" + "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", + "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini-no-skills/investigate-reliability-003-edge-function-5xx-correlation.json" }, { "experiment": "codex-gpt-5.4-mini-no-skills", @@ -13370,55 +12838,49 @@ "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "resolve-security-002-rls-cross-tenant-leak", + "eval": "resolve-dataapi-001-empty-results", "stage": "resolve", "product": [ + "data-api", "database", "auth" ], "topic": [ "rls", - "security" + "sdk" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "RLS enabled on notes", - "passed": true - }, - { - "name": "tenant A sees only org A notes", - "passed": true - }, - { - "name": "tenant B cannot read org A notes", + "name": "RLS still enabled on bookmarks", "passed": true }, { - "name": "tenant A author can update own note", + "name": "user A reads own bookmarks", "passed": true }, { - "name": "tenant B cannot update org A note", + "name": "user B cannot read user A bookmarks", "passed": true }, { - "name": "tenant B author can delete own note", + "name": "anon reads no bookmarks", "passed": true }, { - "name": "tenant B cannot delete org A note", + "name": "user A can save a new bookmark", "passed": true }, { - "name": "tenant A can insert note in own org", + "name": "user B cannot insert a bookmark as user A", "passed": true }, { - "name": "tenant B cannot insert into org A", - "passed": true + "name": "diagnosed RLS and added owner-scoped policies", + "passed": true, + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and created authenticated owner-scoped SELECT and INSERT policies using auth.uid() = user_id. Extra owner-scoped UPDATE/DELETE policies are acceptable." } ], "skills": { @@ -13428,414 +12890,414 @@ "docs": { "calls": [] }, - "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", - "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", + "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-security-002-rls-cross-tenant-leak.json" + "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-dataapi-001-empty-results.json" }, { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", + "experiment": "codex-gpt-5.4-mini-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", - "modelId": "gpt-5.6-sol", + "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-auth-001-email-password-flow", - "stage": "build", + "eval": "resolve-database-001-migration-history-mismatch", + "stage": "resolve", "product": [ - "auth", "database" ], "topic": [ - "sdk", - "rls" + "migrations" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "auth module loads and the driver completes", - "passed": true, - "notes": "driver produced a result" - }, - { - "name": "signUp creates the account and returns its user id", - "passed": true, - "notes": "db user 54178c78-bfc4-4a47-8331-65384278fdef, signUp returned {\"userId\":\"54178c78-bfc4-4a47-8331-65384278fdef\"}" - }, - { - "name": "signup metadata reaches the profile (display name)", - "passed": true, - "notes": "profiles.display_name = \"Alex Doe\"" + "name": "the avatar_url column is applied on the hosted profiles table", + "passed": true }, { - "name": "wrong password is rejected gracefully (no throw, no session)", - "passed": true, - "notes": "{\"error\":\"Invalid login credentials\"}" + "name": "migration 20240220000000 is recorded in the remote history", + "passed": true }, { - "name": "signIn with the right password returns the user id", - "passed": true, - "notes": "{\"userId\":\"54178c78-bfc4-4a47-8331-65384278fdef\"}" + "name": "remote migration history matches local migration files", + "passed": true }, { - "name": "getMyProfile returns the signed-in user's profile", - "passed": true, - "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + "name": "local migrations are a valid reconciled sequence", + "passed": true }, { - "name": "app code does not use the secret / service-role key", - "passed": true, - "notes": "no secret-key references found" + "name": "production profile data is intact (not reset)", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", + "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "notes": "imports found in: app/src/auth.mjs" + "judgeNotes": "`supabase db push --db-url \"$(cat supabase/.temp/pooler-url)\" --yes` applied `20240220000000_add_avatar_url.sql` and finished successfully. History was reconciled by adding local placeholder migration `20240115000000_align_remote_history.sql`, then pushing. No prohibited workaround was used." } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase-js signUp email password options data user metadata signInWithPassword getUser select single profile\", limit: 5) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } } } }", + "query": "query { searchDocs(query: \"gen_random_uuid migration create table pgcrypto Supabase\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", - "title": "Migrate from Auth0 to Supabase Auth" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", + "title": "Resumable WebSockets with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#next-steps", + "title": "Next steps" }, { - "url": "https://supabase.com/docs/guides/auth/passwords", - "title": "Password-based Auth" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#why-this-pattern-works", + "title": "Why this pattern works" }, { - "url": "https://supabase.com/docs/guides/auth/passkeys", - "title": "Passkey authentication" - } - ], - "resultChars": 80822 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- changelog auth mentions ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'breaking-change|auth|supabase-js' | sed -n '1,220p'; printf '%s\\\\n' '--- auth.mjs ---'; cat app/src/auth.mjs; printf '%s\\\\n' '--- app directory ---'; find app -maxdepth 3 -type f -o -type l | sort | xargs -r ls -l; printf '%s\\\\n' '--- service status ---'; supabase status -o env\"", - "pages": [ + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#browser-client", + "title": "Browser client" + }, { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 1410 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"JavaScript signUp email password options data display_name\", limit: 10) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#edge-function-websocket-proxy", + "title": "Edge Function (WebSocket proxy)" + }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#database-schema", + "title": "Database schema" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signup" + "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets#architecture", + "title": "Architecture" }, { - "url": "https://supabase.com/docs/guides/auth/auth-email-passwordless", - "title": "Passwordless email logins" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp", + "title": "uuid-ossp: Unique Identifiers" }, { - "url": "https://supabase.com/docs/reference/dart/auth-signinwithpassword" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#uuid_generate_v1", + "title": "uuid_generate_v1()" }, { - "url": "https://supabase.com/docs/reference/csharp/auth-signinwithpassword", - "title": "SignIn(email, password)" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#uuid_generate_v4", + "title": "uuid_generate_v4()" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-verifyotp" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#enable-the-extension", + "title": "Enable the extension" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-passkey-list" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#overview", + "title": "Overview" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signinanonymously" + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#examples", + "title": "Examples" }, { - "url": "https://supabase.com/docs/reference/dart/auth-signup" - } - ], - "resultChars": 19311 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"JavaScript auth getUser current user select maybeSingle profiles table\", limit: 8) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#within-a-query", + "title": "Within a query" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#as-a-primary-key", + "title": "As a primary key" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/uuid-ossp#the-uuid-type", + "title": "The uuid type" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase", + "title": "Migrating to Supabase" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase#migration-guides", + "title": "Migration guides" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations", + "title": "Database migrations" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#database-migrations", + "title": "Database migrations" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#add-sample-data", + "title": "Add sample data" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#diffing-changes", + "title": "Diffing changes" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#deploy-your-project", + "title": "Deploy your project" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#log-in-to-the-supabase-cli", + "title": "Log in to the Supabase CLI" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#link-your-project", + "title": "Link your project" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#deploy-database-changes", + "title": "Deploy database changes" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#deploy-edge-functions", + "title": "Deploy Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#use-auth-locally", + "title": "Use Auth locally" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#sync-storage-buckets", + "title": "Sync storage buckets" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#sync-any-schema-with---schema", + "title": "Sync any schema with --schema" + }, + { + "url": "https://supabase.com/docs/guides/local-development/database-migrations#limitations-and-considerations", + "title": "Limitations and considerations" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#create-a-data-transfer-object", + "title": "Create a data transfer object" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#provide-supabase-instances-with-hilt", + "title": "Provide Supabase instances with Hilt" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#set-up-hilt-for-dependency-injection", + "title": "Set up Hilt for dependency injection" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#set-up-supabase-dependencies", + "title": "Set up Supabase dependencies" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#create-local-environment-secret", + "title": "Create local environment secret" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#create-new-android-project", + "title": "Create new Android project" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#set-up-api-key-and-secret-securely", + "title": "Set up API key and secret securely" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#building-the-app", + "title": "Building the app" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#set-up-google-authentication", + "title": "Set up Google authentication" + }, { - "url": "https://supabase.com/docs/reference/javascript/auth-getuser" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#get-api-details", + "title": "Get API details" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-getuserbyid" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#set-up-the-database-schema", + "title": "Set up the database schema" }, { - "url": "https://supabase.com/docs/reference/javascript/select" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#create-a-project", + "title": "Create a project" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-listusers" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#project-setup", + "title": "Project setup" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-createuser" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#use-value-from-buildconfig", + "title": "Use value from BuildConfig" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-updateuser" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#read-and-set-value-to-buildconfig", + "title": "Read and set value to BuildConfig" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#create-the-success-screen", + "title": "Create the success screen" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#implement-the-mainactivity", + "title": "Implement the MainActivity" }, { - "url": "https://supabase.com/docs/reference/javascript/using-modifiers-maybesingle" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#implement-screens", + "title": "Implement screens" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin#implement-repositories", + "title": "Implement repositories" } ], - "resultChars": 7456 + "resultChars": 165740 } ] }, - "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", - "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-auth-001-email-password-flow.json" + "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", + "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-database-001-migration-history-mismatch.json" }, { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", + "experiment": "codex-gpt-5.4-mini-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", - "modelId": "gpt-5.6-sol", + "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-cli-001-bootstrap-app", - "stage": "build", + "eval": "resolve-performance-001-slow-query-cpu-spike", + "stage": "resolve", "product": [ - "database", - "data-api" + "database" ], "topic": [ - "migrations", - "rls" + "observability", + "sql" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase project initialised (supabase/config.toml exists)", - "passed": true - }, - { - "name": "todos table is created by a migration file", + "name": "inspected pg_stat_statements for query performance", "passed": true }, { - "name": "todos table exists with at least 2 seeded rows", - "passed": true, - "notes": "found 2 rows" - }, - { - "name": "row level security is enabled on todos", + "name": "ran EXPLAIN on the expensive query", "passed": true }, { - "name": "a SELECT policy targets the authenticated role", + "name": "created index covering user_id and created_at", "passed": true }, { - "name": "REST API returns no todos to anonymous requests", + "name": "query plan uses an index and avoids sequential scan", "passed": true, - "notes": "0 rows" + "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" }, { - "name": "REST API returns the todos to authenticated requests", - "passed": true, - "notes": "2 rows" + "name": "inserts still work", + "passed": true } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- CLAUDE SUPABASE ---'; sed -n '1,240p' .claude/skills/supabase/SKILL.md; printf '%s\\\\n' '--- CLAUDE POSTGRES ---'; sed -n '1,220p' .claude/skills/supabase-postgres-best-practices/SKILL.md; printf '%s\\\\n' '--- SECURITY REFS ---'; find .agents/skills/supabase-postgres-best-practices/references -maxdepth 1 -type f -printf '%f\\\\n' | sort | rg 'security|schema'; printf '%s\\\\n' '--- RLS REFERENCES ---'; cat .agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md 2>/dev/null; cat .agents/skills/supabase-postgres-best-practices/references/security-rls.md 2>/dev/null; printf '%s\\\\n' '--- CLI VERSION ---'; supabase --version; printf '%s\\\\n' '--- GIT ---'; git status --short --branch 2>/dev/null || true; printf '%s\\\\n' '--- CHANGELOG MATCHES ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'breaking-change|row level|rls|local development|cli' | head -n 120\"", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 8747 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Data API expose table grant anon authenticated RLS select policy authenticated local development CLI migrations db reset\", limit: 8) { nodes { __typename title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" - }, - { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" - }, - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", - "title": "Token Security and Row Level Security" - }, - { - "url": "https://supabase.com/docs/reference/cli/supabase-db-reset", - "title": "Resets the local database to current migrations" - } - ], - "resultChars": 124182 - } - ] + "calls": [] }, - "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", - "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", + "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", + "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-cli-001-bootstrap-app.json" + "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-performance-001-slow-query-cpu-spike.json" }, { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", + "experiment": "codex-gpt-5.4-mini-no-skills", + "experimentSuite": "no-skills", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", - "modelId": "gpt-5.6-sol", + "modelId": "gpt-5.4-mini", "reasoningEffort": "medium" }, - "eval": "build-cli-002-declarative-schema", - "stage": "build", + "eval": "resolve-security-002-rls-cross-tenant-leak", + "stage": "resolve", "product": [ - "database" + "database", + "auth" ], "topic": [ - "declarative-schema", - "migrations" + "rls", + "security" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase db diff used to generate the migration", + "name": "RLS enabled on notes", "passed": true }, { - "name": "schema file updated to include description column", + "name": "tenant A sees only org A notes", "passed": true }, { - "name": "a new migration was generated for the change", + "name": "tenant B cannot read org A notes", "passed": true }, { - "name": "description column exists in the live database", + "name": "tenant A author can update own note", + "passed": true + }, + { + "name": "tenant B cannot update org A note", + "passed": true + }, + { + "name": "tenant B author can delete own note", + "passed": true + }, + { + "name": "tenant B cannot delete org A note", + "passed": true + }, + { + "name": "tenant A can insert note in own org", + "passed": true + }, + { + "name": "tenant B cannot insert into org A", "passed": true } ], "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] + "available": [], + "loaded": [] }, "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase declarative database schemas generate migration db diff local\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", - "title": "Declarative database schemas" - }, - { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" - }, - { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" - }, - { - "url": "https://supabase.com/docs/guides/local-development/database-migrations", - "title": "Database migrations" - }, - { - "url": "https://supabase.com/docs/guides/deployment/managing-environments", - "title": "Managing Environments" - } - ], - "resultChars": 82866 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|declarative|migration|db diff' | head -80; printf '\\\\n--- CONFIG ---\\\\n'; sed -n '1,220p' supabase/config.toml; printf '\\\\n--- SCHEMA ---\\\\n'; cat supabase/schemas/products.sql; printf '\\\\n--- MIGRATION ---\\\\n'; cat supabase/migrations/20260101000000_create_products.sql; printf '\\\\n--- STATUS ---\\\\n'; supabase status || true\"", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 8129 - } - ] + "calls": [] }, - "prompt": "Add a description text column to the `products` table in my local Supabase stack", - "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-cli-002-declarative-schema.json" + "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", + "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.4-mini-no-skills/resolve-security-002-rls-cross-tenant-leak.json" }, { "experiment": "codex-gpt-5.6", @@ -13846,36 +13308,60 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-cli-003-pg-cron-queue-workflow", + "eval": "build-auth-001-email-password-flow", "stage": "build", "product": [ - "database", - "edge-functions", - "cron", - "queues" + "auth", + "database" ], "topic": [ - "sql", - "sdk" + "sdk", + "rls" ], "suite": "benchmark", "interface": "cli", + "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", + "name": "auth module loads and the driver completes", + "passed": true, + "notes": "driver produced a result" + }, + { + "name": "signUp creates the account and returns its user id", + "passed": true, + "notes": "db user 86598dc2-1a19-45be-a7d6-e8e4619dc762, signUp returned {\"userId\":\"86598dc2-1a19-45be-a7d6-e8e4619dc762\"}" + }, + { + "name": "signup metadata reaches the profile (display name)", + "passed": true, + "notes": "profiles.display_name = \"Alex Doe\"" + }, + { + "name": "wrong password is rejected gracefully (no throw, no session)", + "passed": true, + "notes": "{\"error\":\"Invalid login credentials\"}" + }, + { + "name": "signIn with the right password returns the user id", "passed": true, - "notes": "schedule='* * * * *', active=true" + "notes": "{\"userId\":\"86598dc2-1a19-45be-a7d6-e8e4619dc762\"}" }, { - "name": "cron command enqueues to the 'tasks' queue", + "name": "getMyProfile returns the signed-in user's profile", "passed": true, - "notes": "queue depth 0 -> 1" + "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" }, { - "name": "process-tasks function drains the queue", + "name": "app code does not use the secret / service-role key", "passed": true, - "notes": "function removed the seeded message (id 4) from the queue" + "notes": "no secret-key references found" + }, + { + "name": "implementation uses @supabase/supabase-js", + "passed": true, + "notes": "imports found in: app/src/auth.mjs" } ], "skills": { @@ -13884,128 +13370,119 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Queues pgmq create queue send read delete Edge Function cron schedule every minute\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"supabase-js createClient auth signUp options data display_name signInWithPassword select single current session\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", + "title": "Configure SAML SSO" }, { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-figma", + "title": "Login with Figma" }, { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-slack", + "title": "Login with Slack" }, { - "url": "https://supabase.com/docs/guides/queues", - "title": "Supabase Queues" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-zoom", + "title": "Login with Zoom" }, { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-github", + "title": "Login with GitHub" }, { - "url": "https://supabase.com/docs/guides/cron/install", - "title": "Install" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-linkedin", + "title": "Login with LinkedIn" }, { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-discord", + "title": "Login with Discord" }, { - "url": "https://supabase.com/docs/guides/queues/quickstart", - "title": "Quickstart" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-gitlab", + "title": "Login with GitLab" } ], - "resultChars": 44996 + "resultChars": 151090 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Cron schedule database function cron.schedule pgmq send queue\", limit: 6) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"JavaScript signUp email password options data user metadata\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, - { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" + "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", + "title": "Customizing Emails by Language" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", - "title": "pg_cron debugging guide" + "url": "https://supabase.com/docs/reference/javascript/auth-signup" }, { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" }, { - "url": "https://supabase.com/docs/guides/cron/install", - "title": "Install" + "url": "https://supabase.com/docs/guides/auth/auth-mfa", + "title": "Multi-Factor Authentication" }, { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" - } - ], - "resultChars": 35015 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- CHANGELOG MATCHES ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'breaking-change|queue|cron|edge function' | head -n 160 || true; printf '%s\\\\n' '--- CONFIG RELEVANT ---'; rg -n '\"'^'\"\\\\[|enabled|verify_jwt|additional_search_path|port' supabase/config.toml; printf '%s\\\\n' '--- MIGRATION HEAD ---'; sed -n '1,100p' supabase/migrations/20260101000000_enable_cron_and_queues.sql; printf '%s\\\\n' '--- MIGRATION TAIL ---'; tail -n 80 supabase/migrations/20260101000000_enable_cron_and_queues.sql; printf '%s\\\\n' '--- MIGRATION SYMBOLS ---'; rg -n 'create extension|pgmq.create|cron.schedule|pgmq_public|create schema' supabase/migrations/20260101000000_enable_cron_and_queues.sql\"", - "pages": [ - { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/auth/auth-email-passwordless", + "title": "Passwordless email logins" } ], - "resultChars": 19533 + "resultChars": 34247 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions SUPABASE_URL SUPABASE_SERVICE_ROLE_KEY environment variables local serve createClient\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"JavaScript auth getUser current signed in user select profiles maybeSingle single\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/reference/javascript/auth-getuser" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/reference/javascript/auth-admin-getuserbyid" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithsso" }, { - "url": "https://supabase.com/docs/guides/functions/unit-test", - "title": "Testing your Edge Functions" + "url": "https://supabase.com/docs/reference/javascript/auth-signout" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/reference/javascript/auth-signinanonymously" + }, + { + "url": "https://supabase.com/docs/reference/javascript/auth-updateuser" } ], - "resultChars": 40557 + "resultChars": 5795 + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"printf '%s\\\\n' '---AUTH CHANGELOG MATCHES---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|auth|supabase-js' | sed -n '1,100p'; printf '%s\\\\n' '---PACKAGE VERSION---'; npm view @supabase/supabase-js version\"", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 8 } ] }, - "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", - "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", + "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", + "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-cli-003-pg-cron-queue-workflow.json" + "sourcePath": "codex-gpt-5.6/build-auth-001-email-password-flow.json" }, { "experiment": "codex-gpt-5.6", @@ -14016,44 +13493,50 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-dataapi-001-relational-report", + "eval": "build-cli-001-bootstrap-app", "stage": "build", "product": [ - "data-api", - "database" + "database", + "data-api" ], "topic": [ - "sdk" + "migrations", + "rls" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" + "name": "supabase project initialised (supabase/config.toml exists)", + "passed": true }, { - "name": "report numbers match the database (per customer, sorted)", - "passed": true, - "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" + "name": "todos table is created by a migration file", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", + "name": "todos table exists with at least 2 seeded rows", "passed": true, - "notes": "publishable read errored: permission denied for table customers" + "notes": "found 2 rows" }, { - "name": "implementation uses @supabase/supabase-js", + "name": "row level security is enabled on todos", + "passed": true + }, + { + "name": "a SELECT policy targets the authenticated role", + "passed": true + }, + { + "name": "REST API returns no todos to anonymous requests", "passed": true, - "notes": "imports found in: app/report.mjs" + "notes": "0 rows" }, { - "name": "report queries via the Data API, not raw SQL", + "name": "REST API returns the todos to authenticated requests", "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "notes": "2 rows" } ], "skills": { @@ -14068,48 +13551,80 @@ }, "docs": { "calls": [ + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase javascript select nested foreign tables service role secret key createClient Node\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Supabase CLI local development init start migrations seed.sql row level security REST API authentication testing\", limit: 8) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/reference/javascript/oauth-admin-createclient" + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" }, { - "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", - "title": "Integrating with Supabase Database (Postgres)" + "url": "https://supabase.com/docs/guides/cli", + "title": "Local Dev with CLI" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/database/testing", + "title": "Testing Your Database" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", - "title": "Performing administration tasks on the server side with a secret key" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/reference/javascript/oauth-admin-updateclient" + "url": "https://supabase.com/docs/guides/local-development/cli/getting-started", + "title": "Supabase CLI" + }, + { + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" + }, + { + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" + }, + { + "url": "https://supabase.com/docs/guides/functions/development-environment", + "title": "Development Environment" } ], - "resultChars": 22127 + "resultChars": 112630 }, { "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- changelog relevant scan ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -n -m 20 'breaking-change|supabase-js|secret key|postgrest|data api' || true; printf '%s\\\\n' '--- root listing ---'; ls -la; printf '%s\\\\n' '--- app listing ---'; find app -maxdepth 2 -type f -print -exec sed -n '1,80p' {} \\\\;; printf '%s\\\\n' '--- node/npm ---'; node --version; npm --version; npm root -g; printf '%s\\\\n' '--- installed candidates ---'; find . -maxdepth 3 -type d \\\\( -name '@supabase' -o -name 'node_modules' \\\\) -print; printf '%s\\\\n' '--- supabase status env ---'; supabase status -o env\"", + "query": "/bin/bash -lc \"set -o pipefail\nprintf '%s\\\\n' '--- tool versions ---'\n(command -v supabase && supabase --version) || true\n(command -v docker && docker --version) || true\n(command -v node && node --version) || true\n(command -v curl && curl --version | head -1) || true\nprintf '%s\\\\n' '--- changelog breaking changes ---'\ncurl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|breaking change' | head -30 || true\nprintf '%s\\\\n' '--- git status ---'\ngit status --short --branch 2>/dev/null || true\nprintf '%s\\\\n' '--- skill references ---'\nrg --files /tmp/sandbox-3353bacf/.agents/skills/supabase-postgres-best-practices/references | rg '(security-rls|schema-primary|schema-data|query-missing)' | head -20\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 1554 + "resultChars": 6277 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically", + "pages": [ + { + "url": "https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically" + } + ] } ] }, - "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", - "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6/build-dataapi-001-relational-report.json" + "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", + "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6/build-cli-001-bootstrap-app.json" }, { "experiment": "codex-gpt-5.6", @@ -14120,44 +13635,34 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-dataapi-002-restock-alert-report", + "eval": "build-cli-002-declarative-schema", "stage": "build", "product": [ - "data-api", "database" ], "topic": [ - "sdk" + "declarative-schema", + "migrations" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", - "passed": false, + "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" - }, - { - "name": "alerts match the database (below threshold, sorted)", - "passed": true, - "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" + "name": "supabase db diff used to generate the migration", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", - "passed": true, - "notes": "publishable read errored: permission denied for table inventory" + "name": "schema file updated to include description column", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "a new migration was generated for the change", + "passed": true }, { - "name": "report queries via the Data API, not raw SQL", - "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "name": "description column exists in the live database", + "passed": true } ], "skills": { @@ -14174,48 +13679,48 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase-js select nested foreign tables createClient secret key Node backend order results\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"local development declarative database schemas schema_paths db diff migration\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/engineering-for-scale", - "title": "Engineering for Scale" + "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", + "title": "Declarative database schemas" }, { - "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", - "title": "Integrating with Supabase Database (Postgres)" + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", - "title": "Performing administration tasks on the server side with a secret key" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/guides/api/creating-routes", - "title": "Creating API Routes" + "url": "https://supabase.com/docs/guides/deployment/managing-environments", + "title": "Managing Environments" }, { - "url": "https://supabase.com/docs/guides/api/quickstart", - "title": "Build an API route in less than 2 minutes." + "url": "https://supabase.com/docs/reference/cli/supabase-db-diff", + "title": "Diffs the local database for schema changes" } ], - "resultChars": 27813 + "resultChars": 72112 }, { "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- app/package.json ---'; cat app/package.json; printf '%s\\\\n' '--- git status ---'; git status --short; printf '%s\\\\n' '--- supabase status ---'; supabase status -o env; printf '%s\\\\n' '--- relevant changelog scan ---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|secret key|supabase-js|postgrest|data api' | head -80\"", + "query": "/bin/bash -lc \"command -v apply_patch || find / -type f -name apply_patch 2>/dev/null | head -20; printf '\\\\n--- changelog scan ---\\\\n'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|declarative|migration|db diff' | head -40 || true; printf '\\\\n--- files now ---\\\\n'; cat supabase/schemas/products.sql; ls -la supabase/migrations\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 15363 + "resultChars": 6610 } ] }, - "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", - "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6/build-dataapi-002-restock-alert-report.json" + "prompt": "Add a description text column to the `products` table in my local Supabase stack", + "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6/build-cli-002-declarative-schema.json" }, { "experiment": "codex-gpt-5.6", @@ -14226,37 +13731,36 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-database-001-migrate-postgres-to-supabase", + "eval": "build-cli-003-pg-cron-queue-workflow", "stage": "build", "product": [ - "database" + "database", + "edge-functions", + "cron", + "queues" ], "topic": [ - "migrations" + "sql", + "sdk" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "all 3 tables exist (teams, members, tasks)", - "passed": true - }, - { - "name": "row counts match (teams=5, members=10, tasks=13)", - "passed": true - }, - { - "name": "foreign key constraints survived the restore", - "passed": true + "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", + "passed": true, + "notes": "schedule='* * * * *', active=true" }, { - "name": "tasks_team_status_idx index survived the restore", - "passed": true + "name": "cron command enqueues to the 'tasks' queue", + "passed": true, + "notes": "queue depth 0 -> 1" }, { - "name": "sequences synced (next insert won't conflict with existing IDs)", - "passed": true + "name": "process-tasks function drains the queue", + "passed": true, + "notes": "function removed the seeded message (id 4) from the queue" } ], "skills": { @@ -14273,776 +13777,1028 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"restore pg_restore local Supabase binary dump roles ownership extensions\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Supabase Queues pgmq create queue send message read messages delete Edge Function cron schedule every minute local development\", limit: 8) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues#features", + "title": "Features" + }, + { + "url": "https://supabase.com/docs/guides/queues#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" + }, + { + "url": "https://supabase.com/docs/guides/cron#how-does-cron-work", + "title": "How does Cron work?" + }, + { + "url": "https://supabase.com/docs/guides/cron#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions#examples", + "title": "Examples" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions#invoke-an-edge-function-every-minute", + "title": "Invoke an Edge Function every minute" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#consuming-messages-in-an-edge-function", + "title": "Consuming messages in an Edge Function" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_delete", + "title": "http_delete" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#debugging-requests", + "title": "Debugging requests" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#analyzing-responses", + "title": "Analyzing responses" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#delete-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-signature", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_post", + "title": "http_post" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-signature", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_get", + "title": "http_get" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#enable-the-extension", + "title": "Enable the extension" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#limitations", + "title": "Limitations" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#send-multiple-table-rows-in-one-request", + "title": "Send multiple table rows in one request" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#execute-pg_net-in-a-trigger", + "title": "Execute pg_net in a trigger" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#call-an-endpoint-every-minute-with-pg_cron", + "title": "Call an endpoint every minute with pg_cron" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#invoke-a-supabase-edge-function", + "title": "Invoke a Supabase Edge Function" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#examples", + "title": "Examples" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#alter-settings", + "title": "Alter settings" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-current-settings", + "title": "Get current settings" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#configuration", + "title": "Configuration" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#inspecting-failed-requests", + "title": "Inspecting failed requests" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#inspecting-request-data", + "title": "Inspecting request data" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-signature-1", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#pull-based-queue", + "title": "Pull-Based Queue" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#create-queues", + "title": "Create Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#queue-types", + "title": "Queue types" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#message", + "title": "Message" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#enqueueing-and-dequeueing-messages", + "title": "Enqueueing and dequeueing messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#grant-permissions-to-pgmq_public-database-functions", + "title": "Grant permissions to pgmq_public database functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#enable-rls-on-your-tables-in-pgmq-schema", + "title": "Enable RLS on your tables in pgmq schema" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#expose-queues-to-client-side-consumers", + "title": "Expose Queues to client-side consumers" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#what-happens-when-you-create-a-queue", + "title": "What happens when you create a queue?" + }, + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicpopqueue_name", + "title": "pgmq_public.pop(queue_name)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsendqueue_name-message-sleep_seconds", + "title": "pgmq_public.send(queue_name, message, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsend_batchqueue_name-messages-sleep_seconds", + "title": "pgmq_public.send_batch(queue_name, messages, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicarchivequeue_name-message_id", + "title": "pgmq_public.archive(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicdeletequeue_name-message_id", + "title": "pgmq_public.delete(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicreadqueue_name-sleep_seconds-n", + "title": "pgmq_public.read(queue_name, sleep_seconds, n)" + }, + { + "url": "https://supabase.com/docs/guides/cron/install", + "title": "Install" + }, + { + "url": "https://supabase.com/docs/guides/cron/install#uninstall", + "title": "Uninstall" + } + ], + "resultChars": 123109 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Cron create job cron.schedule SQL every minute database function Supabase\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", - "title": "Restore a Platform Project to Self-Hosted" + "url": "https://supabase.com/docs/guides/cron/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#call-a-database-stored-procedure", + "title": "Call a database stored procedure" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#schedule-a-job", + "title": "Schedule a job" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#edit-a-job", + "title": "Edit a job" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#activatedeactivate-a-job", + "title": "Activate/Deactivate a job" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#unschedule-a-job", + "title": "Unschedule a job" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#inspecting-job-runs", + "title": "Inspecting job runs" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#examples", + "title": "Examples" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#delete-data-every-week", + "title": "Delete data every week" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#run-a-vacuum-every-day", + "title": "Run a vacuum every day" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#call-a-database-function-every-5-minutes", + "title": "Call a database function every 5 minutes" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#invoke-supabase-edge-function-every-30-seconds", + "title": "Invoke Supabase Edge Function every 30 seconds" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart#caution-scheduling-system-maintenance", + "title": "Caution: Scheduling system maintenance" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#enable-the-extension", + "title": "Enable the extension" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#debugging-requests", + "title": "Debugging requests" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#analyzing-responses", + "title": "Analyzing responses" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#delete-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_get", + "title": "http_get" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-signature", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_post", + "title": "http_post" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-signature", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#http_delete", + "title": "http_delete" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#post-signature-1", + "title": "Signature " + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#inspecting-request-data", + "title": "Inspecting request data" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#inspecting-failed-requests", + "title": "Inspecting failed requests" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#configuration", + "title": "Configuration" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#get-current-settings", + "title": "Get current settings" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#alter-settings", + "title": "Alter settings" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#examples", + "title": "Examples" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#invoke-a-supabase-edge-function", + "title": "Invoke a Supabase Edge Function" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#call-an-endpoint-every-minute-with-pg_cron", + "title": "Call an endpoint every minute with pg_cron" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#execute-pg_net-in-a-trigger", + "title": "Execute pg_net in a trigger" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#send-multiple-table-rows-in-one-request", + "title": "Send multiple table rows in one request" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#limitations", + "title": "Limitations" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pg_net#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-postgres-extensions", - "title": "Custom Postgres Extensions" + "url": "https://supabase.com/docs/guides/cron#how-does-cron-work", + "title": "How does Cron work?" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/transferring-from-cloud-to-self-host-in-supabase-2oWNvW", - "title": "Transferring from platform to self-hosted Supabase" + "url": "https://supabase.com/docs/guides/cron#resources", + "title": "Resources" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", - "title": "Migrate from Postgres to Supabase" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", - "title": "Restoring a downloaded backup locally" - } - ], - "resultChars": 50510 - } - ] - }, - "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", - "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-database-001-migrate-postgres-to-supabase.json" - }, - { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.6-sol", - "reasoningEffort": "medium" - }, - "eval": "build-functions-004-service-role-bypass", - "stage": "build", - "product": [ - "edge-functions", - "auth", - "database" - ], - "topic": [ - "rls", - "security", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "rejects missing auth", - "passed": true, - "notes": "status=401" - }, - { - "name": "user A reads own note", - "passed": true, - "notes": "status=200" - }, - { - "name": "reads only with the caller's JWT", - "passed": true, - "notes": "bearer_tokens=2, all_match=true" - }, - { - "name": "user A cannot force-read user B note", - "passed": true, - "notes": "status=200" - }, - { - "name": "user B cannot force-read user A note", - "passed": true, - "notes": "status=200" - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions authenticate user Authorization header createClient service role getUser RLS\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#optional-clearing-embeddings-on-update", + "title": "(Optional) Clearing embeddings on update" + }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#step-2-create-utility-functions", + "title": "Step 2: Create utility functions" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#step-3-create-queue-and-triggers", + "title": "Step 3: Create queue and triggers" }, { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#why-not-generate-all-embeddings-in-a-single-edge-function-request", + "title": "Why not generate all embeddings in a single Edge Function request?" }, { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" - } - ], - "resultChars": 73053 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions auth getUser Authorization header SUPABASE_ANON_KEY createClient\", limit: 10) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#why-not-one-request-per-row", + "title": "Why not one request per row?" + }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#why-queue-requests-instead-of-processing-them-immediately", + "title": "Why queue requests instead of processing them immediately?" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#how-do-visibility-timeouts-work", + "title": "How do visibility timeouts work?" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#how-do-we-handle-retries", + "title": "How do we handle retries?" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#is-10-seconds-a-good-interval-for-processing", + "title": "Is 10 seconds a good interval for processing?" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#step-4-create-the-edge-function", + "title": "Step 4: Create the Edge Function" }, { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#usage", + "title": "Usage" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", - "title": "Resumable WebSockets with Edge Functions" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#1-create-table-to-store-documents-with-embeddings", + "title": "1. Create table to store documents with embeddings" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", - "title": "Configure SAML SSO" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#2-create-triggers-to-enqueue-embedding-jobs", + "title": "2. Create triggers to enqueue embedding jobs" }, { - "url": "https://supabase.com/docs/guides/functions/storage-caching", - "title": "Integrating with Supabase Storage" - } - ], - "resultChars": 96751 - }, - { - "source": "web_search", - "query": "https://supabase.com/changelog.md", - "pages": [ + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#3-insert-and-update-documents", + "title": "3. Insert and update documents" + }, { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#see-also", + "title": "See also" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#conclusion", + "title": "Conclusion" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#troubleshooting", + "title": "Troubleshooting" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#understanding-the-challenge", + "title": "Understanding the challenge" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#understanding-the-architecture", + "title": "Understanding the architecture" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#implementation", + "title": "Implementation" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings#step-1-enable-extensions", + "title": "Step 1: Enable extensions" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook", + "title": "Send Email Hook" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook#email-change-behavior-and-token-hash-mapping", + "title": "Email change behavior and token hash mapping" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook#email-sending-behavior", + "title": "Email sending behavior" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook#what-to-send", + "title": "What to send" } - ] + ], + "resultChars": 235673 }, - { - "source": "web_search", - "query": "site:supabase.com/changelog.md Supabase changelog breaking change Edge Functions auth API keys", - "pages": [] - } - ] - }, - "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", - "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-functions-004-service-role-bypass.json" - }, - { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.6-sol", - "reasoningEffort": "medium" - }, - "eval": "build-functions-005-dual-auth-user-secret", - "stage": "build", - "product": [ - "edge-functions", - "auth", - "database" - ], - "topic": [ - "sdk", - "rls", - "security" - ], - "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", - "passed": true, - "checks": [ - { - "name": "seed rows present", - "passed": true, - "notes": "found 2/2 seeded rows" - }, - { - "name": "rejects request with no credentials", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "user with JWT reads only their own rows", - "passed": true, - "notes": "status 200: [{\"user_id\":\"c2a94e60-d0fd-41fa-9393-3d88c36ccd1e\",\"metric\":\"steps_a_msj16f6m\",\"value\":111}]" - }, - { - "name": "user cannot read another user's rows by passing user_id", - "passed": true, - "notes": "status 200: [{\"user_id\":\"c2a94e60-d0fd-41fa-9393-3d88c36ccd1e\",\"metric\":\"steps_a_msj16f6m\",\"value\":111}]" - }, - { - "name": "service key bypasses RLS to read the target user's rows", - "passed": true, - "notes": "status 200: [{\"user_id\":\"29d6a26d-c31f-496e-a486-a4bd4a0adeee\",\"metric\":\"steps_b_msj16f6m\",\"value\":222}]" - }, - { - "name": "non-service key is not granted service access", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "rejects an unverified (forged) user token", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "a user token in the apikey slot is not treated as the service key", - "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" - }, - { - "name": "implementation uses @supabase/server", - "passed": true, - "notes": "imports @supabase/server / withSupabase" - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions JWT verification authorization header service role apikey header Deno serve createClient auth getUser\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Edge Function consume Supabase Queue pgmq_public read delete createClient service role\", limit: 8) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#consuming-messages-in-an-edge-function", + "title": "Consuming messages in an Edge Function" + }, + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicpopqueue_name", + "title": "pgmq_public.pop(queue_name)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsend_batchqueue_name-messages-sleep_seconds", + "title": "pgmq_public.send_batch(queue_name, messages, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicarchivequeue_name-message_id", + "title": "pgmq_public.archive(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicdeletequeue_name-message_id", + "title": "pgmq_public.delete(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicreadqueue_name-sleep_seconds-n", + "title": "pgmq_public.read(queue_name, sleep_seconds, n)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsendqueue_name-message-sleep_seconds", + "title": "pgmq_public.send(queue_name, message, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#pull-based-queue", + "title": "Pull-Based Queue" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#enqueueing-and-dequeueing-messages", + "title": "Enqueueing and dequeueing messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#grant-permissions-to-pgmq_public-database-functions", + "title": "Grant permissions to pgmq_public database functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#enable-rls-on-your-tables-in-pgmq-schema", + "title": "Enable RLS on your tables in pgmq schema" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#expose-queues-to-client-side-consumers", + "title": "Expose Queues to client-side consumers" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#what-happens-when-you-create-a-queue", + "title": "What happens when you create a queue?" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#create-queues", + "title": "Create Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#queue-types", + "title": "Queue types" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#message", + "title": "Message" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#concepts", + "title": "Concepts" }, { "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#example", + "title": "Example" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", - "title": "Resumable WebSockets with Edge Functions" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#setting-up-auth-context", + "title": "Setting up auth context" }, { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#fetching-the-user", + "title": "Fetching the user" }, { - "url": "https://supabase.com/docs/guides/functions/http-methods", - "title": "Routing" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt#row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", - "title": "Why is my service role key client getting RLS errors or not returning data?" - } - ], - "resultChars": 60939 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- CHANGELOG BREAKING TAGS ---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|edge function|secret key|service.role' | head -80; printf '%s\\\\n' '--- PROJECT FILES ---'; find .. -name AGENTS.md -print; rg --files -g '\"'!node_modules'\"' -g '\"'!vendor'\"' | sort | sed -n '1,240p'; printf '%s\\\\n' '--- SUPABASE CONFIG ---'; test -f supabase/config.toml && sed -n '1,240p' supabase/config.toml || true; printf '%s\\\\n' '--- MIGRATION MATCHES ---'; rg -n \\\"user_stats|create policy|enable row level security\\\" supabase . --glob '*.sql' --glob '\"'!node_modules'\"' || true\"", - "pages": [ + "url": "https://supabase.com/docs/guides/functions/recursive-functions#handling-rate-limit-errors", + "title": "Handling rate limit errors" + }, { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 24755 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Securing Edge Functions verify_jwt false custom JWT validation apikey service role key Authorization header\", limit: 10) { nodes { title href content } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/functions/recursive-functions#tips-for-avoiding-rate-limits", + "title": "Tips for avoiding rate limits" + }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#1-batch-operations-instead-of-individual-calls", + "title": "1. Batch operations instead of individual calls" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#2-limit-recursion-depth", + "title": "2. Limit recursion depth" }, { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#3-use-queues-for-large-workloads", + "title": "3. Use queues for large workloads" }, { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#4-use-shared-libraries-instead-of-separate-functions", + "title": "4. Use shared libraries instead of separate functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#5-add-delays-for-non-urgent-processing", + "title": "5. Add delays for non-urgent processing" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/functions/recursive-functions#common-patterns-and-their-impact", + "title": "Common patterns and their impact" + }, + { + "url": "https://supabase.com/docs/guides/functions/recursive-functions#increasing-rate-limits", + "title": "Increasing rate limits" + }, + { + "url": "https://supabase.com/docs/guides/functions/recursive-functions#rate-limit-budget", + "title": "Rate limit budget" + }, + { + "url": "https://supabase.com/docs/guides/functions/recursive-functions#what-gets-rate-limited", + "title": "What gets rate limited" }, { "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#before-you-start", + "title": "Before you start" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", - "title": "Envoy API Gateway" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#next-steps", + "title": "Next steps" }, { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - } - ], - "resultChars": 121781 - } - ] - }, - "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", - "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6/build-functions-005-dual-auth-user-secret.json" - }, - { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.6-sol", - "reasoningEffort": "medium" - }, - "eval": "build-rls-003-org-roles-permissions", - "stage": "build", - "product": [ - "database", - "auth" - ], - "topic": [ - "rls", - "security" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "RLS enabled on documents", - "passed": true - }, - { - "name": "viewer sees only documents in their org", - "passed": true - }, - { - "name": "viewer cannot insert", - "passed": true - }, - { - "name": "editor can insert own org document", - "passed": true - }, - { - "name": "editor can update own document", - "passed": true - }, - { - "name": "editor cannot update another user's document", - "passed": true - }, - { - "name": "editor cannot delete another user's document", - "passed": true - }, - { - "name": "admin can update any document in their org", - "passed": true - }, - { - "name": "admin can delete any document in their org", - "passed": true - }, - { - "name": "admin cannot affect another org", - "passed": true - }, - { - "name": "WITH CHECK blocks editor from moving document to another org", - "passed": true - }, - { - "name": "editor can still see their own org's roster", - "passed": true - }, - { - "name": "cannot see another org's membership roster", - "passed": true - }, - { - "name": "a viewer role in one org doesn't grant admin power in another org", - "passed": true - }, - { - "name": "multi-org user can act as admin in the org where they hold that role", - "passed": true - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"row level security policies auth.uid organization membership security definer performance\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-3-swap-the-secret-key-in-backend-code", + "title": "Step 3: Swap the secret key in backend code" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-2-swap-the-publishable-key-in-client-code", + "title": "Step 2: Swap the publishable key in client code" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-1-create-the-new-api-keys", + "title": "Step 1: Create the new API keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#database-webhooks-and-pg_net", + "title": "Database Webhooks and pg_net" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-4-update-edge-functions", + "title": "Step 4: Update Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-1-read-the-new-keys-from-the-environment", + "title": "Option 1: Read the new keys from the environment" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#known-limitations", + "title": "Known limitations" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-6-deactivate-the-legacy-keys", + "title": "Step 6: Deactivate the legacy keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#step-5-verify-nothing-uses-the-legacy-keys", + "title": "Step 5: Verify nothing uses the legacy keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys#option-2-adopt-the-supabaseserver-sdk", + "title": "Option 2: Adopt the @supabase/server SDK" + }, { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", + "title": "Integrating with Supabase Database (Postgres)" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#ssl-connections", + "title": "SSL connections" }, { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0003_auth_rls_initplan", - "title": "Database Advisor: Lint 0003_auth_rls_initplan" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#using-supabase-js", + "title": "Using supabase-js" }, { - "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", - "title": "Column Level Security" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#using-a-postgres-client", + "title": "Using a Postgres client" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - } - ], - "resultChars": 58492 - }, - { - "source": "web_search", - "query": "https://supabase.com/changelog.md", - "pages": [ + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#using-drizzle", + "title": "Using Drizzle" + }, { - "url": "https://supabase.com/changelog.md" - } - ] - }, - { - "source": "web_search", - "query": "site:supabase.com changelog row level security breaking change Supabase", - "pages": [] - } - ] - }, - "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", - "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-rls-003-org-roles-permissions.json" - }, - { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.6-sol", - "reasoningEffort": "medium" - }, - "eval": "build-storage-001-private-bucket-access", - "stage": "build", - "product": [ - "storage", - "database" - ], - "topic": [ - "rls", - "sdk" - ], - "suite": "benchmark", - "interface": "mcp", - "passed": true, - "checks": [ - { - "name": "bucket user-files exists", - "passed": true - }, - { - "name": "bucket user-files is private", - "passed": true - }, - { - "name": "RLS still enabled on storage.objects", - "passed": true - }, - { - "name": "user A lists only own files", - "passed": true, - "notes": "saw: 019fdc8e-c286-72ec-86c2-693b611d4fc9/receipt-alpha.pdf, 019fdc8e-c286-72ec-86c2-693b611d4fc9/receipt-beta.pdf" - }, - { - "name": "user B cannot read user A files", - "passed": true - }, - { - "name": "anon reads no files", - "passed": true - }, - { - "name": "user A can upload into own folder", - "passed": true - }, - { - "name": "user B cannot upload into user A folder", - "passed": true - }, - { - "name": "configured private per-user storage access", - "passed": true, - "judgeNotes": "The answer creates a private user-files bucket, keeps storage.objects RLS enabled, adds authenticated SELECT and INSERT policies scoped to bucket and user-owned path via auth.uid(), and provides supabase-js createSignedUrl with a 15-minute expiry. No fail conditions present." - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Storage access control RLS policies foldername auth.uid createSignedUrl private bucket upload download\", limit: 8) { nodes { title href content } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#production", + "title": "Production" + }, { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres#local-development", + "title": "Local development" }, { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" }, { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" + "url": "https://supabase.com/docs/guides/database/secure-data#direct-database-connections", + "title": "Direct database connections" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" + "url": "https://supabase.com/docs/guides/database/secure-data#edge-functions", + "title": "Edge Functions" }, { - "url": "https://supabase.com/docs/guides/realtime/getting_started", - "title": "Getting Started with Realtime" + "url": "https://supabase.com/docs/guides/database/secure-data#data-api", + "title": "Data API" }, { - "url": "https://supabase.com/docs/guides/storage/schema/custom-roles", - "title": "Custom Roles" + "url": "https://supabase.com/docs/guides/database/secure-data#connecting-your-app-securely", + "title": "Connecting your app securely" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt", - "title": "Why can't I upload/list/etc my public bucket?" + "url": "https://supabase.com/docs/guides/database/secure-data#more-information", + "title": "More information" }, { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" + "url": "https://supabase.com/docs/guides/database/secure-data#frontend-access", + "title": "Frontend access" } ], - "resultChars": 46298 + "resultChars": 140143 }, { "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|storage|signed url|rls' | head -80\"", - "hasContent": true, + "query": "/bin/bash -lc \"printf '%s\\\\n' '--- changelog queue/cron breaking changes ---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i -C 2 'breaking-change|queues|pgmq|cron' | sed -n '1,220p'; printf '%s\\\\n' '--- tool versions/status ---'; supabase --version; supabase status 2>&1 || true; printf '%s\\\\n' '--- git status ---'; git status --short 2>&1 || true\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 14020 + "resultChars": 1996 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"JavaScript createSignedUrl storage expiresIn private bucket signed URL\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Supabase Queues quickstart SQL pgmq.create queue create('basic_queue')\", limit: 5) { nodes { title href content ... on Guide { subsections { nodes { title href content } } } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/serving/image-transformations", - "title": "Storage Image Transformations" + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" }, { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" + "url": "https://supabase.com/docs/guides/queues/quickstart#enable-rls-on-your-tables-in-pgmq-schema", + "title": "Enable RLS on your tables in pgmq schema" }, { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" + "url": "https://supabase.com/docs/guides/queues/quickstart#what-happens-when-you-create-a-queue", + "title": "What happens when you create a queue?" }, { - "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" + "url": "https://supabase.com/docs/guides/queues/quickstart#expose-queues-to-client-side-consumers", + "title": "Expose Queues to client-side consumers" }, { - "url": "https://supabase.com/docs/guides/storage/serving/downloads", - "title": "Serving assets from Storage" - } - ], - "resultChars": 25918 - } - ] - }, - "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", - "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-storage-001-private-bucket-access.json" - }, - { - "experiment": "codex-gpt-5.6", - "experimentSuite": "benchmark", - "experimentDisplay": { - "agent": "codex", - "modelProvider": "openai", - "modelId": "gpt-5.6-sol", - "reasoningEffort": "medium" - }, - "eval": "build-tests-001-rls-tenant-isolation", - "stage": "build", - "product": [ - "database" - ], - "topic": [ - "tests", - "rls" - ], - "suite": "benchmark", - "interface": "cli", - "passed": true, - "checks": [ - { - "name": "pgTAP test file(s) written under supabase/tests/", - "passed": true, - "notes": "1 file(s): supabase/tests/database/tenant_isolation.test.sql" - }, - { - "name": "pgTAP isolation tests ran and pass", - "passed": true, - "notes": "36 passed, 0 failed" - }, - { - "name": "agent correctly identifies the posts isolation bug from test results", - "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as having a tenant isolation flaw: the policy omits `org_id`, allowing tenant A to see posts from tenant B. It grounds this in reproduced query results and adds pgTAP coverage. It does not blame `notes` instead or dismiss test results." - } - ], - "skills": { - "available": [ - "supabase", - "supabase-postgres-best-practices" - ], - "loaded": [ - "supabase", - "supabase-postgres-best-practices" - ] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "query { searchDocs(query: \"row level security testing policies auth.uid tenant isolation pgTAP\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/queues/quickstart#grant-permissions-to-pgmq_public-database-functions", + "title": "Grant permissions to pgmq_public database functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#enqueueing-and-dequeueing-messages", + "title": "Enqueueing and dequeueing messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#pull-based-queue", + "title": "Pull-Based Queue" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#message", + "title": "Message" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#queue-types", + "title": "Queue types" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart#create-queues", + "title": "Create Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/queues#features", + "title": "Features" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#create_unlogged", + "title": "create_unlogged" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#detach_archive", + "title": "detach_archive" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#drop_queue", + "title": "drop_queue" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#sending-messages", + "title": "Sending messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#send", + "title": "send" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#send_batch", + "title": "send_batch" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#reading-messages", + "title": "Reading messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#read", + "title": "read" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#read_with_poll", + "title": "read_with_poll" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#pop", + "title": "pop" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#deletingarchiving-messages", + "title": "Deleting/Archiving messages" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#delete-single", + "title": "delete (single)" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#delete-batch", + "title": "delete (batch)" + }, { - "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", - "title": "Advanced pgTAP Testing" + "url": "https://supabase.com/docs/guides/queues/pgmq#purge_queue", + "title": "purge_queue" }, { - "url": "https://supabase.com/docs/guides/local-development/testing/overview", - "title": "Testing Overview" + "url": "https://supabase.com/docs/guides/queues/pgmq#archive-single", + "title": "archive (single)" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgtap", - "title": "pgTAP: Unit Testing" + "url": "https://supabase.com/docs/guides/queues/pgmq#archive-batch", + "title": "archive (batch)" }, { - "url": "https://supabase.com/docs/guides/database/testing", - "title": "Testing Your Database" + "url": "https://supabase.com/docs/guides/queues/pgmq#utilities", + "title": "Utilities" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", + "url": "https://supabase.com/docs/guides/queues/pgmq#set_vt", + "title": "set_vt" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#list_queues", + "title": "list_queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#metrics", + "title": "metrics" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#metrics_all", + "title": "metrics_all" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#message_record", + "title": "message_record" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#types", + "title": "Types" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#features", "title": "Features" - } - ], - "resultChars": 56902 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- skill relevant sections ---'; rg -n \\\"RLS|policy|test|docs|changelog\\\" .claude/skills/supabase/SKILL.md; printf '%s\\\\n' '--- security references ---'; find .claude/skills/supabase-postgres-best-practices/references -maxdepth 1 -type f | sort | rg 'security|index'; printf '%s\\\\n' '--- read security rules ---'; cat .claude/skills/supabase-postgres-best-practices/references/security-rls.md 2>/dev/null || true; cat .claude/skills/supabase-postgres-best-practices/references/security-rls-performance.md 2>/dev/null || true; printf '%s\\\\n' '--- changelog relevant ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'breaking-change|row.level|rls|pgtap' | head -n 120; printf '%s\\\\n' '--- workspace ---'; find . -name AGENTS.md -print; ls -la; printf '%s\\\\n' '--- repo files ---'; rg --files -g '\"'!node_modules'\"' -g '\"'!vendor'\"' | sed -n '1,240p'\"", - "pages": [ + }, { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/queues/pgmq#enable-the-extension", + "title": "Enable the extension" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#get-usage", + "title": "Usage " + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#queue-management", + "title": "Queue management" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq#create", + "title": "create" + }, + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicarchivequeue_name-message_id", + "title": "pgmq_public.archive(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicdeletequeue_name-message_id", + "title": "pgmq_public.delete(queue_name, message_id)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicreadqueue_name-sleep_seconds-n", + "title": "pgmq_public.read(queue_name, sleep_seconds, n)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicpopqueue_name", + "title": "pgmq_public.pop(queue_name)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsend_batchqueue_name-messages-sleep_seconds", + "title": "pgmq_public.send_batch(queue_name, messages, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/api#pgmq_publicsendqueue_name-message-sleep_seconds", + "title": "pgmq_public.send(queue_name, message, sleep_seconds)" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#concepts", + "title": "Concepts" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions#consuming-messages-in-an-edge-function", + "title": "Consuming messages in an Edge Function" } ], - "resultChars": 17714 + "resultChars": 112910 } ] }, - "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", - "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", + "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", + "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-tests-001-rls-tenant-isolation.json" + "sourcePath": "codex-gpt-5.6/build-cli-003-pg-cron-queue-workflow.json" }, { "experiment": "codex-gpt-5.6", @@ -15053,50 +14809,44 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-vectors-001-rag-with-permissions", + "eval": "build-dataapi-001-relational-report", "stage": "build", "product": [ - "database", - "vectors" + "data-api", + "database" ], "topic": [ - "sql", - "rls" + "sdk" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "document_sections.embedding is vector(384)", + "name": "report runs and prints JSON", "passed": true, - "notes": "vector(384)" + "notes": "exit 0" }, { - "name": "HNSW index on the embedding column", + "name": "report numbers match the database (per customer, sorted)", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" }, { - "name": "index operator class matches the search operator", + "name": "tables stay locked down (publishable key reads nothing)", "passed": true, - "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" - }, - { - "name": "user A search returns only own sections, best match first", - "passed": true - }, - { - "name": "user B search returns only own sections, best match first", - "passed": true + "notes": "publishable read errored: permission denied for table customers" }, { - "name": "user A reads only own sections through the API", - "passed": true + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "user A reads only own documents through the API", - "passed": true + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -15113,92 +14863,86 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"pgvector semantic search match documents RLS HNSW vector extension Edge Functions\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"supabase-js select nested relationships count aggregate Node service role secret key\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/ai/hybrid-search", - "title": "Hybrid search" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" + "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", + "title": "Integrating with Supabase Database (Postgres)" }, { - "url": "https://supabase.com/docs/guides/ai/vector-indexes", - "title": "Vector indexes" + "url": "https://supabase.com/docs/reference/cli/supabase-inspect-db-role-connections", + "title": "Show information about roles on the database" }, { - "url": "https://supabase.com/docs/guides/ai/going-to-prod", - "title": "Going to Production" + "url": "https://supabase.com/docs/guides/troubleshooting/performing-administration-tasks-on-the-server-side-with-the-servicerole-secret-BYM4Fa", + "title": "Performing administration tasks on the server side with a secret key" } ], - "resultChars": 52858 + "resultChars": 29585 }, { - "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Edge Functions gte-small vector dimensions 384 match_document_sections\", limit: 8) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", - "hasContent": true, + "source": "web_search", + "query": "https://supabase.com/changelog.md", "pages": [ { - "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", - "title": "Semantic Search" - }, + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"printf '%s\\\\n' '--- migration ---'; cat supabase/migrations/0000_orders_schema.sql; printf '%s\\\\n' '--- config ---'; sed -n '1,220p' supabase/config.toml; printf '%s\\\\n' '--- app files ---'; find app -maxdepth 2 -type f -print -exec sed -n '1,220p' {} \\\\;; printf '%s\\\\n' '--- root ---'; ls -la; printf '%s\\\\n' '--- git status ---'; git status --short; printf '%s\\\\n' '--- changelog tags ---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking-change|supabase-js|secret key|api key' | head -80 || true\"", + "pages": [ { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" - }, + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 16099 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Data REST API JavaScript fetch apikey header secret key pagination range limit offset\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/ai/choosing-compute-addon", - "title": "Choosing your Compute Add-on" + "url": "https://supabase.com/docs/reference/javascript/using-modifiers-range" }, { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" }, { - "url": "https://supabase.com/docs/guides/functions/recursive-functions", - "title": "Recursive / Nested Function Calls" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/ai/langchain", - "title": "LangChain" + "url": "https://supabase.com/docs/reference/javascript/using-modifiers-limit" }, { - "url": "https://supabase.com/docs/guides/functions/architecture", - "title": "Edge Functions Architecture" + "url": "https://supabase.com/docs/reference/javascript/functions-corsheaders" }, { - "url": "https://supabase.com/docs/guides/storage/vector/working-with-indexes", - "title": "Working with Vector Indexes" + "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", + "title": "OAuth 2.1 Flows" } ], - "resultChars": 110370 - }, - { - "source": "web_search", - "query": "https://supabase.com/changelog.md", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ] - }, - { - "source": "web_search", - "query": "site:supabase.com/changelog.md Supabase changelog pgvector Edge Functions semantic search", - "pages": [] + "resultChars": 98062 } ] }, - "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", - "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/build-vectors-001-rag-with-permissions.json" + "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", + "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6/build-dataapi-001-relational-report.json" }, { "experiment": "codex-gpt-5.6", @@ -15209,31 +14953,44 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-database-001-prometheus-metrics", - "stage": "deploy", + "eval": "build-dataapi-002-restock-alert-report", + "stage": "build", "product": [ + "data-api", "database" ], "topic": [ - "observability" + "sdk" ], "suite": "benchmark", "interface": "cli", - "passed": true, + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "preserved existing app scrape job", - "passed": true + "name": "report runs and prints JSON", + "passed": true, + "notes": "exit 0" }, { - "name": "configured the Supabase Metrics API scrape correctly", + "name": "alerts match the database (below threshold, sorted)", "passed": true, - "judgeNotes": "Prometheus preserves the app job and adds a deployable Supabase scrape over HTTPS to /customer/v1/privileged/metrics for evalshostedprojectxy.supabase.co using basic_auth with password_file. docker-compose wires the matching password file via a Compose secret." + "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" }, { - "name": "documented live deployment and verification steps", + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table inventory" + }, + { + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + }, + { + "name": "report queries via the Data API, not raw SQL", "passed": true, - "judgeNotes": "README includes creating a Supabase Secret API key, storing it in the Compose secret file path, recreating the stack, and verifying via Prometheus targets plus a direct metrics API curl check." + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -15242,52 +14999,94 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Prometheus metrics endpoint customer v1 privileged metrics service_role basic auth hosted project\", limit: 5) { nodes { __typename title href content } } }", + "query": "query { searchDocs(query: \"supabase secret key backend JavaScript REST API Authorization apikey embedded relationships select foreign tables PostgREST pagination range\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" + "url": "https://supabase.com/docs/guides/api/sql-to-api", + "title": "Converting SQL to JavaScript API" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" + "url": "https://supabase.com/docs/guides/api/handling-errors-in-supabase-js", + "title": "Handling errors in `supabase-js`" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/guides/api", + "title": "Data REST API" + }, + { + "url": "https://supabase.com/docs/guides/api/creating-routes", + "title": "Creating API Routes" + } + ], + "resultChars": 20401 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | rg -n -i -C 2 'breaking-change|secret key|postgrest|data api|api key' | head -n 160\"", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 20081 + "resultChars": 11926 }, { - "source": "shell_fetch", - "query": "/bin/bash -lc \"curl -fsSL https://supabase.com/changelog.md | rg -n -i 'metrics|prometheus|breaking-change' | head -80\"", + "source": "search_docs", + "query": "query { searchDocs(query: \"new secret keys sb_secret Authorization header apikey backend Data API\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" } ], - "resultChars": 3574 + "resultChars": 128239 } ] }, - "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", - "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/deploy-database-001-prometheus-metrics.json" + "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", + "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6/build-dataapi-002-restock-alert-report.json" }, { "experiment": "codex-gpt-5.6", @@ -15298,34 +15097,36 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-functions-001-edge-function-secrets", - "stage": "deploy", + "eval": "build-database-001-migrate-postgres-to-supabase", + "stage": "build", "product": [ - "edge-functions" + "database" ], "topic": [ - "security" + "migrations" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "WEATHER_API_KEY is set as a Function secret on the project", + "name": "all 3 tables exist (teams, members, tasks)", "passed": true }, { - "name": "the weather function is deployed to the project", - "passed": true, - "notes": "status ACTIVE" + "name": "row counts match (teams=5, members=10, tasks=13)", + "passed": true }, { - "name": "the weather function reads WEATHER_API_KEY from the environment", - "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "name": "foreign key constraints survived the restore", + "passed": true }, { - "name": "WEATHER_API_KEY value is not committed to the repo", + "name": "tasks_team_status_idx index survived the restore", + "passed": true + }, + { + "name": "sequences synced (next insert won't conflict with existing IDs)", "passed": true } ], @@ -15343,90 +15144,48 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions secrets environment variables WEATHER_API_KEY deploy CLI invoke CORS\", limit: 6) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"restore pg_restore binary custom format dump local Supabase database migration existing Postgres\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" }, { - "url": "https://supabase.com/docs/guides/functions/development-environment", - "title": "Development Environment" + "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", + "title": "Restoring a downloaded backup locally" }, { - "url": "https://supabase.com/docs/guides/deployment/branching/troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/vercel-postgres", + "title": "Migrate from Vercel Postgres to Supabase" }, { - "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", - "title": "Supabase for Platforms" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/neon", + "title": "Migrate from Neon to Supabase" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/heroku", + "title": "Migrate from Heroku to Supabase" } ], - "resultChars": 64693 + "resultChars": 25230 }, { - "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Edge Functions deploy secrets set env-file Deno.env.get invoke no verify jwt browser CORS\", limit: 10) { nodes { title href content } } }", - "hasContent": true, + "source": "shell_fetch", + "query": "/bin/bash -lc \"set -o pipefail\nprintf '%s\\\\n' '== relevant changelog entries ==' \ncurl -fsSL https://supabase.com/changelog.md | rg -i -n -m 20 'breaking-change|postgres|cli|local development|restore|backup' || true\nprintf '%s\\\\n' '== inspect with PostgreSQL 17 ==' \ndocker run --rm -v \\\"\"'$PWD:/work:ro\" postgres:17 pg_restore -l /work/source.dump | sed -n '\"'1,120p'\"", "pages": [ { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/functions/quickstart-dashboard", - "title": "Getting Started with Edge Functions (Dashboard)" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", - "title": "Inspecting edge function environment variables" - }, - { - "url": "https://supabase.com/docs/guides/ai/examples/openai", - "title": "Generating OpenAI GPT3 completions" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", - "title": "Serverless Drivers" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" - }, - { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/quickstart", - "title": "Getting Started with Edge Functions" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 82037 + "resultChars": 3940 } ] }, - "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", - "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", + "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/deploy-functions-001-edge-function-secrets.json" + "sourcePath": "codex-gpt-5.6/build-database-001-migrate-postgres-to-supabase.json" }, { "experiment": "codex-gpt-5.6", @@ -15437,35 +15196,46 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-self-hosting-001-docker-compose", - "stage": "deploy", + "eval": "build-functions-004-service-role-bypass", + "stage": "build", "product": [ - "database", + "edge-functions", "auth", - "storage" + "database" ], "topic": [ - "self-hosting" + "rls", + "security", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", - "passed": true + "name": "rejects missing auth", + "passed": true, + "notes": "status=401" }, { - "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", - "passed": true + "name": "user A reads own note", + "passed": true, + "notes": "status=200" }, { - "name": "secrets rotated off the shipped defaults", - "passed": true + "name": "reads only with the caller's JWT", + "passed": true, + "notes": "bearer_tokens=2, all_match=true" }, { - "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", - "passed": true + "name": "user A cannot force-read user B note", + "passed": true, + "notes": "status=200" + }, + { + "name": "user B cannot force-read user A note", + "passed": true, + "notes": "status=200" } ], "skills": { @@ -15473,66 +15243,90 @@ "supabase", "supabase-postgres-best-practices" ], - "loaded": [] + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"self-hosting Docker docker-compose .env secrets JWT keys Vault logflare pooler official\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Edge Functions authenticate user Authorization header createClient SUPABASE_ANON_KEY RLS getUser verify_jwt\", limit: 5) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", - "title": "Configure Social Login (OAuth) Providers" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", - "title": "Envoy API Gateway" + "url": "https://supabase.com/docs/guides/functions/websockets", + "title": "Handling WebSockets" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa", - "title": "Configure Phone Login & MFA" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" + } + ], + "resultChars": 38558 + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc 'curl -fsSL https://supabase.com/changelog.md | rg -n -i \"breaking-change|edge function|jwt|auth|rls\" | head -80'", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 14791 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Edge Functions default environment variables SUPABASE_PUBLISHABLE_KEYS SUPABASE_ANON_KEY\", limit: 6) { nodes { __typename title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates", - "title": "Custom Email Templates" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" - } - ], - "resultChars": 131466 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"set -e\nprintf '%s\\\\n' '--- changelog tags relevant to self-hosting ---'\ncurl -fsSL https://supabase.com/changelog.md | rg -i -n -m 30 'breaking-change|self-host|docker|auth key|api key' || true\nrm -rf /tmp/supabase-upstream\ngit clone --depth 1 --filter=blob:none --sparse https://github.com/supabase/supabase.git /tmp/supabase-upstream >/tmp/supabase-clone.log 2>&1\ngit -C /tmp/supabase-upstream sparse-checkout set docker\nprintf '%s\\\\n' '--- upstream revision ---'\ngit -C /tmp/supabase-upstream rev-parse HEAD\ngit -C /tmp/supabase-upstream log -1 --format='%cI %s'\nprintf '%s\\\\n' '--- docker files ---'\nfind /tmp/supabase-upstream/docker -maxdepth 3 -type f | sed 's#/tmp/supabase-upstream/docker/##' | sort | sed -n '1,240p'\nprintf '%s\\\\n' '--- docker changelog head ---'\nsed -n '1,220p' /tmp/supabase-upstream/docker/CHANGELOG.md\nprintf '%s\\\\n' '--- env variables ---'\nsed -n '1,260p' /tmp/supabase-upstream/docker/.env.example\"", - "pages": [ + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + }, { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" } ], - "resultChars": 29108 + "resultChars": 57956 } ] }, - "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", - "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", + "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", + "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/deploy-self-hosting-001-docker-compose.json" + "sourcePath": "codex-gpt-5.6/build-functions-004-service-role-bypass.json" }, { "experiment": "codex-gpt-5.6", @@ -15543,48 +15337,67 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "investigate-auth-001-deleted-user-access", - "stage": "investigate", + "eval": "build-functions-005-dual-auth-user-secret", + "stage": "build", "product": [ - "auth" + "edge-functions", + "auth", + "database" ], "topic": [ - "security", - "sdk" + "sdk", + "rls", + "security" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", + "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "victim session active before delete-account", - "passed": true + "name": "seed rows present", + "passed": true, + "notes": "found 2/2 seeded rows" + }, + { + "name": "rejects request with no credentials", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "delete_account flow ran for the victim", - "passed": true + "name": "user with JWT reads only their own rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"8897e297-26cb-42e1-a799-aa23f614a733\",\"metric\":\"steps_a_mt93yfud\",\"value\":111}]" }, { - "name": "delete-account revokes the user's sessions", + "name": "user cannot read another user's rows by passing user_id", "passed": true, - "notes": "sessions left: 0" + "notes": "status 200: [{\"user_id\":\"8897e297-26cb-42e1-a799-aa23f614a733\",\"metric\":\"steps_a_mt93yfud\",\"value\":111}]" }, { - "name": "deleted user's refresh token is rejected", - "passed": true + "name": "service key bypasses RLS to read the target user's rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"e7157980-6ad5-4cd5-9493-84f29bb67566\",\"metric\":\"steps_b_mt93yfud\",\"value\":222}]" }, { - "name": "deleted user cannot sign back in", - "passed": true + "name": "non-service key is not granted service access", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "other users keep their sessions and access", - "passed": true + "name": "rejects an unverified (forged) user token", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "diagnosed and explained session revocation", + "name": "a user token in the apikey slot is not treated as the service key", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + }, + { + "name": "implementation uses @supabase/server", "passed": true, - "judgeNotes": "The answer identifies the soft-delete-only root cause, implements deletion of auth.users and RLS checks to close the data path for stale JWTs, consistently explains that JWTs remain cryptographically valid until exp while data access is blocked by the implemented RLS, and correctly distinguishes publishable/frontend/RLS keys from secret/backend/bypass-RLS keys." + "notes": "imports @supabase/server / withSupabase" } ], "skills": { @@ -15593,108 +15406,171 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"printf '%s\\\\n' '--- config.toml ---' && cat supabase/config.toml && printf '%s\\\\n' '--- migration ---' && cat supabase/migrations/0000_stats_schema.sql && printf '%s\\\\n' '--- versions ---' && (supabase --version || npx supabase --version || true) && printf '%s\\\\n' '--- changelog relevant tags ---' && curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'edge function|function|jwt|apikey|secret key|service role|breaking-change' | head -n 180\"", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 12181 + }, { "source": "search_docs", - "query": "query { searchDocs(query: \"delete user existing access token session revoke refresh token admin deleteUser signOut scope global\", limit: 8) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"Edge Functions authentication verify_jwt false Authorization header getUser service_role apikey secret key environment variables Supabase\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/auth/signout", - "title": "Signing out" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", - "title": "OAuth 2.1 Flows" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-signout" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { - "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" } ], - "resultChars": 68746 + "resultChars": 74549 }, { - "source": "shell_fetch", - "query": "/bin/bash -lc \"cat .agents/skills/supabase-postgres-best-practices/references/security-privileges.md; printf '\\\\n---RLS---\\\\n'; cat .agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md; printf '\\\\n---CHANGELOG MATCHES---\\\\n'; curl -fsSL https://supabase.com/changelog.md | rg -i -n 'breaking-change|auth|jwt|api key|publishable|secret' | head -80\"", + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase Edge Functions config.toml verify_jwt false per function secrets SUPABASE_SECRET_KEY SUPABASE_SERVICE_ROLE_KEY Deno env\", limit: 10) { nodes { title href content } } }", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", + "title": "Serverless Drivers" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", + "title": "Building an MCP Server with mcp-lite" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/functions/websockets", + "title": "Handling WebSockets" + }, + { + "url": "https://supabase.com/docs/guides/functions/quickstart", + "title": "Getting Started with Edge Functions" } ], - "resultChars": 14841 + "resultChars": 71906 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"publishable key secret key RLS bypass service_role anon new API keys sb_publishable sb_secret\", limit: 10) { nodes { ... on Guide { title href content } ... on ManagementApiReference { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"verify_jwt config.toml Edge Functions per function false\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/functions/deploy", + "title": "Deploy to Production" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" }, { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + } + ], + "resultChars": 35951 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"@supabase/server combining auth modes user secret Edge Functions authMode\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", - "title": "Envoy API Gateway" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", - "title": "Why is my service role key client getting RLS errors or not returning data?" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", + "title": "Which package to use" } ], - "resultChars": 137700 + "resultChars": 31975 } ] }, - "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", - "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6/investigate-auth-001-deleted-user-access.json" + "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", + "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6/build-functions-005-dual-auth-user-secret.json" }, { "experiment": "codex-gpt-5.6", @@ -15705,44 +15581,79 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "investigate-realtime-001-subscribed-no-events", - "stage": "investigate", + "eval": "build-rls-003-org-roles-permissions", + "stage": "build", "product": [ - "realtime", - "database" + "database", + "auth" ], "topic": [ - "sdk" + "rls", + "security" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "orders table added to supabase_realtime publication", + "name": "RLS enabled on documents", "passed": true }, { - "name": "courier_locations still in supabase_realtime publication", + "name": "viewer sees only documents in their org", "passed": true }, { - "name": "publication still publishes INSERT events", + "name": "viewer cannot insert", "passed": true }, { - "name": "RLS still enabled on orders", + "name": "editor can insert own org document", "passed": true }, { - "name": "staff can still read orders through RLS", - "passed": true, - "notes": "authenticated sees 2 of 2 orders" + "name": "editor can update own document", + "passed": true }, { - "name": "diagnosed missing publication membership", - "passed": true, - "judgeNotes": "Identified orders missing from supabase_realtime despite SUBSCRIBED channel, fixed with ALTER PUBLICATION ADD TABLE public.orders, preserved courier_locations and RLS/policies." + "name": "editor cannot update another user's document", + "passed": true + }, + { + "name": "editor cannot delete another user's document", + "passed": true + }, + { + "name": "admin can update any document in their org", + "passed": true + }, + { + "name": "admin can delete any document in their org", + "passed": true + }, + { + "name": "admin cannot affect another org", + "passed": true + }, + { + "name": "WITH CHECK blocks editor from moving document to another org", + "passed": true + }, + { + "name": "editor can still see their own org's roster", + "passed": true + }, + { + "name": "cannot see another org's membership roster", + "passed": true + }, + { + "name": "a viewer role in one org doesn't grant admin power in another org", + "passed": true + }, + { + "name": "multi-org user can act as admin in the org where they hold that role", + "passed": true } ], "skills": { @@ -15759,48 +15670,48 @@ "calls": [ { "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- files ---'; rg --files -g '\"'!node_modules'\"' -g '\"'!dist'\"' | sed -n '1,240p'; printf '%s\\\\n' '--- realtime/order refs ---'; rg -n \\\"postgres_changes|orders|courier|supabase_realtime|publication\\\" -g '\"'!node_modules'\"' -g '\"'!dist'\"' . || true; printf '%s\\\\n' '--- changelog realtime refs ---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i \\\"realtime|postgres_changes|publication\\\" | head -40 || true\"", + "query": "/bin/bash -lc \"printf '%s\\\\n' '---ROOT---'; ls -la; printf '%s\\\\n' '---AGENTS---'; find .. -name AGENTS.md -print; printf '%s\\\\n' '---ALL FILES---'; rg --files -g '\"'!node_modules'\"' -g '\"'!vendor'\"' | sed -n '1,260p'; printf '%s\\\\n' '---RLS REFERENCES---'; for f in .agents/skills/supabase-postgres-best-practices/references/security-*.md; do echo \\\"### \"'$f\"; sed -n '\"'1,220p' \\\"\"'$f\"; done; printf '\"'%s\\\\n' '---CHANGELOG HITS---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i 'breaking|rls|row.level|policy|auth|postgres' | sed -n '1,120p'\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 28635 + "resultChars": 27305 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Postgres Changes enable table supabase_realtime publication add table postgres_changes RLS\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"Row Level Security policies auth.uid organization membership security definer functions\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes", - "title": "Subscribing to Database Changes" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes", - "title": "Postgres Changes" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" }, { - "url": "https://supabase.com/docs/guides/realtime/authorization", - "title": "Realtime Authorization" + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" }, { - "url": "https://supabase.com/docs/guides/realtime/benchmarks", - "title": "Benchmarks" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" } ], - "resultChars": 92624 + "resultChars": 77235 } ] }, - "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", - "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", + "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", + "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/investigate-realtime-001-subscribed-no-events.json" + "sourcePath": "codex-gpt-5.6/build-rls-003-org-roles-permissions.json" }, { "experiment": "codex-gpt-5.6", @@ -15811,32 +15722,57 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "investigate-reliability-003-edge-function-5xx-correlation", - "stage": "investigate", + "eval": "build-storage-001-private-bucket-access", + "stage": "build", "product": [ - "edge-functions" + "storage", + "database" ], "topic": [ - "observability" + "rls", + "sdk" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "identified image-transform and the recurring 503 pattern", - "passed": true, - "judgeNotes": "The assistant explicitly identified `image-transform` as affected and described eight recurring 503 responses across 07:00–12:00 UTC on 2026-04-28, matching the required pattern." + "name": "bucket user-files exists", + "passed": true }, { - "name": "attributed recurring 503s to gateway/platform layer, not function code", + "name": "bucket user-files is private", + "passed": true + }, + { + "name": "RLS still enabled on storage.objects", + "passed": true + }, + { + "name": "user A lists only own files", "passed": true, - "judgeNotes": "The assistant explicitly attributes the recurring image-transform 503s to the API Gateway/Edge Runtime/platform layer before invocation, not function code. This is grounded in valid observations: the 503s reached the gateway but had no Edge Function execution records, nearby invocations succeeded, and it distinguishes the unrelated avatar-upload 500 as an application-level error. It also advises not to redeploy or modify function/storage/database config." + "notes": "saw: 01a03a87-204e-745c-9ca3-5a55e52db6d5/receipt-alpha.pdf, 01a03a87-204e-745c-9ca3-5a55e52db6d5/receipt-beta.pdf" }, { - "name": "recommended a concrete next step", + "name": "user B cannot read user A files", + "passed": true + }, + { + "name": "anon reads no files", + "passed": true + }, + { + "name": "user A can upload into own folder", + "passed": true + }, + { + "name": "user B cannot upload into user A folder", + "passed": true + }, + { + "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "The assistant recommended concrete next steps, including opening a Supabase support ticket with the project, UTC window, and request IDs, plus capturing specific failure metadata and adding retries." + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT policies, RLS preserved, and short-lived createSignedUrl sharing code are all provided." } ], "skills": { @@ -15851,83 +15787,106 @@ }, "docs": { "calls": [ - { - "source": "web_search", - "query": "https://supabase.com/changelog.md", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ] - }, - { - "source": "web_search", - "query": "site:supabase.com/changelog.md Supabase changelog storage April 2026", - "pages": [] - }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions 503 gateway before invocation logs troubleshooting retry transient errors\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Storage access control RLS policies foldername auth.uid signed URL createSignedUrl supabase-js\", limit: 8) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", - "title": "Edge Function 503 error response" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", - "title": "Edge Function 504 error response" + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" }, { - "url": "https://supabase.com/docs/guides/functions/recursive-functions", - "title": "Recursive / Nested Function Calls" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/storage/s3/authentication", + "title": "S3 Authentication" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", + "title": "Firebase Auth" + }, + { + "url": "https://supabase.com/docs/guides/storage/schema/custom-roles", + "title": "Custom Roles" + }, + { + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" + } + ], + "resultChars": 46405 + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"printf '%s\\\\n' '---CHANGELOG STORAGE BREAKING CHANGES---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i -C 2 'breaking-change|storage|signed url' | sed -n '1,220p'; printf '%s\\\\n' '---RLS BASICS---'; cat .agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md; printf '%s\\\\n' '---RLS PERFORMANCE---'; cat .agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md; printf '%s\\\\n' '---PRIVILEGES---'; cat .agents/skills/supabase-postgres-best-practices/references/security-privileges.md\"", + "pages": [ + { + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 43053 + "resultChars": 20985 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"function_edge_logs execution_id function_id internal_failure 503\", limit: 3) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"JavaScript storage createSignedUrl expiresIn download upload getUser supabase-js\", limit: 10) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", - "title": "Edge Function 503 error response" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", - "title": "Edge Function 504 error response" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-500-error-response", - "title": "Edge Function 500 error response" - } - ], - "resultChars": 32009 - }, - { - "source": "web_search", - "query": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", - "pages": [ + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" + }, + { + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" + }, + { + "url": "https://supabase.com/docs/guides/storage/uploads/resumable-uploads", + "title": "Resumable Uploads" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", + "title": "Configure SAML SSO" + }, + { + "url": "https://supabase.com/docs/reference/javascript/file-buckets-uploadtosignedurl" + }, + { + "url": "https://supabase.com/docs/guides/storage/serving/image-transformations", + "title": "Storage Image Transformations" + }, + { + "url": "https://supabase.com/docs/guides/platform/manage-your-usage/storage-image-transformations", + "title": "Manage Storage Image Transformations usage" + }, { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-zoom", + "title": "Login with Zoom" } - ] + ], + "resultChars": 92096 } ] }, - "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", - "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6/investigate-reliability-003-edge-function-5xx-correlation.json" + "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", + "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6/build-storage-001-private-bucket-access.json" }, { "experiment": "codex-gpt-5.6", @@ -15938,49 +15897,33 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "resolve-dataapi-001-empty-results", - "stage": "resolve", + "eval": "build-tests-001-rls-tenant-isolation", + "stage": "build", "product": [ - "data-api", - "database", - "auth" + "database" ], "topic": [ - "rls", - "sdk" + "tests", + "rls" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "RLS still enabled on bookmarks", - "passed": true - }, - { - "name": "user A reads own bookmarks", - "passed": true - }, - { - "name": "user B cannot read user A bookmarks", - "passed": true - }, - { - "name": "anon reads no bookmarks", - "passed": true - }, - { - "name": "user A can save a new bookmark", - "passed": true + "name": "pgTAP test file(s) written under supabase/tests/", + "passed": true, + "notes": "1 file(s): supabase/tests/database/tenant_isolation.test.sql" }, { - "name": "user B cannot insert a bookmark as user A", - "passed": true + "name": "pgTAP isolation tests ran and pass", + "passed": true, + "notes": "8 passed, 0 failed" }, { - "name": "diagnosed RLS and added owner-scoped policies", + "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "Diagnosed RLS enabled with no policies causing deny-all Data API behavior, kept RLS enabled, and created authenticated SELECT and INSERT policies scoped to user_id = auth.uid() with WITH CHECK for inserts. No permissive/public/anon policies or RLS disabling." + "judgeNotes": "Correctly identifies `posts` as leaking cross-organization data, states `notes` isolates correctly, and grounds the conclusion in the failing pgTAP baseline." } ], "skills": { @@ -15995,50 +15938,50 @@ }, "docs": { "calls": [ - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"cat .agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md; printf '\\\\n---PERF---\\\\n'; cat .agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md; printf '\\\\n---PRIVILEGES---\\\\n'; cat .agents/skills/supabase-postgres-best-practices/references/security-privileges.md; printf '\\\\n---CHANGELOG MATCHES---\\\\n'; curl -fsSL https://supabase.com/changelog.md | rg -i -C 2 'breaking-change|data api|row level|rls' | head -120\"", - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 8535 - }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Data API table grants authenticated RLS select insert policy auth.uid bookmarks\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"row level security testing pgTAP auth.uid tenant isolation policies\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" + "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", + "title": "Advanced pgTAP Testing" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" }, { - "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", - "title": "Token Security and Row Level Security" + "url": "https://supabase.com/docs/guides/database/extensions/pgtap", + "title": "pgTAP: Unit Testing" }, { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" + "url": "https://supabase.com/docs/guides/database/testing", + "title": "Testing Your Database" }, { - "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", - "title": "Storage Helper Functions" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + } + ], + "resultChars": 70562 + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"printf '%s\\\\n' '--- changelog security scan ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -n -m 20 'breaking-change|row level|rls|pgtap|test' || true; printf '%s\\\\n' '--- repository files ---'; rg --files -g 'AGENTS.md' -g '\"'!node_modules'\"' -g '\"'!vendor'\"'; printf '%s\\\\n' '--- top-level ---'; ls -la; printf '%s\\\\n' '--- supabase/db candidates ---'; rg --files | rg '(\"'^|/)(supabase|database|db|tests?)(/|$)|'\"\\\\.sql\"'$'\"' | head -300\"", + "pages": [ + { + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 51520 + "resultChars": 4966 } ] }, - "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", - "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", + "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", + "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/resolve-dataapi-001-empty-results.json" + "sourcePath": "codex-gpt-5.6/build-tests-001-rls-tenant-isolation.json" }, { "experiment": "codex-gpt-5.6", @@ -16049,42 +15992,50 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "resolve-database-001-migration-history-mismatch", - "stage": "resolve", + "eval": "build-vectors-001-rag-with-permissions", + "stage": "build", "product": [ - "database" + "database", + "vectors" ], "topic": [ - "migrations" + "sql", + "rls" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "the avatar_url column is applied on the hosted profiles table", - "passed": true + "name": "document_sections.embedding is vector(384)", + "passed": true, + "notes": "vector(384)" + }, + { + "name": "HNSW index on the embedding column", + "passed": true, + "notes": "CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" + }, + { + "name": "index operator class matches the search operator", + "passed": true, + "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" }, { - "name": "migration 20240220000000 is recorded in the remote history", + "name": "user A search returns only own sections, best match first", "passed": true }, { - "name": "remote migration history matches local migration files", + "name": "user B search returns only own sections, best match first", "passed": true }, { - "name": "local migrations are a valid reconciled sequence", + "name": "user A reads only own sections through the API", "passed": true }, { - "name": "production profile data is intact (not reset)", + "name": "user A reads only own documents through the API", "passed": true - }, - { - "name": "the avatar migration and history reconciliation were done via the Supabase CLI", - "passed": true, - "judgeNotes": "PASS. The agent added the missing local bio migration file `supabase/migrations/20240115000000_add_profile_bio.sql`, which reconciled the orphan remote history entry for CLI pushes. The pending avatar migration was then applied through a real `supabase db push` in command #10, whose output includes `Finished supabase db push` (and #11 confirms remote history contains `20240220000000 | add_avatar_url`). No prohibited direct-SQL mutation or prepared-statement workaround was seen." } ], "skills": { @@ -16099,90 +16050,89 @@ }, "docs": { "calls": [ + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase CLI db push migration history repair linked project deploy migrations\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"pgvector semantic search match_documents RPC ivfflat hnsw row level security auth.uid security invoker\", limit: 8) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" + "url": "https://supabase.com/docs/guides/ai/going-to-prod", + "title": "Going to Production" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-migration-repair", - "title": "Repair the migration history table" + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-db-push", - "title": "Push new migrations to the remote database" + "url": "https://supabase.com/docs/guides/ai/hybrid-search", + "title": "Hybrid search" }, { - "url": "https://supabase.com/docs/guides/local-development/database-migrations", - "title": "Database migrations" - } - ], - "resultChars": 61657 - }, - { - "source": "shell_fetch", - "query": "/bin/bash -lc \"set -o pipefail\nprintf '%s\\\\n' '--- CHANGELOG BREAKING CHANGES ---'\ncurl -fsSL https://supabase.com/changelog.md | rg -n -i -C 2 'breaking-change|migration|db push' | head -120 || true\nprintf '%s\\\\n' '--- GIT STATUS ---'\ngit status --short --branch 2>&1 || true\nprintf '%s\\\\n' '--- SUPABASE FILES ---'\nfind supabase -maxdepth 4 -type f -print | sort\nprintf '%s\\\\n' '--- CONFIG ---'\nsed -n '1,260p' supabase/config.toml 2>/dev/null || true\nprintf '%s\\\\n' '--- MIGRATIONS ---'\nfor f in supabase/migrations/*.sql; do echo \\\"===== \"'$f\"; sed -n '\"'1,260p' \\\"\"'$f\"; done\nprintf '\"'%s\\\\n' '--- LOCAL LINK METADATA ---'\nfind supabase/.temp -maxdepth 2 -type f -print -exec sh -c 'echo \\\"--- \"'$1\"; cat \"$1\"'\"' _ {} \\\\; 2>/dev/null || true\nprintf '%s\\\\n' '--- CLI / ENV NAMES ---'\nsupabase --version\nprintf 'SUPABASE vars: '; env | cut -d= -f1 | rg '\"'^(SUPABASE|POSTGRES|PG)'\"' | sort | tr '\\\\n' ' '; echo\nprintf '%s\\\\n' '--- PROFILE ---'\ncat .supabase-eval-profile.yaml\"", - "pages": [ + "url": "https://supabase.com/docs/guides/ai/vector-indexes/ivf-indexes", + "title": "IVFFlat indexes" + }, { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/database/extensions/pgvector", + "title": "pgvector: Embeddings and vector similarity" + }, + { + "url": "https://supabase.com/docs/guides/ai/vector-indexes", + "title": "Vector indexes" + }, + { + "url": "https://supabase.com/docs/guides/database/full-text-search", + "title": "Full Text Search" } ], - "resultChars": 478 + "resultChars": 103265 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase migration history remote migration versions not found local migration repair db pull migration fetch\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Supabase AI gte-small embedding dimensions 384 vector\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" - }, - { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/new-branch-doesnt-copy-database", - "title": "Why are my Supabase branches empty?" - }, - { - "url": "https://supabase.com/docs/reference/cli/supabase-migration-repair", - "title": "Repair the migration history table" + "url": "https://supabase.com/docs/guides/ai/choosing-compute-addon", + "title": "Choosing your Compute Add-on" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/branch-in-migrations-failed-status", - "title": "Troubleshooting MIGRATIONS_FAILED: missing tables or an incomplete schema on your branch" + "url": "https://supabase.com/docs/guides/ai/concepts", + "title": "Concepts" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-db-push", - "title": "Push new migrations to the remote database" + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-migration-fetch", - "title": "Fetch migration files from history table" + "url": "https://supabase.com/docs/guides/ai", + "title": "AI & Vectors" }, { - "url": "https://supabase.com/docs/reference/cli/supabase-db-pull", - "title": "Pull schema from the remote database" + "url": "https://supabase.com/docs/guides/ai/vector-columns", + "title": "Vector columns" } ], - "resultChars": 58381 + "resultChars": 53612 } ] }, - "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", - "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", + "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/resolve-database-001-migration-history-mismatch.json" + "sourcePath": "codex-gpt-5.6/build-vectors-001-rag-with-permissions.json" }, { "experiment": "codex-gpt-5.6", @@ -16193,39 +16143,31 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "resolve-performance-001-slow-query-cpu-spike", - "stage": "resolve", + "eval": "deploy-database-001-prometheus-metrics", + "stage": "deploy", "product": [ "database" ], "topic": [ - "observability", - "sql" + "observability" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "inspected pg_stat_statements for query performance", - "passed": true - }, - { - "name": "ran EXPLAIN on the expensive query", - "passed": true - }, - { - "name": "created index covering user_id and created_at", + "name": "preserved existing app scrape job", "passed": true }, { - "name": "query plan uses an index and avoids sequential scan", + "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "notes": "Limit (cost=79.74..79.86 rows=50 width=58)\n -> Sort (cost=79.74..79.99 rows=100 width=58)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=5.06..76.42 rows=100 width=58)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..5.03 rows=100 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + "judgeNotes": "Valid HTTPS Supabase Metrics API scrape with the required path, Basic Auth password_file, preserved app job, and correctly wired Docker Compose secret mount." }, { - "name": "inserts still work", - "passed": true + "name": "documented live deployment and verification steps", + "passed": true, + "judgeNotes": "README documents creating a dedicated Secret API key, placing it at the matching Compose secret path, recreating Prometheus, and verifying the Supabase target via /targets or PromQL." } ], "skills": { @@ -16234,49 +16176,347 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"project metrics Prometheus endpoint observability Grafana authentication service role metrics\", limit: 8) { nodes { __typename title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#components", + "title": "Components" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#1-define-the-scrape-job", + "title": "1. Define the scrape job" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#collector-specific-notes", + "title": "Collector-specific notes" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#2-secure-the-credentials", + "title": "2. Secure the credentials" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#3-downstream-dashboards", + "title": "3. Downstream dashboards" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#4-alerts-and-automation", + "title": "4. Alerts and automation" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic#5-multi-project-setups", + "title": "5. Multi-project setups" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#what-you-can-do-with-the-metrics-api", + "title": "What you can do with the Metrics API" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#choose-your-monitoring-stack", + "title": "Choose your monitoring stack" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics#additional-resources", + "title": "Additional resources" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#6-troubleshooting", + "title": "6. Troubleshooting" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#2-install-the-supabase-integration-for-grafana-cloud", + "title": "2. Install the Supabase integration for Grafana Cloud" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#3-configure-the-supabase-integration", + "title": "3. Configure the Supabase integration" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#4-import-the-supabase-dashboard", + "title": "4. Import the Supabase dashboard" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#5-configure-alerts-optional", + "title": "5. Configure alerts (optional)" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#installation", + "title": "Installation" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#manual-setup", + "title": "Manual setup" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#prerequisites", + "title": "Prerequisites" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud#1-create-a-grafana-cloud-stack", + "title": "1. Create a Grafana Cloud stack" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#architecture", + "title": "Architecture" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#1-deploy-prometheus", + "title": "1. Deploy Prometheus" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#2-deploy-grafana", + "title": "2. Deploy Grafana" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#3-import-supabase-dashboards", + "title": "3. Import Supabase dashboards" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#4-configure-alerting", + "title": "4. Configure alerting" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted#5-operating-tips", + "title": "5. Operating tips" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas", + "title": "Read Replicas" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#metrics", + "title": "Metrics" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#about-read-replicas", + "title": "About Read Replicas" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#features", + "title": "Features" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#dedicated-endpoints", + "title": "Dedicated endpoints" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#dedicated-connection-pool", + "title": "Dedicated connection pool" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#api-load-balancer", + "title": "API load balancer" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#querying-through-the-sql-editor", + "title": "Querying through the SQL editor" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#logging", + "title": "Logging" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#centralized-configuration-management", + "title": "Centralized configuration management" + }, + { + "url": "https://supabase.com/docs/guides/platform/read-replicas#pricing", + "title": "Pricing" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_", + "title": "How to View Database Metrics" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management", + "title": "Connection management" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#dashboard-monitoring-charts", + "title": "Dashboard monitoring charts" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#grafana-dashboard", + "title": "Grafana Dashboard" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#observing-live-connections", + "title": "Observing live connections" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#connections", + "title": "Connections" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#configuring-supavisors-pool-size", + "title": "Configuring Supavisor's pool size" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#monitoring-connections", + "title": "Monitoring connections" + }, + { + "url": "https://supabase.com/docs/guides/database/connection-management#capturing-historical-usage", + "title": "Capturing historical usage" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit", + "title": "PGAudit: Postgres Auditing" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#logging-observed-table-rows", + "title": "Logging observed table rows" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#logging-function-parameters", + "title": "Logging function parameters" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#does-pgaudit-support-system-wide-configurations", + "title": "Does PGAudit support system wide configurations?" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#resources", + "title": "Resources" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#enable-the-extension", + "title": "Enable the extension" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#configure-the-extension", + "title": "Configure the extension" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#session-mode-categories", + "title": "Session mode categories" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#session-logging", + "title": "Session logging" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#user-logging", + "title": "User logging" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#global-logging", + "title": "Global logging" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#object-logging", + "title": "Object logging" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#interpreting-audit-logs", + "title": "Interpreting Audit Logs" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#finding-and-filtering-audit-logs", + "title": "Finding and filtering audit logs" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#monitoring-api-events", + "title": "Monitoring API events" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#practical-examples", + "title": "Practical examples" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#monitoring-the-authusers-table", + "title": "Monitoring the auth.users table" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#best-practices", + "title": "Best practices" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#disabling-excess-logging", + "title": "Disabling excess logging" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#faq", + "title": "FAQ" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#using-pgaudit-to-debug-database-functions", + "title": "Using PGAudit to debug database functions" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgaudit#downloading-database-logs", + "title": "Downloading database logs" + } + ], + "resultChars": 161567 + }, { "source": "shell_fetch", - "query": "/bin/bash -lc 'curl -fsSL https://supabase.com/changelog.md | rg -n -i \"breaking-change|postgres|index|database\" | head -40'", - "hasContent": true, + "query": "/bin/bash -lc \"printf '%s\\\\n' '---CHANGELOG RELEVANCE---'; curl -fsSL https://supabase.com/changelog.md | rg -n -i -C 2 'metrics|prometheus|monitoring|breaking-change' | head -120 || true; printf '%s\\\\n' '---COMPOSE---'; sed -n '1,240p' observability/docker-compose.yml; printf '%s\\\\n' '---PROMETHEUS---'; sed -n '1,240p' observability/prometheus.yml; printf '%s\\\\n' '---README---'; sed -n '1,260p' observability/README.md; printf '%s\\\\n' '---SUPABASE TREE---'; find supabase -maxdepth 3 -type f -print -exec sed -n '1,160p' {} \\\\;\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 7495 + "resultChars": 9184 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Postgres query optimization composite index ORDER BY WHERE EXPLAIN\", limit: 3) { nodes { ... on Guide { title href content } } } }", + "query": "query { searchDocs(query: \"Metrics API availability plan project metrics endpoint secret API key rate scrape interval 60 seconds\", limit: 5) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/database/query-optimization", - "title": "Query Optimization" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/database/orioledb", - "title": "OrioleDB Overview" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" }, { - "url": "https://supabase.com/docs/guides/realtime/reports", - "title": "Realtime Reports" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" } ], - "resultChars": 63315 + "resultChars": 20751 } ] }, - "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", - "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", + "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", + "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/resolve-performance-001-slow-query-cpu-spike.json" + "sourcePath": "codex-gpt-5.6/deploy-database-001-prometheus-metrics.json" }, { "experiment": "codex-gpt-5.6", @@ -16287,54 +16527,34 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "resolve-security-002-rls-cross-tenant-leak", - "stage": "resolve", + "eval": "deploy-functions-001-edge-function-secrets", + "stage": "deploy", "product": [ - "database", - "auth" + "edge-functions" ], "topic": [ - "rls", "security" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "RLS enabled on notes", - "passed": true - }, - { - "name": "tenant A sees only org A notes", - "passed": true - }, - { - "name": "tenant B cannot read org A notes", - "passed": true - }, - { - "name": "tenant A author can update own note", - "passed": true - }, - { - "name": "tenant B cannot update org A note", - "passed": true - }, - { - "name": "tenant B author can delete own note", + "name": "WEATHER_API_KEY is set as a Function secret on the project", "passed": true }, { - "name": "tenant B cannot delete org A note", - "passed": true + "name": "the weather function is deployed to the project", + "passed": true, + "notes": "status ACTIVE" }, { - "name": "tenant A can insert note in own org", - "passed": true + "name": "the weather function reads WEATHER_API_KEY from the environment", + "passed": true, + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get(\"WEATHER_API_KEY\")." }, { - "name": "tenant B cannot insert into org A", + "name": "WEATHER_API_KEY value is not committed to the repo", "passed": true } ], @@ -16350,788 +16570,1151 @@ }, "docs": { "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Edge Functions secrets environment variables Deno.env.get deploy functions invoke CORS\", limit: 8) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/unable-to-call-edge-function", + "title": "Unable to call Edge Function" + }, + { + "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", + "title": "Testing and linting" + }, + { + "url": "https://supabase.com/docs/guides/functions/cors", + "title": "CORS (Cross-Origin Resource Sharing) support for Invoking from the browser" + }, + { + "url": "https://supabase.com/docs/guides/functions/http-methods", + "title": "Routing" + } + ], + "resultChars": 51077 + }, { "source": "shell_fetch", - "query": "/bin/bash -lc \"printf '%s\\\\n' '--- files ---'; rg --files -g 'AGENTS.md' -g 'supabase/**' -g 'package.json' -g '*.sql' | sed -n '1,240p'; printf '%s\\\\n' '--- changelog security/rls mentions ---'; curl -fsSL https://supabase.com/changelog.md | rg -i -n -m 20 'breaking-change|row level|rls|policy|security'\"", + "query": "/bin/bash -lc \"set -e\nprintf '%s\\\\n' '--- CHANGELOG EDGE FUNCTION ITEMS ---'\ncurl -fsSL https://supabase.com/changelog.md | rg -i -n -C 2 'breaking-change|edge function|functions deploy|secret' | head -120 || true\nprintf '%s\\\\n' '--- TREE ---'\nfind supabase -maxdepth 4 -type f -o -type d | sort\nprintf '%s\\\\n' '--- CONFIG ---'\nif [ -f supabase/config.toml ]; then sed -n '1,240p' supabase/config.toml; else echo 'no config.toml'; fi\nprintf '%s\\\\n' '--- ENV KEYS ---'\nsed -E 's/=.*\"'$/=/'\"' .env\nprintf '%s\\\\n' '--- GITIGNORE ---'\ncat .gitignore\nprintf '%s\\\\n' '--- CLI ---'\n(supabase --version || npx supabase --version) 2>&1\nprintf '%s\\\\n' '--- LINK STATE ---'\nfind supabase/.temp -maxdepth 2 -type f -print -exec sh -c 'printf \\\" \\\"; sed -E \\\"s/(token|key|password).*//Ig\\\" \\\"\"'$1\"'\"' _ {} \\\\; 2>/dev/null || true\nprintf '%s\\\\n' '--- AUTH ENV NAMES ---'\nenv | cut -d= -f1 | rg '\"'^(SUPABASE|SB_)'\"' | sort || true\"", "pages": [ { "url": "https://supabase.com/changelog.md" } ], - "resultChars": 4349 + "resultChars": 465 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"row level security multi tenant workspace membership policies auth uid index policy performance\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"Supabase CLI secrets set env-file Edge Functions deploy no-verify-jwt config.toml function invoke\", limit: 10) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/ai/examples/openai", + "title": "Generating OpenAI GPT3 completions" }, { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" + "url": "https://supabase.com/docs/guides/functions/examples/upstash-redis", + "title": "Upstash Redis" }, { - "url": "https://supabase.com/docs/guides/database/database-advisors", - "title": "Performance and Security Advisors" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", - "title": "Column Level Security" + "url": "https://supabase.com/docs/guides/functions/development-tips", + "title": "Development tips" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/github-actions", + "title": "GitHub Actions" + }, + { + "url": "https://supabase.com/docs/guides/integrations/supabase-for-platforms", + "title": "Supabase for Platforms" + }, + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", + "title": "Transcription Telegram Bot" } ], - "resultChars": 48168 + "resultChars": 75541 } ] }, - "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", - "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", + "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", + "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6/resolve-security-002-rls-cross-tenant-leak.json" + "sourcePath": "codex-gpt-5.6/deploy-functions-001-edge-function-secrets.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-auth-001-email-password-flow", - "stage": "build", + "eval": "deploy-self-hosting-001-docker-compose", + "stage": "deploy", "product": [ + "database", "auth", - "database" + "storage" ], "topic": [ - "sdk", - "rls" + "self-hosting" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "auth module loads and the driver completes", - "passed": true, - "notes": "driver produced a result" - }, - { - "name": "signUp creates the account and returns its user id", - "passed": true, - "notes": "db user 14e42a99-dd08-453c-a361-a8b7871b40cc, signUp returned {\"userId\":\"14e42a99-dd08-453c-a361-a8b7871b40cc\"}" - }, - { - "name": "signup metadata reaches the profile (display name)", - "passed": true, - "notes": "profiles.display_name = \"Alex Doe\"" - }, - { - "name": "wrong password is rejected gracefully (no throw, no session)", - "passed": true, - "notes": "{\"error\":\"Invalid login credentials\"}" - }, - { - "name": "signIn with the right password returns the user id", - "passed": true, - "notes": "{\"userId\":\"14e42a99-dd08-453c-a361-a8b7871b40cc\"}" + "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", + "passed": true }, { - "name": "getMyProfile returns the signed-in user's profile", - "passed": true, - "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" + "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", + "passed": true }, { - "name": "app code does not use the secret / service-role key", - "passed": true, - "notes": "no secret-key references found" + "name": "secrets rotated off the shipped defaults", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": true, - "notes": "imports found in: app/src/auth.mjs" + "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", + "passed": true } ], "skills": { - "available": [], + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], "loaded": [] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"supabase-js createClient signUp user metadata signInWithPassword getSession select single profiles\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"self-hosting Docker compose .env secrets JWT_SECRET ANON_KEY SERVICE_ROLE_KEY POSTGRES_PASSWORD DASHBOARD_PASSWORD POOLER_TENANT_ID\", limit: 8) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", - "title": "Migrate from Auth0 to Supabase Auth" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-linkedin", - "title": "Login with LinkedIn" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", - "title": "Configure SAML SSO" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17", + "title": "Upgrade to Postgres 17" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", + "title": "Configure Social Login (OAuth) Providers" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access", + "title": "Remove Superuser Access from Studio" }, { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-figma", - "title": "Login with Figma" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + } + ], + "resultChars": 155675 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Self-hosting with Docker quick start Linux generate keys secrets docker compose\", limit: 5) { nodes { __typename title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-google", - "title": "Login with Google" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-gitlab", - "title": "Login with GitLab" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" }, { - "url": "https://supabase.com/docs/guides/auth/social-login/auth-slack", - "title": "Login with Slack" - }, + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", + "title": "Configure Social Login (OAuth) Providers" + } + ], + "resultChars": 96000 + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc \"set -e\nprintf '%s\\\\n' '--- docs docker guide ---'\ncurl -fsSL https://supabase.com/docs/guides/self-hosting/docker.md | sed -n '1,260p'\nprintf '%s\\\\n' '--- docker changelog (top) ---'\ncurl -fsSL https://raw.githubusercontent.com/supabase/supabase/master/docker/CHANGELOG.md | sed -n '1,220p'\nprintf '%s\\\\n' '--- repository head ---'\ngit ls-remote https://github.com/supabase/supabase.git refs/heads/master\"", + "pages": [ { - "url": "https://supabase.com/docs/guides/auth", - "title": "Auth" + "url": "https://supabase.com/docs/guides/self-hosting/docker.md" } ], - "resultChars": 166581 + "resultChars": 19164 } ] }, - "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", - "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", + "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", + "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-auth-001-email-password-flow.json" + "sourcePath": "codex-gpt-5.6/deploy-self-hosting-001-docker-compose.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-cli-001-bootstrap-app", - "stage": "build", + "eval": "investigate-auth-001-deleted-user-access", + "stage": "investigate", "product": [ - "database", - "data-api" + "auth" ], "topic": [ - "migrations", - "rls" + "security", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase project initialised (supabase/config.toml exists)", + "name": "victim session active before delete-account", "passed": true }, { - "name": "todos table is created by a migration file", + "name": "delete_account flow ran for the victim", "passed": true }, { - "name": "todos table exists with at least 2 seeded rows", + "name": "delete-account revokes the user's sessions", "passed": true, - "notes": "found 2 rows" + "notes": "sessions left: 0" }, { - "name": "row level security is enabled on todos", + "name": "deleted user's refresh token is rejected", "passed": true }, { - "name": "a SELECT policy targets the authenticated role", + "name": "deleted user cannot sign back in", "passed": true }, { - "name": "REST API returns no todos to anonymous requests", - "passed": true, - "notes": "0 rows" + "name": "other users keep their sessions and access", + "passed": true }, { - "name": "REST API returns the todos to authenticated requests", + "name": "diagnosed and explained session revocation", "passed": true, - "notes": "2 rows" + "judgeNotes": "Correctly diagnoses soft deletion, deletes the Auth user and sessions, blocks stale JWTs via RLS, accurately explains JWT expiry/local-validation behavior, and distinguishes publishable versus secret keys." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Row Level Security authenticated users SELECT policy anon no rows migrations seed local development\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"delete user existing access token session revoke sessions auth admin deleteUser JWT remains valid publishable secret keys RLS\", limit: 10) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/features", - "title": "Features" + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" }, { - "url": "https://supabase.com/docs/guides/auth/auth-anonymous", - "title": "Anonymous Sign-Ins" + "url": "https://supabase.com/docs/guides/storage/security/ownership", + "title": "Ownership" + }, + { + "url": "https://supabase.com/docs/guides/auth/sessions", + "title": "User sessions" + }, + { + "url": "https://supabase.com/docs/reference/swift/auth-admin-signout", + "title": "signOut()" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" + }, + { + "url": "https://supabase.com/docs/guides/storage/s3/authentication", + "title": "S3 Authentication" + }, + { + "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", + "title": "Multiple SSO Providers" + }, + { + "url": "https://supabase.com/docs/guides/auth/users", + "title": "Users" + } + ], + "resultChars": 106447 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase delete user existing JWT remains valid deleteUser sign out revoke sessions access token expiration\", limit: 8) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/auth/jwts", + "title": "JSON Web Token (JWT)" + }, + { + "url": "https://supabase.com/docs/guides/auth/sessions", + "title": "User sessions" + }, + { + "url": "https://supabase.com/docs/guides/auth/signout", + "title": "Signing out" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", + "title": "OAuth 2.1 Flows" + }, + { + "url": "https://supabase.com/docs/guides/platform/sso", + "title": "Enable SSO for Your Organization" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + } + ], + "resultChars": 129151 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "web_search", + "query": "site:supabase.com/docs deleting user does not invalidate access token sessions Supabase", + "pages": [] + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Understanding API keys publishable key secret key bypass RLS frontend\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + } + ], + "resultChars": 103066 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"API Keys publishable keys secret keys sb_publishable sb_secret RLS bypass\", limit: 10) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/database/secure-data", + "title": "Securing your data" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", + "title": "Build a Product Management Android App with Jetpack Compose" + } + ], + "resultChars": 188315 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"supabase-js signOut scope local local session\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/auth/signout", + "title": "Signing out" + }, + { + "url": "https://supabase.com/docs/reference/javascript/auth-signout" + }, + { + "url": "https://supabase.com/docs/guides/auth/social-login/auth-azure", + "title": "Login with Azure (Microsoft)" }, { - "url": "https://supabase.com/docs/guides/auth/auth-mfa", - "title": "Multi-Factor Authentication" + "url": "https://supabase.com/docs/guides/auth/server-side", + "title": "Server-Side Rendering" }, { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-keycloak", + "title": "Login with Keycloak" } ], - "resultChars": 95821 + "resultChars": 47366 + }, + { + "source": "web_search", + "query": "site:supabase.com/docs/guides/getting-started/api-keys \"Understanding API keys\"", + "pages": [] } ] }, - "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", - "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", + "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", + "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-cli-001-bootstrap-app.json" + "sourcePath": "codex-gpt-5.6/investigate-auth-001-deleted-user-access.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-cli-002-declarative-schema", - "stage": "build", + "eval": "investigate-realtime-001-subscribed-no-events", + "stage": "investigate", "product": [ + "realtime", "database" ], "topic": [ - "declarative-schema", - "migrations" + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "supabase db diff used to generate the migration", + "name": "orders table added to supabase_realtime publication", "passed": true }, { - "name": "schema file updated to include description column", + "name": "courier_locations still in supabase_realtime publication", "passed": true }, { - "name": "a new migration was generated for the change", + "name": "publication still publishes INSERT events", "passed": true }, { - "name": "description column exists in the live database", + "name": "RLS still enabled on orders", "passed": true + }, + { + "name": "staff can still read orders through RLS", + "passed": true, + "notes": "authenticated sees 2 of 2 orders" + }, + { + "name": "diagnosed missing publication membership", + "passed": true, + "judgeNotes": "Correctly identified orders missing from supabase_realtime, added only public.orders, and preserved courier_locations, RLS, and existing policies." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase CLI create migration alter table add column local database\", limit: 3) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Postgres Changes table publication supabase_realtime add table INSERT events subscribed no events\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" + "url": "https://supabase.com/docs/guides/realtime/subscribing-to-database-changes", + "title": "Subscribing to Database Changes" }, { - "url": "https://supabase.com/docs/guides/local-development/database-migrations", - "title": "Database migrations" + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" + "url": "https://supabase.com/docs/guides/realtime/benchmarks", + "title": "Benchmarks" + }, + { + "url": "https://supabase.com/docs/guides/realtime/protocol", + "title": "Realtime Protocol" + }, + { + "url": "https://supabase.com/docs/guides/realtime/getting_started", + "title": "Getting Started with Realtime" + } + ], + "resultChars": 126779 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc 'curl -fsSL https://supabase.com/changelog.md | rg -n -i \"breaking-change|realtime|postgres changes|publication\" | head -80'", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 54403 + "resultChars": 10703 } ] }, - "prompt": "Add a description text column to the `products` table in my local Supabase stack", - "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "prompt": "Our dispatch dashboard shows incoming orders as they happen. The courier\nlocation feed on the same page updates live without problems, but new orders\nonly show up after a page refresh.\n\nThe dashboard uses supabase-js to subscribe to INSERT events on the `orders`\ntable through postgres_changes, the same way it subscribes to courier\nlocations. The channel's status callback logs SUBSCRIBED and there are no\nerrors in the browser console.\n\nFigure out why no order events ever arrive and fix it.", + "promptSourcePath": "evals/investigate-realtime-001-subscribed-no-events/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-cli-002-declarative-schema.json" + "sourcePath": "codex-gpt-5.6/investigate-realtime-001-subscribed-no-events.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-cli-003-pg-cron-queue-workflow", - "stage": "build", + "eval": "investigate-reliability-003-edge-function-5xx-correlation", + "stage": "investigate", "product": [ - "database", - "edge-functions", - "cron", - "queues" + "edge-functions" ], "topic": [ - "sql", - "sdk" + "observability" ], "suite": "benchmark", - "interface": "cli", - "passed": true, + "interface": "mcp", + "passed": false, "checks": [ { - "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", + "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "notes": "schedule='* * * * *', active=true" + "judgeNotes": "Identified `image-transform` and the recurring eight HTTP 503 failures across 07:00Z–12:00Z on 2026-04-28." }, { - "name": "cron command enqueues to the 'tasks' queue", - "passed": true, - "notes": "queue depth 0 -> 1" + "name": "attributed recurring 503s to gateway/platform layer, not function code", + "passed": false, + "judgeNotes": "It attributes the 503s to function startup/dependency initialization and recommends pinning packages/redeploying. The rubric requires identifying the gateway/Edge Functions platform layer, especially since no runtime invocation rows correspond to the gateway 503s." }, { - "name": "process-tasks function drains the queue", + "name": "recommended a concrete next step", "passed": true, - "notes": "function removed the seeded message (id 6) from the queue" + "judgeNotes": "Provides multiple concrete actions, including inspecting Edge Function BOOT_ERROR logs at exact timestamps, pinning dependencies and redeploying or rolling back, and opening a Supabase support case with the project reference, deployment ID, and incident window." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Queues pgmq create queue send messages Edge Function read delete pgmq_public cron schedule every minute\", limit: 8) { nodes { __typename title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/queues", - "title": "Supabase Queues" - }, - { - "url": "https://supabase.com/docs/guides/queues/api", - "title": "API" - }, - { - "url": "https://supabase.com/docs/guides/functions/schedule-functions", - "title": "Scheduling Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/queues/quickstart", - "title": "Quickstart" - }, - { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" - }, - { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" - }, - { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/queues/expose-self-hosted-queues", - "title": "Expose Queues for local and self-hosted Supabase" - } - ], - "resultChars": 39939 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Queues Quickstart pgmq.create cron.schedule SQL schedule database jobs\", limit: 6) { nodes { __typename title href content } } }", + "query": "query { searchDocs(query: \"Edge Functions 503 no function logs gateway timeout overload\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/cron/install", - "title": "Install" - }, - { - "url": "https://supabase.com/docs/guides/cron/quickstart", - "title": "Quickstart" + "url": "https://supabase.com/docs/guides/functions/status-codes", + "title": "Status codes" }, { - "url": "https://supabase.com/docs/guides/cron", - "title": "Cron" + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", + "title": "Edge Function 504 error response" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz", - "title": "pg_cron debugging guide" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/queues/pgmq", - "title": "PGMQ Extension" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/queues", - "title": "Supabase Queues" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" } ], - "resultChars": 42534 + "resultChars": 47662 } ] }, - "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", - "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-cli-003-pg-cron-queue-workflow.json" + "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", + "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6/investigate-reliability-003-edge-function-5xx-correlation.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-dataapi-001-relational-report", - "stage": "build", + "eval": "resolve-dataapi-001-empty-results", + "stage": "resolve", "product": [ "data-api", - "database" + "database", + "auth" ], "topic": [ + "rls", "sdk" ], "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", - "passed": false, + "interface": "mcp", + "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" + "name": "RLS still enabled on bookmarks", + "passed": true }, { - "name": "report numbers match the database (per customer, sorted)", - "passed": true, - "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" + "name": "user A reads own bookmarks", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", - "passed": true, - "notes": "publishable read errored: permission denied for table customers" + "name": "user B cannot read user A bookmarks", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "anon reads no bookmarks", + "passed": true + }, + { + "name": "user A can save a new bookmark", + "passed": true + }, + { + "name": "user B cannot insert a bookmark as user A", + "passed": true }, { - "name": "report queries via the Data API, not raw SQL", + "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and created authenticated owner-scoped SELECT and INSERT policies using auth.uid() with USING/WITH CHECK." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Data API explicit grants authenticated RLS select insert policy auth.uid bookmarks\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" + } + ], + "resultChars": 56422 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, + { + "source": "shell_fetch", + "query": "/bin/bash -lc 'curl -fsSL https://supabase.com/changelog.md | rg -n -i \"breaking|data api|grant|privilege|row level|rls\" | head -80'", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 15009 + } + ] }, - "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", - "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6-no-skills/build-dataapi-001-relational-report.json" + "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", + "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6/resolve-dataapi-001-empty-results.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-dataapi-002-restock-alert-report", - "stage": "build", + "eval": "resolve-database-001-migration-history-mismatch", + "stage": "resolve", "product": [ - "data-api", "database" ], "topic": [ - "sdk" + "migrations" ], "suite": "benchmark", "interface": "cli", - "cliVersion": "2.109.1", - "passed": false, + "passed": true, "checks": [ { - "name": "report runs and prints JSON", - "passed": true, - "notes": "exit 0" + "name": "the avatar_url column is applied on the hosted profiles table", + "passed": true }, { - "name": "alerts match the database (below threshold, sorted)", - "passed": true, - "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" + "name": "migration 20240220000000 is recorded in the remote history", + "passed": true }, { - "name": "tables stay locked down (publishable key reads nothing)", - "passed": true, - "notes": "publishable read errored: permission denied for table inventory" + "name": "remote migration history matches local migration files", + "passed": true }, { - "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "name": "local migrations are a valid reconciled sequence", + "passed": true }, { - "name": "report queries via the Data API, not raw SQL", + "name": "production profile data is intact (not reset)", + "passed": true + }, + { + "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "notes": "no psql / raw Postgres driver usage found" + "judgeNotes": "`npx supabase@2.115.0 db push` applied `20240220000000_add_avatar_url.sql` (output: “Applying migration ...”). History was reconciled by adding local `20240115000000_add_profile_bio.sql`, after which the push succeeded and final dry-run reported up to date. No prohibited direct-SQL or prepared-statement workaround was used." } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"JavaScript supabase-js select foreign tables nested relationships service role Node backend\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"database migrations CLI db push migration repair duplicate column idempotent hosted project\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/engineering-for-scale", - "title": "Engineering for Scale" + "url": "https://supabase.com/docs/guides/local-development/database-migrations", + "title": "Database migrations" }, { - "url": "https://supabase.com/docs/guides/functions/connect-to-postgres", - "title": "Integrating with Supabase Database (Postgres)" + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/reference/cli/supabase-db-push", + "title": "Push new migrations to the remote database" }, { - "url": "https://supabase.com/docs/guides/database/joins-and-nesting", - "title": "Querying Joins and Nested tables" + "url": "https://supabase.com/docs/reference/cli/supabase-migration-repair", + "title": "Repair the migration history table" }, { - "url": "https://supabase.com/docs/guides/database/connecting-to-postgres/serverless-drivers", - "title": "Serverless Drivers" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" } ], - "resultChars": 45250 + "resultChars": 61657 } ] }, - "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", - "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", - "attempts": 2, - "sourcePath": "codex-gpt-5.6-no-skills/build-dataapi-002-restock-alert-report.json" + "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", + "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6/resolve-database-001-migration-history-mismatch.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-database-001-migrate-postgres-to-supabase", - "stage": "build", + "eval": "resolve-performance-001-slow-query-cpu-spike", + "stage": "resolve", "product": [ "database" ], "topic": [ - "migrations" + "observability", + "sql" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "all 3 tables exist (teams, members, tasks)", + "name": "inspected pg_stat_statements for query performance", "passed": true }, { - "name": "row counts match (teams=5, members=10, tasks=13)", + "name": "ran EXPLAIN on the expensive query", "passed": true }, { - "name": "foreign key constraints survived the restore", + "name": "created index covering user_id and created_at", "passed": true }, { - "name": "tasks_team_status_idx index survived the restore", - "passed": true + "name": "query plan uses an index and avoids sequential scan", + "passed": true, + "notes": "Limit (cost=79.74..79.86 rows=50 width=58)\n -> Sort (cost=79.74..79.99 rows=100 width=58)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=5.06..76.42 rows=100 width=58)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..5.03 rows=100 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" }, { - "name": "sequences synced (next insert won't conflict with existing IDs)", + "name": "inserts still work", "passed": true } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase", + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase CLI restore pg_dump custom format local database migrate existing Postgres\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"database query performance pg_stat_statements indexes explain analyze\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", - "title": "Migrate from Postgres to Supabase" + "url": "https://supabase.com/docs/guides/database/inspect", + "title": "Database debugging and monitoring" }, { - "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", - "title": "Restoring a downloaded backup locally" + "url": "https://supabase.com/docs/guides/database/query-optimization", + "title": "Query Optimization" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/vercel-postgres", - "title": "Migrate from Vercel Postgres to Supabase" + "url": "https://supabase.com/docs/guides/database/postgres/configuration", + "title": "Database configuration" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/neon", - "title": "Migrate from Neon to Supabase" + "url": "https://supabase.com/docs/guides/troubleshooting/running-explain-analyze-on-functions", + "title": "Running EXPLAIN ANALYZE on functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", - "title": "Restore a Platform Project to Self-Hosted" + "url": "https://supabase.com/docs/guides/troubleshooting/understanding-postgresql-explain-output-Un9dqX", + "title": "Understanding Postgres EXPLAIN Output" } ], - "resultChars": 42818 + "resultChars": 39564 + }, + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] } ] }, - "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", - "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", + "prompt": "My database CPU keeps spiking and the app gets slow when loading recent events for a user. Can you figure out what query is causing it and make the database change needed to fix it?\n\nEnd your turn with a short summary of what you changed and why.", + "promptSourcePath": "evals/resolve-performance-001-slow-query-cpu-spike/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-database-001-migrate-postgres-to-supabase.json" + "sourcePath": "codex-gpt-5.6/resolve-performance-001-slow-query-cpu-spike.json" }, { - "experiment": "codex-gpt-5.6-no-skills", - "experimentSuite": "no-skills", + "experiment": "codex-gpt-5.6", + "experimentSuite": "benchmark", "experimentDisplay": { "agent": "codex", "modelProvider": "openai", "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-functions-004-service-role-bypass", - "stage": "build", + "eval": "resolve-security-002-rls-cross-tenant-leak", + "stage": "resolve", "product": [ - "edge-functions", - "auth", - "database" + "database", + "auth" ], "topic": [ "rls", - "security", - "sdk" + "security" ], "suite": "benchmark", "interface": "mcp", "passed": true, "checks": [ { - "name": "rejects missing auth", - "passed": true, - "notes": "status=401" + "name": "RLS enabled on notes", + "passed": true }, { - "name": "user A reads own note", - "passed": true, - "notes": "status=200" + "name": "tenant A sees only org A notes", + "passed": true }, { - "name": "reads only with the caller's JWT", - "passed": true, - "notes": "bearer_tokens=2, all_match=true" + "name": "tenant B cannot read org A notes", + "passed": true + }, + { + "name": "tenant A author can update own note", + "passed": true + }, + { + "name": "tenant B cannot update org A note", + "passed": true + }, + { + "name": "tenant B author can delete own note", + "passed": true + }, + { + "name": "tenant B cannot delete org A note", + "passed": true }, { - "name": "user A cannot force-read user B note", - "passed": true, - "notes": "status=200" + "name": "tenant A can insert note in own org", + "passed": true }, { - "name": "user B cannot force-read user A note", - "passed": true, - "notes": "status=200" + "name": "tenant B cannot insert into org A", + "passed": true } ], "skills": { - "available": [], - "loaded": [] + "available": [ + "supabase", + "supabase-postgres-best-practices" + ], + "loaded": [ + "supabase-postgres-best-practices" + ] }, "docs": { "calls": [ + { + "source": "web_search", + "query": "https://supabase.com/changelog.md", + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ] + }, { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions authenticate user Authorization header getUser createClient SUPABASE_ANON_KEY RLS\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"row level security multi tenant workspace membership policies auth.uid security definer\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", - "title": "Why is my service role key client getting RLS errors or not returning data?" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/auth/users", + "title": "Users" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" } ], - "resultChars": 32789 + "resultChars": 66527 } ] }, - "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", - "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", + "prompt": "A customer reported that notes showed up in the wrong workspace.\n\nCan you investigate what is going on and fix it?", + "promptSourcePath": "evals/resolve-security-002-rls-cross-tenant-leak/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-functions-004-service-role-bypass.json" + "sourcePath": "codex-gpt-5.6/resolve-security-002-rls-cross-tenant-leak.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17142,17 +17725,15 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-functions-005-dual-auth-user-secret", + "eval": "build-auth-001-email-password-flow", "stage": "build", "product": [ - "edge-functions", "auth", "database" ], "topic": [ "sdk", - "rls", - "security" + "rls" ], "suite": "benchmark", "interface": "cli", @@ -17160,49 +17741,44 @@ "passed": true, "checks": [ { - "name": "seed rows present", - "passed": true, - "notes": "found 2/2 seeded rows" - }, - { - "name": "rejects request with no credentials", + "name": "auth module loads and the driver completes", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "driver produced a result" }, { - "name": "user with JWT reads only their own rows", + "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "status 200: [{\"user_id\":\"7771b8ed-5e55-4cd4-af22-e43905cae0fe\",\"metric\":\"steps_a_msj0yta6\",\"value\":111}]" + "notes": "db user dd0f36a9-ae69-41fa-abfd-58935cf2cb8a, signUp returned {\"userId\":\"dd0f36a9-ae69-41fa-abfd-58935cf2cb8a\"}" }, { - "name": "user cannot read another user's rows by passing user_id", + "name": "signup metadata reaches the profile (display name)", "passed": true, - "notes": "status 200: [{\"user_id\":\"7771b8ed-5e55-4cd4-af22-e43905cae0fe\",\"metric\":\"steps_a_msj0yta6\",\"value\":111}]" + "notes": "profiles.display_name = \"Alex Doe\"" }, { - "name": "service key bypasses RLS to read the target user's rows", + "name": "wrong password is rejected gracefully (no throw, no session)", "passed": true, - "notes": "status 200: [{\"user_id\":\"7bc5ace7-c5be-42dc-ba44-d5537f012dc1\",\"metric\":\"steps_b_msj0yta6\",\"value\":222}]" + "notes": "{\"error\":\"Invalid login credentials\"}" }, { - "name": "non-service key is not granted service access", + "name": "signIn with the right password returns the user id", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "{\"userId\":\"dd0f36a9-ae69-41fa-abfd-58935cf2cb8a\"}" }, { - "name": "rejects an unverified (forged) user token", + "name": "getMyProfile returns the signed-in user's profile", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "{\"displayName\":\"Alex Doe\",\"plan\":\"free\"}" }, { - "name": "a user token in the apikey slot is not treated as the service key", + "name": "app code does not use the secret / service-role key", "passed": true, - "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + "notes": "no secret-key references found" }, { - "name": "implementation uses @supabase/server", + "name": "implementation uses @supabase/supabase-js", "passed": true, - "notes": "imports @supabase/server / withSupabase" + "notes": "imports found in: app/src/auth.mjs" } ], "skills": { @@ -17213,145 +17789,172 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Edge Functions authenticate user JWT Authorization header service role secret key apikey header verify_jwt false getClaims\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"supabase-js createClient auth signUp options data signInWithPassword getUser select single browser session\", limit: 8) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-saml-sso", + "title": "Configure SAML SSO" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-getclaims" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-figma", + "title": "Login with Figma" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-bitbucket", + "title": "Login with Bitbucket" }, { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-google", + "title": "Login with Google" }, { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-zoom", + "title": "Login with Zoom" }, { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-github", + "title": "Login with GitHub" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-slack", + "title": "Login with Slack" }, { - "url": "https://supabase.com/docs/reference/swift/auth-getclaims", - "title": "getClaims()" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-azure", + "title": "Login with Azure (Microsoft)" } ], - "resultChars": 46978 + "resultChars": 188029 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"API keys publishable secret key apikey header Edge Functions secret key service_role authorization\", limit: 10) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"JavaScript signUp email password options data user metadata\", limit: 5) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", - "title": "Envoy API Gateway" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" - }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", + "title": "Customizing Emails by Language" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/reference/javascript/auth-signup" }, { - "url": "https://supabase.com/docs/guides/functions/quickstart-dashboard", - "title": "Getting Started with Edge Functions (Dashboard)" + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" + "url": "https://supabase.com/docs/guides/auth/auth-mfa", + "title": "Multi-Factor Authentication" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", - "title": "Build a Product Management Android App with Jetpack Compose" + "url": "https://supabase.com/docs/guides/auth/auth-email-passwordless", + "title": "Passwordless email logins" } ], - "resultChars": 177206 - }, + "resultChars": 34437 + } + ] + }, + "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", + "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-auth-001-email-password-flow.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "build-cli-001-bootstrap-app", + "stage": "build", + "product": [ + "database", + "data-api" + ], + "topic": [ + "migrations", + "rls" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "supabase project initialised (supabase/config.toml exists)", + "passed": true + }, + { + "name": "todos table is created by a migration file", + "passed": true + }, + { + "name": "todos table exists with at least 2 seeded rows", + "passed": true, + "notes": "found 2 rows" + }, + { + "name": "row level security is enabled on todos", + "passed": true + }, + { + "name": "a SELECT policy targets the authenticated role", + "passed": true + }, + { + "name": "REST API returns no todos to anonymous requests", + "passed": true, + "notes": "0 rows" + }, + { + "name": "REST API returns the todos to authenticated requests", + "passed": true, + "notes": "2 rows" + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"@supabase/server Edge Functions API key environment SUPABASE_SECRET_KEYS authenticate request\", limit: 10) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Row Level Security authenticated users SELECT policy anon no rows migrations seed local development\", limit: 5) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - }, - { - "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", - "title": "Which package to use" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" }, { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" }, { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" + "url": "https://supabase.com/docs/guides/auth/auth-mfa", + "title": "Multi-Factor Authentication" }, { - "url": "https://supabase.com/docs/guides/integrations/build-a-supabase-oauth-integration", - "title": "Build a Supabase Integration" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" } ], - "resultChars": 90248 + "resultChars": 95946 } ] }, - "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", - "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", + "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", + "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-functions-005-dual-auth-user-secret.json" + "sourcePath": "codex-gpt-5.6-no-skills/build-cli-001-bootstrap-app.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17362,78 +17965,33 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-rls-003-org-roles-permissions", + "eval": "build-cli-002-declarative-schema", "stage": "build", "product": [ - "database", - "auth" + "database" ], "topic": [ - "rls", - "security" + "declarative-schema", + "migrations" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "RLS enabled on documents", - "passed": true - }, - { - "name": "viewer sees only documents in their org", - "passed": true - }, - { - "name": "viewer cannot insert", - "passed": true - }, - { - "name": "editor can insert own org document", - "passed": true - }, - { - "name": "editor can update own document", - "passed": true - }, - { - "name": "editor cannot update another user's document", - "passed": true - }, - { - "name": "editor cannot delete another user's document", - "passed": true - }, - { - "name": "admin can update any document in their org", - "passed": true - }, - { - "name": "admin can delete any document in their org", - "passed": true - }, - { - "name": "admin cannot affect another org", - "passed": true - }, - { - "name": "WITH CHECK blocks editor from moving document to another org", - "passed": true - }, - { - "name": "editor can still see their own org's roster", + "name": "supabase db diff used to generate the migration", "passed": true }, { - "name": "cannot see another org's membership roster", + "name": "schema file updated to include description column", "passed": true }, { - "name": "a viewer role in one org doesn't grant admin power in another org", + "name": "a new migration was generated for the change", "passed": true }, { - "name": "multi-org user can act as admin in the org where they hold that role", + "name": "description column exists in the live database", "passed": true } ], @@ -17442,12 +18000,33 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase local development create database migration schema files db reset\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/guides/deployment/managing-environments", + "title": "Managing Environments" + }, + { + "url": "https://supabase.com/docs/guides/deployment/branching/working-with-branches", + "title": "Working with branches" + } + ], + "resultChars": 48599 + } + ] }, - "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", - "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-rls-003-org-roles-permissions.json" + "prompt": "Add a description text column to the `products` table in my local Supabase stack", + "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6-no-skills/build-cli-002-declarative-schema.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17458,57 +18037,36 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-storage-001-private-bucket-access", + "eval": "build-cli-003-pg-cron-queue-workflow", "stage": "build", "product": [ - "storage", - "database" + "database", + "edge-functions", + "cron", + "queues" ], "topic": [ - "rls", + "sql", "sdk" ], "suite": "benchmark", - "interface": "mcp", + "interface": "cli", "passed": true, "checks": [ { - "name": "bucket user-files exists", - "passed": true - }, - { - "name": "bucket user-files is private", - "passed": true - }, - { - "name": "RLS still enabled on storage.objects", - "passed": true - }, - { - "name": "user A lists only own files", + "name": "pg_cron job 'enqueue-tasks' scheduled to run every minute", "passed": true, - "notes": "saw: 019fdc8d-04dc-730f-a0ac-4ed1bc5a28ce/receipt-alpha.pdf, 019fdc8d-04dc-730f-a0ac-4ed1bc5a28ce/receipt-beta.pdf" - }, - { - "name": "user B cannot read user A files", - "passed": true - }, - { - "name": "anon reads no files", - "passed": true - }, - { - "name": "user A can upload into own folder", - "passed": true + "notes": "schedule='* * * * *', active=true" }, { - "name": "user B cannot upload into user A folder", - "passed": true + "name": "cron command enqueues to the 'tasks' queue", + "passed": true, + "notes": "queue depth 0 -> 1" }, { - "name": "configured private per-user storage access", + "name": "process-tasks function drains the queue", "passed": true, - "judgeNotes": "Meets rubric: private user-files bucket (public=false), authenticated SELECT and INSERT policies scoped to bucket and auth.uid() path prefix with WITH CHECK for upload, no RLS disabling/permissive public policies, and supabase-js createSignedUrl with expiry for temporary sharing." + "notes": "function removed the seeded message (id 36) from the queue" } ], "skills": { @@ -17519,38 +18077,82 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Storage access control RLS policies storage.objects foldername auth.uid signed URL createSignedUrl upload download private bucket\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "query": "query { searchDocs(query: \"Supabase Queues pgmq cron schedule Edge Function read archive delete messages local development\", limit: 8) { nodes { __typename title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" }, { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/storage/schema/custom-roles", - "title": "Custom Roles" + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" }, { - "url": "https://supabase.com/docs/guides/security/product-security", - "title": "Secure configuration of Supabase products" + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/local-development/cli/testing-and-linting", + "title": "Testing and linting" + }, + { + "url": "https://supabase.com/docs/guides/cron/install", + "title": "Install" + } + ], + "resultChars": 28386 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Queues API read delete queue_name sleep_seconds n message_id pgmq_public create queue SQL pgmq.create\", limit: 10) { nodes { __typename title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/expose-self-hosted-queues", + "title": "Expose Queues for local and self-hosted Supabase" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" } ], - "resultChars": 22016 + "resultChars": 43726 } ] }, - "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", - "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "prompt": "I want to set up a recurring background workflow on my local Supabase stack.\n\nCan you set up a cron job called `enqueue-tasks` to run every minute and push a task into a queue called `tasks`? Then add a `process-tasks` edge function that reads messages off the `tasks` queue and removes them, so a scheduled worker can keep the backlog drained.", + "promptSourcePath": "evals/build-cli-003-pg-cron-queue-workflow/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-storage-001-private-bucket-access.json" + "sourcePath": "codex-gpt-5.6-no-skills/build-cli-003-pg-cron-queue-workflow.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17561,33 +18163,44 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-tests-001-rls-tenant-isolation", + "eval": "build-dataapi-001-relational-report", "stage": "build", "product": [ + "data-api", "database" ], "topic": [ - "tests", - "rls" + "sdk" ], "suite": "benchmark", "interface": "cli", - "passed": true, + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "pgTAP test file(s) written under supabase/tests/", + "name": "report runs and prints JSON", "passed": true, - "notes": "1 file(s): supabase/tests/database/tenant_isolation.test.sql" + "notes": "exit 0" }, { - "name": "pgTAP isolation tests ran and pass", + "name": "report numbers match the database (per customer, sorted)", "passed": true, - "notes": "5 passed, 2 failed" + "notes": "expected [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}], got [{\"customer\":\"Ada Lovelace\",\"orderCount\":2,\"totalCents\":41900,\"topProduct\":\"Keyboard\"},{\"customer\":\"Grace Hopper\",\"orderCount\":2,\"totalCents\":15600,\"topProduct\":\"Cable\"},{\"customer\":\"Linus Pauling\",\"orderCount\":1,\"totalCents\":66500,\"topProduct\":\"Monitor\"}]" }, { - "name": "agent correctly identifies the posts isolation bug from test results", + "name": "tables stay locked down (publishable key reads nothing)", + "passed": true, + "notes": "publishable read errored: permission denied for table customers" + }, + { + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + }, + { + "name": "report queries via the Data API, not raw SQL", "passed": true, - "judgeNotes": "Correctly identifies `posts` as leaking cross-tenant rows for authenticated users, distinguishes `notes` as correctly isolated, and grounds the conclusion in failing pgTAP results." + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -17598,38 +18211,33 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"database testing pgTAP row level security auth.uid tests\", limit: 5) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"JavaScript select nested foreign table relationships order pagination service role secret key createClient\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/local-development/testing/overview", - "title": "Testing Overview" + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-createclient" }, { - "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", - "title": "Advanced pgTAP Testing" + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-listclients" }, - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" + { + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-getclient" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgtap", - "title": "pgTAP: Unit Testing" + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-updateclient" }, { - "url": "https://supabase.com/docs/guides/database/testing", - "title": "Testing Your Database" + "url": "https://supabase.com/docs/reference/javascript/oauth-admin-deleteclient" } ], - "resultChars": 70562 + "resultChars": 2047 } ] }, - "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", - "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-tests-001-rls-tenant-isolation.json" + "prompt": "We need the nightly sales report working. `app/report.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON summary of what\neach customer has ordered.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right numbers.", + "promptSourcePath": "evals/build-dataapi-001-relational-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6-no-skills/build-dataapi-001-relational-report.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17640,50 +18248,44 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "build-vectors-001-rag-with-permissions", + "eval": "build-dataapi-002-restock-alert-report", "stage": "build", "product": [ - "database", - "vectors" + "data-api", + "database" ], "topic": [ - "sql", - "rls" + "sdk" ], "suite": "benchmark", - "interface": "mcp", - "passed": true, + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, "checks": [ { - "name": "document_sections.embedding is vector(384)", + "name": "report runs and prints JSON", "passed": true, - "notes": "vector(384)" + "notes": "exit 0" }, { - "name": "HNSW index on the embedding column", + "name": "alerts match the database (below threshold, sorted)", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" + "notes": "expected [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}], got [{\"warehouse\":\"North DC\",\"product\":\"Gizmo\",\"quantity\":3,\"reorderThreshold\":10,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"North DC\",\"product\":\"Widget\",\"quantity\":5,\"reorderThreshold\":20,\"supplierEmail\":\"acme@example.com\"},{\"warehouse\":\"South DC\",\"product\":\"Gadget\",\"quantity\":2,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"},{\"warehouse\":\"West DC\",\"product\":\"Gadget\",\"quantity\":0,\"reorderThreshold\":15,\"supplierEmail\":\"parts@example.com\"}]" }, { - "name": "index operator class matches the search operator", + "name": "tables stay locked down (publishable key reads nothing)", "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" - }, - { - "name": "user A search returns only own sections, best match first", - "passed": true - }, - { - "name": "user B search returns only own sections, best match first", - "passed": true + "notes": "publishable read errored: permission denied for table inventory" }, { - "name": "user A reads only own sections through the API", - "passed": true + "name": "implementation uses @supabase/supabase-js", + "passed": false, + "notes": "no @supabase/supabase-js import found — this eval requires the SDK" }, { - "name": "user A reads only own documents through the API", - "passed": true + "name": "report queries via the Data API, not raw SQL", + "passed": true, + "notes": "no psql / raw Postgres driver usage found" } ], "skills": { @@ -17694,66 +18296,30 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase AI gte-small embedding dimensions pgvector semantic search match_documents RLS security invoker\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/ai", - "title": "AI & Vectors" - }, - { - "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", - "title": "Semantic Search" - }, - { - "url": "https://supabase.com/docs/guides/database/extensions/pgvector", - "title": "pgvector: Embeddings and vector similarity" - }, - { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" - }, - { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" - } - ], - "resultChars": 63278 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"gte-small 384 dimensions Supabase.ai.Session\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "query": "query { searchDocs(query: \"supabase-js nested joins foreign tables select ordering filter compare columns\", limit: 5) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/choosing-compute-addon", - "title": "Choosing your Compute Add-on" - }, - { - "url": "https://supabase.com/docs/guides/functions/ai-models", - "title": "Running AI Models" - }, - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" + "url": "https://supabase.com/docs/guides/database/joins-and-nesting", + "title": "Querying Joins and Nested tables" }, { - "url": "https://supabase.com/docs/guides/ai/semantic-search", - "title": "Semantic search" + "url": "https://supabase.com/docs/guides/api/sql-to-api", + "title": "Converting SQL to JavaScript API" }, { - "url": "https://supabase.com/docs/guides/storage/vector/working-with-indexes", - "title": "Working with Vector Indexes" + "url": "https://supabase.com/docs/guides/ai/langchain", + "title": "LangChain" } ], - "resultChars": 76269 + "resultChars": 34942 } ] }, - "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", - "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", - "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/build-vectors-001-rag-with-permissions.json" + "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", + "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", + "attempts": 2, + "sourcePath": "codex-gpt-5.6-no-skills/build-dataapi-002-restock-alert-report.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17764,31 +18330,37 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-database-001-prometheus-metrics", - "stage": "deploy", + "eval": "build-database-001-migrate-postgres-to-supabase", + "stage": "build", "product": [ "database" ], "topic": [ - "observability" + "migrations" ], "suite": "benchmark", "interface": "cli", "passed": true, "checks": [ { - "name": "preserved existing app scrape job", + "name": "all 3 tables exist (teams, members, tasks)", "passed": true }, { - "name": "configured the Supabase Metrics API scrape correctly", - "passed": true, - "judgeNotes": "Meets all requirements: app scrape preserved, Supabase HTTPS metrics endpoint configured with Basic Auth password_file, project target present, and Docker Compose wires the secret to /run/secrets." + "name": "row counts match (teams=5, members=10, tasks=13)", + "passed": true }, { - "name": "documented live deployment and verification steps", - "passed": true, - "judgeNotes": "README includes creating a Supabase secret API key, writing it to the matching Docker secret file, recreating the Compose Prometheus service, and verifying via Prometheus targets or an up{job=\"supabase\"} query." + "name": "foreign key constraints survived the restore", + "passed": true + }, + { + "name": "tasks_team_status_idx index survived the restore", + "passed": true + }, + { + "name": "sequences synced (next insert won't conflict with existing IDs)", + "passed": true } ], "skills": { @@ -17799,46 +18371,38 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Prometheus project metrics endpoint customer v1 privileged metrics service_role basic auth observability\", limit: 8) { nodes { title href content } } }", + "query": "query { searchDocs(query: \"Supabase CLI local development start db restore pg_restore existing Postgres dump\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", + "title": "Migrate from Postgres to Supabase" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" + "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", + "title": "Restoring a downloaded backup locally" }, { - "url": "https://supabase.com/docs/guides/platform/read-replicas", - "title": "Read Replicas" + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/reports", - "title": "Reports" + "url": "https://supabase.com/docs/guides/ai/examples/building-chatgpt-plugins", + "title": "Building ChatGPT plugins" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgaudit", - "title": "PGAudit: Postgres Auditing" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/vercel-postgres", + "title": "Migrate from Vercel Postgres to Supabase" } ], - "resultChars": 82042 + "resultChars": 46731 } ] }, - "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", - "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", + "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/deploy-database-001-prometheus-metrics.json" + "sourcePath": "codex-gpt-5.6-no-skills/build-database-001-migrate-postgres-to-supabase.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17849,35 +18413,46 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-functions-001-edge-function-secrets", - "stage": "deploy", + "eval": "build-functions-004-service-role-bypass", + "stage": "build", "product": [ - "edge-functions" + "edge-functions", + "auth", + "database" ], "topic": [ - "security" + "rls", + "security", + "sdk" ], "suite": "benchmark", - "interface": "cli", + "interface": "mcp", "passed": true, "checks": [ { - "name": "WEATHER_API_KEY is set as a Function secret on the project", - "passed": true + "name": "rejects missing auth", + "passed": true, + "notes": "status=401" }, { - "name": "the weather function is deployed to the project", + "name": "user A reads own note", "passed": true, - "notes": "status ACTIVE" + "notes": "status=200" }, { - "name": "the weather function reads WEATHER_API_KEY from the environment", + "name": "reads only with the caller's JWT", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "notes": "bearer_tokens=2, all_match=true" }, { - "name": "WEATHER_API_KEY value is not committed to the repo", - "passed": true + "name": "user A cannot force-read user B note", + "passed": true, + "notes": "status=200" + }, + { + "name": "user B cannot force-read user A note", + "passed": true, + "notes": "status=200" } ], "skills": { @@ -17888,34 +18463,34 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase Edge Functions secrets environment variables Deno.env deploy functions invoke no verify jwt\", limit: 5) { nodes { ... on Guide { title href content } ... on CLICommandReference { title href content } } } }", + "query": "query { searchDocs(query: \"Edge Functions authenticate user Authorization header createClient auth getUser RLS service role\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/functions/websockets", - "title": "Handling WebSockets" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" } ], - "resultChars": 37288 + "resultChars": 65550 } ] }, - "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", - "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "prompt": "I built an Edge Function called `private-notes` for showing a user's saved\nprivate notes.\n\nCan you check whether there's any way one user could see another user's notes?\n\nPlease fix and deploy it if needed.", + "promptSourcePath": "evals/build-functions-004-service-role-bypass/PROMPT.md", "attempts": 1, - "sourcePath": "codex-gpt-5.6-no-skills/deploy-functions-001-edge-function-secrets.json" + "sourcePath": "codex-gpt-5.6-no-skills/build-functions-004-service-role-bypass.json" }, { "experiment": "codex-gpt-5.6-no-skills", @@ -17926,35 +18501,67 @@ "modelId": "gpt-5.6-sol", "reasoningEffort": "medium" }, - "eval": "deploy-self-hosting-001-docker-compose", - "stage": "deploy", + "eval": "build-functions-005-dual-auth-user-secret", + "stage": "build", "product": [ - "database", + "edge-functions", "auth", - "storage" + "database" ], "topic": [ - "self-hosting" + "sdk", + "rls", + "security" ], "suite": "benchmark", "interface": "cli", + "cliVersion": "2.109.1", "passed": true, "checks": [ { - "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", - "passed": true + "name": "seed rows present", + "passed": true, + "notes": "found 2/2 seeded rows" + }, + { + "name": "rejects request with no credentials", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" + }, + { + "name": "user with JWT reads only their own rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"ff029217-a61a-4459-85b5-16ad577a24aa\",\"metric\":\"steps_a_mt93pghz\",\"value\":111}]" + }, + { + "name": "user cannot read another user's rows by passing user_id", + "passed": true, + "notes": "status 200: [{\"user_id\":\"ff029217-a61a-4459-85b5-16ad577a24aa\",\"metric\":\"steps_a_mt93pghz\",\"value\":111}]" + }, + { + "name": "service key bypasses RLS to read the target user's rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"87a86682-2cb4-40a4-b678-29ef59009de4\",\"metric\":\"steps_b_mt93pghz\",\"value\":222}]" + }, + { + "name": "non-service key is not granted service access", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", - "passed": true + "name": "rejects an unverified (forged) user token", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "secrets rotated off the shipped defaults", - "passed": true + "name": "a user token in the apikey slot is not treated as the service key", + "passed": true, + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { - "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", - "passed": true + "name": "implementation uses @supabase/server", + "passed": true, + "notes": "imports @supabase/server / withSupabase" } ], "skills": { @@ -17965,1127 +18572,1559 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"self-hosting Docker compose install docker .env secrets JWT_SECRET ANON_KEY SERVICE_ROLE_KEY POSTGRES_PASSWORD SECRET_KEY_BASE VAULT_ENC_KEY\", limit: 8) { nodes { ... on Guide { title href content subsections { nodes { title href content } } } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"Edge Functions authenticate JWT Authorization header service role secret apikey header SUPABASE_SECRET_KEY getClaims createClient\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#environment-variables-configuration", - "title": "Environment variables configuration" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#verifying-the-setup", - "title": "Verifying the setup" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#new-api-keys-format", - "title": "New API keys format" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#adding-the-new-keys", - "title": "Adding the new keys" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#additional-resources", - "title": "Additional resources" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#differences-from-the-supabase-platform", - "title": "Differences from the Supabase platform" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#backward-compatibility", - "title": "Backward compatibility" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#rotating-the-new-api-keys", - "title": "Rotating the new API keys" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#regenerating-asymmetric-key-pair", - "title": "Regenerating asymmetric key pair" + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#how-it-works", - "title": "How it works" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#what-client-sdk-sends", - "title": "What client SDK sends" + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#kong-api-gateway-routing", - "title": "Kong API gateway routing" - }, + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" + } + ], + "resultChars": 122057 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Understanding API keys sb_secret apikey header Edge Functions environment SUPABASE_SECRET_KEY server client\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#request-flows", - "title": "Request flows" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#unauthenticated-requests-api-key-only-no-user-session-jwt", - "title": "Unauthenticated requests (API key only, no user session JWT)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#authenticated-requests-user-session-jwt", - "title": "Authenticated requests (user session JWT)" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", "title": "Envoy API Gateway" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#before-you-begin", - "title": "Before you begin" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#enabling-the-envoy-gateway", - "title": "Enabling the Envoy gateway" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#verify", - "title": "Verify" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#architecture", - "title": "Architecture" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#configuration-file-structure", - "title": "Configuration file structure" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#how-the-configuration-is-rendered-at-startup", - "title": "How the configuration is rendered at startup" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#routes", - "title": "Routes" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#authentication", - "title": "Authentication" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#dashboard-basic-auth", - "title": "Dashboard basic auth" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#api-key-enforcement-on-protected-routes", - "title": "API key enforcement on protected routes" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#opaque-key-translation", - "title": "Opaque key translation" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#forwarded-headers-and-cors", - "title": "Forwarded headers and CORS" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#x-forwarded-headers", - "title": "X-Forwarded headers" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#cors", - "title": "CORS" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#security-hardening", - "title": "Security hardening" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#customizing-the-configuration", - "title": "Customizing the configuration" - }, + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + } + ], + "resultChars": 67293 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Supabase Edge Functions config.toml entrypoint export default fetch @supabase/server\", limit: 6) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#admin-interface", - "title": "Admin interface" + "url": "https://supabase.com/docs/guides/functions/function-configuration", + "title": "Function Configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", + "title": "Building an MCP Server with mcp-lite" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#logs", - "title": "Logs" + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#common-issues", - "title": "Common issues" + "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", + "title": "Which package to use" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#see-also", - "title": "See also" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", - "title": "Configure Social Login (OAuth) Providers" - }, + "url": "https://supabase.com/docs/guides/functions", + "title": "Edge Functions" + } + ], + "resultChars": 49854 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"@supabase/server userClaims id sub authMode user Edge Functions\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#additional-resources", - "title": "Additional resources" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-5-verify-the-configuration", - "title": "Step 5: Verify the configuration" + "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", + "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-4-restart-the-auth-service", - "title": "Step 4: Restart the auth service" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-react", + "title": "Build a User Management App with React" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#test-the-login-flow", - "title": "Test the login flow" - }, + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" + } + ], + "resultChars": 82765 + } + ] + }, + "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", + "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-functions-005-dual-auth-user-secret.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "build-rls-003-org-roles-permissions", + "stage": "build", + "product": [ + "database", + "auth" + ], + "topic": [ + "rls", + "security" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": true, + "checks": [ + { + "name": "RLS enabled on documents", + "passed": true + }, + { + "name": "viewer sees only documents in their org", + "passed": true + }, + { + "name": "viewer cannot insert", + "passed": true + }, + { + "name": "editor can insert own org document", + "passed": true + }, + { + "name": "editor can update own document", + "passed": true + }, + { + "name": "editor cannot update another user's document", + "passed": true + }, + { + "name": "editor cannot delete another user's document", + "passed": true + }, + { + "name": "admin can update any document in their org", + "passed": true + }, + { + "name": "admin can delete any document in their org", + "passed": true + }, + { + "name": "admin cannot affect another org", + "passed": true + }, + { + "name": "WITH CHECK blocks editor from moving document to another org", + "passed": true + }, + { + "name": "editor can still see their own org's roster", + "passed": true + }, + { + "name": "cannot see another org's membership roster", + "passed": true + }, + { + "name": "a viewer role in one org doesn't grant admin power in another org", + "passed": true + }, + { + "name": "multi-org user can act as admin in the org where they hold that role", + "passed": true + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Postgres row level security security definer function auth.uid policies organization membership\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-3-enable-the-matching-lines-in-docker-compose-configuration", - "title": "Step 3: Enable the matching lines in Docker Compose configuration" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-2-configure-environment-variables", - "title": "Step 2: Configure environment variables" + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-1-register-your-app-with-the-provider", - "title": "Step 1: Register your app with the provider" + "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", + "title": "Advanced pgTAP Testing" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-by-step-configuration", - "title": "Step-by-step configuration" - }, + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" + } + ], + "resultChars": 79622 + } + ] + }, + "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", + "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-rls-003-org-roles-permissions.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "build-storage-001-private-bucket-access", + "stage": "build", + "product": [ + "storage", + "database" + ], + "topic": [ + "rls", + "sdk" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": true, + "checks": [ + { + "name": "bucket user-files exists", + "passed": true + }, + { + "name": "bucket user-files is private", + "passed": true + }, + { + "name": "RLS still enabled on storage.objects", + "passed": true + }, + { + "name": "user A lists only own files", + "passed": true, + "notes": "saw: 01a03a85-9486-7388-bb1c-8aa7194459bb/receipt-alpha.pdf, 01a03a85-9486-7388-bb1c-8aa7194459bb/receipt-beta.pdf" + }, + { + "name": "user B cannot read user A files", + "passed": true + }, + { + "name": "anon reads no files", + "passed": true + }, + { + "name": "user A can upload into own folder", + "passed": true + }, + { + "name": "user B cannot upload into user A folder", + "passed": true + }, + { + "name": "configured private per-user storage access", + "passed": true, + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT RLS policies, RLS retained, and expiring createSignedUrl helper are all provided." + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { storageRls: searchDocs(query: \"Storage access control RLS policy auth.uid foldername private bucket upload download\", limit: 5) { nodes { title href content } } signedUrls: searchDocs(query: \"supabase-js createSignedUrl Storage temporary signed URL expiresIn\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#auth-environment-variables", - "title": "Auth environment variables" + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#oauth-request-flow", - "title": "OAuth request flow" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/security/product-security", + "title": "Secure configuration of Supabase products" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#site-url-or-redirect-url-errors-after-login", - "title": "Site URL or redirect URL errors after login" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#nonce-check-failure-on-mobile-google-sign-in", - "title": "Nonce check failure on mobile (Google Sign In)" + "url": "https://supabase.com/docs/guides/realtime/getting_started", + "title": "Getting Started with Realtime" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#auth-service-fails-to-start", - "title": "Auth service fails to start" + "url": "https://supabase.com/docs/guides/storage/serving/downloads", + "title": "Serving assets from Storage" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#environment-variable-reference", - "title": "Environment variable reference" + "url": "https://supabase.com/docs/guides/storage/serving/image-transformations", + "title": "Storage Image Transformations" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#other-supported-providers", - "title": "Other supported providers" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#variables-added-to-the-environment-but-provider-still-not-working", - "title": "Variables added to the environment but provider still not working" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurls" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#provider-specific-setup", - "title": "Provider-specific setup" - }, + "url": "https://supabase.com/docs/reference/dart/file-buckets-createsignedurl" + } + ], + "resultChars": 66039 + } + ] + }, + "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", + "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-storage-001-private-bucket-access.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "build-tests-001-rls-tenant-isolation", + "stage": "build", + "product": [ + "database" + ], + "topic": [ + "tests", + "rls" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "pgTAP test file(s) written under supabase/tests/", + "passed": true, + "notes": "1 file(s): supabase/tests/tenant_isolation_test.sql" + }, + { + "name": "pgTAP isolation tests ran and pass", + "passed": true, + "notes": "6 passed, 4 failed" + }, + { + "name": "agent correctly identifies the posts isolation bug from test results", + "passed": true, + "judgeNotes": "Correctly identifies the `posts` policy’s missing organization correlation and cites the failing cross-tenant pgTAP assertion. It does not blame `notes` and treats test results as authoritative." + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Row Level Security database testing pgTAP auth.uid tenant isolation policies\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" + "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", + "title": "Advanced pgTAP Testing" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#generate-keys-and-secrets", - "title": "Generate keys and secrets" + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase", - "title": "Configuring and securing Supabase" + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#manual-installation", - "title": "Manual installation" + "url": "https://supabase.com/docs/guides/database/extensions/pgtap", + "title": "pgTAP: Unit Testing" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#quick-start-linux", - "title": "Quick start (Linux)" - }, + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + } + ], + "resultChars": 81583 + } + ] + }, + "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", + "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-tests-001-rls-tenant-isolation.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "build-vectors-001-rag-with-permissions", + "stage": "build", + "product": [ + "database", + "vectors" + ], + "topic": [ + "sql", + "rls" + ], + "suite": "benchmark", + "interface": "mcp", + "passed": true, + "checks": [ + { + "name": "document_sections.embedding is vector(384)", + "passed": true, + "notes": "vector(384)" + }, + { + "name": "HNSW index on the embedding column", + "passed": true, + "notes": "CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" + }, + { + "name": "index operator class matches the search operator", + "passed": true, + "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_hnsw_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops) WHERE (embedding IS NOT NULL)" + }, + { + "name": "user A search returns only own sections, best match first", + "passed": true + }, + { + "name": "user B search returns only own sections, best match first", + "passed": true + }, + { + "name": "user A reads only own sections through the API", + "passed": true + }, + { + "name": "user A reads only own documents through the API", + "passed": true + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"pgvector semantic search match_documents row level security auth.uid owner embeddings HNSW\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker#installing-supabase", - "title": "Installing Supabase" + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#system-requirements", - "title": "System requirements" + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/ai/hybrid-search", + "title": "Hybrid search" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#contents", - "title": "Contents" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#exposing-your-postgres-database", - "title": "Exposing your Postgres database" - }, + "url": "https://supabase.com/docs/guides/ai/vector-indexes", + "title": "Vector indexes" + } + ], + "resultChars": 74718 + } + ] + }, + "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", + "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/build-vectors-001-rag-with-permissions.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "deploy-database-001-prometheus-metrics", + "stage": "deploy", + "product": [ + "database" + ], + "topic": [ + "observability" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "preserved existing app scrape job", + "passed": true + }, + { + "name": "configured the Supabase Metrics API scrape correctly", + "passed": true, + "judgeNotes": "Meets all requirements: HTTPS Supabase target, correct metrics path, Basic Auth with password_file, matching Compose secret mount, and preserved app scrape." + }, + { + "name": "documented live deployment and verification steps", + "passed": true, + "judgeNotes": "README provides Secret API key creation, matching secret-file placement, Compose startup/recreation steps, and concrete verification through Prometheus targets with 401 troubleshooting." + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Prometheus metrics endpoint customer v1 privileged metrics service_role basic auth self-hosted scrape configuration\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-log_min_messages-in-postgres", - "title": "Setting log_min_messages in Postgres" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#using-file-backend-in-storage-on-macos", - "title": "Using file backend in Storage on macOS" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-ai-assistant", - "title": "Configuring Supabase AI Assistant" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres-through-supavisor", - "title": "Accessing Postgres through Supavisor" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-s3-storage", - "title": "Configuring S3 Storage" - }, + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" + } + ], + "resultChars": 20609 + } + ] + }, + "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", + "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/deploy-database-001-prometheus-metrics.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "deploy-functions-001-edge-function-secrets", + "stage": "deploy", + "product": [ + "edge-functions" + ], + "topic": [ + "security" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "WEATHER_API_KEY is set as a Function secret on the project", + "passed": true + }, + { + "name": "the weather function is deployed to the project", + "passed": true, + "notes": "status ACTIVE" + }, + { + "name": "the weather function reads WEATHER_API_KEY from the environment", + "passed": true, + "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + }, + { + "name": "WEATHER_API_KEY value is not committed to the repo", + "passed": true + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Edge Functions environment variables secrets deploy supabase functions secrets set env file Deno.env.get\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-an-email-server", - "title": "Configuring an email server" + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-phone-login-sms-and-mfa", - "title": "Configuring phone login, SMS, and MFA" + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-social-login-oauth-providers", - "title": "Configuring social login (OAuth) providers" + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", + "title": "Transcription Telegram Bot" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-services", - "title": "Configuring Supabase services" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-secrets", - "title": "Configuring secrets" - }, + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-generate-speech-stream", + "title": "Streaming Speech with ElevenLabs" + } + ], + "resultChars": 37900 + } + ] + }, + "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", + "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", + "attempts": 1, + "sourcePath": "codex-gpt-5.6-no-skills/deploy-functions-001-edge-function-secrets.json" + }, + { + "experiment": "codex-gpt-5.6-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "codex", + "modelProvider": "openai", + "modelId": "gpt-5.6-sol", + "reasoningEffort": "medium" + }, + "eval": "deploy-self-hosting-001-docker-compose", + "stage": "deploy", + "product": [ + "database", + "auth", + "storage" + ], + "topic": [ + "self-hosting" + ], + "suite": "benchmark", + "interface": "cli", + "passed": true, + "checks": [ + { + "name": "cloned the self-host stack (docker-compose.yml + volumes/db)", + "passed": true + }, + { + "name": "didn't conflate with the CLI (no supabase/config.toml in the stack)", + "passed": true + }, + { + "name": "secrets rotated off the shipped defaults", + "passed": true + }, + { + "name": "ANON_KEY and SERVICE_ROLE_KEY are HS256 JWTs signed by JWT_SECRET", + "passed": true + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"self-hosting Docker compose docker environment variables JWT secret anon key service role key postgres password dashboard username password pooler secret encryption key SMTP\", limit: 10) { nodes { __typename title href content ... on Guide { subsections { nodes { title href content } } } } } }", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker#changing-database-password", - "title": "Changing database password" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-database-password", - "title": "Setting database password" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#environment-variables-configuration", + "title": "Environment variables configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#architecture", - "title": "Architecture" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#verifying-the-setup", + "title": "Verifying the setup" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#advanced-topics", - "title": "Advanced topics" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#new-api-keys-format", + "title": "New API keys format" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#uninstalling", - "title": "Uninstalling" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#adding-the-new-keys", + "title": "Adding the new keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#updating", - "title": "Updating" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#before-you-begin", + "title": "Before you begin" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-the-stack", - "title": "Managing the stack" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#additional-resources", + "title": "Additional resources" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-https", - "title": "Configuring HTTPS" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#authenticated-requests-user-session-jwt", + "title": "Authenticated requests (user session JWT)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#enabling-analytics", - "title": "Enabling analytics" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#unauthenticated-requests-api-key-only-no-user-session-jwt", + "title": "Unauthenticated requests (API key only, no user session JWT)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-apis", - "title": "Accessing APIs" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#request-flows", + "title": "Request flows" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-edge-functions", - "title": "Accessing Edge Functions" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#kong-api-gateway-routing", + "title": "Kong API gateway routing" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres", - "title": "Accessing Postgres" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#what-client-sdk-sends", + "title": "What client SDK sends" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-supabase-studio-dashboard", - "title": "Accessing Supabase Studio (Dashboard)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#how-it-works", + "title": "How it works" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#demo", - "title": "Demo" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#regenerating-asymmetric-key-pair", + "title": "Regenerating asymmetric key pair" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-your-secrets", - "title": "Managing your secrets" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#rotating-the-new-api-keys", + "title": "Rotating the new API keys" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#starting-and-stopping", - "title": "Starting and stopping" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#backward-compatibility", + "title": "Backward compatibility" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#studio-authentication", - "title": "Studio authentication" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#differences-from-the-supabase-platform", + "title": "Differences from the Supabase platform" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#where-to-find-your-credentials", - "title": "Where to find your credentials" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access", + "title": "Remove Superuser Access from Studio" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configure-supabase-urls", - "title": "Configure Supabase URLs" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#verify-roles", + "title": "Verify roles" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#step-3-restart-supabase", + "title": "Step 3: Restart Supabase" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#memory-or-timeout-errors", - "title": "Memory or timeout errors" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#step-2-update-environment-variables-in-docker-composeyml", + "title": "Step 2: Update environment variables in docker-compose.yml" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#custom-env-vars-not-available-in-functions", - "title": "Custom env vars not available in functions" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#step-1-update-database-object-ownership", + "title": "Step 1: Update database object ownership" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#changes-to-function-code-not-reflected-after-editing", - "title": "Changes to function code not reflected after editing" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#changing-the-configuration", + "title": "Changing the configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#500-error-on-invocation", - "title": "500 error on invocation" + "url": "https://supabase.com/docs/guides/self-hosting/remove-superuser-access#overview", + "title": "Overview" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#copying-functions-from-supabase-platform", - "title": "Copying functions from Supabase platform" + "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-the-stack", + "title": "Managing the stack" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#deploying-functions-to-a-remote-server", - "title": "Deploying functions to a remote server" + "url": "https://supabase.com/docs/guides/self-hosting/docker#quick-start-linux", + "title": "Quick start (Linux)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#managing-functions-via-dashboard", - "title": "Managing functions via dashboard" + "url": "https://supabase.com/docs/guides/self-hosting/docker#manual-installation", + "title": "Manual installation" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#internal-vs-external-urls", - "title": "Internal vs external URLs" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase", + "title": "Configuring and securing Supabase" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#calling-supabase-services-from-functions", - "title": "Calling Supabase services from functions" + "url": "https://supabase.com/docs/guides/self-hosting/docker#generate-keys-and-secrets", + "title": "Generate keys and secrets" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#accessing-variables-in-functions", - "title": "Accessing variables in functions" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configure-supabase-urls", + "title": "Configure Supabase URLs" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#using-inline-environment-variables", - "title": "Using inline environment variables" + "url": "https://supabase.com/docs/guides/self-hosting/docker#where-to-find-your-credentials", + "title": "Where to find your credentials" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#using-an-env-file-recommended", - "title": "Using an env file (recommended)" + "url": "https://supabase.com/docs/guides/self-hosting/docker#studio-authentication", + "title": "Studio authentication" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#custom-environment-variables", - "title": "Custom environment variables" + "url": "https://supabase.com/docs/guides/self-hosting/docker#starting-and-stopping", + "title": "Starting and stopping" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-3-invoke-your-function", - "title": "Step 3: Invoke your function" + "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-supabase-studio-dashboard", + "title": "Accessing Supabase Studio (Dashboard)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-2-restart-the-functions-service-to-pick-up-the-new-function", - "title": "Step 2: Restart the functions service to pick up the new function" + "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres", + "title": "Accessing Postgres" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-1-add-a-new-function-directory-and-the-function-code", - "title": "Step 1: Add a new function directory and the function code" + "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-edge-functions", + "title": "Accessing Edge Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#create-a-new-function", - "title": "Create a new function" + "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-apis", + "title": "Accessing APIs" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#invoke-the-default-function", - "title": "Invoke the default function" + "url": "https://supabase.com/docs/guides/self-hosting/docker#enabling-analytics", + "title": "Enabling analytics" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates", - "title": "Custom Email Templates" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-https", + "title": "Configuring HTTPS" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-1-create-a-templates-directory", - "title": "Step 1: Create a templates directory" + "url": "https://supabase.com/docs/guides/self-hosting/docker#demo", + "title": "Demo" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#overview", - "title": "Overview" + "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-your-secrets", + "title": "Managing your secrets" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#authentication-email-templates", - "title": "Authentication email templates" + "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-log_min_messages-in-postgres", + "title": "Setting log_min_messages in Postgres" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#example", - "title": "Example" + "url": "https://supabase.com/docs/guides/self-hosting/docker#exposing-your-postgres-database", + "title": "Exposing your Postgres database" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-2-update-docker-composeyml", - "title": "Step 2: Update docker-compose.yml" + "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres-through-supavisor", + "title": "Accessing Postgres through Supavisor" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#what-this-configuration-does", - "title": "What this configuration does" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-ai-assistant", + "title": "Configuring Supabase AI Assistant" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-3-restart-containers", - "title": "Step 3: Restart containers" + "url": "https://supabase.com/docs/guides/self-hosting/docker#using-file-backend-in-storage-on-macos", + "title": "Using file backend in Storage on macOS" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#notification-email-templates", - "title": "Notification email templates" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-s3-storage", + "title": "Configuring S3 Storage" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#example-1", - "title": "Example" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-an-email-server", + "title": "Configuring an email server" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-1-create-the-templates-directory", - "title": "Step 1: Create the templates directory" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-phone-login-sms-and-mfa", + "title": "Configuring phone login, SMS, and MFA" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-2-update-docker-composeyml-1", - "title": "Step 2: Update docker-compose.yml" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-social-login-oauth-providers", + "title": "Configuring social login (OAuth) providers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-3-restart-containers-1", - "title": "Step 3: Restart containers" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-services", + "title": "Configuring Supabase services" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", - "title": "Configure S3 Storage" + "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-secrets", + "title": "Configuring secrets" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#signature-mismatch-errors", - "title": "Signature mismatch errors" + "url": "https://supabase.com/docs/guides/self-hosting/docker#changing-database-password", + "title": "Changing database password" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#test-with-the-aws-cli", - "title": "Test with the AWS CLI" + "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-database-password", + "title": "Setting database password" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#test-with-rclone", - "title": "Test with rclone" + "url": "https://supabase.com/docs/guides/self-hosting/docker#architecture", + "title": "Architecture" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#how-to-configure-an-s3-backend", - "title": "How to configure an S3 backend" + "url": "https://supabase.com/docs/guides/self-hosting/docker#advanced-topics", + "title": "Advanced topics" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-rustfs", - "title": "Using RustFS" + "url": "https://supabase.com/docs/guides/self-hosting/docker#uninstalling", + "title": "Uninstalling" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-minio", - "title": "Using MinIO" + "url": "https://supabase.com/docs/guides/self-hosting/docker#updating", + "title": "Updating" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-aws-s3", - "title": "Using AWS S3" + "url": "https://supabase.com/docs/guides/self-hosting/docker#contents", + "title": "Contents" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#s3-compatible-providers", - "title": "S3-compatible providers" + "url": "https://supabase.com/docs/guides/self-hosting/docker#before-you-begin", + "title": "Before you begin" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#verify", - "title": "Verify" + "url": "https://supabase.com/docs/guides/self-hosting/docker#system-requirements", + "title": "System requirements" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#session-token", - "title": "Session token" + "url": "https://supabase.com/docs/guides/self-hosting/docker#installing-supabase", + "title": "Installing Supabase" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth", + "title": "Configure Social Login (OAuth) Providers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#tus-upload-errors-on-cloudflare-r2", - "title": "TUS upload errors on Cloudflare R2" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#nonce-check-failure-on-mobile-google-sign-in", + "title": "Nonce check failure on mobile (Google Sign In)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#permission-denied-on-uploads", - "title": "Permission denied on uploads" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#site-url-or-redirect-url-errors-after-login", + "title": "Site URL or redirect URL errors after login" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#upload-urls-point-to-localhost", - "title": "Upload URLs point to localhost" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#variables-added-to-the-environment-but-provider-still-not-working", + "title": "Variables added to the environment but provider still not working" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#additional-resources", - "title": "Additional resources" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#before-you-begin", + "title": "Before you begin" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#enable-the-s3-protocol-endpoint", - "title": "Enable the S3 protocol endpoint" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#oauth-request-flow", + "title": "OAuth request flow" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17", - "title": "Upgrade to Postgres 17" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#auth-environment-variables", + "title": "Auth environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#new-deployment-with-postgres-17", - "title": "New deployment with Postgres 17" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#other-supported-providers", + "title": "Other supported providers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#provider-specific-setup", + "title": "Provider-specific setup" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#run-the-upgrade", - "title": "Run the upgrade" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-5-verify-the-configuration", + "title": "Step 5: Verify the configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#restoring-from-a-manual-backup", - "title": "Restoring from a manual backup" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-4-restart-the-auth-service", + "title": "Step 4: Restart the auth service" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#postgres-17-fails-to-start-with-a-leftover-db-config-volume", - "title": "Postgres 17 fails to start with a leftover db-config volume" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-3-enable-the-matching-lines-in-docker-compose-configuration", + "title": "Step 3: Enable the matching lines in Docker Compose configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#disk-space-issues-during-upgrade", - "title": "Disk space issues during upgrade" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-2-configure-environment-variables", + "title": "Step 2: Configure environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#services-fail-to-connect-after-upgrade", - "title": "Services fail to connect after upgrade" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-1-register-your-app-with-the-provider", + "title": "Step 1: Register your app with the provider" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#pgsodium--supabase-vault-errors", - "title": "pgsodium / Supabase Vault errors" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#step-by-step-configuration", + "title": "Step-by-step configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#pg_upgrade-fails-with-replication-slot-errors", - "title": "pg_upgrade fails with replication slot errors" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#troubleshooting", + "title": "Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#test-the-login-flow", + "title": "Test the login flow" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#upgrade-process-details", - "title": "Upgrade process details" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#additional-resources", + "title": "Additional resources" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#custom-postgres-configuration", - "title": "Custom Postgres configuration" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#environment-variable-reference", + "title": "Environment variable reference" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#rollback", - "title": "Rollback" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#auth-service-fails-to-start", + "title": "Auth service fails to start" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#after-the-upgrade", - "title": "After the upgrade" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#extensions-removed-in-postgres-17", - "title": "Extensions removed in Postgres 17" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#custom-env-vars-not-available-in-functions", + "title": "Custom env vars not available in functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#requirements", - "title": "Requirements" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#changes-to-function-code-not-reflected-after-editing", + "title": "Changes to function code not reflected after editing" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#create-a-backup", - "title": "Create a backup" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#500-error-on-invocation", + "title": "500 error on invocation" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#what-the-upgrade-does", - "title": "What the upgrade does" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#troubleshooting", + "title": "Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#upgrade-an-existing-postgres-15-deployment", - "title": "Upgrade an existing Postgres 15 deployment" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#copying-functions-from-supabase-platform", + "title": "Copying functions from Supabase platform" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#provider-not-enabled-or-provider-seen-as-false-in-settings" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#deploying-functions-to-a-remote-server", + "title": "Deploying functions to a remote server" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#401-invalid-jwt" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#managing-functions-via-dashboard", + "title": "Managing functions via dashboard" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#400-missing-function-name-in-request" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#internal-vs-external-urls", + "title": "Internal vs external URLs" }, { - "url": "https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17#permission-denied-on-the-data-directory" - } - ], - "resultChars": 450330 - }, - { - "source": "search_docs", - "query": "query { searchDocs(query: \"Docker self-hosting quick start Linux git clone supabase docker copy .env.example generate-keys.sh\", limit: 5) { nodes { ... on Guide { title href content subsections { nodes { title href content } } } } } }", - "hasContent": true, - "pages": [ + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#calling-supabase-services-from-functions", + "title": "Calling Supabase services from functions" + }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker", - "title": "Self-Hosting with Docker" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#accessing-variables-in-functions", + "title": "Accessing variables in functions" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-ai-assistant", - "title": "Configuring Supabase AI Assistant" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#using-inline-environment-variables", + "title": "Using inline environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#changing-database-password", - "title": "Changing database password" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#using-an-env-file-recommended", + "title": "Using an env file (recommended)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-secrets", - "title": "Configuring secrets" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#custom-environment-variables", + "title": "Custom environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-supabase-services", - "title": "Configuring Supabase services" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-3-invoke-your-function", + "title": "Step 3: Invoke your function" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-social-login-oauth-providers", - "title": "Configuring social login (OAuth) providers" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-2-restart-the-functions-service-to-pick-up-the-new-function", + "title": "Step 2: Restart the functions service to pick up the new function" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-phone-login-sms-and-mfa", - "title": "Configuring phone login, SMS, and MFA" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#step-1-add-a-new-function-directory-and-the-function-code", + "title": "Step 1: Add a new function directory and the function code" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-an-email-server", - "title": "Configuring an email server" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#create-a-new-function", + "title": "Create a new function" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-s3-storage", - "title": "Configuring S3 Storage" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#invoke-the-default-function", + "title": "Invoke the default function" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#using-file-backend-in-storage-on-macos", - "title": "Using file backend in Storage on macOS" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#memory-or-timeout-errors", + "title": "Memory or timeout errors" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres-through-supavisor", - "title": "Accessing Postgres through Supavisor" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates", + "title": "Custom Email Templates" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#exposing-your-postgres-database", - "title": "Exposing your Postgres database" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#authentication-email-templates", + "title": "Authentication email templates" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-log_min_messages-in-postgres", - "title": "Setting log_min_messages in Postgres" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#overview", + "title": "Overview" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-your-secrets", - "title": "Managing your secrets" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#example", + "title": "Example" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#demo", - "title": "Demo" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-1-create-a-templates-directory", + "title": "Step 1: Create a templates directory" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#contents", - "title": "Contents" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-2-update-docker-composeyml", + "title": "Step 2: Update docker-compose.yml" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#what-this-configuration-does", + "title": "What this configuration does" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#system-requirements", - "title": "System requirements" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-3-restart-containers", + "title": "Step 3: Restart containers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#installing-supabase", - "title": "Installing Supabase" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#example-1", + "title": "Example" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#quick-start-linux", - "title": "Quick start (Linux)" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#notification-email-templates", + "title": "Notification email templates" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#manual-installation", - "title": "Manual installation" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-3-restart-containers-1", + "title": "Step 3: Restart containers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase", - "title": "Configuring and securing Supabase" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-2-update-docker-composeyml-1", + "title": "Step 2: Update docker-compose.yml" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#generate-keys-and-secrets", - "title": "Generate keys and secrets" + "url": "https://supabase.com/docs/guides/self-hosting/custom-email-templates#step-1-create-the-templates-directory", + "title": "Step 1: Create the templates directory" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configure-supabase-urls", - "title": "Configure Supabase URLs" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa", + "title": "Configure Phone Login & MFA" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#where-to-find-your-credentials", - "title": "Where to find your credentials" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#otp-expires-too-quickly", + "title": "OTP expires too quickly" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#studio-authentication", - "title": "Studio authentication" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#before-you-begin", + "title": "Before you begin" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#starting-and-stopping", - "title": "Starting and stopping" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#sms-provider-configuration", + "title": "SMS provider configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-supabase-studio-dashboard", - "title": "Accessing Supabase Studio (Dashboard)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#step-1-uncomment-and-configure-the-environment-variables", + "title": "Step 1: Uncomment and configure the environment variables" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres", - "title": "Accessing Postgres" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#step-2-uncomment-the-matching-lines-in-docker-compose-configuration", + "title": "Step 2: Uncomment the matching lines in Docker Compose configuration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-edge-functions", - "title": "Accessing Edge Functions" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#step-3-restart-the-auth-service", + "title": "Step 3: Restart the auth service" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#accessing-apis", - "title": "Accessing APIs" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#step-4-verify", + "title": "Step 4: Verify" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#enabling-analytics", - "title": "Enabling analytics" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#otp-settings", + "title": "OTP settings" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#configuring-https", - "title": "Configuring HTTPS" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#expiration", + "title": "Expiration" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#managing-the-stack", - "title": "Managing the stack" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#length", + "title": "Length" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#updating", - "title": "Updating" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#rate-limiting", + "title": "Rate limiting" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#uninstalling", - "title": "Uninstalling" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#test-otps-for-development", + "title": "Test OTPs for development" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#advanced-topics", - "title": "Advanced topics" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#multi-factor-authentication-mfa", + "title": "Multi-factor authentication (MFA)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#architecture", - "title": "Architecture" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#app-authenticator-totp", + "title": "App authenticator (TOTP)" }, { - "url": "https://supabase.com/docs/guides/self-hosting/docker#setting-database-password", - "title": "Setting database password" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#phone-mfa", + "title": "Phone MFA" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#maximum-enrolled-factors", + "title": "Maximum enrolled factors" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#how-it-works", - "title": "How it works" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#troubleshooting", + "title": "Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#sms-not-being-delivered", + "title": "SMS not being delivered" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#adding-the-new-keys", - "title": "Adding the new keys" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#variables-added-to-the-environment-but-not-working", + "title": "Variables added to the environment but not working" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#new-api-keys-format", - "title": "New API keys format" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#rate-limit-errors", + "title": "Rate limit errors" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#verifying-the-setup", - "title": "Verifying the setup" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa#additional-resources", + "title": "Additional resources" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#environment-variables-configuration", - "title": "Environment variables configuration" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#differences-from-the-supabase-platform", - "title": "Differences from the Supabase platform" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#dashboard-basic-auth", + "title": "Dashboard basic auth" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#backward-compatibility", - "title": "Backward compatibility" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#opaque-key-translation", + "title": "Opaque key translation" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#rotating-the-new-api-keys", - "title": "Rotating the new API keys" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#api-key-enforcement-on-protected-routes", + "title": "API key enforcement on protected routes" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#regenerating-asymmetric-key-pair", - "title": "Regenerating asymmetric key pair" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#cors", + "title": "CORS" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#what-client-sdk-sends", - "title": "What client SDK sends" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#common-issues", + "title": "Common issues" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#kong-api-gateway-routing", - "title": "Kong API gateway routing" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#x-forwarded-headers", + "title": "X-Forwarded headers" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#request-flows", - "title": "Request flows" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#forwarded-headers-and-cors", + "title": "Forwarded headers and CORS" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#unauthenticated-requests-api-key-only-no-user-session-jwt", - "title": "Unauthenticated requests (API key only, no user session JWT)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#see-also", + "title": "See also" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#authenticated-requests-user-session-jwt", - "title": "Authenticated requests (user session JWT)" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#logs", + "title": "Logs" }, { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys#additional-resources", - "title": "Additional resources" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#troubleshooting", + "title": "Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows", - "title": "Local development workflow" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#admin-interface", + "title": "Admin interface" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-4-add-seed-data", - "title": "Step 4: Add seed data" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#customizing-the-configuration", + "title": "Customizing the configuration" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-5-verify", - "title": "Step 5: Verify" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#security-hardening", + "title": "Security hardening" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-6-commit", - "title": "Step 6: Commit" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#before-you-begin", + "title": "Before you begin" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#the-daily-workflow", - "title": "The daily workflow" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#enabling-the-envoy-gateway", + "title": "Enabling the Envoy gateway" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#making-schema-changes", - "title": "Making schema changes" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#verify", + "title": "Verify" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#generating-types", - "title": "Generating types" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#architecture", + "title": "Architecture" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#staying-in-sync-with-your-team", - "title": "Staying in sync with your team" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#configuration-file-structure", + "title": "Configuration file structure" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#pushing-to-a-remote-project", - "title": "Pushing to a remote project" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#how-the-configuration-is-rendered-at-startup", + "title": "How the configuration is rendered at startup" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#resetting-a-remote-dev-or-staging-project", - "title": "Resetting a remote dev or staging project" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#routes", + "title": "Routes" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#key-commands-at-a-glance", - "title": "Key commands at a glance" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy#authentication", + "title": "Authentication" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#cleaning-up-generated-migrations", - "title": "Cleaning up generated migrations" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#grants", - "title": "Grants" + "url": "https://supabase.com/docs/guides/auth/signing-keys#why-are-anon-and-service_role-jwt-based-keys-no-longer-recommended", + "title": "Why are anon and service_role JWT-based keys no longer recommended?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#revokere-grant-patterns", - "title": "Revoke/re-grant patterns" + "url": "https://supabase.com/docs/guides/auth/signing-keys#why-is-it-not-possible-to-extract-the-private-key-or-shared-secret-from-supabase", + "title": "Why is it not possible to extract the private key or shared secret from Supabase?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#extension-statements", - "title": "Extension statements" + "url": "https://supabase.com/docs/guides/auth/signing-keys#frequently-asked-questions", + "title": "Frequently asked questions" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#known-limitations-of-db-diff", - "title": "Known limitations of db diff" + "url": "https://supabase.com/docs/guides/auth/signing-keys#choosing-the-right-signing-algorithm", + "title": "Choosing the right signing algorithm" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#troubleshooting", - "title": "Troubleshooting" + "url": "https://supabase.com/docs/guides/auth/signing-keys#public-key-discovery-and-caching", + "title": "Public key discovery and caching" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-3-create-your-schema", - "title": "Step 3: Create your schema" + "url": "https://supabase.com/docs/guides/auth/signing-keys#lifetime-of-a-signing-key", + "title": "Lifetime of a signing key" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-2-start-the-local-stack", - "title": "Step 2: Start the local stack" + "url": "https://supabase.com/docs/guides/auth/signing-keys#rotating-and-revoking-keys", + "title": "Rotating and revoking keys" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-1-initialize-1", - "title": "Step 1: Initialize" + "url": "https://supabase.com/docs/guides/auth/signing-keys#getting-started", + "title": "Getting started" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#start-a-new-project-from-scratch", - "title": "Start a new project from scratch" + "url": "https://supabase.com/docs/guides/auth/signing-keys#benefits-of-the-signing-keys-system", + "title": "Benefits of the signing keys system" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-7-commit", - "title": "Step 7: Commit" + "url": "https://supabase.com/docs/guides/auth/signing-keys#overview", + "title": "Overview" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-6-verify", - "title": "Step 6: Verify" + "url": "https://supabase.com/docs/guides/auth/signing-keys#using-jwt-based-anon-key-in-a-mobile-desktop-or-cli-application-and-need-to-rotate-a-service_role-jwt-secret", + "title": "Using JWT-based anon key in a mobile, desktop, or CLI application and need to rotate a service_role JWT secret?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-5-create-seed-data", - "title": "Step 5: Create seed data" + "url": "https://supabase.com/docs/guides/auth/signing-keys#why-does-revoking-the-legacy-jwt-secret-require-disabling-of-anon-and-service_role-api-keys", + "title": "Why does revoking the legacy JWT secret require disabling of anon and service_role API keys?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-4-pull-the-remote-schema", - "title": "Step 4: Pull the remote schema" + "url": "https://supabase.com/docs/guides/auth/signing-keys#why-is-deleting-the-legacy-jwt-secret-disallowed", + "title": "Why is deleting the legacy JWT secret disallowed?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-3-link-to-your-remote-project", - "title": "Step 3: Link to your remote project" + "url": "https://supabase.com/docs/guides/auth/signing-keys#why-is-a-5-minute-wait-imposed-when-changing-signing-key-states", + "title": "Why is a 5 minute wait imposed when changing signing key states?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-2-authenticate", - "title": "Step 2: Authenticate" + "url": "https://supabase.com/docs/guides/auth/signing-keys#how-to-create-mint-jwts-if-access-to-the-private-key-or-shared-secret-is-not-possible", + "title": "How to create (mint) JWTs if access to the private key or shared secret is not possible?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#before-you-begin", - "title": "Before you begin" + "url": "https://supabase.com/docs/guides/auth/signing-keys#how-are-publishable-and-secret-keys-implemented-on-the-hosted-platform", + "title": "How are publishable and secret keys implemented on the hosted platform?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#the-supabase-directory", - "title": "The ./supabase directory" + "url": "https://supabase.com/docs/guides/auth/signing-keys#how-to-deactivate-the-anon-and-service_role-jwt-based-api-keys-after-moving-to-publishable-and-secret-keys", + "title": "How to deactivate the anon and service_role JWT-based API keys after moving to publishable and secret keys?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#move-an-existing-project-to-local-development", - "title": "Move an existing project to local development" + "url": "https://supabase.com/docs/guides/auth/signing-keys#can-you-still-use-an-old-anon-and-service-role-api-keys-after-enabling-the-publishable-and-secret-keys", + "title": "Can you still use an old anon and service-role API keys after enabling the publishable and secret keys?" }, { - "url": "https://supabase.com/docs/guides/local-development/cli-workflows#step-1-initialize", - "title": "Step 1: Initialize" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started", - "title": "Supabase CLI" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#upload-urls-point-to-localhost", + "title": "Upload URLs point to localhost" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#how-to-opt-out", - "title": "How to opt out" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#test-with-the-aws-cli", + "title": "Test with the AWS CLI" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#telemetry", - "title": "Telemetry" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#test-with-rclone", + "title": "Test with rclone" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#stopping-local-services", - "title": "Stopping local services" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#how-to-configure-an-s3-backend", + "title": "How to configure an S3 backend" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#access-your-projects-services", - "title": "Access your project's services" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-rustfs", + "title": "Using RustFS" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#running-supabase-locally", - "title": "Running Supabase locally" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-minio", + "title": "Using MinIO" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#updating-the-supabase-cli", - "title": "Updating the Supabase CLI" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#using-aws-s3", + "title": "Using AWS S3" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#beta-channel", - "title": "Beta channel" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#s3-compatible-providers", + "title": "S3-compatible providers" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#installing-the-supabase-cli", - "title": "Installing the Supabase CLI" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#verify", + "title": "Verify" }, { - "url": "https://supabase.com/docs/guides/local-development/cli/getting-started#learn-more", - "title": "Learn more" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#session-token", + "title": "Session token" }, { - "url": "https://supabase.com/docs/guides/self-hosting", - "title": "Self-Hosting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#troubleshooting", + "title": "Troubleshooting" }, { - "url": "https://supabase.com/docs/guides/self-hosting#community-driven-projects", - "title": "Community-driven projects" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#signature-mismatch-errors", + "title": "Signature mismatch errors" }, { - "url": "https://supabase.com/docs/guides/self-hosting#about-self-hosting", - "title": "About self-hosting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#tus-upload-errors-on-cloudflare-r2", + "title": "TUS upload errors on Cloudflare R2" }, { - "url": "https://supabase.com/docs/guides/self-hosting#how-self-hosted-supabase-differs", - "title": "How self-hosted Supabase differs" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#permission-denied-on-uploads", + "title": "Permission denied on uploads" }, { - "url": "https://supabase.com/docs/guides/self-hosting#your-responsibilities-when-self-hosting", - "title": "Your responsibilities when self-hosting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#enable-the-s3-protocol-endpoint", + "title": "Enable the S3 protocol endpoint" }, { - "url": "https://supabase.com/docs/guides/self-hosting#telemetry", - "title": "Telemetry" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3#additional-resources", + "title": "Additional resources" }, { - "url": "https://supabase.com/docs/guides/self-hosting#support-and-community", - "title": "Support and community" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-oauth#provider-not-enabled-or-provider-seen-as-false-in-settings" }, { - "url": "https://supabase.com/docs/guides/self-hosting#enterprise-self-hosting", - "title": "Enterprise self-hosting" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#401-invalid-jwt" }, { - "url": "https://supabase.com/docs/guides/self-hosting#get-started", - "title": "Get started" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions#400-missing-function-name-in-request" } ], - "resultChars": 353761 + "resultChars": 614741 } ] }, @@ -19144,7 +20183,7 @@ { "name": "diagnosed and explained session revocation", "passed": true, - "judgeNotes": "Meets rubric: identifies soft-delete-only root cause, implements auth user deletion plus RLS live-account gate, correctly explains JWTs remain cryptographically valid while protected data path has no post-commit window due to RLS, and correctly distinguishes publishable frontend keys from secret backend-only RLS-bypassing keys." + "judgeNotes": "Correctly diagnoses the soft-delete flaw, implements Auth-user/session deletion plus RLS defense-in-depth, consistently explains JWT expiry behavior, and accurately distinguishes publishable and secret keys." } ], "skills": { @@ -19155,166 +20194,117 @@ "calls": [ { "source": "search_docs", - "query": "query { keys: searchDocs(query: \"publishable key secret key legacy anon service_role RLS frontend\", limit: 5) { nodes { ... on Guide { title href content } ... on ManagementApiReference { title href content } } } sessions: searchDocs(query: \"delete user access token remains valid until expiry session sign out JWT revoke\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } delete: searchDocs(query: \"delete user admin API JWT remains valid delete account\", limit: 5) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", + "query": "query { searchDocs(query: \"delete user auth admin deleteUser JWT session remains valid RLS publishable secret keys legacy anon service_role\", limit: 8) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" }, { "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", "title": "Migrating to publishable and secret API keys" }, - { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" - }, { "url": "https://supabase.com/docs/guides/auth/jwt-fields", "title": "JWT Claims Reference" }, { - "url": "https://supabase.com/docs/guides/database/secure-data", - "title": "Securing your data" - }, - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" + "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/should-i-set-a-shorter-max-age-parameter-on-the-cookies-8sbF4V", - "title": "Should I set a shorter Max-Age parameter on the cookies?" + "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0012_auth_allow_anonymous_sign_ins", + "title": "Database Advisor: Lint 0012_auth_allow_anonymous_sign_ins" }, { "url": "https://supabase.com/docs/guides/auth/managing-user-data", "title": "User Management" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" - }, - { - "url": "https://supabase.com/docs/guides/platform/sso/testing-best-practices", - "title": "SSO Testing and Best Practices" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" } ], - "resultChars": 230051 + "resultChars": 84675 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"API keys publishable secret key sb_publishable sb_secret RLS\", limit: 10) { nodes { ... on Guide { title href content } } } }", + "query": "query { searchDocs(query: \"publishable key secret key frontend safe RLS Authorization header bypass RLS\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", - "title": "New API Keys and Asymmetric Authentication" + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" }, { - "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", - "title": "Creating a Supabase client for SSR" + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", - "title": "Build a User Management App with RedwoodJS" + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", + "title": "Why is my service role key client getting RLS errors or not returning data?" }, { "url": "https://supabase.com/docs/guides/database/secure-data", "title": "Securing your data" }, { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", - "title": "Build a User Management App with SvelteKit" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-solidjs", - "title": "Build a User Management App with SolidJS" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-vue-3", - "title": "Build a User Management App with Vue 3" + "url": "https://supabase.com/docs/guides/realtime/getting_started", + "title": "Getting Started with Realtime" }, { - "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", - "title": "Token Security and Row Level Security" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" } ], - "resultChars": 225824 + "resultChars": 71041 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"sign out JWT remains valid until expires revoke refresh tokens access token\", limit: 8) { nodes { ... on Guide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"API keys publishable key sb_publishable frontend anon role secret key sb_secret service_role\", limit: 3) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/should-i-set-a-shorter-max-age-parameter-on-the-cookies-8sbF4V", - "title": "Should I set a shorter Max-Age parameter on the cookies?" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-signout" - }, { "url": "https://supabase.com/docs/guides/auth/signing-keys", "title": "JWT Signing Keys" }, { - "url": "https://supabase.com/docs/guides/auth/server-side/advanced-guide", - "title": "Advanced guide" - }, - { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/oauth-flows", - "title": "OAuth 2.1 Flows" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/how-do-i-make-the-cookies-httponly-vwweFx", - "title": "How do I make the cookies HttpOnly?" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", + "title": "Build a User Management App with RedwoodJS" } ], - "resultChars": 103031 + "resultChars": 74473 }, { "source": "search_docs", - "query": "query { searchDocs(query: \"admin deleteUser delete user existing JWT access token valid until expiry\", limit: 6) { nodes { ... on ClientLibraryFunctionReference { title href content language methodName } ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"supabase js signOut scope local current session local storage\", limit: 4) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" - }, - { - "url": "https://supabase.com/docs/guides/auth/sessions", - "title": "User sessions" + "url": "https://supabase.com/docs/guides/auth/signout", + "title": "Signing out" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" + "url": "https://supabase.com/docs/guides/auth/server-side", + "title": "Server-Side Rendering" }, { - "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" + "url": "https://supabase.com/docs/reference/javascript/auth-signout" }, { - "url": "https://supabase.com/docs/guides/auth/jwt-fields", - "title": "JWT Claims Reference" + "url": "https://supabase.com/docs/guides/auth/social-login/auth-azure", + "title": "Login with Azure (Microsoft)" } ], - "resultChars": 33037 + "resultChars": 30075 } ] }, @@ -19369,7 +20359,7 @@ { "name": "diagnosed missing publication membership", "passed": true, - "judgeNotes": "The assistant correctly identified that orders was absent from the supabase_realtime publication despite the channel being subscribed, applied exactly ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, preserved courier_locations and RLS/policies, and did not blame or alter RLS/client/networking." + "judgeNotes": "Correctly diagnosed orders missing from supabase_realtime, added only public.orders, verified courier_locations remained published, and preserved RLS/policies." } ], "skills": { @@ -19380,7 +20370,7 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Postgres Changes add table supabase_realtime publication ALTER PUBLICATION\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } } } }", + "query": "query { searchDocs(query: \"postgres_changes table replication publication enable Realtime supabase_realtime publication INSERT events\", limit: 5) { nodes { ... on Guide { title href content } ... on TroubleshootingGuide { title href content } ... on ClientLibraryFunctionReference { title href content language methodName } } } }", "hasContent": true, "pages": [ { @@ -19388,23 +20378,23 @@ "title": "Subscribing to Database Changes" }, { - "url": "https://supabase.com/docs/guides/realtime/postgres-changes", - "title": "Postgres Changes" + "url": "https://supabase.com/docs/guides/realtime/architecture", + "title": "Realtime Architecture" }, { "url": "https://supabase.com/docs/guides/database/replication/pipelines", "title": "Set up Pipelines" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", - "title": "Backup and Restore using the CLI" + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" }, { "url": "https://supabase.com/docs/guides/realtime/benchmarks", "title": "Benchmarks" } ], - "resultChars": 121815 + "resultChars": 89987 } ] }, @@ -19437,17 +20427,17 @@ { "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "judgeNotes": "Identified image-transform as affected and described eight intermittent HTTP 503s across 07:00–12:00 UTC on 2026-04-28, noting the recurring gateway pattern." + "judgeNotes": "Identified image-transform and the recurring eight HTTP 503 failures from 07:00–12:00 UTC on 2026-04-28." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": true, - "judgeNotes": "Attributes the 503s to the gateway/platform layer before function execution, grounded in gateway logs without corresponding Edge Function logs and nearby successful invocations on the same deployment. It also distinguishes the separate avatar-upload 500 as a runtime-level issue." + "judgeNotes": "Attributes the recurring image-transform 503s to the Edge gateway/platform before handler execution, supported by absent runtime logs and successful requests on the unchanged deployment. It also distinguishes avatar-upload’s function-level 500." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "Recommended concrete next steps, including escalating to Supabase support with request IDs and timestamps, plus retry and alerting actions." + "judgeNotes": "The assistant gave concrete next steps, including escalating to Supabase Support with specific timestamps and gateway IDs, capturing future request IDs, adding retries, and improving function error logging." } ], "skills": { @@ -19455,7 +20445,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Edge Functions 503 gateway request does not appear in function logs troubleshooting\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/status-codes", + "title": "Status codes" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", + "title": "Edge Function 503 error response" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", + "title": "Edge Function 504 error response" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-404-error-response", + "title": "Edge Function 404 error response" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/debugging", + "title": "Debugging guide" + } + ], + "resultChars": 47868 + } + ] }, "prompt": "Users have been reporting that image uploads are intermittently failing with server errors throughout the morning of `2026-04-28`.\n\nCan you investigate the project logs and tell me what is going on and what we\nshould do next?", "promptSourcePath": "evals/investigate-reliability-003-edge-function-5xx-correlation/PROMPT.md", @@ -19513,7 +20532,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "Diagnosed RLS deny-all due to no policies, kept RLS enabled, and created authenticated SELECT and INSERT policies scoped to user_id = auth.uid() with WITH CHECK for inserts." + "judgeNotes": "Correctly diagnosed deny-all RLS, kept RLS enabled, and created authenticated owner-scoped SELECT and INSERT policies using auth.uid() with USING/WITH CHECK." } ], "skills": { @@ -19521,7 +20540,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"Row Level Security policies auth.uid select insert Data API\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/features", + "title": "Features" + }, + { + "url": "https://supabase.com/docs/guides/local-development/testing/pgtap-extended", + "title": "Advanced pgTAP Testing" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" + } + ], + "resultChars": 93255 + } + ] }, "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", @@ -19572,7 +20620,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "Avatar migration was applied by `supabase db push --db-url \"$DB_URL\" --yes` in action #11, which succeeded and left remote migration history containing `20240220000000 | add_avatar_url`. The orphan bio migration was reconciled by adding local file `supabase/migrations/20240115000000_add_profile_bio.sql` in action #10, then running the same Supabase CLI push. No forbidden direct SQL mutation or prepared-statement workaround was seen; psql usage was read-only inspection." + "judgeNotes": "`supabase db push --db-url \"$DB_URL\" --workdir . --yes` applied `20240220000000_add_avatar_url.sql`, with output confirming “Applying migration” and “Finished supabase db push.” History was reconciled by adding local `20240115000000_add_profile_bio.sql`, aligning it with the existing remote migration, then running the same CLI push. The `psql` uses were read-only; no prohibited workaround was used." } ], "skills": { @@ -19583,37 +20631,37 @@ "calls": [ { "source": "search_docs", - "query": "query { searchDocs(query: \"Supabase CLI db push migration history mismatch repair deploy hosted project\", limit: 5) { nodes { __typename title href content } } }", + "query": "query { searchDocs(query: \"Supabase CLI db push migration history mismatch remote migration versions repair\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/deployment/database-migrations", - "title": "Database Migrations" - }, { "url": "https://supabase.com/docs/reference/cli/supabase-migration-repair", "title": "Repair the migration history table" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", - "title": "Backup and Restore using the CLI" - }, - { - "url": "https://supabase.com/docs/guides/local-development/database-migrations", - "title": "Database migrations" + "url": "https://supabase.com/docs/guides/deployment/database-migrations", + "title": "Database Migrations" }, { "url": "https://supabase.com/docs/guides/local-development/cli-workflows", "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/reference/cli/supabase-db-push", + "title": "Push new migrations to the remote database" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-within-supabase/backup-restore", + "title": "Backup and Restore using the CLI" } ], - "resultChars": 96189 + "resultChars": 84771 } ] }, "prompt": "I'm trying to ship a migration to our hosted project and it's not working. Can you figure out what's wrong and get it deployed?", "promptSourcePath": "evals/resolve-database-001-migration-history-mismatch/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "codex-gpt-5.6-no-skills/resolve-database-001-migration-history-mismatch.json" }, { @@ -19775,7 +20823,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user cbbc700e-775b-4489-94a7-6a2ce1ab7257, signUp returned {\"userId\":\"cbbc700e-775b-4489-94a7-6a2ce1ab7257\"}" + "notes": "db user e0365c26-b3e1-499a-9648-a3e98052cdaa, signUp returned {\"userId\":\"e0365c26-b3e1-499a-9648-a3e98052cdaa\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -19790,7 +20838,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"cbbc700e-775b-4489-94a7-6a2ce1ab7257\"}" + "notes": "{\"userId\":\"e0365c26-b3e1-499a-9648-a3e98052cdaa\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -19828,34 +20876,38 @@ "url": "https://supabase.com/changelog.md" } ], - "resultChars": 93795 + "resultChars": 94610 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"signUp email password user metadata display_name options data\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"signUp signInWithPassword email password user metadata display name supabase-js v2\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q", - "title": "Customizing Emails by Language" + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", + "title": "Migrate from Auth0 to Supabase Auth" }, { - "url": "https://supabase.com/docs/guides/auth/managing-user-data", - "title": "User Management" + "url": "https://supabase.com/docs/guides/auth/passwords", + "title": "Password-based Auth" }, { - "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/auth0", - "title": "Migrate from Auth0 to Supabase Auth" + "url": "https://supabase.com/docs/guides/auth/passkeys", + "title": "Passkey authentication" }, { - "url": "https://supabase.com/docs/guides/auth/auth-email-passwordless", - "title": "Passwordless email logins" + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-signup" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native", + "title": "Build a User Management App with Expo React Native" + }, + { + "url": "https://supabase.com/docs/guides/auth/social-login/auth-google", + "title": "Login with Google" } ], - "resultChars": 36311 + "resultChars": 155516 } ] }, @@ -19929,7 +20981,19 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + } + ] }, "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", @@ -20029,7 +21093,7 @@ { "name": "process-tasks function drains the queue", "passed": true, - "notes": "function removed the seeded message (id 3) from the queue" + "notes": "function removed the seeded message (id 6) from the queue" } ], "skills": { @@ -20044,39 +21108,68 @@ }, "docs": { "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, { "source": "search_docs", - "query": "{ searchDocs(query: \"pgmq queue cron schedule edge function pop read delete messages\", limit: 6) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"pg_cron schedule job every minute cron.schedule\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" }, { - "url": "https://supabase.com/docs/guides/queues/pgmq", - "title": "PGMQ Extension" + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" }, { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-sms-hook", + "title": "Send SMS Hook" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pg_net", - "title": "pg_net: Async Networking" + "url": "https://supabase.com/docs/guides/cron", + "title": "Cron" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook", + "title": "Send Email Hook" } ], - "resultChars": 68777 + "resultChars": 83290 }, { - "source": "shell_fetch", - "query": "curl -s https://supabase.com/changelog.md | grep -i -B2 -A2 \"breaking\" | grep -i -B1 -A1 -E \"cron|pgmq|queue|edge function\" | head -40; echo \"---done---\"", + "source": "search_docs", + "query": "{ searchDocs(query: \"Supabase Queues pgmq create queue send message edge function consume\", limit: 5) { nodes { title href content } } }", + "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/queues", + "title": "Supabase Queues" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/queues/api", + "title": "API" + }, + { + "url": "https://supabase.com/docs/guides/queues/quickstart", + "title": "Quickstart" } ], - "resultChars": 1492 + "resultChars": 18714 } ] }, @@ -20208,7 +21301,39 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"secret API key sb_secret REST API apikey Authorization header\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + } + ], + "resultChars": 52730 + } + ] }, "prompt": "Purchasing needs a restock alert. `app/restock.mjs` has the spec in a\ncomment — it runs in our Node backend worker and prints a JSON list of what\nneeds reordering, with who to email about it.\n\nThe data lives in the Supabase project in `supabase/` (already running\nlocally). Finish the script and make sure it prints the right alerts.", "promptSourcePath": "evals/build-dataapi-002-restock-alert-report/PROMPT.md", @@ -20337,30 +21462,30 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"edge function verify JWT auth getUser getClaims authorization header\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function get authenticated user from Authorization header auth.getUser\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", - "title": "Build a User Management App with Next.js" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" + "url": "https://supabase.com/docs/reference/javascript/auth-getuser" }, { "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", "title": "Integrating With Supabase Auth" }, { - "url": "https://supabase.com/docs/reference/javascript/auth-getclaims" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" + }, + { + "url": "https://supabase.com/docs/guides/functions/auth", + "title": "Securing Edge Functions" }, { - "url": "https://supabase.com/docs/reference/swift/auth-getclaims", - "title": "getClaims()" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs", + "title": "Build a User Management App with Next.js" } ], - "resultChars": 52010 + "resultChars": 58472 }, { "source": "web_fetch", @@ -20372,6 +21497,28 @@ } ], "resultChars": 7275 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/docs/guides/functions/auth-headers.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/auth-headers.md" + } + ], + "resultChars": 3331 } ] }, @@ -20413,37 +21560,37 @@ { "name": "rejects request with no credentials", "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { "name": "user with JWT reads only their own rows", "passed": true, - "notes": "status 200: [{\"user_id\":\"1f7a732a-f911-4415-80cd-89a9f4e1e75e\",\"metric\":\"steps_a_msj163uc\",\"value\":111}]" + "notes": "status 200: [{\"user_id\":\"2ecfc3d8-88fe-488a-b377-49d1da56adcb\",\"metric\":\"steps_a_mt93ven6\",\"value\":111}]" }, { "name": "user cannot read another user's rows by passing user_id", "passed": true, - "notes": "status 200: [{\"user_id\":\"1f7a732a-f911-4415-80cd-89a9f4e1e75e\",\"metric\":\"steps_a_msj163uc\",\"value\":111}]" + "notes": "status 200: [{\"user_id\":\"2ecfc3d8-88fe-488a-b377-49d1da56adcb\",\"metric\":\"steps_a_mt93ven6\",\"value\":111}]" }, { "name": "service key bypasses RLS to read the target user's rows", "passed": true, - "notes": "status 200: [{\"user_id\":\"9a247c74-daaa-4e1f-9bd6-4c24ce42abcd\",\"metric\":\"steps_b_msj163uc\",\"value\":222}]" + "notes": "status 200: [{\"user_id\":\"3d161b6e-0fcc-4bb0-a7dc-ad0203880f6a\",\"metric\":\"steps_b_mt93ven6\",\"value\":222}]" }, { "name": "non-service key is not granted service access", "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { "name": "rejects an unverified (forged) user token", "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { "name": "a user token in the apikey slot is not treated as the service key", "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" + "notes": "status 401: {\"message\":\"Invalid credentials\",\"code\":\"INVALID_CREDENTIALS\"}" }, { "name": "implementation uses @supabase/server", @@ -20457,76 +21604,49 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" - ] - }, - "docs": { - "calls": [ - { - "source": "web_fetch", - "query": "https://supabase.com/changelog.md", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 93795 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"edge function environment variables SUPABASE_URL SUPABASE_SERVICE_ROLE_KEY secret key publishable key\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" - }, - { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - }, + "supabase" + ] + }, + "docs": { + "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ { - "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", - "title": "Build a Social Auth App with Expo React Native" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 94601 + "resultChars": 94610 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"@supabase/server SDK edge functions createServerClient\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"edge function auth verify JWT apikey header Authorization bearer\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/reference/javascript/oauth-admin-createclient" + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" }, { - "url": "https://supabase.com/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers", - "title": "Migrating to the SSR package from Auth Helpers" + "url": "https://supabase.com/docs/guides/functions/auth-headers", + "title": "Authorization headers" }, { - "url": "https://supabase.com/docs/guides/auth/choosing-a-server-package", - "title": "Which package to use" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-auth-keys", + "title": "New API Keys and Asymmetric Authentication" }, { - "url": "https://supabase.com/docs/guides/functions/examples/resumable-websockets", - "title": "Resumable WebSockets with Edge Functions" + "url": "https://supabase.com/docs/guides/getting-started/api-keys", + "title": "Understanding API keys" }, { - "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", - "title": "Creating a Supabase client for SSR" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-envoy", + "title": "Envoy API Gateway" } ], - "resultChars": 59816 + "resultChars": 65992 }, { "source": "web_fetch", @@ -20538,6 +21658,28 @@ } ], "resultChars": 7275 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/docs/guides/functions/secrets.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/secrets.md" + } + ], + "resultChars": 5106 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/docs/guides/functions/auth-headers.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/auth-headers.md" + } + ], + "resultChars": 3331 } ] }, @@ -20640,7 +21782,47 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, + { + "source": "search_docs", + "query": "{\n searchDocs(query: \"RLS security definer function revoke execute policy permission\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/api/custom-claims-and-role-based-access-control-rbac", + "title": "Custom Claims & Role-based Access Control (RBAC)" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-hooks", + "title": "Auth Hooks" + } + ], + "resultChars": 85069 + } + ] }, "prompt": "Access control on our shared docs feature needs work, people can see and edit documents they shouldn't. Viewers should just be able to read, editors should only manage their own docs, and admins should be able to manage anything in their org. People should only be able to see who's in their own org.", "promptSourcePath": "evals/build-rls-003-org-roles-permissions/PROMPT.md", @@ -20684,7 +21866,7 @@ { "name": "user A lists only own files", "passed": true, - "notes": "saw: 019fdc8e-ae2d-7481-a05e-6e5700e0781e/receipt-alpha.pdf, 019fdc8e-ae2d-7481-a05e-6e5700e0781e/receipt-beta.pdf" + "notes": "saw: 01a03a92-dc24-76bf-ba48-b428b8037016/receipt-alpha.pdf, 01a03a92-dc24-76bf-ba48-b428b8037016/receipt-beta.pdf" }, { "name": "user B cannot read user A files", @@ -20705,7 +21887,7 @@ { "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "Meets all criteria: private user-files bucket, authenticated owner-scoped SELECT and INSERT policies with WITH CHECK, no RLS disabling or permissive/public policies, and supabase-js createSignedUrl with expiry for temporary sharing." + "judgeNotes": "Private bucket, authenticated owner-scoped SELECT/INSERT RLS policies, and expiring createSignedUrl client code are all provided; no disallowed public or service-role access." } ], "skills": { @@ -20714,14 +21896,54 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase" + "supabase", + "supabase-postgres-best-practices" ] }, "docs": { "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"storage access control RLS policies bucket private auth.uid() folder name\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/security/product-security", + "title": "Secure configuration of Supabase products" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-s3", + "title": "Configure S3 Storage" + }, + { + "url": "https://supabase.com/docs/guides/storage/schema/helper-functions", + "title": "Storage Helper Functions" + } + ], + "resultChars": 22486 + }, { "source": "search_docs", - "query": "{ searchDocs(query: \"storage createSignedUrl supabase-js expiresIn private bucket\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"createSignedUrl supabase-js storage temporary expiring download link private bucket\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -20737,20 +21959,19 @@ "title": "Manage Storage Image Transformations usage" }, { - "url": "https://supabase.com/docs/guides/storage/uploads/resumable-uploads", - "title": "Resumable Uploads" + "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsignedurl" }, { "url": "https://supabase.com/docs/reference/javascript/file-buckets-createsigneduploadurl" } ], - "resultChars": 44528 + "resultChars": 30316 } ] }, "prompt": "Our app lets signed-in users keep personal files like receipts and bank\nstatements. These files are private — a user must only ever be able to upload\nand download their own. The app uploads each file under a path that starts\nwith the owner's user id, e.g. `/receipt-march.pdf`.\n\nSet up a `user-files` bucket on our project and lock it down that way.\n\nUsers also sometimes share one of their files with someone else through a\ntemporary link that expires. Include the supabase-js code the app should use\nfor that.", "promptSourcePath": "evals/build-storage-001-private-bucket-access/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "opencode-kimi-k3/build-storage-001-private-bucket-access.json" }, { @@ -20782,12 +22003,12 @@ { "name": "pgTAP isolation tests ran and pass", "passed": true, - "notes": "3 passed, 1 failed" + "notes": "8 passed, 4 failed" }, { "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as the table with broken tenant isolation, explains that authenticated members can read posts from orgs they are not members of, and grounds this in the pgTAP result where the `posts` negative test fails. It also correctly states `notes` is isolated and treats test results as authoritative." + "judgeNotes": "Correctly identifies `posts` as the tenant-isolation flaw and grounds it in pgTAP failures showing cross-organization reads. It correctly distinguishes `notes` as isolated." } ], "skills": { @@ -20838,12 +22059,12 @@ { "name": "HNSW index on the embedding column", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" }, { "name": "index operator class matches the search operator", "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" }, { "name": "user A search returns only own sections, best match first", @@ -20883,11 +22104,11 @@ "url": "https://supabase.com/changelog.md" } ], - "resultChars": 93795 + "resultChars": 94610 }, { "source": "search_docs", - "query": "{ searchDocs(query: \"semantic search pgvector match_document_sections embedding function\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"semantic search pgvector match_documents embedding hnsw index\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { @@ -20899,30 +22120,19 @@ "title": "Semantic Search" }, { - "url": "https://supabase.com/docs/guides/ai/hybrid-search", - "title": "Hybrid search" + "url": "https://supabase.com/docs/guides/ai/vector-indexes", + "title": "Vector indexes" }, { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" + "url": "https://supabase.com/docs/guides/ai/going-to-prod", + "title": "Going to Production" }, { - "url": "https://supabase.com/docs/guides/database/extensions/pgvector", - "title": "pgvector: Embeddings and vector similarity" - } - ], - "resultChars": 68270 - }, - { - "source": "web_fetch", - "query": "https://supabase.com/docs/guides/ai/semantic-search.md", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/ai/semantic-search.md" + "url": "https://supabase.com/docs/guides/ai/hybrid-search", + "title": "Hybrid search" } ], - "resultChars": 12827 + "resultChars": 45208 } ] }, @@ -20958,12 +22168,12 @@ { "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "judgeNotes": "Meets all requirements: HTTPS Supabase Metrics API scrape for the project target, correct metrics path, Basic Auth with password_file, app scrape preserved, and docker-compose mounts the secrets directory containing the password file." + "judgeNotes": "All required Supabase scrape settings and secret wiring are present; the existing app scrape is preserved." }, { "name": "documented live deployment and verification steps", "passed": true, - "judgeNotes": "README includes Secret API key creation, matching secret file placement, stack restart/reload, and concrete verification via Prometheus targets plus direct curl check. Endpoint/auth and mounted secret path are consistent, with no hardcoded secret." + "judgeNotes": "README clearly covers creating a dedicated Secret API key, writing it to the matching mounted password file, restarting or reloading Compose, and verifying via Prometheus targets and PromQL." } ], "skills": { @@ -20977,48 +22187,44 @@ }, "docs": { "calls": [ - { - "source": "web_fetch", - "query": "https://supabase.com/changelog.md", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/changelog.md" - } - ], - "resultChars": 93795 - }, { "source": "search_docs", - "query": "{ searchDocs(query: \"metrics API prometheus endpoint scrape\") { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Prometheus metrics endpoint observability\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", - "title": "Metrics API with Prometheus & Grafana (self-hosted)" - }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", "title": "Metrics API" }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" + }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", "title": "Metrics API with Grafana Cloud" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_", - "title": "How to View Database Metrics" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", + "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { "url": "https://supabase.com/docs/guides/platform/read-replicas", "title": "Read Replicas" } ], - "resultChars": 29060 + "resultChars": 28211 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 } ] }, @@ -21059,7 +22265,7 @@ { "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment via Deno.env.get(\"WEATHER_API_KEY\")." }, { "name": "WEATHER_API_KEY value is not committed to the repo", @@ -21076,7 +22282,32 @@ ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"edge function secrets environment variables Deno.env.get deploy\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" + } + ], + "resultChars": 51266 + } + ] }, "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", @@ -21135,25 +22366,25 @@ "calls": [ { "source": "web_fetch", - "query": "https://supabase.com/docs/guides/self-hosting/docker.md", + "query": "https://supabase.com/changelog.md", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/self-hosting/docker.md" + "url": "https://supabase.com/changelog.md" } ], - "resultChars": 30709 + "resultChars": 94610 }, { "source": "web_fetch", - "query": "https://supabase.com/changelog.md", + "query": "https://supabase.com/docs/guides/self-hosting/docker.md", "hasContent": true, "pages": [ { - "url": "https://supabase.com/changelog.md" + "url": "https://supabase.com/docs/guides/self-hosting/docker.md" } ], - "resultChars": 93795 + "resultChars": 28536 } ] }, @@ -21211,7 +22442,7 @@ { "name": "diagnosed and explained session revocation", "passed": true, - "judgeNotes": "The answer diagnoses the soft-delete-only bug, implements real auth user/session/refresh-token removal, explains the remaining stale JWT access-token window consistently with its fix (including mitigation), and correctly distinguishes publishable frontend keys from secret/server keys that bypass RLS." + "judgeNotes": "Correctly diagnoses soft deletion, deletes the auth user and cascading sessions/refresh tokens/identities, hardens RLS against stale JWTs, accurately explains stateless access-token behavior and residual local-validation window, and correctly distinguishes publishable frontend keys from secret server-only RLS-bypassing keys." } ], "skills": { @@ -21220,45 +22451,55 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"publishable key secret key anon service_role API keys RLS\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"publishable secret API keys anon service_role migration RLS\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/getting-started/api-keys", - "title": "Understanding API keys" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", + "title": "Build a User Management App with RedwoodJS" }, { - "url": "https://supabase.com/docs/guides/auth/signing-keys", - "title": "JWT Signing Keys" + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" }, { - "url": "https://supabase.com/docs/guides/auth/server-side/creating-a-client", - "title": "Creating a Supabase client for SSR" + "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", + "title": "Build a Social Auth App with Expo React Native" }, { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", + "title": "Build a User Management App with SvelteKit" }, { - "url": "https://supabase.com/docs/guides/functions/secrets", - "title": "Environment Variables" + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + } + ], + "resultChars": 169611 + }, + { + "source": "web_fetch", + "query": "https://supabase.com/docs/guides/api/api-keys.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/api/api-keys.md" } ], - "resultChars": 101422 + "resultChars": 13494 } ] }, "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "opencode-kimi-k3/investigate-auth-001-deleted-user-access.json" }, { @@ -21306,7 +22547,7 @@ { "name": "diagnosed missing publication membership", "passed": true, - "judgeNotes": "Identified orders missing from supabase_realtime publication as root cause, added public.orders to the existing publication, and preserved courier_locations, RLS, and policies. Did not blame client/RLS/networking as root cause or weaken security." + "judgeNotes": "Correctly identified the missing orders table in supabase_realtime, added only public.orders to the existing publication, and preserved RLS, policies, and courier_locations." } ], "skills": { @@ -21349,17 +22590,17 @@ { "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "judgeNotes": "Identified image-transform as the affected function and explicitly described the recurring 8 HTTP 503 gateway failures across the morning of 2026-04-28 from 07:00Z to 12:00Z." + "judgeNotes": "Identified `image-transform` as the affected function and explicitly listed all eight recurring HTTP 503 failures from 07:00Z through 12:00Z on 2026-04-28." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": false, - "judgeNotes": "Although it cites a valid observation (503s only in gateway logs with no function execution logs), it ultimately attributes the primary cause to the function's unpinned npm dependency/worker boot and recommends pinning/redeploying the functions, rather than attributing the 503s to the gateway/platform layer in front of the function." + "judgeNotes": "Although it notes no matching invocation logs, it ultimately attributes the issue to function boot/loading and an unpinned dependency, then recommends redeploying the function. This conflicts with the required gateway/platform-layer attribution." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "The assistant recommended concrete next steps: pinning Edge Function dependencies, vendoring dependencies with lockfile checks, checking npm publish/registry history for the affected time window, and adding gateway 5xx alerting." + "judgeNotes": "The assistant provided multiple concrete actions, including capturing error headers, redeploying with pinned dependencies, testing cold starts, reviewing scheduled jobs, and escalating to Supabase support with timestamps and missing execution-log correlation." } ], "skills": { @@ -21375,31 +22616,59 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"edge functions 503 error npm dependencies pin version deno.json import map cold start\", limit: 5) { nodes { title href content } } }", + "query": "{ searchDocs(query: \"Edge Functions limits timeouts memory concurrent requests\", limit: 5) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-dependency-analysis", - "title": "Edge Function dependency analysis" + "url": "https://supabase.com/docs/guides/functions/status-codes", + "title": "Status codes" }, { - "url": "https://supabase.com/docs/guides/security/npm-security", - "title": "Securing npm installs" + "url": "https://supabase.com/docs/guides/functions/error-codes", + "title": "Error codes" }, { - "url": "https://supabase.com/docs/guides/troubleshooting/importing-stripe-or-other-modules-from-esmsh-on-deno-edge-functions-throws-an-error-TmbB5p", - "title": "Importing Stripe or other modules from esm.sh on Deno Edge Functions throws an error" + "url": "https://supabase.com/docs/guides/functions/limits", + "title": "Limits" }, { - "url": "https://supabase.com/docs/guides/functions/examples/mcp-server-mcp-lite", - "title": "Building an MCP Server with mcp-lite" + "url": "https://supabase.com/docs/guides/functions/recursive-functions", + "title": "Recursive / Nested Function Calls" }, { - "url": "https://supabase.com/docs/guides/functions", - "title": "Edge Functions" + "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", + "title": "Self-Hosted Functions" + } + ], + "resultChars": 34736 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"Edge Functions 503 error troubleshooting logs\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-503-response", + "title": "Edge Function 503 error response" + }, + { + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/debugging", + "title": "Debugging guide" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-504-error-response", + "title": "Edge Function 504 error response" + }, + { + "url": "https://supabase.com/docs/guides/functions/status-codes", + "title": "Status codes" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/edge-function-500-error-response", + "title": "Edge Function 500 error response" } ], - "resultChars": 43609 + "resultChars": 55290 } ] }, @@ -21458,7 +22727,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "The assistant correctly diagnosed RLS enabled with no policies as the cause of empty Data API results, kept RLS enabled, and created authenticated SELECT and INSERT owner-scoped policies using auth.uid(), including WITH CHECK for inserts." + "judgeNotes": "Correctly diagnosed deny-all RLS with no policies, kept RLS enabled, and added authenticated-only SELECT and INSERT policies scoped by user_id = auth.uid() using USING and WITH CHECK." } ], "skills": { @@ -21467,12 +22736,140 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"auth.uid() request.jwt.claims current_setting RLS policy\") { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/realtime/authorization", + "title": "Realtime Authorization" + }, + { + "url": "https://supabase.com/docs/guides/api/securing-your-api", + "title": "Securing your API" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security-performance", + "title": "Row Level Security performance" + }, + { + "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", + "title": "RAG with Permissions" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/rls-performance-and-best-practices-Z5Jjwv", + "title": "RLS Performance and Best Practices" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", + "title": "Token Security and Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/clerk", + "title": "Clerk" + }, + { + "url": "https://supabase.com/docs/guides/realtime/getting_started", + "title": "Getting Started with Realtime" + }, + { + "url": "https://supabase.com/docs/guides/realtime/broadcast", + "title": "Broadcast" + }, + { + "url": "https://supabase.com/docs/guides/resources/glossary", + "title": "Glossary" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-anonymous", + "title": "Anonymous Sign-Ins" + }, + { + "url": "https://supabase.com/docs/guides/auth/oauth-server/getting-started", + "title": "Getting Started with OAuth 2.1 Server" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/ownership", + "title": "Ownership" + }, + { + "url": "https://supabase.com/docs/guides/storage/debugging/error-codes", + "title": "Error Codes" + }, + { + "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0003_auth_rls_initplan", + "title": "Database Advisor: Lint 0003_auth_rls_initplan" + }, + { + "url": "https://supabase.com/docs/guides/realtime/postgres-changes", + "title": "Postgres Changes" + }, + { + "url": "https://supabase.com/docs/guides/auth/third-party/firebase-auth", + "title": "Firebase Auth" + }, + { + "url": "https://supabase.com/docs/guides/auth/enterprise-sso/auth-sso-saml", + "title": "Single Sign-On with SAML 2.0 for Projects" + }, + { + "url": "https://supabase.com/docs/guides/auth/auth-mfa", + "title": "Multi-Factor Authentication" + }, + { + "url": "https://supabase.com/docs/guides/api/custom-claims-and-role-based-access-control-rbac", + "title": "Custom Claims & Role-based Access Control (RBAC)" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/column-level-security", + "title": "Column Level Security" + }, + { + "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", + "title": "Storage Buckets" + }, + { + "url": "https://supabase.com/docs/guides/realtime/reports", + "title": "Realtime Reports" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/auth/jwt-fields", + "title": "JWT Claims Reference" + }, + { + "url": "https://supabase.com/docs/guides/local-development/declarative-database-schemas", + "title": "Declarative database schemas" + }, + { + "url": "https://supabase.com/docs/guides/auth/users", + "title": "Users" + }, + { + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-select-returning-an-empty-data-array-and-i-have-data-in-the-table-xvOPgx", + "title": "Why is my select returning an empty data array and I have data in the table?" + } + ], + "resultChars": 460726 + } + ] }, "prompt": "Our app lets signed-in users save bookmarks and view them on their dashboard. Bookmarks are stored in the `bookmarks` table and are private — a user must only ever see their own. \nUsers also need to be able to save new bookmarks from the app.\n\nI can see the rows when I query the table directly, but the dashboard shows an empty list for every user.\n\nFind out why the Data API returns nothing and fix it.", "promptSourcePath": "evals/resolve-dataapi-001-empty-results/PROMPT.md", @@ -21522,7 +22919,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "PASS: The avatar_url migration was applied through the Supabase CLI with `supabase db push` in action #26, which shows `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration history was reconciled by adding the missing local migration file `supabase/migrations/20240115000000_add_bio.sql` in actions #22-#24, after which `supabase migration list` (#25/#28) showed local and remote history aligned. Read-only psql inspections were used, but no prohibited direct SQL mutation or prepared-statement workaround was seen." + "judgeNotes": "`supabase db push --yes` applied `20240220000000_add_avatar_url.sql` and finished successfully. The orphan bio history was reconciled by adding `20240115000000_add_profile_bio.sql` locally (after `supabase migration fetch`) before the successful push. The `psql` commands were read-only; no prohibited workaround was used." } ], "skills": { @@ -21531,8 +22928,7 @@ "supabase-postgres-best-practices" ], "loaded": [ - "supabase", - "supabase-postgres-best-practices" + "supabase" ] }, "docs": { @@ -21579,7 +22975,7 @@ { "name": "query plan uses an index and avoids sequential scan", "passed": true, - "notes": "Limit (cost=55.55..55.61 rows=25 width=88)\n -> Sort (cost=55.55..55.61 rows=25 width=88)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=4.48..54.97 rows=25 width=88)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..4.47 rows=25 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + "notes": "Limit (cost=79.74..79.86 rows=50 width=58)\n -> Sort (cost=79.74..79.99 rows=100 width=58)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=5.06..76.42 rows=100 width=58)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..5.03 rows=100 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" }, { "name": "inserts still work", @@ -21712,7 +23108,7 @@ { "name": "signUp creates the account and returns its user id", "passed": true, - "notes": "db user 21c579b2-ae12-44ca-83f7-24fe17e54af5, signUp returned {\"userId\":\"21c579b2-ae12-44ca-83f7-24fe17e54af5\"}" + "notes": "db user db4a61c4-525a-4cd9-8f53-cb671401d719, signUp returned {\"userId\":\"db4a61c4-525a-4cd9-8f53-cb671401d719\"}" }, { "name": "signup metadata reaches the profile (display name)", @@ -21727,7 +23123,7 @@ { "name": "signIn with the right password returns the user id", "passed": true, - "notes": "{\"userId\":\"21c579b2-ae12-44ca-83f7-24fe17e54af5\"}" + "notes": "{\"userId\":\"db4a61c4-525a-4cd9-8f53-cb671401d719\"}" }, { "name": "getMyProfile returns the signed-in user's profile", @@ -21750,7 +23146,29 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"signUp signInWithPassword user metadata options data javascript\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpassword" + }, + { + "url": "https://supabase.com/docs/reference/javascript/auth-signinwithpasskey" + }, + { + "url": "https://supabase.com/docs/reference/dart/auth-signinwithpassword" + }, + { + "url": "https://supabase.com/docs/reference/swift/auth-signinwithpassword", + "title": "signInWithPassword()" + } + ], + "resultChars": 2871 + } + ] }, "prompt": "Our app in `app/` needs accounts. Wire up `app/src/auth.mjs` — the stubs in\nthere describe what each function should do. People sign up with an email,\npassword, and display name, sign back in later, and the app greets them with\ntheir profile.\n\nThe Supabase project for this app is in `supabase/` and already running\nlocally. When you're done, the functions should work for real against it.", "promptSourcePath": "evals/build-auth-001-email-password-flow/PROMPT.md", @@ -21816,7 +23234,43 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "web_fetch", + "query": "https://supabase.com/changelog.md", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/changelog.md" + } + ], + "resultChars": 94610 + }, + { + "source": "search_docs", + "query": "query { searchDocs(query: \"local development CLI create migration seed data supabase db reset\", limit: 4) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/local-development/cli-workflows", + "title": "Local development workflow" + }, + { + "url": "https://supabase.com/docs/reference/cli/supabase-db-reset", + "title": "Resets the local database to current migrations" + }, + { + "url": "https://supabase.com/docs/guides/local-development/seeding-your-database", + "title": "Seeding your database" + }, + { + "url": "https://supabase.com/docs/guides/cli", + "title": "Local Dev with CLI" + } + ], + "resultChars": 33254 + } + ] }, "prompt": "We're kicking off a todos app and I want the Supabase side ready for the team\nto build on. Set it up the way we'd run it in development, with schema changes\ntracked as migrations so they can be reviewed and replayed.\n\nFor the first slice we just need a `todos` table. Todos aren't public: anyone\nsigned in can read all of them, but nothing should be writable through the API\nfor now. Add a couple of sample todos so there's something to look at.\n\nBefore you hand it back, make sure the running API actually behaves that way —\nsigned-in users get the todos, signed-out requests get nothing.", "promptSourcePath": "evals/build-cli-001-bootstrap-app/PROMPT.md", @@ -21870,7 +23324,7 @@ }, "prompt": "Add a description text column to the `products` table in my local Supabase stack", "promptSourcePath": "evals/build-cli-002-declarative-schema/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "opencode-kimi-k3-no-skills/build-cli-002-declarative-schema.json" }, { @@ -21905,73 +23359,51 @@ { "name": "cron command enqueues to the 'tasks' queue", "passed": true, - "notes": "queue depth 0 -> 1" + "notes": "queue depth 1 -> 2" }, { "name": "process-tasks function drains the queue", "passed": true, - "notes": "function removed the seeded message (id 5) from the queue" + "notes": "function removed the seeded message (id 37) from the queue" } ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{ searchDocs(query: \"pgmq queues consume messages with edge function read delete\", limit: 5) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", - "title": "Consuming Supabase Queue Messages with Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/queues/pgmq", - "title": "PGMQ Extension" - }, - { - "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", - "title": "Automatic embeddings" - }, - { - "url": "https://supabase.com/docs/guides/queues/api", - "title": "API" - }, - { - "url": "https://supabase.com/docs/guides/queues/quickstart", - "title": "Quickstart" - } - ], - "resultChars": 68440 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"expose queues PostgREST edge function pgmq_public read delete example\", limit: 3) { nodes { title href subsections { nodes { title content } } } } }", - "hasContent": true, - "pages": [] - }, + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"expose queues PostgREST edge function pgmq_public read delete example\", limit: 3) { nodes { title href ... on Guide { subsections { nodes { title content } } } } } }", + "query": "{ searchDocs(query: \"pgmq queue cron job pg_cron send message edge function pop\", limit: 6) { nodes { title href content } } }", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/queues/quickstart", - "title": "Quickstart" + "url": "https://supabase.com/docs/guides/ai/automatic-embeddings", + "title": "Automatic embeddings" }, { - "url": "https://supabase.com/docs/guides/queues/api", - "title": "API" + "url": "https://supabase.com/docs/guides/queues/pgmq", + "title": "PGMQ Extension" }, { - "url": "https://supabase.com/docs/guides/queues/expose-self-hosted-queues", - "title": "Expose Queues for local and self-hosted Supabase" + "url": "https://supabase.com/docs/guides/database/extensions/pg_net", + "title": "pg_net: Async Networking" + }, + { + "url": "https://supabase.com/docs/guides/functions/schedule-functions", + "title": "Scheduling Edge Functions" + }, + { + "url": "https://supabase.com/docs/guides/cron/quickstart", + "title": "Quickstart" + }, + { + "url": "https://supabase.com/docs/guides/queues/consuming-messages-with-edge-functions", + "title": "Consuming Supabase Queue Messages with Edge Functions" } ], - "resultChars": 22663 + "resultChars": 79310 } ] }, @@ -22000,7 +23432,7 @@ "suite": "benchmark", "interface": "cli", "cliVersion": "2.109.1", - "passed": false, + "passed": true, "checks": [ { "name": "report runs and prints JSON", @@ -22019,8 +23451,8 @@ }, { "name": "implementation uses @supabase/supabase-js", - "passed": false, - "notes": "no @supabase/supabase-js import found — this eval requires the SDK" + "passed": true, + "notes": "imports found in: app/report.mjs" }, { "name": "report queries via the Data API, not raw SQL", @@ -22146,7 +23578,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"migrate existing postgres database dump pg_restore local development\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/postgres", + "title": "Migrate from Postgres to Supabase" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/vercel-postgres", + "title": "Migrate from Vercel Postgres to Supabase" + }, + { + "url": "https://supabase.com/docs/guides/platform/migrating-to-supabase/neon", + "title": "Migrate from Neon to Supabase" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/restore-from-platform", + "title": "Restore a Platform Project to Self-Hosted" + }, + { + "url": "https://supabase.com/docs/guides/local-development/restoring-downloaded-backup", + "title": "Restoring a downloaded backup locally" + } + ], + "resultChars": 41280 + } + ] }, "prompt": "I have an existing Postgres database I want to migrate to Supabase. There's a binary dump at `source.dump` in the current directory.\n\nCan you set up a local Supabase project and restore the dump into it?", "promptSourcePath": "evals/build-database-001-migrate-postgres-to-supabase/PROMPT.md", @@ -22215,215 +23676,87 @@ "attempts": 1, "sourcePath": "opencode-kimi-k3-no-skills/build-functions-004-service-role-bypass.json" }, - { - "experiment": "opencode-kimi-k3-no-skills", - "experimentSuite": "no-skills", - "experimentDisplay": { - "agent": "opencode", - "modelProvider": "moonshotai", - "modelId": "moonshotai/kimi-k3" - }, - "eval": "build-functions-005-dual-auth-user-secret", - "stage": "build", - "product": [ - "edge-functions", - "auth", - "database" - ], - "topic": [ - "sdk", - "rls", - "security" - ], - "suite": "benchmark", - "interface": "cli", - "cliVersion": "2.109.1", - "passed": true, - "checks": [ - { - "name": "seed rows present", - "passed": true, - "notes": "found 2/2 seeded rows" - }, - { - "name": "rejects request with no credentials", - "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" - }, - { - "name": "user with JWT reads only their own rows", - "passed": true, - "notes": "status 200: [{\"user_id\":\"8de5d728-6f94-47d9-833a-f4104a74539f\",\"metric\":\"steps_a_msj15kas\",\"value\":111}]" - }, - { - "name": "user cannot read another user's rows by passing user_id", - "passed": true, - "notes": "status 200: [{\"user_id\":\"8de5d728-6f94-47d9-833a-f4104a74539f\",\"metric\":\"steps_a_msj15kas\",\"value\":111}]" - }, - { - "name": "service key bypasses RLS to read the target user's rows", - "passed": true, - "notes": "status 200: [{\"user_id\":\"b33c6f83-e1ca-49a7-8520-64ff05e415e9\",\"metric\":\"steps_b_msj15kas\",\"value\":222}]" - }, - { - "name": "non-service key is not granted service access", - "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" - }, - { - "name": "rejects an unverified (forged) user token", - "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" - }, - { - "name": "a user token in the apikey slot is not treated as the service key", - "passed": true, - "notes": "status 401: {\"error\":\"Invalid credentials\"}" - }, - { - "name": "implementation uses @supabase/server", - "passed": true, - "notes": "imports @supabase/server / withSupabase" - } - ], - "skills": { - "available": [], - "loaded": [] - }, - "docs": { - "calls": [ - { - "source": "search_docs", - "query": "{searchDocs(query: \"edge function verify JWT get user from access token service role bypass RLS\") {nodes {title href content}}}", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-service-role-key-client-getting-rls-errors-or-not-returning-data-7_1K9z", - "title": "Why is my service role key client getting RLS errors or not returning data?" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-headers", - "title": "Authorization headers" - }, - { - "url": "https://supabase.com/docs/guides/functions/error-codes", - "title": "Error codes" - }, - { - "url": "https://supabase.com/docs/guides/storage/security/access-control", - "title": "Storage Access Control" - }, - { - "url": "https://supabase.com/docs/guides/api/custom-claims-and-role-based-access-control-rbac", - "title": "Custom Claims & Role-based Access Control (RBAC)" - }, - { - "url": "https://supabase.com/docs/guides/self-hosting/self-hosted-functions", - "title": "Self-Hosted Functions" - }, - { - "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", - "title": "Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/token-security", - "title": "Token Security and Row Level Security" - }, - { - "url": "https://supabase.com/docs/guides/auth/third-party/clerk", - "title": "Clerk" - }, - { - "url": "https://supabase.com/docs/guides/resources/glossary", - "title": "Glossary" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-mfa", - "title": "Multi-Factor Authentication" - }, - { - "url": "https://supabase.com/docs/guides/functions/function-configuration", - "title": "Function Configuration" - }, - { - "url": "https://supabase.com/docs/guides/auth/auth-anonymous", - "title": "Anonymous Sign-Ins" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth-legacy-jwt", - "title": "Integrating With Supabase Auth" - }, - { - "url": "https://supabase.com/docs/guides/auth/jwts", - "title": "JSON Web Token (JWT)" - }, - { - "url": "https://supabase.com/docs/guides/api/securing-your-api", - "title": "Securing your API" - }, - { - "url": "https://supabase.com/docs/guides/functions/auth", - "title": "Securing Edge Functions" - }, - { - "url": "https://supabase.com/docs/guides/storage/buckets/fundamentals", - "title": "Storage Buckets" - }, - { - "url": "https://supabase.com/docs/guides/auth/users", - "title": "Users" - }, - { - "url": "https://supabase.com/docs/guides/auth/jwt-fields", - "title": "JWT Claims Reference" - }, - { - "url": "https://supabase.com/docs/reference/javascript/auth-getclaims" - }, - { - "url": "https://supabase.com/docs/reference/swift/auth-getclaims", - "title": "getClaims()" - }, - { - "url": "https://supabase.com/docs/guides/ai/rag-with-permissions", - "title": "RAG with Permissions" - }, - { - "url": "https://supabase.com/docs/guides/functions/status-codes", - "title": "Status codes" - }, - { - "url": "https://supabase.com/docs/guides/auth/oauth-server/getting-started", - "title": "Getting Started with OAuth 2.1 Server" - }, - { - "url": "https://supabase.com/docs/guides/troubleshooting/why-is-my-select-returning-an-empty-data-array-and-i-have-data-in-the-table-xvOPgx", - "title": "Why is my select returning an empty data array and I have data in the table?" - }, - { - "url": "https://supabase.com/docs/guides/storage/security/ownership", - "title": "Ownership" - }, - { - "url": "https://supabase.com/docs/reference/swift/auth-getuser", - "title": "user()" - }, - { - "url": "https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0012_auth_allow_anonymous_sign_ins", - "title": "Database Advisor: Lint 0012_auth_allow_anonymous_sign_ins" - }, - { - "url": "https://supabase.com/docs/guides/platform/sso/multiple-providers", - "title": "Multiple SSO Providers" - } - ], - "resultChars": 271984 - } - ] + { + "experiment": "opencode-kimi-k3-no-skills", + "experimentSuite": "no-skills", + "experimentDisplay": { + "agent": "opencode", + "modelProvider": "moonshotai", + "modelId": "moonshotai/kimi-k3" + }, + "eval": "build-functions-005-dual-auth-user-secret", + "stage": "build", + "product": [ + "edge-functions", + "auth", + "database" + ], + "topic": [ + "sdk", + "rls", + "security" + ], + "suite": "benchmark", + "interface": "cli", + "cliVersion": "2.109.1", + "passed": false, + "checks": [ + { + "name": "seed rows present", + "passed": true, + "notes": "found 2/2 seeded rows" + }, + { + "name": "rejects request with no credentials", + "passed": true, + "notes": "status 401: {\"error\":\"unauthorized\"}" + }, + { + "name": "user with JWT reads only their own rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"d796887a-9a37-4cf8-acbb-4c6de7e42f0b\",\"metric\":\"steps_a_mt94bxmd\",\"value\":111}]" + }, + { + "name": "user cannot read another user's rows by passing user_id", + "passed": true, + "notes": "status 200: [{\"user_id\":\"d796887a-9a37-4cf8-acbb-4c6de7e42f0b\",\"metric\":\"steps_a_mt94bxmd\",\"value\":111}]" + }, + { + "name": "service key bypasses RLS to read the target user's rows", + "passed": true, + "notes": "status 200: [{\"user_id\":\"7ec86fb6-42d8-4919-9c18-da70354108c5\",\"metric\":\"steps_b_mt94bxmd\",\"value\":222}]" + }, + { + "name": "non-service key is not granted service access", + "passed": true, + "notes": "status 401: {\"error\":\"unauthorized\"}" + }, + { + "name": "rejects an unverified (forged) user token", + "passed": true, + "notes": "status 401: {\"error\":\"unauthorized\"}" + }, + { + "name": "a user token in the apikey slot is not treated as the service key", + "passed": true, + "notes": "status 401: {\"error\":\"unauthorized\"}" + }, + { + "name": "implementation uses @supabase/server", + "passed": false, + "notes": "hand-rolled (raw supabase-js or other) — this eval requires @supabase/server" + } + ], + "skills": { + "available": [], + "loaded": [] + }, + "docs": { + "calls": [] }, "prompt": "Build and serve a Supabase Edge Function named `user-stats` for this project,\nreachable over HTTP at `/functions/v1/user-stats`.\n\nOur product stores per-user metrics in the existing `user_stats` table.\n\nTwo very different callers need to hit this one endpoint:\n\n1. **Our mobile app**, acting for a signed-in user. It sends that user's\n Supabase access token. The endpoint should return the user's own stats.\n\n2. **Our internal billing service**, a trusted backend with no signed-in user.\n It authenticates with the project's secret (service-role) key in the `apikey`\n header, and names the target user with a `user_id` in the JSON request body.\n It needs that user's stats.\n\nReturn the matching rows as JSON. The endpoint must be secure: only ever serve\nstats to a caller that is genuinely entitled to them, and turn away callers that\nare not.", "promptSourcePath": "evals/build-functions-005-dual-auth-user-secret/PROMPT.md", - "attempts": 1, + "attempts": 2, "sourcePath": "opencode-kimi-k3-no-skills/build-functions-005-dual-auth-user-secret.json" }, { @@ -22558,7 +23891,7 @@ { "name": "user A lists only own files", "passed": true, - "notes": "saw: 019fdc8d-4da9-7774-82e4-97e7592afbcb/receipt-alpha.pdf, 019fdc8d-4da9-7774-82e4-97e7592afbcb/receipt-beta.pdf" + "notes": "saw: 01a03a87-6b46-7058-9dd8-eb4fd286be2f/receipt-alpha.pdf, 01a03a87-6b46-7058-9dd8-eb4fd286be2f/receipt-beta.pdf" }, { "name": "user B cannot read user A files", @@ -22579,7 +23912,7 @@ { "name": "configured private per-user storage access", "passed": true, - "judgeNotes": "Meets the rubric: creates a private user-files bucket, adds authenticated owner-scoped SELECT and INSERT policies on storage.objects using the user-id path segment, does not disable RLS or use public access, and provides supabase-js createSignedUrl code with an expiry." + "judgeNotes": "Creates a private bucket, authenticated owner-scoped INSERT and SELECT policies, retains RLS, and uses createSignedUrl with a 10-minute expiry." } ], "skills": { @@ -22618,17 +23951,17 @@ { "name": "pgTAP test file(s) written under supabase/tests/", "passed": true, - "notes": "1 file(s): supabase/tests/tenant_isolation.sql" + "notes": "1 file(s): supabase/tests/tenant_isolation.test.sql" }, { "name": "pgTAP isolation tests ran and pass", "passed": true, - "notes": "10 passed, 2 failed" + "notes": "6 passed, 3 failed" }, { "name": "agent correctly identifies the posts isolation bug from test results", "passed": true, - "judgeNotes": "The agent correctly identifies `posts` as the broken tenant isolation policy, explains that authenticated members can read posts from organizations they do not belong to, and grounds the conclusion in pgTAP failures. It also correctly notes `notes` is isolated and treats the test results as authoritative." + "judgeNotes": "Correctly identifies `posts` as having a cross-tenant read policy flaw and grounds it in pgTAP failures showing members can read other organizations’ posts. It also correctly distinguishes `notes` as isolated." } ], "skills": { @@ -22636,7 +23969,28 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "query { searchDocs(query: \"pgTAP database tests RLS row level security supabase test db\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/local-development/testing/overview", + "title": "Testing Overview" + }, + { + "url": "https://supabase.com/docs/guides/database/postgres/row-level-security", + "title": "Row Level Security" + }, + { + "url": "https://supabase.com/docs/guides/storage/security/access-control", + "title": "Storage Access Control" + } + ], + "resultChars": 41683 + } + ] }, "prompt": "Can you audit the tenant isolation on our tables? Write some database tests covering both the happy path and the negative case, run them, and share the results.", "promptSourcePath": "evals/build-tests-001-rls-tenant-isolation/PROMPT.md", @@ -22673,12 +24027,12 @@ { "name": "HNSW index on the embedding column", "passed": true, - "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" }, { "name": "index operator class matches the search operator", "passed": true, - "notes": "function operators: <=>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_cosine_ops)" + "notes": "function operators: <#>\nindexes: CREATE INDEX document_sections_embedding_idx ON public.document_sections USING hnsw (embedding vector_ip_ops)" }, { "name": "user A search returns only own sections, best match first", @@ -22702,7 +24056,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{\n searchDocs(query: \"semantic search pgvector gte-small embedding dimensions match documents function\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/ai/semantic-search", + "title": "Semantic search" + }, + { + "url": "https://supabase.com/docs/guides/ai/vector-columns", + "title": "Vector columns" + }, + { + "url": "https://supabase.com/docs/guides/ai/hybrid-search", + "title": "Hybrid search" + }, + { + "url": "https://supabase.com/docs/guides/database/extensions/pgvector", + "title": "pgvector: Embeddings and vector similarity" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/semantic-search", + "title": "Semantic Search" + } + ], + "resultChars": 45321 + } + ] }, "prompt": "We're adding semantic search to our internal knowledge base app. I already wrote the edge functions, but search doesn't work yet. Can you set up whatever the database needs to make search work end to end?\n\nSome documents are confidential, so users should only have access to documents they own.", "promptSourcePath": "evals/build-vectors-001-rag-with-permissions/PROMPT.md", @@ -22736,12 +24119,12 @@ { "name": "configured the Supabase Metrics API scrape correctly", "passed": true, - "judgeNotes": "Meets all requirements: app scrape preserved, Supabase HTTPS metrics endpoint configured with Basic Auth password_file, project target present, and docker-compose mounts the secrets directory containing the password file." + "judgeNotes": "HTTPS Supabase scrape uses the correct metrics path and Basic Auth password_file; the matching read-only bind mount is present, project target is valid, and the app job is preserved." }, { "name": "documented live deployment and verification steps", "passed": true, - "judgeNotes": "README includes correct live setup steps: create/copy a Supabase Secret API key, write it to the mounted secret file matching prometheus.yml, restart/recreate or reload the Compose stack, and verify via Prometheus targets and PromQL/Grafana. Endpoint/auth and secret setup are consistent, with no hardcoded real secret." + "judgeNotes": "README provides correct Secret API key creation, matching mounted secret file, Compose restart/reload, and concrete verification via Prometheus targets and Grafana PromQL." } ], "skills": { @@ -22752,53 +24135,37 @@ "calls": [ { "source": "search_docs", - "query": "{ searchDocs(query: \"metrics endpoint prometheus scrape hosted project observability\", limit: 5) { nodes { title href content } } }", + "query": "{\n searchDocs(query: \"metrics endpoint prometheus scrape project metrics\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", "hasContent": true, "pages": [ { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", - "title": "Metrics API" - }, - { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", - "title": "Vendor-agnostic Metrics API setup" + "url": "https://supabase.com/docs/reference/api/v1-scrape-project-metrics", + "title": "Scrape a project's metrics" }, { "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted", "title": "Metrics API with Prometheus & Grafana (self-hosted)" }, { - "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", - "title": "Metrics API with Grafana Cloud" - } - ], - "resultChars": 19334 - }, - { - "source": "search_docs", - "query": "{ searchDocs(query: \"management api create project api key secret sb_secret\", limit: 3) { nodes { title href content } } }", - "hasContent": true, - "pages": [ - { - "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin", - "title": "Build a Product Management Android App with Jetpack Compose" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics", + "title": "Metrics API" }, { - "url": "https://supabase.com/docs/reference/api/v1-create-project-api-key", - "title": "Creates a new API key for the project" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/vendor-agnostic", + "title": "Vendor-agnostic Metrics API setup" }, { - "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", - "title": "Migrating to publishable and secret API keys" + "url": "https://supabase.com/docs/guides/monitoring-and-debugging/metrics/grafana-cloud", + "title": "Metrics API with Grafana Cloud" } ], - "resultChars": 63685 + "resultChars": 19934 } ] }, "prompt": "Can you wire my Supabase project metrics into our existing observability stack and document\nin the observability README what we need to do to make the config live?", "promptSourcePath": "evals/deploy-database-001-prometheus-metrics/PROMPT.md", - "attempts": 2, + "attempts": 1, "sourcePath": "opencode-kimi-k3-no-skills/deploy-database-001-prometheus-metrics.json" }, { @@ -22833,7 +24200,7 @@ { "name": "the weather function reads WEATHER_API_KEY from the environment", "passed": true, - "judgeNotes": "The function reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." + "judgeNotes": "Reads WEATHER_API_KEY from the runtime environment using Deno.env.get(\"WEATHER_API_KEY\")." }, { "name": "WEATHER_API_KEY value is not committed to the repo", @@ -22845,7 +24212,36 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{\n searchDocs(query: \"edge function secrets environment variables deploy CLI\", limit: 5) {\n nodes {\n title\n href\n content\n }\n }\n}", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/functions/secrets", + "title": "Environment Variables" + }, + { + "url": "https://supabase.com/docs/guides/troubleshooting/inspecting-edge-function-environment-variables-wg5qOQ", + "title": "Inspecting edge function environment variables" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/functions/examples/elevenlabs-transcribe-speech", + "title": "Transcription Telegram Bot" + }, + { + "url": "https://supabase.com/docs/guides/deployment/branching/troubleshooting", + "title": "Troubleshooting" + } + ], + "resultChars": 38054 + } + ] }, "prompt": "Our weather widget currently calls WeatherAPI straight from the browser, which\nleaks our API key. I want to move that behind a Supabase Edge Function called\n`weather` that holds the key server-side and proxies the request.\n\nThe function should read the key from an environment variable named\n`WEATHER_API_KEY`. Our key already lives in a local `.env` file at the project\nroot.\n\nDeploy the function to our project so it's live, and make sure the deployed\nfunction can actually read the key at runtime.", "promptSourcePath": "evals/deploy-functions-001-edge-function-secrets/PROMPT.md", @@ -22896,7 +24292,28 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"self-hosting with docker compose\", limit: 3) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/self-hosting/docker", + "title": "Self-Hosting with Docker" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting", + "title": "Self-Hosting" + }, + { + "url": "https://supabase.com/docs/guides/self-hosting/updating", + "title": "Update Your Self-Hosted Deployment" + } + ], + "resultChars": 49769 + } + ] }, "prompt": "I'm moving off the hosted Supabase and running the whole thing myself on a VPS I\njust spun up. Can you get a Docker setup ready for me to copy onto the box?\n\nI don't need it running here, I'll do the actual bring-up once I'm on the\nserver. I just want everything in place and the secrets set up. Put it in a `supabase-docker/`\nfolder at the repo root so I can scp the whole thing across in one go.", "promptSourcePath": "evals/deploy-self-hosting-001-docker-compose/PROMPT.md", @@ -22952,7 +24369,7 @@ { "name": "diagnosed and explained session revocation", "passed": true, - "judgeNotes": "The answer identifies the soft-delete-only root cause, implements real auth/session/refresh-token revocation by deleting sessions and auth user, hardens RLS to close the data API stale-JWT window, and explains the remaining stateless JWT validity caveat consistently. It also correctly distinguishes publishable frontend keys with RLS from secret server-only keys that bypass RLS." + "judgeNotes": "Correctly diagnoses the soft-delete flaw, implements auth-user deletion with session/refresh-token revocation, accurately explains the remaining stateless JWT expiry window and mitigations, and correctly distinguishes frontend publishable keys from server-only RLS-bypassing secret keys." } ], "skills": { @@ -22960,7 +24377,62 @@ "loaded": [] }, "docs": { - "calls": [] + "calls": [ + { + "source": "search_docs", + "query": "{ searchDocs(query: \"delete user account from RPC function auth.users self service\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/reference/javascript/auth-admin-deleteuser" + }, + { + "url": "https://supabase.com/docs/guides/auth/managing-user-data", + "title": "User Management" + }, + { + "url": "https://supabase.com/docs/reference/swift/auth-admin-deleteuser", + "title": "deleteUser()" + }, + { + "url": "https://supabase.com/docs/reference/dart/auth-admin-deleteuser" + }, + { + "url": "https://supabase.com/docs/reference/kotlin/auth-admin-deleteuser", + "title": "deleteUser()" + } + ], + "resultChars": 7878 + }, + { + "source": "search_docs", + "query": "{ searchDocs(query: \"publishable secret API keys migrate legacy anon service_role RLS\", limit: 5) { nodes { title href content } } }", + "hasContent": true, + "pages": [ + { + "url": "https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys", + "title": "Migrating to publishable and secret API keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs", + "title": "Build a User Management App with RedwoodJS" + }, + { + "url": "https://supabase.com/docs/guides/auth/quickstarts/with-expo-react-native-social-auth", + "title": "Build a Social Auth App with Expo React Native" + }, + { + "url": "https://supabase.com/docs/guides/auth/signing-keys", + "title": "JWT Signing Keys" + }, + { + "url": "https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit", + "title": "Build a User Management App with SvelteKit" + } + ], + "resultChars": 169611 + } + ] }, "prompt": "Last week support removed a user through our app's delete-account flow — the\napp calls the `delete_account` function over RPC as the signed-in user. This\nmorning that same person was back: still signed in, reading and saving their\ndata like nothing happened.\n\nFigure out why the account still works, fix the flow so a deleted account\nloses access, and tell me whether there is any window where they could still\nget in after the fix.\n\nOne more thing while you're at it: we're migrating off the legacy\nanon/service_role API keys to the new publishable and secret keys, and the\nteam isn't sure which one belongs in the frontend and what each means for\nRLS. Give us a quick rundown.", "promptSourcePath": "evals/investigate-auth-001-deleted-user-access/PROMPT.md", @@ -23012,7 +24484,7 @@ { "name": "diagnosed missing publication membership", "passed": true, - "judgeNotes": "Identifies orders missing from supabase_realtime publication as root cause despite SUBSCRIBED status, applies ALTER PUBLICATION supabase_realtime ADD TABLE public.orders, verifies existing courier_locations remains, and does not weaken RLS/policies or blame client/networking." + "judgeNotes": "Correctly identified orders missing from supabase_realtime, added only public.orders to the existing publication, and preserved RLS, policies, and courier_locations." } ], "skills": { @@ -23050,17 +24522,17 @@ { "name": "identified image-transform and the recurring 503 pattern", "passed": true, - "judgeNotes": "The assistant clearly identified image-transform as the affected function and described the recurring pattern of 8 HTTP 503 gateway responses on 2026-04-28 between 07:00Z and 12:00Z, while correctly distinguishing unrelated old billing-webhook 503s." + "judgeNotes": "Identified `image-transform` as the affected function and explicitly listed all eight recurring HTTP 503 gateway failures across 07:00Z–12:00Z on 2026-04-28, while correctly distinguishing the older billing-webhook incident." }, { "name": "attributed recurring 503s to gateway/platform layer, not function code", "passed": true, - "judgeNotes": "Attributes the 503s to the gateway/edge platform layer, not function code, and grounds this in valid evidence: gateway-only 503s with no failed function invocations, successful nearby executions on same deployment/version, and distinction from a function-level avatar-upload 500." + "judgeNotes": "Attributes the 503s to the gateway/Edge Functions platform rather than application code, supported by gateway-only 503s with no matching function executions, nearby successful invocations, and distinction from avatar-upload’s function-level 500." }, { "name": "recommended a concrete next step", "passed": true, - "judgeNotes": "The assistant recommended concrete next steps, including opening a Supabase support ticket with project ref, request IDs, and time window, checking platform incident/status, adding retries, and setting up alerting." + "judgeNotes": "Provides multiple concrete actions: audit half-hourly schedulers, stagger jobs, add 503 retries, configure alerts, and move batch transforms to a queue." } ], "skills": { @@ -23125,7 +24597,7 @@ { "name": "diagnosed RLS and added owner-scoped policies", "passed": true, - "judgeNotes": "The assistant correctly diagnosed RLS enabled with no policies causing deny-all Data API results, kept RLS enabled, and created authenticated SELECT and INSERT policies scoped to auth.uid() = user_id using USING and WITH CHECK." + "judgeNotes": "Correctly diagnosed default-deny RLS with no policies, kept RLS enabled, and added authenticated-only SELECT and INSERT policies scoped by user_id = auth.uid() using USING and WITH CHECK." } ], "skills": { @@ -23183,7 +24655,7 @@ { "name": "the avatar migration and history reconciliation were done via the Supabase CLI", "passed": true, - "judgeNotes": "Avatar_url was applied through `supabase db push` in #17, which shows `Applying migration 20240220000000_add_avatar_url.sql...` and `Finished supabase db push.` The orphan bio migration was reconciled by adding the missing local migration file `20240115000000_add_profile_bio.sql` in #15, after which Supabase CLI migration list showed local and remote aligned. No prohibited workaround or direct mutation was used." + "judgeNotes": "`supabase db push` (#22) applied `20240220000000_add_avatar_url.sql` and finished successfully. The orphan bio history was reconciled by adding the matching local file `20240115000000_add_profile_bio.sql` (#20), confirmed aligned by `supabase migration list` (#21/#24), allowing the push. The `psql` commands were read-only inspections; no prohibited workaround was used." } ], "skills": { @@ -23234,7 +24706,7 @@ { "name": "query plan uses an index and avoids sequential scan", "passed": true, - "notes": "Limit (cost=79.74..79.86 rows=50 width=58)\n -> Sort (cost=79.74..79.99 rows=100 width=58)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=5.06..76.42 rows=100 width=58)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on idx_events_user_created_at (cost=0.00..5.03 rows=100 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" + "notes": "Limit (cost=79.74..79.86 rows=50 width=58)\n -> Sort (cost=79.74..79.99 rows=100 width=58)\n Sort Key: created_at DESC\n -> Bitmap Heap Scan on events (cost=5.06..76.42 rows=100 width=58)\n Recheck Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)\n -> Bitmap Index Scan on events_user_id_created_at_idx (cost=0.00..5.03 rows=100 width=0)\n Index Cond: (user_id = '00000000-0000-0000-0000-000000000001'::uuid)" }, { "name": "inserts still work",