feat(evals): add build-cli-004-worktree-stacks (CLI-2400) - #307
kanadgupta wants to merge 4 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
f4af609 to
9e35200
Compare
c883a62 to
3158ffd
Compare
|
Heads-up: I rebased this branch ( Why: #281 was split into two PRs this morning — #308 (the Nothing you need to do. Your eval is already in Two things from the review round on #308 that touch your runs, for awareness only:
|
Final chunk of the closed #308 — the piece @mattrossman asked for: the minimal CLI suite plumbing and CODEOWNERS, standalone, with no CLI experiment internals to review. **15 files, 260 lines**, and four of those files are 11–13 lines each. Everything it depended on is now on `main` (#315's `experiments/<owner>/` layout, and #324 + #325's sandbox options), so this is based on `main` and the diff is only its own content. ## What it adds `cli` as an eval suite and an experiment suite, `@supabase/cli` ownership over `/evals/cli/`, `/experiments/cli/` and `cli-eval-results.json`, and the workflow wiring so `eval-refresh` and `append-gh-pages-history` know the suite exists. The substance is five environment columns: one scenario run unchanged across forced CLI environments, so a failure isolates to *which* environment broke. They're thin now that `experiments/presets.ts` exists — the whole of the Docker-less column is: ```ts export default defineExperiment({ ...codexGpt6Luna, suite: ['cli'], // beta: the Docker-less path only exists in the managed stack, which ships in beta. localStack: localStackRuntime({ cliVersion: 'beta', docker: 'absent' }), skipEval: skipUnlessDockerless, }); ``` | column | environment | picks up | |---|---|---| | `codex-gpt-6-luna-cli-pinned` | repo-pinned CLI, Docker available | every `interface: cli` eval that isn't hosted-linked | | `…-cli-stable` | npm `latest` | same | | `…-cli-beta` | npm `beta` | same | | `…-cli-nodaemon` | beta, daemon unreachable | also needs `needsDocker: false` + `projectRunning: false` | | `…-cli-absent` | beta, no `docker` binary | also needs `needsDocker: false` + `projectRunning: false` | All five columns share one `skipEval: skipUnlessCli`, so they run the same eval set and stay comparable — which is the whole point of the suite. An earlier revision made the pinned column the shared benchmark experiment with `'cli'` appended to its `suite`; that experiment has no `skipEval`, so it picked up hosted-linked evals the other four skip. A CLI-owned pinned experiment fixes that and leaves this PR touching nothing outside CLI-owned paths. `skipUnlessCli` / `skipUnlessDockerless` are the only things left over from the old `experiments/_lib/`; they live in `experiments/cli/lib/`, which discovery ignores for free since it only matches `*.experiment.ts` directly under an owner directory. ## Verified, including the parts tests can't reach `format:check`, `typecheck`, and the sandbox, core, framework, `test:cli-lib`, vercel-runner and web suites all pass. Two things unit tests can't cover, checked directly instead: - **Discovery**, since it's filename-convention-based and fails silently: all 16 experiments resolve and load, `experiments/cli/lib/` is correctly not treated as an experiment, and the five columns resolve to the intended runtimes and channels (`beta`, `beta`, `beta`, `stable`, and none for the pinned baseline). - **The workflow**, which only ever runs in CI, no longer resolves channels at all — it passes through the manual `cli_stable_version` / `cli_beta_version` dispatch inputs and otherwise lets `run-vercel-evals.ts` derive the channels from the actual pairs. Pre-filling both env vars would have short-circuited that narrowing. Each run's results now record the CLI version the sandbox actually installed, read from the session's environment marker, so a `stable` row names its binary rather than just its channel. That needed `cliVersionSchema` widened — it rejected every prerelease, so a beta run's real version could not have been recorded at all. `test:cli-lib` carries `--passWithNoTests` deliberately: `evals/cli/` has no scorer tests until #281/#314/#316 land, and without the flag the script's exit code depends on which of its two paths happens to be populated. ## Note on the column names These follow the `gpt-6-luna` rename from #328. They key `cli-eval-results.json`, and no results exist yet, so there is nothing to churn — but that also means the names should settle before the suite is first run. ## Next #281, #314, #316 and #307 get re-parented onto `main` once this lands — they currently point at the retained branch of the closed #308. /cc @Rodriguespn @kanadgupta
…2400) One human plus N coding agents, each in its own git worktree, is the headline workflow for the Slim CLI launch (FDBKIN-20391). Each worktree needs its own isolated local Supabase stack with zero leakage between them. Nothing in this repo measured that. Scenario: starting from an empty sandbox, the agent creates a repo with worktrees feature-a/b/c, starts a local stack in each, and adds a different table (widgets/gadgets/gizmos) plus one seed row per worktree. No seed data and no framework changes: the agent builds everything, including the worktrees. Scorer (end state only, all via ctx.exec because the harness's built-in ctx.query/stackStatus resolve a single stack from the workspace root): - three real git worktrees on distinct branches, discovered by finding a repo in the workspace and asking `git worktree list --porcelain`, so worktrees the agent placed outside the workspace still count and three plain directories don't; - one live stack per worktree with three distinct host:port database endpoints, which is what catches aliasing/reuse; - per-table schema isolation via to_regclass against all three stacks; - at least one row per table in its home stack; - each table created by a migration file in its worktree; - an always-passing metrics check reporting fleet wall-clock across the three stacks, CLI version/channel, per-stack backend and runtime, and the number of `supabase start` invocations. Stack resolution asks the managed backend first (SUPABASE_EXPERIMENTAL_STACK=1 supabase stack status --env) and falls back to the legacy one, the same shape as build-database-002-stack-lifecycle. Verified against CLI 2.118.0-beta.37: the managed backend rejects the legacy -o flag, the DB password is random per stack, and the legacy backend cannot see managed stacks. Suite placement follows #281: `evals/cli/` with `needsDocker: false`, so the eval runs on the pinned Codex Luna baseline plus the four `codex-gpt-5.6-luna-cli-*` arms with no experiment edits. `services:` is omitted because the sandbox shim's legacy `-x` names are rejected by the managed backend. Two details come from the first CI run of an earlier draft (#295, 18 runs across six experiments): - The prompt now says the project is brand-new and asks for the worktrees as folders in this directory. The earlier "set this repo up" made 12 of 18 agents look for a repository in the empty workspace and stop to ask for one within about ten seconds. - Worktree discovery goes through git rather than a name search under the workspace. Two agents built everything correctly with worktrees at /tmp/feature-*, and the name search reported them as missing. The two runs that passed did so on the legacy backend by hand-editing project_id and every port per worktree; the metrics check records the backend so that path stays distinguishable from a managed-stack pass. Pure helpers are unit-tested in scoring.test.ts (run hint at the top of the file); the shapes in the fixtures were captured from real beta CLI output. The full scorer was also run against three hand-built native stacks on the beta CLI, with worktrees both inside and outside the workspace, and passes all checks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…entMarker()
Replace the local /tmp/supabase-eval-runtime.json reader with the
scoring context's environmentMarker(), which reads as root and
validates the marker's shape. Update the README's stale
codex-gpt-5.6-luna-cli-{stable,beta,nodaemon,absent} arm names to the
current five codex-gpt-6-luna-cli-{pinned,stable,beta,nodaemon,absent}
environments, and correct the claim that pinned is a separate shared
baseline rather than one of the five. Drop leftover references to the
removed experiments/_lib/docker-aware-local-stack.ts helper.
bdc011c to
c3c6459
Compare
1974f30 to
365772b
Compare
Tracks CLI-2400 under the Slim CLI evals RFC. Supersedes #295.
Note
Stacked on #281 and uses its
clisuite andneedsDockerfield. The diff shows Colum's commits until #281 lands; this PR's own change is the singleevals/cli/build-cli-004-worktree-stacks/folder.The problem it's solving
The headline agent workflow for the Slim CLI launch is one human plus N coding agents, each working in its own git worktree, each needing its own isolated local Supabase stack. Nothing in this repo measured whether an agent can get there: three worktrees, three stacks, zero leakage.
What the PR adds
One new eval in the
clisuite,evals/cli/build-cli-004-worktree-stacks/. Starting from an empty sandbox, the agent is asked to set up a repo with worktreesfeature-a,feature-b,feature-c, start a local stack in each, and add a different table (widgets/gadgets/gizmos) plus one sample row per worktree. No seed data, no framework changes, no experiment edits:needsDocker: falseputs it on the Docker-less arms, the interface rule puts it on the stable and beta arms, and theclisuite puts it on the pinned Codex Luna baseline.A scorer that grades the end state, never the method. Because the harness's built-in
ctx.query/stackStatusresolve a single stack from the workspace root, every check addresses stacks itself bycd-ing into each worktree:git worktree list --porcelain(so worktrees placed outside the workspace still count; three plain directories don't);to_regclassagainst all three stacks;metricscheck reporting fleet wall-clock across the three stacks, CLI version and channel, per-stack backend and runtime, and the number ofsupabase startinvocations.Stack resolution asks the managed backend first (
SUPABASE_EXPERIMENTAL_STACK=1 supabase stack status --env --output-format json) and falls back to the legacy one, the same shape #281 landed on. Environment-agnostic: the scorer never branches on which arm it runs under.Deliberate choices
experimental.stack). Whether agents can discover that is part of what's measured.services:is omitted, for the reason feat(evals): add build-database-002-stack-lifecycle CLI eval (CLI-2398) #281 documents: the sandbox shim's legacy-x gotrue,kong,...is rejected by the managed backend.supabase initpins ports inconfig.toml; the managed stack treats them as exact intents, so the second worktree's start fails withPersisted database port is unavailableuntil the ports are removed. That is the "no port surgery" promise the launch makes.What the first CI run showed (#295, 18 runs across six experiments)
Two passes, both on the legacy backend, each with a hand-edited
project_idand a full set of shifted ports per worktree. That is real signal about what agents do today, and themetricscheck records the backend so it stays distinguishable from a managed-stack pass.The 16 failures were two harness defects, both fixed here:
build-database-002-stack-lifecycle, and asks for the worktrees as folders in this directory, followingdeploy-self-hosting-001's location hint./tmp/feature-*and the scorer's name-based search under the workspace missed them. Discovery now goes through git.Verification
Verified by hand against CLI 2.118.0-beta.37 on the native runtime: three sibling worktrees get three distinct stack identities with no config edits, and a table created in one is absent from the others.
scoring.test.ts, 28 cases; fixtures captured from real beta CLI output)pnpm typecheck, Biomepnpm eval:dry -- --suite cli --experiment-suite cli→ 5 experiments × 2 evalsrun-evals-changedlabel on this PR (no Anthropic or OpenAI keys locally)🤖 Generated with Claude Code