fix: budget the real-CLI tests; destroy removes the emptied Project#106
Merged
Conversation
These two spawn the real prisma-composer binary, which resolves both /control entries and evaluates a config, and neither set a timeout — so they inherited bun test's 5000ms default. Real CI runs take 5148ms and 5747ms, so they failed roughly two runs in three across unrelated PRs, and the symptom hid the cause: the process is killed before it writes, so the assertion reports an empty stderr rather than a timeout. Not flaky — mis-budgeted. 30s of headroom; they cost ~1.7s locally, and CI is about 3x slower under contention. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
destroy tore down a stack's resources but the Project survived forever, so
hand-run stacks accumulated as empty Projects until the workspace hit its plan
limit. The CI sweeper cannot fix this: it only runs against CI's own workspace
and only matches ^<prefix>-ci-\d+$.
Mirrors the Branch cleanup one level up — destroy --stage already deletes its
Branch after a successful alchemy destroy, so destroy --production now deletes
its Project, and the API's own refusal is the guard.
Cleanup is best-effort and never throws: the destroy already succeeded, and
failing the command over a cleanup step would be worse than leaving a shell. A
Project still holding another stage's resources is kept.
Note the API contract differs from Branch delete, which was the assumption
going in: DELETE /v1/projects/{id} answers 400 "existing dependencies" — there
is no 409 in that operation's schema (only branch delete has one), so 400 is
the kept case.
Users can observe this, so per the user-facing-surface rule it lands in the
deploying guide and the skill in this PR.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
commit: |
wmadden
approved these changes
Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two unrelated fixes, both from the same incident — a dev workspace hitting
planLimitReached.1. The integration tests were mis-budgeted, not flaky
test/integration/test/cli.extension-config.test.tsspawns the realprisma-composerbinary — which resolves both/controlentries and evaluates a config — and neither test set a timeout, so both inherited bun test's 5000ms default. Real CI runs take 5148ms and 5747ms.So they failed roughly two runs in three across unrelated PRs, and the symptom hid the cause: the process is killed before it writes, so you get
which reads as a broken CLI, not a budget. Now 30s — they cost ~1.7s locally, and CI is ~3× slower under contention.
Worse than the flake itself: neither
Testnor the deploy canary is a required check, so this was a red check people learn to ignore.2.
destroy --productionnow removes the app's Projectdestroytore down a stack's resources but the Project survived forever, so hand-run stacks piled up as empty Projects until the workspace hit its plan limit. The CI sweeper can't help — it only runs against CI's own workspace and only matches^<prefix>-ci-\d+$.This mirrors the Branch cleanup one level up:
destroy --stagealready deletes its Branch after a successfulalchemy destroy(relying on the API refusing to delete a Branch with live members). Sodestroy --productionnow deletes its Project, with the API's own refusal as the guard.Cleanup is best-effort and never throws — the destroy already succeeded, and failing the command over a cleanup step would be worse than leaving a shell:
The API contract differs from the assumption going in. I expected a 409, mirroring Branch delete. It isn't:
deleteV1ProjectsByIdanswers 204/400/401/404 — there's no 409 in that operation's schema at all; only branch delete has one. Verified against@prisma/management-api-sdk's types, and consistent with the existingpostgres/Project.tsresource. So 400 is the kept case.Users can observe this, so per
.agents/rules/user-facing-surface-changes.mdcit lands indocs/guides/deploying.mdand the skill in this PR.Tests
container.test.ts—deleteProjectissues the DELETE, tolerates 404, surfaces other errors.ensure-containers.test.ts— success, 404, 400 keeps the Project and does not throw, other errors warn, missing token warns. The 400 case was mutation-checked: making it throw fails the test; reverted, green.run.test.ts—--productiondeletes the Project;--stagenever touches it; a failed destroy skips it;deploynever touches it.--productiontests that had nodeleteProjectseam and no token, so the real function's warning broke anot.toHaveBeenCalled()assertion.Green: lowering 103, CLI 95, integration 2 (1.6s/1.7s). Typecheck,
lint:deps,biomeclean. No live deploy run.🤖 Generated with Claude Code