Services get a full resource surface: deployment subgroup, create/list, and the lifecycle verbs - #162
Conversation
…s) added to the plan The S8 design discussion (2026-08-12) settled the plan's four questions: no Composer-ownership note for now, records verified compatible between Composer and the legacy deploy path, the log-ownership conflict dissolved (composer log reads the local dev daemon, not the platform), and service logs stays shelved while the operator asks the API owners whether deployment logs can be served over plain HTTP. The contract carries the command tree (deployment subgroup, old spellings deleted, five new commands) and two presenter corrections. S10 is new at operator instruction: after the surface stops moving, every skill teaching these CLIs is rewritten against v8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Four dispatches: the deployment subgroup with the presenter corrections; service list + create; the deployment lifecycle commands; closure records. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
`list-deploys`, `show-deploy`, `promote`, and `rollback` become `service deployment list|show|promote|rollback`. The old spellings are deleted with no aliases: paths, command ids, help text, presenter copy, error next-actions, and test names all move, and the group gains its own brief entry next to `service domain`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
`service deployment show` now renders the promoted endpoint domain the deploy reported instead of the deployment's preview domain, falling back to the preview domain only when the owning service cannot be found. The live deployment is derived from the service's latest deployment id alone: the local-state fallback (`readKnownLiveDeployment`) is gone from the service commands, and so is the dead scan for a provider-supplied live flag that `listDeployments` never sets. `service show` presents a live url only when the service has a live deployment, because a service that was never promoted still carries an endpoint domain and that domain does not resolve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The API owners accept HTTP for deployment logs provided live streaming can come later, so no engine socket is built and the WebSocket design shelves as the future streaming path. R-S8-3 is amended twice from D1's findings: deployment show's url follows liveness (promoted domain only for the live deployment), and local CLI live-state retires in both directions — the contract's claim that only legacy app deploy wrote it was false. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…tired `service deployment show` presented the service's promoted `appEndpointDomain` for every deployment. That address only serves the live deployment, so a non-live deployment showed a url that does not reach it, and a service that was never promoted showed a placeholder domain that resolves to nothing. The url is now the promoted address only when the shown deployment is the one the service names as latest, and the deployment's own preview domain otherwise. `service deployment promote` and `rollback` also still wrote the local live-deployment cache. Nothing in v8 reads that state any more — the read fallback went in the previous commit — so the writes are dead and go with the reads. The legacy `app` family keeps its own writes and the store helper stays for them. The local-state test for `service deployment show` did not discriminate: its fixture still named a live deployment, so the deleted lookup was never reached. It now uses a service with no latest deployment and seeds both the remembered project and the cache entry, which is what the retired code path needed to report `dep_1` live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The error a user sees when promote, rollback, or remove cannot find a service rendered the bare verb: "Service promote requires an existing service" and "rerun promote with --service <name>". Those are the spellings this slice deleted — the command is `service deployment promote` now. `resolveServiceReleaseState` already computed the mounted path for the read state's `commandName`, so that string is hoisted to one const and passed to the error as well, which also removes the duplicated mapping of "remove" to its own path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
`POST /v1/apps` was reachable only through `createBranchApp`, the deploy flow's private helper, which answers with the narrow shape that flow needs and drops the rest of the record. A `service create` command needs the whole service back — in particular whether it names a live deployment, which decides whether it has a URL worth showing. `createComputeService` is that call, returning a full `AppRecord` and whether the service already existed. `createBranchApp` now delegates to it, so the create body has one site rather than two that can drift, and the 409-means-it-already-exists behavior is shared rather than copied. The raw-record mapping the listing already did is extracted to `toAppRecord` and used by both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Until now a service could only be born as a side effect of deploying to it, and there was no way to see which services a project has without picking one first. Both are result commands on endpoints that already exist. `service list` reports every service on the resolved branch as a table, following the `project list` precedent: the human table names an absent region and an undeployed service in words, the stdout lane leaves both empty so a consumer does not have to parse them back out. `service create` sends exactly the four fields the API's create body takes — displayName, project, optional region, optional branch — and nothing else. A name already taken on the branch comes back as the existing service rather than an error, which is the `service domain add` precedent in this same group, and the result says which of the two happened. Neither command presents a live URL for a service that names no live deployment. The endpoint domain such a service already carries does not resolve until the first promote, so showing it would hand the user a dead address — the same correction D1 made to the deployment presenters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…s e2e coverage The optional service positional on `service list` fed a config target into the context helper, but listing every service selects none, so the only value the command took from that call was the project directory — which does not depend on the target. The positional's sole observable effect was failing when it named a target the config does not define. It goes, and the call passes undefined, as `service create` already did. The e2e run that removes the created service sat inside the `service list` block. `describeCommand`'s argument is the marker the coverage check reads, so a real `service remove` happy path existed while the backlog still listed that command as owed. It gets its own block and leaves AWAITING_COVERAGE. Now that it is a coverage case rather than teardown, it asserts what it removed instead of warning and returning on failure: the scratch project's own teardown deletes everything it contains, so nothing in this file has to double as cleanup. The comment above the backlog also said these commands need a deployed service, which is what kept `service remove` on the list; `service create` falsified that for the commands that only need the service to exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…nce note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The compute SDK already had startDeployment, stopDeployment and deleteDeployment; nothing in this repo reached them, because the only paths that stop or delete a deployment went through the SDK's own app-teardown and promote-switchover flows. Three thin wrappers put them beside promoteDeployment, each raising the API's message on failure the way the existing wrappers do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Two result commands on endpoints that already existed. Each resolves the service and the named deployment the way promote does, then calls the API — unless the deployment already has the status being asked for, in which case the run makes no call and warns, following promote's already-live precedent. The API refuses to start a deployment whose artifact has not been uploaded. The CLI checks no such precondition of its own: the call goes out and, if the API refuses, its message is what the user reads. A test pins that, since the temptation to guess at the precondition is exactly what the contract rules out. Both commands are excluded from e2e coverage rather than added to the backlog, per that file's rule that new commands need a test or a reason: they act on a deployment, and only `composer deploy` can produce one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The destructive verb of the subgroup, following the `service remove` precedent: the deployment id has to be typed back, or passed to --confirm, before anything is deleted. --yes alone cannot grant it. The contract asked for the live-deployment case to be settled before this error path was shaped, and it is settled: the API allows deleting the deployment a service currently points at. It detaches the endpoint, stops the VM, deletes it, and clears the service's latestDeploymentId in the same transaction. The only 409 documented on this endpoint is the stop precondition — promotion is never consulted. So the CLI adds no guard, and a test pins that deleting the live deployment succeeds. The service is left with an endpointDomain that no longer resolves, but that is already handled: every presenter added in this slice reports a live url only when latestDeploymentId is set, which is null by then. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… from the control plane's source The API tears down rather than refuses; no CLI-side guard. The undeleted endpointDomain consequence joins D4's divergence list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
start, stop and delete each report a step-started before the API call and a step-finished after it, and no test read those events on the path where the call happens. The suite stayed green if the report lines were deleted or the step was misspelled, which is the one thing these assertions exist to catch. Each happy path now asserts events[0] and events.at(-1) against the exact step, copying what promote, rollback and remove already do. The skip and refusal paths keep asserting an empty stream, which only means something next to a case that pins what a command does emit. Verified by misspelling start's step name and watching the test fail on that assertion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…-S2b-9 The `service remove` test asserting that local live-deployment state is cleared observed a key nothing had written, so it passed whether or not the clearing happened. The key is now seeded between the show and the remove run. The clearing is not dead code — the legacy `app` family still writes it for the same project — so seeding was the right option of the two offered, rather than dropping the claim. Verified by removing the clear call and watching the test fail. The backlog comment in e2e-coverage said its remaining entries act on a deployed service. That holds for `service open`, the four `service deployment *` commands and `build logs`, but not for `service show` or the five `service domain *` commands, which need only a service that exists. The comment now separates the two reasons instead of stating one that is false for six of eleven entries. Walking the acceptance list turned up the same defect one slice earlier than D3 found it: `service list` and `service create` asserted no events at all, where R-S2b-9 asks every command to assert them. Both stream nothing, and now say so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The divergence file records what an S2c user sees change: the four renames and their deleted spellings (including the command ids, which is what a script notices), the five new commands, live deriving from the platform record with local state retired in both directions, the two presenter corrections, and the narrower liveUrl rule service show actually implements. It also carries what the review rounds surfaced and chose not to fix: deployment list rows reporting live: null rather than false when nothing is live, a json-only change; --branch resolving or creating, so a typo makes a branch; create returning an existing service on 409, with the semantics flagged as an operator ruling still pending; the endpointDomain left non-resolving after the live deployment is deleted; and stop taking production offline with no consent while delete demands a typed token, which is contract-faithful but reads as an oversight now that the two verbs sit side by side. deferred.md gains the ownership-note revisit and the service logs follow-up, both with the facts that make them actionable rather than vague — no managedBy marker exists, and the transport question is answered — plus two e2e follow-ups: tightening the service-id prefix once someone can run the suite, and service show's now-unblocked happy path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… precondition Reviewer finding D4-R1-1: on a machine with no cache entry the rows were already null, byte-identical to today — the entry now scopes the change to where promote or rollback had written the cache. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
|
Warning Review limit reached
Next review available in: 35 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
Summary by CodeRabbit
WalkthroughThis change delivers the S8 service-primitives slice. It adds 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> # Conflicts: # packages/cli/tests/e2e-coverage.test.ts
Merging main restored the agent entries the branch's backlog comment rewrite carried; main's e2e suite now covers them, and the coverage check rightly refused a command both covered and owed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
commit: |
Every service command settled SERVICE.LOCAL_STATE_STALE against the real API. The service tree carries its own copy of the project listing, to avoid dragging the legacy controller's import graph, and that copy filtered by comparing the API's workspace id against the credential's. Those are the same workspace under two ids: the credential's `workspace_id` claim carries the bare form, the management API returns it `wksp_`-prefixed. The comparison matched nothing, so the listing came back empty, so the project pinned in .prisma/local.json looked like it had left the workspace. Every service command resolves a project through that function, so all of them were broken, not just create. #144 removed this exact filter from the legacy listing and explained why: a credential names one workspace and the API answers within it, so the comparison has no true-positive case and one catastrophic false positive. The copy here was written from the version that still had it. It goes the same way, along with the workspace parameter, so nothing invites it back. Nothing caught this because the fixtures wrote both sides of the comparison as `ws_1`. The session suite now has a fixture that reports the project the way the API really does, prefixed, against a bare credential claim; it fails if the filter returns. Two tests there rested on a two-workspace listing the API never produces, so they are reshaped the way #144 reshaped its equivalents: one now refuses a project the API did not return, the other proves the acting workspace comes from the token's claims by what it presents rather than by which project resolves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…found by S8's review sweep Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.drive/projects/prisma-cli-v8/plan.md:
- Around line 90-97: The settled design note in the plan still says the operator
is asking the transport question. Update the transport-status wording near the
“Design settled 2026-08-12” section to record that HTTP is acceptable per the S8
service specification and WebSocket design record, while keeping service logs
shelved for a future HTTP endpoint and avoiding any implication that the
question remains open.
In @.drive/projects/prisma-cli-v8/plans/s8-services.md:
- Line 14: Update the D1, D2, D3, and D4 headings in the plan to level-two
Markdown headings so they follow the file’s level-one heading without orphaned
level-three sections. Preserve the existing heading text and surrounding
content.
In `@packages/cli/src/v8/service/deployment-start.ts`:
- Around line 93-98: Update the result construction in
packages/cli/src/v8/service/deployment-start.ts lines 93-98 to use the
deployment status observed by a post-startDeployment read, or preserve the
pre-call status and have the presenter indicate that start was requested; do not
force "running". Apply the same change in
packages/cli/src/v8/service/deployment-stop.ts lines 89-94 after stopDeployment,
avoiding a forced "stopped" status. Use the existing lifecycle handlers and
deployment-fetching symbols.
In `@packages/cli/src/v8/service/deployment-stop.ts`:
- Around line 42-112: Extract the duplicated lifecycle logic from
serviceDeploymentStartCommand and the shown stop handler into a shared
runDeploymentStateChange helper in the deployment run-state module. Parameterize
the release command, target status, provider operation, failure summary,
diagnostic code/summary, and presentation function; preserve the existing target
resolution, deployment listing errors, selection persistence, step reporting,
result construction, and already-in-state behavior. Update both start and stop
commands to delegate to the helper.
In `@packages/cli/src/v8/service/errors.ts`:
- Around line 222-233: Update both service-level error handlers in
packages/cli/src/v8/service/errors.ts: releaseTargetRequiredError (lines
222-233) and serviceSelectionInvalidError (lines 114-131). Replace their
deployment-list next action with runCommandAction("List services", "service
list") so users are directed to the service-level listing command.
In `@packages/cli/src/v8/service/presentation.ts`:
- Around line 127-137: Update the empty-services branch in the next action
callback to avoid using the literal placeholder in the runCommandAction command;
emit service create without an argument so serviceCreateCommand reports the
missing positional, or move the placeholder text into the action reason while
keeping command executable.
In `@packages/cli/src/v8/service/target.ts`:
- Around line 234-257: Update listWorkspaceProjects to destructure and validate
the GET /v1/projects response error before mapping data. Throw the returned API
error when present, while preserving the existing project sorting and mapping
for successful responses.
In `@packages/cli/tests/v8-service-remove.test.ts`:
- Line 410: Update the assertion in the relevant v8 service removal test to read
remediation actions from frame.envelope.error.nextActions rather than
frame.envelope.nextActions, while preserving the expected action values.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7294019a-29ac-403b-9037-513451ee7ba6
📒 Files selected for processing (43)
.drive/projects/prisma-cli-v8/assets/engine/websocket-transport-design.md.drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s8.md.drive/projects/prisma-cli-v8/deferred.md.drive/projects/prisma-cli-v8/plan.md.drive/projects/prisma-cli-v8/plans/s8-services.md.drive/projects/prisma-cli-v8/specs/s8-services.mdpackages/cli/e2e/service.e2e.tspackages/cli/src/lib/app/app-provider.tspackages/cli/src/v8/cli.tspackages/cli/src/v8/service/create.tspackages/cli/src/v8/service/deployment-delete.tspackages/cli/src/v8/service/deployment-list.tspackages/cli/src/v8/service/deployment-promote.tspackages/cli/src/v8/service/deployment-rollback.tspackages/cli/src/v8/service/deployment-show.tspackages/cli/src/v8/service/deployment-start.tspackages/cli/src/v8/service/deployment-stop.tspackages/cli/src/v8/service/errors.tspackages/cli/src/v8/service/list.tspackages/cli/src/v8/service/open.tspackages/cli/src/v8/service/presentation.tspackages/cli/src/v8/service/release.tspackages/cli/src/v8/service/results.tspackages/cli/src/v8/service/show-deploy.tspackages/cli/src/v8/service/show.tspackages/cli/src/v8/service/target.tspackages/cli/tests/e2e-coverage.test.tspackages/cli/tests/v8-mount-coverage.test.tspackages/cli/tests/v8-service-create.test.tspackages/cli/tests/v8-service-deployment-delete.test.tspackages/cli/tests/v8-service-deployment-list.test.tspackages/cli/tests/v8-service-deployment-promote.test.tspackages/cli/tests/v8-service-deployment-rollback.test.tspackages/cli/tests/v8-service-deployment-show.test.tspackages/cli/tests/v8-service-deployment-start.test.tspackages/cli/tests/v8-service-deployment-stop.test.tspackages/cli/tests/v8-service-list.test.tspackages/cli/tests/v8-service-open.test.tspackages/cli/tests/v8-service-remove.test.tspackages/cli/tests/v8-service-session.test.tspackages/cli/tests/v8-service-show-deploy.test.tspackages/cli/tests/v8-service-show.test.tspackages/cli/tests/v8-service-testkit.ts
💤 Files with no reviewable changes (2)
- packages/cli/src/v8/service/show-deploy.ts
- packages/cli/tests/v8-service-show-deploy.test.ts
…patch headings increment properly Two CodeRabbit findings on #162: plan.md's S8 entry still described the transport question as open, and the dispatch plan's D-headings skipped from h1 to h3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The service tree's project listing destructured only `data`, so a 401, 403 or 500 came back as zero projects. The caller then found the pinned project missing and told the user their local binding was stale — sending them to re-link a project that was never the problem. That is the same wrong recovery path the workspace filter produced, reached from a different direction. The listing now checks the response and raises the API's own refusal, through `projectApiError`, which is what the legacy listing this mirrors already did. The fetch moves out of the `listProjects` callback to its call site. `resolveProjectTarget` runs its body inside a Result generator, and a throw from the callback surfaces as "generator body threw" rather than the API's message; listing first lets the error settle as itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ested Both handlers spread the deployment record they fetched before the call and overwrote `status` with the value being asked for. Nothing re-read afterwards, so the output stated a settled status the API had never confirmed — and the start and stop endpoints answer with an empty body, so there was nothing to confirm it with. A deployment still coming up was reported as running. The provider gains `readDeployment`, a single-deployment read that does not hunt for the owning service the way `showDeployment` does, since these callers already know which service they are acting on. Both handlers re-read after the call and present what came back. A deployment that reports "starting" is now reported as starting. This follows the direction #158 took for postgres: stop reporting what the API never said. The two handlers were near-identical and this made them more so, but every value that differs between them is decided by one discriminant, so the shared body moves to `changeDeploymentRunState(ctx, args, verb)` and the command files keep only their own help and arguments. A helper taking eight unrelated parameters would not have been worth it; one taking a verb is. The test fixtures made the same assumption the code did: their recording routes replaced the status transition the shared release fixture performs, so they would have passed against a fake API that never changed anything. They now model the transition, and each command has a case where the API reports a transitional status and the command repeats it rather than claiming the target state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Two recoveries sent the user somewhere that fails the same way they just did. When no service could be selected, `releaseTargetRequiredError` and `serviceSelectionInvalidError` both offered `service deployment list` — a command that selects a service before it lists anything. They now offer `service list`, which is the one that works without a selection. `service list` on an empty project offered a run-command carrying `service create <name>`. A consumer executes `command` verbatim, and `create` takes its name as a positional, so following that action would create a service called "<name>". Naming it is the user's decision, so it becomes a user-choice action — which is how the project family already handles a command with a placeholder in it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…lowed API refusal Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
|
@coderabbitai review |
|
Records only. Marks S8 closed in the plan and the contract's status line: shipped as #162, acceptance verified line by line at closure, with the e2e-caught workspace-filter defect and its fix recorded. One ruling stays open (`service create`'s 409-idempotent semantics — divergence file marks it operator-ruling-pending); follow-ups live in `deferred.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ipeline Operator rulings 2026-08-12: the existing publish mechanisms stand (STOP-1); S7 carries the install smoke while S6 lands in parallel (STOP-5); pin convergence waits until 8.0.0-rc.1 publishes (STOP-7). STOP-6 closed by events - #162 merged first and this branch carries the merge. versioning.md documents the verification stage between the version decision and the registry; plan.md and deferred.md record where S7 stands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…the rulings Review findings (CodeRabbit). The substantive one: a workflow rerun or re-publish dispatch met npm's refusal to publish over an existing version and died before the Release step could repair a missing Release or its assets. The publish step now treats an already-published version as done and still fails on every other error. The rest are record consistency: the rollout table's @prisma/cli row follows the next-tag ruling; the spec and dispatch plan are marked revision 3 with the final STOP dispositions instead of the working defaults they were drafted against; two markdownlint complaints (heading levels, a line starting with #162) fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The decision. The Management API already draws the seam this PR builds on: Composer produces deployments; the CLI manages them. The service commands ported for continuity kept the legacy flat shape (
service list-deploys,service show-deploy, top-levelpromote/rollback) and left real holes — noservice list, noservice create(a service could only be born as a side effect of deploying to it), and no deploymentstart/stop/deletedespite the endpoints existing. This PR reshapes the group around the resource model: aservice deploymentsubgroup owns the deployment verbs, and the five missing commands exist. The old spellings are deleted, not aliased — this CLI is pre-rc, so the renames are divergence-list entries, not compatibility debt.What changed.
service deployment list|show|promote|rollbackreplace the four flat spellings; ids, help, presenters, errors and tests moved together. The engine answers the old spellings withCLI.UNKNOWN_COMMAND.service list(GET /v1/apps) andservice create(POST /v1/apps — exactly the four create-body fields, pinned by a request-capture test).createon a taken name returns the existing service (existing: true) — semantics flagged for an operator ruling in the divergence file.service deployment start|stop(POST .../start|stop) anddelete(DELETE, typed consent per theservice removeprecedent).start's artifact-not-uploaded refusal is the API's answer presented, not a CLI-invented precondition.urlfollows liveness (promoted domain only for the live deployment, its own preview domain otherwise), andlivederives from the service record alone — the local live-state cache is retired in both directions.The parity record is
.drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s8.md; the slice contract with every ruling is.drive/projects/prisma-cli-v8/specs/s8-services.md. The new e2e coverage (service create/list/remove) has its first real run in this PR's CI — it needs the e2e service token, so it self-skips locally.Alternatives. Keeping the old spellings as aliases was rejected (doubles the grammar for four commands with no users to protect). A CLI-side guard on deleting the live deployment was rejected after reading the server's delete path — the API handles it.
service logsstays shelved deliberately: the API owners accepted serving deployment logs over plain HTTP with live streaming later, so it lands as a small follow-up shaped likebuild logsonce the endpoint serves HTTP, and the engine grows no WebSocket transport.🤖 Generated with Claude Code